Scaffolds the phase-3-enterprise OpenSpec change (proposal only — awaiting CEO approval before implementation). 6 workstreams, 95 implementation tasks: WS1: Multi-Tenancy (21 tasks) — org model, RLS, admin API WS2: W3C DIDs (12 tasks) — DID:WEB, agent DID documents, AGNTCY cards WS3: OIDC (12 tasks) — oidc-provider, ID tokens, JWKS, discovery WS4: Federation (11 tasks) — cross-instance trust, JWT assertions WS5: Webhooks (17 tasks) — subscriptions, Bull queue, HMAC, retry WS6: SOC2 (22 tasks) — encryption at rest, Merkle audit chain, controls Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
14 KiB
14 KiB
Phase 3: Enterprise — Tasks
Status: Proposed — awaiting CEO approval
CEO Approval Gates (required before implementation)
- A0.1 Approve dependency:
did-resolver+web-did-resolver(W3C DID support) - A0.2 Approve dependency:
oidc-provider(certified OIDC server library) - A0.3 Approve dependency:
bull(Redis-backed webhook delivery queue) - A0.4 Approve dependency:
kafkajs(optional Kafka adapter for webhooks) - A0.5 Approve dependency:
node-forge(column-level encryption for SOC 2)
Workstream 1: Multi-Tenancy
- 1.1 Write
src/db/migrations/006_create_organizations_table.sql— organizations table with slug, plan_tier, max_agents, max_tokens_per_month, status - 1.2 Write
src/db/migrations/007_create_organization_members_table.sql— organization_members with agent_id FK and role - 1.3 Write
src/db/migrations/008_add_organization_id_to_agents.sql— add organization_id column + index + RLS policy on agents - 1.4 Write
src/db/migrations/009_add_organization_id_to_credentials.sql— add organization_id column + index + RLS policy on credentials - 1.5 Write
src/db/migrations/010_add_organization_id_to_audit_logs.sql— add organization_id column + index + RLS policy on audit_logs - 1.6 Write
src/db/migrations/011_seed_system_organization.sql— insert default system org and backfill existing rows - 1.7 Write
src/types/organization.ts— IOrganization, ICreateOrgRequest, IUpdateOrgRequest, IOrgMember, IPaginatedOrgsResponse, OrgStatus, PlanTier interfaces - 1.8 Write
src/services/OrgService.ts— createOrg, listOrgs, getOrg, updateOrg, deleteOrg, addMember; all methods accept organizationId context - 1.9 Write
src/controllers/OrgController.ts— request parsing and validation for all 6 org endpoints - 1.10 Write
src/routes/organizations.ts— mount all 6 org endpoints with admin:orgs scope guard - 1.11 Write
src/middleware/orgContext.ts— OrgContextMiddleware: extracts organization_id from JWT and calls SET LOCAL app.organization_id before each DB query - 1.12 Update
src/middleware/auth.ts— extend ITokenPayload with organization_id claim; validate org claim on every request - 1.13 Update
src/services/AgentService.ts— add organizationId parameter to all methods; enforce org scoping on all queries - 1.14 Update
src/services/CredentialService.ts— add organizationId parameter to all methods - 1.15 Update
src/services/AuditService.ts— add organizationId parameter to all methods; include organization_id on every audit event insert - 1.16 Update
src/services/OAuth2Service.ts— include organization_id claim in issued JWT payload - 1.17 Update
src/types/index.ts— extend ITokenPayload with organization_id field - 1.18 Update OPA policy
policies/authz.rego— add organization_id check: agents can only access resources in their own organization - 1.19 Write unit tests for OrgService (CRUD, member management, org isolation)
- 1.20 Write integration tests — verify cross-org data isolation: agent in org A cannot be read with a token from org B
- 1.21 QA sign-off: RLS verified via direct DB query, org isolation test passes, zero
any, >80% coverage
Workstream 2: W3C DIDs
- 2.1 Write
src/db/migrations/012_create_agent_did_keys_table.sql— agent_did_keys table with public_key_jwk JSONB and vault_key_path - 2.2 Write
src/db/migrations/013_add_did_columns_to_agents.sql— add did and did_created_at columns to agents - 2.3 Write
src/types/did.ts— IDIDDocument, IVerificationMethod, IDIDService, IDIDResolutionResult, IAgentCard interfaces - 2.4 Write
src/services/DIDService.ts— generateDID (creates key pair, stores private in Vault, public in agent_did_keys), buildInstanceDIDDocument, buildAgentDIDDocument, buildAgentCard, buildResolutionResult - 2.5 Update
src/services/AgentService.ts— call DIDService.generateDID on every new agent registration; populate did column - 2.6 Write
src/controllers/DIDController.ts— handlers for root DID Document, per-agent DID Document, resolution endpoint, agent card - 2.7 Write
src/routes/did.ts— mount/.well-known/did.json,/agents/:id/did,/agents/:id/did/resolve,/agents/:id/did/card - 2.8 Implement Redis caching in DIDService — cache DID Documents with TTL configurable via DID_DOCUMENT_CACHE_TTL_SECONDS
- 2.9 Handle decommissioned agents — DID Document returns
deactivated: truein metadata; HTTP 410 Gone for the DID endpoint - 2.10 Write unit tests for DIDService — DID construction, key pair generation, AGNTCY card format
- 2.11 Write integration tests — GET /.well-known/did.json and GET /agents/:id/did return valid DID Documents; validated by did-resolver
- 2.12 QA sign-off: DID Core 1.0 compliance verified, private key never in response, zero
any, >80% coverage
Workstream 3: OpenID Connect (OIDC)
- 3.1 Write
src/db/migrations/014_create_oidc_keys_table.sql— oidc_keys table with kid, public_key_jwk, vault_key_path, is_current - 3.2 Write
src/services/OIDCKeyService.ts— generateSigningKeyPair (RSA-2048 or EC P-256), storeKeyInVault, getPublicJWKS, getCurrentKeyId, rotateKey - 3.3 Write
src/services/IDTokenService.ts— buildIDTokenClaims (agent claims), signIDToken using current Vault-stored key, verifyIDToken - 3.4 Write
src/types/oidc.ts— IIDTokenClaims, IJWKSResponse, IOIDCDiscoveryDocument, IAgentInfoResponse interfaces - 3.5 Write
src/controllers/OIDCController.ts— handlers for discovery, JWKS, agent-info - 3.6 Write
src/routes/oidc.ts— mount/.well-known/openid-configuration,/.well-known/jwks.json,/agent-info - 3.7 Update
src/services/OAuth2Service.ts— whenopenidscope is present in request, generate and appendid_tokento token response - 3.8 Implement JWKS caching — cache JWKS in Redis with TTL; invalidate on key rotation
- 3.9 Implement key rotation logic — on rotation, old key remains in JWKS until all tokens signed with it have expired
- 3.10 Write unit tests for OIDCKeyService and IDTokenService — key generation, token signing, JWKS format
- 3.11 Write integration tests — POST /oauth2/token with
openidscope returns id_token; validate id_token against JWKS; GET /agent-info returns correct claims - 3.12 QA sign-off: OIDC discovery document passes conformance checks, id_token verifiable,
alg: nonerejected, zeroany, >80% coverage
Workstream 4: AGNTCY Federation
- 4.1 Write
src/db/migrations/015_create_federation_partners_table.sql— federation_partners table with issuer, jwks_uri, allowed_organizations JSONB, status, expires_at - 4.2 Write
src/types/federation.ts— IFederationPartner, ICreatePartnerRequest, IVerifyFederatedTokenRequest, IFederationVerifyResult interfaces - 4.3 Write
src/services/FederationService.ts— registerPartner (validates by fetching JWKS), listPartners, deletePartner, verifyFederatedToken (fetch-or-cache JWKS, verify signature, validate claims) - 4.4 Implement JWKS caching in FederationService — store partner JWKS in Redis with TTL configurable via FEDERATION_JWKS_CACHE_TTL_SECONDS
- 4.5 Write
src/controllers/FederationController.ts— handlers for POST /federation/trust, GET /federation/partners, DELETE /federation/partners/:id, POST /federation/verify - 4.6 Write
src/routes/federation.ts— mount all 4 federation endpoints - 4.7 Implement partner expiry check — partners past
expires_atare treated as statusexpired; their tokens rejected - 4.8 Implement
allowedOrganizationsfilter — reject tokens whoseorganization_idis not in the allow list (if list is non-empty) - 4.9 Write unit tests for FederationService — trust registration, token verification (valid/expired/untrusted/tampered), JWKS cache behavior
- 4.10 Write integration tests — end-to-end: register partner, verify a valid token from that partner, verify rejection for unknown issuer
- 4.11 QA sign-off: tampered token rejected, expired partner rejected, JWKS cache verified, zero
any, >80% coverage
Workstream 5: Webhooks and Event Streaming
- 5.1 Write
src/db/migrations/016_create_webhook_subscriptions_table.sql— webhook_subscriptions with url, events JSONB, secret_hash, vault_secret_path, active, failure_count - 5.2 Write
src/db/migrations/017_create_webhook_deliveries_table.sql— webhook_deliveries with status, http_status_code, attempt_count, next_retry_at - 5.3 Write
src/types/webhook.ts— IWebhookSubscription, ICreateWebhookRequest, IWebhookDelivery, IWebhookPayload, WebhookEventType interfaces - 5.4 Write
src/services/WebhookService.ts— createSubscription (store secret in Vault), listSubscriptions, getSubscription, updateSubscription, deleteSubscription, listDeliveries - 5.5 Write
src/workers/WebhookDeliveryWorker.ts— bull queue worker: fetch subscription, compute HMAC-SHA256 signature, POST to URL with headers, update delivery status, schedule retry on failure - 5.6 Write
src/services/EventPublisher.ts— buildEventPayload, publishEvent (enqueues to bull queue; also produces to Kafka if KAFKA_BROKERS is set) - 5.7 Update
src/services/AgentService.ts— call EventPublisher.publishEvent for: agent.created, agent.updated, agent.suspended, agent.reactivated, agent.decommissioned - 5.8 Update
src/services/CredentialService.ts— call EventPublisher.publishEvent for: credential.generated, credential.rotated, credential.revoked - 5.9 Update
src/services/OAuth2Service.ts— call EventPublisher.publishEvent for: token.issued, token.revoked - 5.10 Write
src/controllers/WebhookController.ts— handlers for all 6 webhook endpoints - 5.11 Write
src/routes/webhooks.ts— mount all 6 webhook endpoints with correct scope guards - 5.12 Implement SSRF protection in WebhookDeliveryWorker — reject delivery to RFC 1918 addresses, loopback, and link-local ranges
- 5.13 Implement dead-letter handling — after max retries, set status to dead_letter and increment
agentidp_webhook_dead_letters_totalPrometheus metric - 5.14 Write
src/adapters/KafkaAdapter.ts— optional Kafka producer; activated only when KAFKA_BROKERS env var is set - 5.15 Write unit tests for WebhookService, WebhookDeliveryWorker, EventPublisher — HMAC computation, retry schedule, dead-letter logic
- 5.16 Write integration tests — create subscription, trigger an event, verify delivery; verify SSRF rejection; verify retry on 5xx response
- 5.17 QA sign-off: HMAC verifiable, SSRF protection active, retry schedule correct, dead-letter metric fires, zero
any, >80% coverage
Workstream 6: SOC 2 Type II Preparation
- 6.1 Enable
pgcryptoPostgreSQL extension insrc/db/migrations/018_enable_pgcrypto.sql - 6.2 Write
src/services/EncryptionService.ts— AES-256-CBC encrypt/decrypt using key from Vault; methods: encryptColumn, decryptColumn, isEncrypted - 6.3 Write
src/db/migrations/019_encrypt_sensitive_columns.sql— re-encrypt existing credentials.secret_hash and credentials.vault_path values using EncryptionService (migration script) - 6.4 Update
src/services/CredentialService.ts— all reads/writes of secret_hash and vault_path go through EncryptionService - 6.5 Update
src/services/WebhookService.ts— vault_secret_path column encrypted via EncryptionService - 6.6 Update
src/services/DIDService.ts— vault_key_path in agent_did_keys encrypted via EncryptionService - 6.7 Write
src/middleware/TLSEnforcementMiddleware.ts— redirect HTTP to HTTPS in production using X-Forwarded-Proto header; passthrough in development - 6.8 Register TLSEnforcementMiddleware in
src/app.ts— first in middleware stack - 6.9 Write
src/db/migrations/020_add_audit_chain_columns.sql— add hash and previous_hash columns to audit_logs; add immutability trigger; backfill chain for existing rows - 6.10 Update
src/services/AuditService.ts— compute Merkle hash on every insert: hash = SHA-256(eventId + timestamp + action + outcome + agentId + organizationId + previousHash) - 6.11 Write
src/services/AuditVerificationService.ts— verifyChain(fromDate?, toDate?): reads rows in order, recomputes hashes, returns IChainVerificationResult - 6.12 Write
src/jobs/SecretsRotationJob.ts— cron job: identify expiring credentials, emitagentidp_credentials_expiring_soon_totalmetric, renew Vault leases - 6.13 Write
src/jobs/AuditChainVerificationJob.ts— cron job: runs verifyChain on a schedule, setsagentidp_audit_chain_integrityPrometheus gauge to 1 (pass) or 0 (fail) - 6.14 Write
src/controllers/ComplianceController.ts— handlers for GET /audit/verify and GET /compliance/controls - 6.15 Write
src/routes/compliance.ts— mount /audit/verify (rate-limited) and /compliance/controls - 6.16 Write
monitoring/prometheus/alerts.yml— all 6 alerting rules: AuthFailureSpike, RateLimitExhaustion, AnomalousTokenIssuance, WebhookDeadLetterAccumulating, AuditChainIntegrityFailed, CredentialExpiryApproaching - 6.17 Update
monitoring/prometheus/prometheus.yml— add alerting rules file reference - 6.18 Write compliance documentation package:
docs/compliance/soc2-controls-matrix.md(Trust Services Criteria → controls map),docs/compliance/encryption-runbook.md(key rotation procedure),docs/compliance/audit-log-runbook.md(chain verification guide) - 6.19 Write operational runbooks:
docs/compliance/incident-response.md(security event procedures),docs/compliance/secrets-rotation.md(credential and signing key rotation guide) - 6.20 Write unit tests for EncryptionService (encrypt/decrypt round-trip, Vault key fetch) and AuditVerificationService (intact chain, tampered chain with correct brokenAtEventId)
- 6.21 Write integration tests — TLS enforcement verified, encrypted columns not plaintext-readable in direct DB query, chain verification returns correct results
- 6.22 QA sign-off: all 5 controls pass GET /compliance/controls, all 6 Prometheus alerts valid, zero
any, >80% coverage
Phase 3 Complete Criteria
All 6 workstreams done. All tasks checked. All QA gates passed. CEO reviewed. SOC 2 audit window begins.