agent-delegation-live-gate.test.mjs
162 lines 5.4 KB
Raw
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 10 days ago
1 /**
2 * Tier 3 — Live gate smoke (Phase 7C-L1): env and policy flips enable delegation handlers.
3 *
4 * Proves DELEGATION_ENABLED posture OFF by default, ON via env or policy file,
5 * and fail-closed when flipped back off mid-session.
6 */
7 import { describe, it, beforeEach, afterEach } from 'node:test';
8 import assert from 'node:assert/strict';
9 import fs from 'node:fs';
10 import path from 'node:path';
11 import { fileURLToPath } from 'node:url';
12
13 import {
14 getDelegationEnabled,
15 handleDelegationGrantMintRequest,
16 handleDelegationGrantListRequest,
17 handleDelegationGrantRevokeRequest,
18 handleDelegationAuditAppendRequest,
19 precheckApprovedDelegationProposal,
20 applyDelegationProposalToIndex,
21 seedDelegationFixtures,
22 DELEGATION_PROPOSAL_SOURCE,
23 DELEGATION_POLICY_FILE,
24 } from '../lib/agent/delegation.mjs';
25 import { createProposal } from '../hub/proposals-store.mjs';
26 import {
27 writeDelegationPolicy,
28 makeAgentIdentity,
29 makeDelegationConsent,
30 TEST_USER_ID,
31 } from './fixtures/agent/delegation-helpers.mjs';
32
33 const __dirname = path.dirname(fileURLToPath(import.meta.url));
34 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-agent-delegation-live-gate');
35
36 describe('Agent delegation — live gate (7C-L1)', () => {
37 const dataDir = path.join(tmpRoot, 'data');
38 const vaultId = 'default';
39
40 beforeEach(() => {
41 fs.rmSync(tmpRoot, { recursive: true, force: true });
42 fs.mkdirSync(dataDir, { recursive: true });
43 delete process.env.DELEGATION_ENABLED;
44 });
45
46 afterEach(() => {
47 fs.rmSync(tmpRoot, { recursive: true, force: true });
48 delete process.env.DELEGATION_ENABLED;
49 });
50
51 it('defaults off with no env and no policy file', () => {
52 assert.equal(getDelegationEnabled(dataDir), false);
53 const mint = handleDelegationGrantMintRequest({
54 dataDir,
55 vaultId,
56 consentId: 'dcons_missing',
57 actorAgentId: 'agent_tutor_test01',
58 });
59 assert.equal(mint.ok, false);
60 assert.equal(mint.code, 'DELEGATION_DISABLED');
61 });
62
63 it('env DELEGATION_ENABLED=1 enables full consent → grant → audit → revoke chain', () => {
64 process.env.DELEGATION_ENABLED = '1';
65 assert.equal(getDelegationEnabled(dataDir), true);
66
67 const identity = makeAgentIdentity({ agentId: 'agent_live_gate01' });
68 const consentBody = makeDelegationConsent({
69 consentId: 'dcons_live_gate01',
70 agentId: identity.agent_id,
71 });
72 seedDelegationFixtures(dataDir, vaultId, identity);
73 const proposal = createProposal(dataDir, {
74 path: 'meta/delegation/consents/live-gate.md',
75 body: JSON.stringify(consentBody),
76 intent: 'delegation_consent_create',
77 source: DELEGATION_PROPOSAL_SOURCE,
78 vault_id: vaultId,
79 proposed_by: TEST_USER_ID,
80 delegation_meta: { record_kind: 'delegation_consent', consent_id: consentBody.consent_id },
81 });
82 const precheck = precheckApprovedDelegationProposal(dataDir, proposal, { author: TEST_USER_ID });
83 assert.equal(precheck.ok, true);
84 applyDelegationProposalToIndex(dataDir, precheck);
85
86 const mint = handleDelegationGrantMintRequest({
87 dataDir,
88 vaultId,
89 consentId: consentBody.consent_id,
90 actorAgentId: identity.agent_id,
91 taskRef: 'task_hw_week3',
92 });
93 assert.equal(mint.ok, true);
94 assert.ok(mint.payload.bearer?.startsWith('dgrnt_bearer_'));
95
96 const audit = handleDelegationAuditAppendRequest({
97 dataDir,
98 vaultId,
99 grantId: mint.payload.grant.grant_id,
100 actorAgentId: identity.agent_id,
101 principalRef: consentBody.principal_ref,
102 action: 'advance_step',
103 evidenceRefs: ['proposal:prop_live_gate'],
104 taskRef: 'task_hw_week3',
105 });
106 assert.equal(audit.ok, true);
107
108 const list = handleDelegationGrantListRequest({ dataDir, vaultId });
109 assert.equal(list.ok, true);
110 assert.equal(JSON.stringify(list.payload).includes('bearer'), false);
111
112 const revoke = handleDelegationGrantRevokeRequest({
113 dataDir,
114 vaultId,
115 grantId: mint.payload.grant.grant_id,
116 });
117 assert.equal(revoke.ok, true);
118
119 const auditAfterRevoke = handleDelegationAuditAppendRequest({
120 dataDir,
121 vaultId,
122 grantId: mint.payload.grant.grant_id,
123 actorAgentId: identity.agent_id,
124 principalRef: consentBody.principal_ref,
125 action: 'advance_step',
126 });
127 assert.equal(auditAfterRevoke.ok, false);
128 });
129
130 it('policy file enabled:true enables when env unset', () => {
131 writeDelegationPolicy(dataDir);
132 assert.equal(getDelegationEnabled(dataDir), true);
133 });
134
135 it('env DELEGATION_ENABLED=0 overrides policy file enabled:true', () => {
136 writeDelegationPolicy(dataDir);
137 process.env.DELEGATION_ENABLED = '0';
138 assert.equal(getDelegationEnabled(dataDir), false);
139 });
140
141 it('flip env off after seed denies new mints', () => {
142 writeDelegationPolicy(dataDir);
143 const identity = makeAgentIdentity({ agentId: 'agent_flip_off01' });
144 const consent = makeDelegationConsent({
145 consentId: 'dcons_flip_off01',
146 agentId: identity.agent_id,
147 });
148 seedDelegationFixtures(dataDir, vaultId, identity, consent);
149
150 process.env.DELEGATION_ENABLED = '0';
151 fs.rmSync(path.join(dataDir, DELEGATION_POLICY_FILE));
152 assert.equal(getDelegationEnabled(dataDir), false);
153
154 const mint = handleDelegationGrantMintRequest({
155 dataDir,
156 vaultId,
157 consentId: consent.consent_id,
158 actorAgentId: identity.agent_id,
159 });
160 assert.equal(mint.code, 'DELEGATION_DISABLED');
161 });
162 });
File History 1 commit
sha256:700fafdd1afa490919f9515d660ca6e75456bcd5bb67513abcd8757a634c01f6 docs: record AIP-b SD-21 land (KN #308) Human 10 days ago