hub-delegation-self-hosted-route.test.mjs
80 lines 3.3 KB
Raw
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 10 days ago
1 /**
2 * Self-hosted Hub delegation routes — contract tests (Phase 7C-L1).
3 */
4 import { describe, it } from 'node:test';
5 import assert from 'node:assert/strict';
6 import fs from 'node:fs';
7 import path from 'node:path';
8 import { fileURLToPath } from 'node:url';
9
10 const __dirname = path.dirname(fileURLToPath(import.meta.url));
11 const repoRoot = path.dirname(__dirname);
12
13 function readRepoFile(relativePath) {
14 return fs.readFileSync(path.join(repoRoot, relativePath), 'utf8');
15 }
16
17 describe('self-hosted Hub delegation routes', () => {
18 it('unit: registers delegation routes gated by DELEGATION_ENABLED handlers', () => {
19 const src = readRepoFile('hub/server.mjs');
20 assert.match(src, /Agent delegation \(Phase 7C-6\)/);
21 assert.match(src, /handleAgentIdentityRegisterProposeRequest/);
22 assert.match(src, /handleDelegationConsentProposeRequest/);
23 assert.match(src, /handleDelegationGrantMintRequest/);
24 assert.match(src, /handleDelegationAuditAppendRequest/);
25 assert.match(src, /app\.post\('\/api\/v1\/agents\/identities'/);
26 assert.match(src, /app\.post\('\/api\/v1\/delegation\/consents'/);
27 assert.match(src, /app\.post\('\/api\/v1\/delegation\/grants'/);
28 assert.match(src, /app\.post\('\/api\/v1\/delegation\/audit'/);
29 });
30
31 it('integration: self-hosted hub approve path wires delegation apply with author', () => {
32 const src = readRepoFile('hub/server.mjs');
33 assert.match(src, /precheckApprovedDelegationProposal\(config\.data_dir, proposal, \{\s*author:/);
34 assert.match(src, /proposal\.proposed_by/);
35 assert.match(src, /applyDelegationProposalToIndex/);
36 });
37
38 it('integration: bridge registers canister proposal create + apply-approved routes', () => {
39 const bridgeRoutes = readRepoFile('hub/bridge/delegation-routes.mjs');
40 assert.match(bridgeRoutes, /createDelegationProposalOnCanister/);
41 assert.match(bridgeRoutes, /applyApprovedDelegationProposalFromCanister/);
42 assert.match(bridgeRoutes, /\/api\/v1\/delegation\/proposals\/:proposal_id\/apply-approved/);
43 });
44
45 it('integration: gateway wires post-approve delegation apply hook', () => {
46 const gw = readRepoFile('hub/gateway/server.mjs');
47 assert.match(gw, /maybeApplyHostedDelegationAfterApprove/);
48 assert.match(gw, /mergeDelegationApplyIntoApproveResponse/);
49 });
50
51 it('end-to-end: OpenAPI documents delegation endpoints', () => {
52 const api = readRepoFile('docs/openapi.yaml');
53 assert.match(api, /\/agents\/identities:/);
54 assert.match(api, /\/delegation\/consents:/);
55 assert.match(api, /\/delegation\/grants:/);
56 assert.match(api, /\/delegation\/audit:/);
57 assert.match(api, /DELEGATION_ENABLED/);
58 });
59
60 it('security: routes require authenticated role; audit uses session principal fallback', () => {
61 const src = readRepoFile('hub/server.mjs');
62 assert.match(
63 src,
64 /app\.post\('\/api\/v1\/delegation\/audit', requireRole\('viewer', 'editor', 'admin', 'evaluator'\)/,
65 );
66 assert.match(src, /hashPrincipalRef\(req\.user\?\.sub/);
67 });
68
69 it('security: SEC-KN-5 grant mint is admin-only (viewer cannot mint bearer authority)', () => {
70 const src = readRepoFile('hub/server.mjs');
71 assert.match(
72 src,
73 /app\.post\('\/api\/v1\/delegation\/grants', requireRole\('admin'\)/,
74 );
75 assert.doesNotMatch(
76 src,
77 /app\.post\('\/api\/v1\/delegation\/grants', requireRole\('viewer'/,
78 );
79 });
80 });
File History 1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 10 days ago