agent-delegation-live-gate.test.mjs
160 lines 5.3 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 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 } from './fixtures/agent/delegation-helpers.mjs';
31
32 const __dirname = path.dirname(fileURLToPath(import.meta.url));
33 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-agent-delegation-live-gate');
34
35 describe('Agent delegation — live gate (7C-L1)', () => {
36 const dataDir = path.join(tmpRoot, 'data');
37 const vaultId = 'default';
38
39 beforeEach(() => {
40 fs.rmSync(tmpRoot, { recursive: true, force: true });
41 fs.mkdirSync(dataDir, { recursive: true });
42 delete process.env.DELEGATION_ENABLED;
43 });
44
45 afterEach(() => {
46 fs.rmSync(tmpRoot, { recursive: true, force: true });
47 delete process.env.DELEGATION_ENABLED;
48 });
49
50 it('defaults off with no env and no policy file', () => {
51 assert.equal(getDelegationEnabled(dataDir), false);
52 const mint = handleDelegationGrantMintRequest({
53 dataDir,
54 vaultId,
55 consentId: 'dcons_missing',
56 actorAgentId: 'agent_tutor_test01',
57 });
58 assert.equal(mint.ok, false);
59 assert.equal(mint.code, 'DELEGATION_DISABLED');
60 });
61
62 it('env DELEGATION_ENABLED=1 enables full consent → grant → audit → revoke chain', () => {
63 process.env.DELEGATION_ENABLED = '1';
64 assert.equal(getDelegationEnabled(dataDir), true);
65
66 const identity = makeAgentIdentity({ agentId: 'agent_live_gate01' });
67 const consentBody = makeDelegationConsent({
68 consentId: 'dcons_live_gate01',
69 agentId: identity.agent_id,
70 });
71 seedDelegationFixtures(dataDir, vaultId, identity);
72 const proposal = createProposal(dataDir, {
73 path: 'meta/delegation/consents/live-gate.md',
74 body: JSON.stringify(consentBody),
75 intent: 'delegation_consent_create',
76 source: DELEGATION_PROPOSAL_SOURCE,
77 vault_id: vaultId,
78 delegation_meta: { record_kind: 'delegation_consent', consent_id: consentBody.consent_id },
79 });
80 const precheck = precheckApprovedDelegationProposal(dataDir, proposal);
81 assert.equal(precheck.ok, true);
82 applyDelegationProposalToIndex(dataDir, precheck);
83
84 const mint = handleDelegationGrantMintRequest({
85 dataDir,
86 vaultId,
87 consentId: consentBody.consent_id,
88 actorAgentId: identity.agent_id,
89 taskRef: 'task_hw_week3',
90 });
91 assert.equal(mint.ok, true);
92 assert.ok(mint.payload.bearer?.startsWith('dgrnt_bearer_'));
93
94 const audit = handleDelegationAuditAppendRequest({
95 dataDir,
96 vaultId,
97 grantId: mint.payload.grant.grant_id,
98 actorAgentId: identity.agent_id,
99 principalRef: consentBody.principal_ref,
100 action: 'advance_step',
101 evidenceRefs: ['proposal:prop_live_gate'],
102 taskRef: 'task_hw_week3',
103 });
104 assert.equal(audit.ok, true);
105
106 const list = handleDelegationGrantListRequest({ dataDir, vaultId });
107 assert.equal(list.ok, true);
108 assert.equal(JSON.stringify(list.payload).includes('bearer'), false);
109
110 const revoke = handleDelegationGrantRevokeRequest({
111 dataDir,
112 vaultId,
113 grantId: mint.payload.grant.grant_id,
114 });
115 assert.equal(revoke.ok, true);
116
117 const auditAfterRevoke = handleDelegationAuditAppendRequest({
118 dataDir,
119 vaultId,
120 grantId: mint.payload.grant.grant_id,
121 actorAgentId: identity.agent_id,
122 principalRef: consentBody.principal_ref,
123 action: 'advance_step',
124 });
125 assert.equal(auditAfterRevoke.ok, false);
126 });
127
128 it('policy file enabled:true enables when env unset', () => {
129 writeDelegationPolicy(dataDir);
130 assert.equal(getDelegationEnabled(dataDir), true);
131 });
132
133 it('env DELEGATION_ENABLED=0 overrides policy file enabled:true', () => {
134 writeDelegationPolicy(dataDir);
135 process.env.DELEGATION_ENABLED = '0';
136 assert.equal(getDelegationEnabled(dataDir), false);
137 });
138
139 it('flip env off after seed denies new mints', () => {
140 writeDelegationPolicy(dataDir);
141 const identity = makeAgentIdentity({ agentId: 'agent_flip_off01' });
142 const consent = makeDelegationConsent({
143 consentId: 'dcons_flip_off01',
144 agentId: identity.agent_id,
145 });
146 seedDelegationFixtures(dataDir, vaultId, identity, consent);
147
148 process.env.DELEGATION_ENABLED = '0';
149 fs.rmSync(path.join(dataDir, DELEGATION_POLICY_FILE));
150 assert.equal(getDelegationEnabled(dataDir), false);
151
152 const mint = handleDelegationGrantMintRequest({
153 dataDir,
154 vaultId,
155 consentId: consent.consent_id,
156 actorAgentId: identity.agent_id,
157 });
158 assert.equal(mint.code, 'DELEGATION_DISABLED');
159 });
160 });
File History 2 commits
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago
sha256:d8c648b20a4d53b2673c5c082ee7edfa7b2fc9b11080832da1f38807b6bf940b fix(7C-L1b): route hosted delegation proposals through cani… Human minor 30 days ago