sec-seam-delegation-hosted-consent-propose.test.mjs
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6
docs: record AIP-b SD-21 land (KN #308)
Human
10 days ago
| 1 | /** |
| 2 | * SEC-SEAM-1 / L-SEAM — hosted delegation consent propose with session-bound learner JWT. |
| 3 | * |
| 4 | * Proves delegate vault-map restriction does not block type:'session' POST |
| 5 | * /api/v1/delegation/consents on Business (F26 DELEGATION-WRITE smoke path). |
| 6 | */ |
| 7 | |
| 8 | import fs from 'node:fs'; |
| 9 | import path from 'node:path'; |
| 10 | import { describe, it } from 'node:test'; |
| 11 | import assert from 'node:assert/strict'; |
| 12 | import { fileURLToPath } from 'node:url'; |
| 13 | |
| 14 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 15 | const ROOT = path.resolve(__dirname, '..'); |
| 16 | |
| 17 | function readRepo(rel) { |
| 18 | return fs.readFileSync(path.join(ROOT, rel), 'utf8'); |
| 19 | } |
| 20 | |
| 21 | describe('SEC-SEAM delegation hosted consent propose — unit', () => { |
| 22 | it('delegation-routes passes sessionBound into createDelegationProposalOnCanister', () => { |
| 23 | const src = readRepo('hub/bridge/delegation-routes.mjs'); |
| 24 | assert.match(src, /function sessionBoundFromReq\(req\)/); |
| 25 | assert.match(src, /isSessionBoundActor/); |
| 26 | assert.match( |
| 27 | src, |
| 28 | /app\.post\('\/api\/v1\/delegation\/consents'[\s\S]*sessionBound: sessionBoundFromReq\(req\)/, |
| 29 | ); |
| 30 | assert.match(src, /sessionBound: ctx\.sessionBound === true/); |
| 31 | assert.match(src, /proposed_by: ctx\.actorUid/); |
| 32 | }); |
| 33 | |
| 34 | it('bridge server expands vault allowlist for session-bound actors', () => { |
| 35 | const src = readRepo('hub/bridge/server.mjs'); |
| 36 | assert.match(src, /resolveAllowedVaultIdsForSessionBoundActor/); |
| 37 | assert.match(src, /bridgeSessionBoundFromReq/); |
| 38 | assert.match(src, /isSessionBoundActor/); |
| 39 | }); |
| 40 | |
| 41 | it('delegation-hosted-proposal augments canister create body (session + pending eval)', () => { |
| 42 | const src = readRepo('lib/agent/delegation-hosted-proposal.mjs'); |
| 43 | assert.match(src, /augmentProposalCreateRequestBody/); |
| 44 | assert.match(src, /sessionBound: opts\.sessionBound === true/); |
| 45 | assert.match(src, /evaluation_status = 'pending'/); |
| 46 | assert.match(src, /source: DELEGATION_PROPOSAL_SOURCE/); |
| 47 | }); |
| 48 | |
| 49 | it('delegation-routes logs consent propose failures with Hub code', () => { |
| 50 | const src = readRepo('hub/bridge/delegation-routes.mjs'); |
| 51 | assert.match(src, /POST \/api\/v1\/delegation\/consents/); |
| 52 | assert.match(src, /vault context denied/); |
| 53 | assert.match(src, /delegation route error/); |
| 54 | }); |
| 55 | }); |
| 56 | |
| 57 | describe('SEC-SEAM delegation hosted consent propose — integration (handler)', () => { |
| 58 | it('consent propose handler succeeds when delegate agent is active in vault', async () => { |
| 59 | const os = await import('node:os'); |
| 60 | const { writeDelegationPolicy, makeAgentIdentity } = await import('./fixtures/agent/delegation-helpers.mjs'); |
| 61 | const { seedDelegationFixtures, handleDelegationConsentProposeRequest } = await import( |
| 62 | '../lib/agent/delegation.mjs' |
| 63 | ); |
| 64 | |
| 65 | const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'kt-sec-seam-delegation-')); |
| 66 | writeDelegationPolicy(dataDir); |
| 67 | process.env.DELEGATION_ENABLED = '1'; |
| 68 | const identity = makeAgentIdentity({ |
| 69 | agentId: 'agent_l1smoke01', |
| 70 | kind: 'delegate', |
| 71 | scopeCeiling: 'personal', |
| 72 | }); |
| 73 | seedDelegationFixtures(dataDir, 'Business', identity); |
| 74 | |
| 75 | const result = await handleDelegationConsentProposeRequest({ |
| 76 | dataDir, |
| 77 | vaultId: 'Business', |
| 78 | userId: 'google:learner-smoke', |
| 79 | delegateAgentId: 'agent_l1smoke01', |
| 80 | scope: 'personal', |
| 81 | createProposal: async (_dir, input) => ({ |
| 82 | proposal_id: 'prop_sec_seam_delegation_01', |
| 83 | path: input.path, |
| 84 | status: 'proposed', |
| 85 | vault_id: input.vault_id, |
| 86 | }), |
| 87 | }); |
| 88 | |
| 89 | assert.equal(result.ok, true); |
| 90 | assert.equal(result.payload.intent, 'delegation_consent_create'); |
| 91 | assert.match(String(result.payload.proposal_id), /^prop_/); |
| 92 | |
| 93 | fs.rmSync(dataDir, { recursive: true, force: true }); |
| 94 | delete process.env.DELEGATION_ENABLED; |
| 95 | }); |
| 96 | }); |
File History
1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6
docs: record AIP-b SD-21 land (KN #308)
Human
10 days ago