This commit is contained in:
+55
-1
@@ -1,5 +1,5 @@
|
||||
import express, { Request, Response, NextFunction, RequestHandler } from 'express';
|
||||
import { existsSync } from 'fs';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { join, resolve, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { Repository, BrowserSessionRepo } from '../db/repository.js';
|
||||
@@ -67,6 +67,12 @@ import type { AuthConfig } from '../config.js';
|
||||
import { attachConsoleWs } from './console-ws-api.js';
|
||||
import { mountGateway, type GatewayMountHandle } from './gateway-mount.js';
|
||||
import { readGatewayConfig } from '../gateway/config.js';
|
||||
import { createA2aOidcProvider, mountA2aOidc } from './a2a/oidc-provider.js';
|
||||
import { createA2aClientsAdminRouter } from './a2a/a2a-clients-admin-api.js';
|
||||
import { createA2aRouter, createSpaceA2aAdminRouter } from './a2a/a2a-api.js';
|
||||
import { mountA2aRequestHandler } from './a2a/request-handler.js';
|
||||
import { A2aTaskReconciler } from './a2a/reconciler.js';
|
||||
import { createUserDelegationsRouter, createAdminDelegationsRouter } from './a2a/delegations-api.js';
|
||||
import { createAdminGatewayStatusRouter } from './admin-gateway-status-api.js';
|
||||
import { createServer as createHttpsServer } from 'https';
|
||||
import { X509Certificate } from 'crypto';
|
||||
@@ -492,6 +498,53 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
// 横断(全スペース)カレンダー: GET /api/calendar/cross
|
||||
app.use('/api/calendar', createCrossCalendarApi({ repo, authActive }));
|
||||
|
||||
// --- A2A OAuth2 Authorization Server ---
|
||||
const a2aCfg = (loadConfig() as any).a2a ?? {};
|
||||
if (a2aCfg.enabled) {
|
||||
if (!authActive) {
|
||||
logger.warn('[a2a-oidc] a2a.enabled but auth is not active; consent flow requires login and will reject all requests');
|
||||
}
|
||||
try {
|
||||
const sessionSecretPath = loadConfig()?.secrets?.sessionSecretPath ?? DEFAULT_SESSION_SECRET_PATH;
|
||||
const cookieKeys = [readFileSync(sessionSecretPath, 'utf-8').trim()];
|
||||
const secretsDir = dirname(resolve(sessionSecretPath));
|
||||
const provider = createA2aOidcProvider({
|
||||
repo,
|
||||
secretsDir,
|
||||
issuer: a2aCfg.issuer,
|
||||
resourceAudience: a2aCfg.resourceAudience,
|
||||
cookieKeys,
|
||||
});
|
||||
mountA2aOidc(app, provider, { repo, resourceAudience: a2aCfg.resourceAudience });
|
||||
app.use('/api/admin/a2a/clients', express.json(), requireAdmin, createA2aClientsAdminRouter(repo, authActive));
|
||||
// Agent Card ルータ (base card = public, extended card = self-authenticates via Bearer)
|
||||
// baseUrl は resourceAudience の origin から導く(例: https://maestro.example.com/a2a → https://maestro.example.com)
|
||||
// version は '1.0.0' 固定(生成済みバージョンファイルが存在しないため定数を使用)
|
||||
const a2aBaseUrl = (() => {
|
||||
try { return new URL(String(a2aCfg.resourceAudience)).origin; } catch { return String(a2aCfg.issuer); }
|
||||
})();
|
||||
app.use(createA2aRouter({ provider, repo, baseUrl: a2aBaseUrl, issuer: String(a2aCfg.issuer), version: '1.0.0' }));
|
||||
// JSON-RPC エンドポイント /a2a(SDK DefaultRequestHandler 経由)
|
||||
// /a2a は /api 配下でないため requireAuth に掛からない。認証は UserBuilder が担う。
|
||||
mountA2aRequestHandler(app, { provider, repo, baseUrl: a2aBaseUrl, issuer: String(a2aCfg.issuer), version: '1.0.0' });
|
||||
// bridge は単一プロセス前提。複数プロセスが同一 DB を共有する構成では
|
||||
// lease が必要になる(将来課題)。
|
||||
const a2aReconciler = new A2aTaskReconciler({ repo });
|
||||
a2aReconciler.start();
|
||||
registerShutdownHook('a2a-reconciler', async () => { a2aReconciler.stop(); });
|
||||
logger.info('[a2a] task reconciler started');
|
||||
// スペース A2A スキル許可リスト管理 API (/api/local は requireAuth 配下)
|
||||
app.use('/api/local/spaces', createSpaceA2aAdminRouter(repo, authActive));
|
||||
// A2A 委任一覧・取消 API
|
||||
// /api/local は L329 で requireAuth 済みのため追加ゲート不要
|
||||
app.use('/api/local/a2a/delegations', express.json(), createUserDelegationsRouter(repo, authActive));
|
||||
app.use('/api/admin/a2a/delegations', express.json(), requireAdmin, createAdminDelegationsRouter(repo, authActive));
|
||||
logger.info('[a2a-oidc] a2a authorization server enabled');
|
||||
} catch (err) {
|
||||
logger.warn(`[a2a-oidc] failed to mount a2a authorization server: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Subtask files API (listing MUST come before wildcard) ---
|
||||
mountSubtaskFilesApi(app, repo);
|
||||
|
||||
@@ -723,6 +776,7 @@ export function createCoreServer(opts: CoreServerOptions): {
|
||||
dataRoot: userFolderRoot,
|
||||
worktreeDir: loadConfig().worktreeDir ?? './data/worktrees',
|
||||
authActive,
|
||||
getPythonPackagesConfig: () => loadConfig().pythonPackages,
|
||||
}));
|
||||
|
||||
// BackendStatusRegistry singleton — probes every configured worker
|
||||
|
||||
Reference in New Issue
Block a user