feat(phase-5): WS2 — A2A Authorization

Implements agent-to-agent delegation chains:
- Migration 024: delegation_chains table with HMAC signature, TTL, revocation
- DelegationCrypto: HMAC-SHA256 sign/verify, UUID token generation
- DelegationService: create (scope subset validation, self-delegation guard,
  same-tenant delegatee check), verify (returns valid: false on expired/revoked,
  never throws), revoke (delegator-only, conflict guard)
- DelegationController + router at /oauth2/token/delegate (POST/DELETE) and
  /oauth2/token/verify-delegation (POST)
- Feature-flagged behind A2A_ENABLED env var (default on)
- Prometheus metrics: delegations_created/verified/revoked_total
- 33 tests (unit + integration): all pass, DelegationService 87.5%+ branch coverage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SentryAgent.ai Developer
2026-04-03 02:49:36 +00:00
parent 0506bc1b8e
commit 16497706d3
9 changed files with 1339 additions and 0 deletions

52
src/routes/delegation.ts Normal file
View File

@@ -0,0 +1,52 @@
/**
* A2A Delegation routes for SentryAgent.ai AgentIdP.
* All three delegation endpoints require Bearer token authentication.
*/
import { Router, RequestHandler } from 'express';
import { DelegationController } from '../controllers/DelegationController.js';
import { asyncHandler } from '../utils/asyncHandler.js';
/**
* Creates and returns the Express router for A2A delegation endpoints.
*
* Routes:
* POST /oauth2/token/delegate — create a delegation chain
* POST /oauth2/token/verify-delegation — verify a delegation token
* DELETE /oauth2/token/delegate/:chainId — revoke a delegation chain
*
* All routes are protected by the JWT authentication middleware.
*
* @param controller - The delegation controller instance.
* @param authMiddleware - The JWT authentication middleware.
* @returns Configured Express router.
*/
export function createDelegationRouter(
controller: DelegationController,
authMiddleware: RequestHandler,
): Router {
const router = Router();
// POST /oauth2/token/delegate — authenticated; creates a delegation chain
router.post(
'/oauth2/token/delegate',
authMiddleware,
asyncHandler(controller.createDelegation.bind(controller)),
);
// POST /oauth2/token/verify-delegation — authenticated; verifies a delegation token
router.post(
'/oauth2/token/verify-delegation',
authMiddleware,
asyncHandler(controller.verifyDelegation.bind(controller)),
);
// DELETE /oauth2/token/delegate/:chainId — authenticated; revokes a delegation chain
router.delete(
'/oauth2/token/delegate/:chainId',
authMiddleware,
asyncHandler(controller.revokeDelegation.bind(controller)),
);
return router;
}