loop-pass-audit-unit.test.mjs
139 lines 4.1 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 10 days ago
1 /**
2 * Loop pass audit mirror — unit + security tiers.
3 *
4 * @see lib/task/loop-pass-audit.mjs
5 */
6 import { describe, it, beforeEach, afterEach } from 'node:test';
7 import assert from 'node:assert/strict';
8 import fs from 'node:fs';
9 import path from 'node:path';
10 import { fileURLToPath } from 'node:url';
11 import {
12 handleLoopPassAuditAppendRequest,
13 checkLoopPassAuditMirrorGate,
14 validateLoopPassAuditRecord,
15 LOOP_PASS_AUDIT_SCHEMA,
16 } from '../lib/task/loop-pass-audit.mjs';
17
18 const __dirname = path.dirname(fileURLToPath(import.meta.url));
19 const tmpRoot = path.join(__dirname, 'fixtures', 'tmp-loop-pass-audit');
20 const vaultId = 'vault-loop-audit';
21
22 function sampleBody(passId) {
23 return {
24 pass_id: passId,
25 loop_id: 'loop_school_trip',
26 instance_task_id: null,
27 graph_id: 'graph_school_trip',
28 outcome: 'scheduled',
29 boundary_policy: 'observe_only',
30 context_refs: [{ kind: 'loop', ref: 'loop_school_trip' }],
31 scooling_pass_audit_ref: passId,
32 occurred_at: '2026-06-25T12:00:00.000Z',
33 scope: 'personal',
34 };
35 }
36
37 describe('loop pass audit — unit', () => {
38 let dataDir;
39
40 beforeEach(() => {
41 fs.rmSync(tmpRoot, { recursive: true, force: true });
42 dataDir = path.join(tmpRoot, 'data');
43 fs.mkdirSync(dataDir, { recursive: true });
44 delete process.env.LOOP_PASS_AUDIT_MIRROR_ENABLED;
45 });
46
47 afterEach(() => {
48 fs.rmSync(tmpRoot, { recursive: true, force: true });
49 delete process.env.LOOP_PASS_AUDIT_MIRROR_ENABLED;
50 });
51
52 it('gate defaults off', () => {
53 const gate = checkLoopPassAuditMirrorGate(dataDir);
54 assert.equal(gate.ok, false);
55 assert.equal(gate.code, 'LOOP_PASS_AUDIT_MIRROR_DISABLED');
56 });
57
58 it('append succeeds when gate on and is idempotent on pass_id', () => {
59 process.env.LOOP_PASS_AUDIT_MIRROR_ENABLED = '1';
60 const passId = 'pass_unit_idempotent';
61 const first = handleLoopPassAuditAppendRequest({
62 dataDir,
63 vaultId,
64 body: sampleBody(passId),
65 });
66 assert.equal(first.ok, true);
67 if (!first.ok) return;
68 assert.equal(first.idempotent, false);
69 assert.equal(first.payload.schema, LOOP_PASS_AUDIT_SCHEMA);
70
71 const second = handleLoopPassAuditAppendRequest({
72 dataDir,
73 vaultId,
74 body: sampleBody(passId),
75 });
76 assert.equal(second.ok, true);
77 if (!second.ok) return;
78 assert.equal(second.idempotent, true);
79 assert.equal(second.payload.audit_id, first.payload.audit_id);
80 });
81
82 it('validate rejects note bodies in context refs shape', () => {
83 const bad = validateLoopPassAuditRecord({
84 schema: LOOP_PASS_AUDIT_SCHEMA,
85 audit_id: 'lpau_bad',
86 pass_id: 'pass_bad',
87 loop_id: 'loop_school_trip',
88 instance_task_id: null,
89 graph_id: null,
90 outcome: 'idle',
91 boundary_policy: 'observe_only',
92 context_refs: [{ kind: 'note', ref: 'note:../../etc/passwd' }],
93 scooling_pass_audit_ref: 'pass_bad',
94 occurred_at: '2026-06-25T12:00:00.000Z',
95 vault_id: vaultId,
96 scope: 'personal',
97 });
98 assert.equal(bad.ok, false);
99 });
100 });
101
102 describe('loop pass audit — security', () => {
103 let dataDir;
104
105 beforeEach(() => {
106 fs.rmSync(tmpRoot, { recursive: true, force: true });
107 dataDir = path.join(tmpRoot, 'data-sec');
108 fs.mkdirSync(dataDir, { recursive: true });
109 process.env.LOOP_PASS_AUDIT_MIRROR_ENABLED = '1';
110 });
111
112 afterEach(() => {
113 fs.rmSync(tmpRoot, { recursive: true, force: true });
114 delete process.env.LOOP_PASS_AUDIT_MIRROR_ENABLED;
115 });
116
117 it('refuses append when gate off even if env unset mid-request path', () => {
118 delete process.env.LOOP_PASS_AUDIT_MIRROR_ENABLED;
119 const result = handleLoopPassAuditAppendRequest({
120 dataDir,
121 vaultId,
122 body: sampleBody('pass_sec_gate'),
123 });
124 assert.equal(result.ok, false);
125 if (result.ok) return;
126 assert.equal(result.code, 'LOOP_PASS_AUDIT_MIRROR_DISABLED');
127 });
128
129 it('rejects invalid pass_id without persistence', () => {
130 const result = handleLoopPassAuditAppendRequest({
131 dataDir,
132 vaultId,
133 body: { ...sampleBody('not_a_pass'), pass_id: 'forged' },
134 });
135 assert.equal(result.ok, false);
136 if (result.ok) return;
137 assert.equal(result.code, 'BAD_REQUEST');
138 });
139 });
File History 1 commit
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago