deadbyte-mcp 0.15.44 → 0.15.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MANIFEST.SHA256 +86 -138
- package/PROVENANCE.json +35 -18
- package/README.txt +22 -21
- package/RELEASE.json +369 -334
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +27 -17
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +1871 -1769
- package/controller/deadbyte-desktop-policy.json +6 -6
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R68-COMPAT-HOST-EXEC-CANDIDATE.md +63 -0
- package/docs/R69-LIVE-OUTCOME-R70-POLICY-TRANSFER.md +136 -0
- package/docs/R70-CODING-DIGEST-SUPERVISOR-CHECKPOINT-20261013.md +42 -0
- package/docs/R70-FINITE-GRANT-OWNER-BOUNDARY-20261013.md +80 -0
- package/docs/R70-OWNER-BOOTSTRAP-CHECKPOINT-20261013.md +60 -0
- package/docs/R70-REFERENCE-MECHANISMS.json +95 -0
- package/docs/R70-TRUST-GUARD-EXPIRY-CHECKPOINT-20261013.md +47 -0
- package/package.json +2 -2
- package/scripts/benchmark-l0-r71.mjs +76 -0
- package/scripts/gate-windows-r71.ps1 +64 -0
- package/scripts/gate-windows-r72.ps1 +76 -0
- package/scripts/npm-release-r48.mjs +4 -0
- package/scripts/npm-release-readiness-r71.mjs +21 -0
- package/scripts/npm-release-readiness-r72.mjs +76 -0
- package/scripts/verify-r70-full-regression.ps1 +72 -0
- package/src/authority-continuity-r65.mjs +28 -8
- package/src/autonomous-mcp-tools.mjs +1 -1
- package/src/autonomous-output-contracts.mjs +4 -1
- package/src/autonomous-policy.mjs +54 -7
- package/src/capability-ledger.mjs +1 -1
- package/src/capability-resolver.mjs +2 -1
- package/src/commander-compat-runtime.mjs +30 -2
- package/src/deadbyte-cli.mjs +722 -719
- package/src/launcher-isolation.mjs +58 -0
- package/src/native-diff-v2.mjs +18 -5
- package/src/native-diff.mjs +21 -5
- package/src/r70-owner-approval.mjs +78 -0
- package/src/remote-authority.mjs +75 -75
- package/src/remote-live-log.mjs +48 -14
- package/src/remote-mcp-machine-smoke-client.mjs +84 -84
- package/src/remote-result-journal.mjs +1 -1
- package/src/runtime-update.mjs +232 -24
- package/src/staging-input-isolation.mjs +79 -0
- package/src/tool-audit.mjs +2 -0
- package/src/version.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +2 -1
- package/test/autonomous-output-contract.test.mjs +17 -1
- package/test/autonomous-supervisor-integration.test.mjs +2 -1
- package/test/capability-resolver.test.mjs +17 -0
- package/test/codex-autonomous-r44.test.mjs +1 -1
- package/test/commander-compat-runtime.test.mjs +42 -0
- package/test/controller-policy-preflight-r59.test.mjs +1 -0
- package/test/deferred-slot-operation-behavior.test.mjs +2 -2
- package/test/native-diff-topology-r36.test.mjs +35 -2
- package/test/native-diff.test.mjs +83 -3
- package/test/r58-cleanup-retention.test.mjs +3 -3
- package/test/r58-concurrent-recovery.test.mjs +3 -3
- package/test/r58-stale-owner.test.mjs +1 -1
- package/test/r59-tool-surface-compat.test.mjs +9 -5
- package/test/r60-authority-coherence.test.mjs +10 -2
- package/test/r65-authority-runtime-epoch.test.mjs +9 -1
- package/test/r67-isolated-slot-rollback-restore.test.mjs +2 -1
- package/test/r67-npm-publish-gate.test.mjs +4 -2
- package/test/r67-release-contract.test.mjs +8 -7
- package/test/r69-live-outcome.test.mjs +137 -0
- package/test/r70-autonomous-grant-expiry.test.mjs +89 -0
- package/test/r70-autonomous-policy-bootstrap.test.mjs +166 -0
- package/test/r70-controller-autonomous-root.test.mjs +104 -0
- package/test/r70-controller-grant-subset.test.mjs +28 -0
- package/test/r70-controller-owner-issue-boundary.test.mjs +80 -0
- package/test/r70-controller-policy-snapshot.test.mjs +66 -0
- package/test/r70-owner-approval.test.mjs +67 -0
- package/test/r71-full-verifier-artifact.test.mjs +28 -0
- package/test/r71-isolated-slot-rollback-restore.test.mjs +62 -0
- package/test/r71-native-diff-mcp-wire.test.mjs +75 -0
- package/test/r71-publish-fence.test.mjs +38 -0
- package/test/r71-release-identity.test.mjs +33 -0
- package/test/r72-launcher-isolation.test.mjs +99 -0
- package/test/r72-publication-fence.test.mjs +56 -0
- package/test/r72-publication-output-integrity.test.mjs +110 -0
- package/test/r72-remote-safe-contract.test.mjs +101 -0
- package/test/r72-staging-input-isolation.test.mjs +87 -0
- package/test/r72-staging-workspace-isolation.test.mjs +114 -0
- package/test/remote-result-journal.test.mjs +12 -0
- package/test/remote-session-cli.test.mjs +112 -65
- package/test/standing-grants.test.mjs +2 -2
- package/test/tool-audit.test.mjs +14 -0
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-desktop-input-r40.obj +0 -0
- package/bin/deadbyte-desktop-observer-r40.obj +0 -0
- package/bin/deadbyte-desktop-uia-r40.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/bin/deadbyte-native-inspect-r67.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/conpty-input-observer.obj +0 -0
- package/miniconpty.obj +0 -0
- package/proof/CONTAINMENT-BUILD.txt +0 -163
- package/proof/MCP-SMOKE-STATUS.txt +0 -9
- package/proof/NODE-SYNTAX.txt +0 -4
- package/proof/PROOF.txt +0 -6
- package/proof/R34-TASK8-SUPERVISOR-CHECKPOINT.json +0 -29
- package/proof/R34-TASK9-MCP-SURFACE-CHECKPOINT.json +0 -28
- package/proof/SECRET-SCAN.txt +0 -4
- package/proof/SOURCE-GATES.txt +0 -16
- package/proof/STATUS.txt +0 -11
- package/proof/TARGET-V0313-CONTAINMENT-PASS.sha256 +0 -1
- package/proof/TARGET-V0313-CONTAINMENT-PASS.txt +0 -215
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.sha256 +0 -1
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.txt +0 -299
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.txt +0 -311
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.txt +0 -313
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.txt +0 -308
- package/proof/TARGET-V044-CONTAINED-PASS.sha256 +0 -1
- package/proof/TARGET-V044-CONTAINED-PASS.txt +0 -432
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.sha256 +0 -1
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.txt +0 -481
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.sha256 +0 -1
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.txt +0 -610
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.sha256 +0 -1
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.txt +0 -642
- package/proof/TARGET-V050-BATCH-GATE-PASS.sha256 +0 -1
- package/proof/TARGET-V050-BATCH-GATE-PASS.txt +0 -713
- package/proof/TESTS.txt +0 -686
- package/proof/TRUST-EPHEMERAL.txt +0 -4
- package/proof/V03-FREEZE.txt +0 -27
- package/proof/V041-IPC-HOTFIX.txt +0 -16
- package/proof/V042-ENV-HOTFIX.txt +0 -15
- package/proof/V043-DRIVE-CWD-HOTFIX.txt +0 -14
- package/proof/V044-LOCALAPPDATA-HOTFIX.txt +0 -18
- package/proof/V045-OPERATION-REGISTRY.txt +0 -7
- package/proof/V046-WORKER-REGISTRY.txt +0 -12
- package/proof/V047-WORKER-MANIFEST.txt +0 -18
- package/proof/V050-BATCH-TRUST-CLOSURE.txt +0 -21
- package/proof/V060-ACTIVE-NETWORK-AUTHORITY.txt +0 -29
- package/proof/V070-NODE-SYNTAX.txt +0 -36
- package/proof/V070-NODE-TESTS.txt +0 -752
- package/proof/V070-PACK-DRY-RUN.txt +0 -126
- package/proof/V070-SOURCE-GATE.txt +0 -30
- package/proof/V070-STATIC-SCAN.txt +0 -4
- package/proof/V070-WINDOWS-GATE-PENDING.txt +0 -25
- package/proof/V071-NODE-SYNTAX.txt +0 -1
- package/proof/V071-NODE-TESTS.txt +0 -796
- package/proof/V071-PACK-DRY-RUN.json +0 -656
- package/proof/V071-SOURCE-GATE.txt +0 -16
- package/proof/V071-WINDOWS-GATE-PENDING.txt +0 -24
- package/proof/V073-NODE-SYNTAX.txt +0 -4
- package/proof/V073-SOURCE-GATE.txt +0 -21
- package/proof/V073-STATIC-SCAN.txt +0 -10
- package/proof/V073-WINDOWS-GATE-PENDING.txt +0 -5
- package/proof/VERIFY.txt +0 -7
- package/proof/WINDOWS-CONTAINED-STATUS.txt +0 -5
- package/proof/WINDOWS-CONTAINMENT-STATUS.txt +0 -3
- package/proof/commander-closure-20260927/CONTINUATION.json +0 -43
- package/proof/commander-closure-20260927/RESULT.json +0 -30
- package/proof/commander-closure-20260927/SEARCH-CONTINUATION.json +0 -30
- package/proof/commander-closure-20260927/XLS-REFERENCE-PROBE.json +0 -13
- package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +0 -122
- package/proof/r59-full-regression-current.json +0 -13
- package/proof/r59-full-regression-current.stderr.log +0 -0
- package/proof/r59-full-regression-current.stdout.log +0 -1268
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import {readFile} from 'node:fs/promises';
|
|
5
|
+
import {classifyRemoteAuditOutcome,createLiveTimelineTracker,createLiveTimelineFilter,createLiveTimelineWriter,formatCompactAuditEvent} from '../src/remote-live-log.mjs';
|
|
6
|
+
|
|
7
|
+
function pair(status,is_error=false,side_effect_state=null){
|
|
8
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii',rootPaths:{local_d:'D:\\'}});
|
|
9
|
+
const args={root_id:'local_d',path:'TECHNICAL/ProgramingLangPJ/tmp/gfx_r3_dev/runtime/gfx/dbyte_gfx3d.dby'};
|
|
10
|
+
const start=tracker.observe({event_type:'tool.request',tool:'coding_file_write',request_id:'r69-example-1',args});
|
|
11
|
+
const done=tracker.observe({event_type:'tool.result',tool:'coding_file_write',request_id:'r69-example-1',
|
|
12
|
+
outcome:{status,is_error,side_effect_state,duration_ms:1}});
|
|
13
|
+
return {tracker,start,done};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
test('R69 failed, denied and observed_failure never produce a false SUCCEEDED line',()=>{
|
|
17
|
+
for(const status of ['failed','denied','rejected','blocked','observed_failure','cancelled']){
|
|
18
|
+
const {tracker,done}=pair(status);
|
|
19
|
+
assert.match(done,/ERR status=/,status);
|
|
20
|
+
assert.doesNotMatch(done,/SUCCEEDED|\bOK\b/,status);
|
|
21
|
+
assert.match(tracker.summary(),/0 ok \| 1 error/,status);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('R69 unavailable and unsupported result envelopes never print mutation SUCCEEDED',()=>{
|
|
26
|
+
for(const status of ['unavailable','unsupported']){
|
|
27
|
+
const {tracker,done}=pair(status);
|
|
28
|
+
assert.match(done,/ERR status=/,status);
|
|
29
|
+
assert.doesNotMatch(done,/SUCCEEDED/,status);
|
|
30
|
+
assert.match(tracker.summary(),/0 ok \| 1 error/,status);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('R69 pending tool result requires continuation, never implies effect committed',()=>{
|
|
35
|
+
for(const status of ['pending','running','input_required','paused','processing','accepted']){
|
|
36
|
+
const {tracker,done}=pair(status);
|
|
37
|
+
assert.match(done,/PENDING status=/,status);
|
|
38
|
+
assert.doesNotMatch(done,/SUCCEEDED|\bOK\b/,status);
|
|
39
|
+
assert.match(tracker.summary(),/0 ok \| 0 errors \| 0 unknown \| 1 pending/,status);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('R69 unknown side-effect outranks every status; no retry claim',()=>{
|
|
44
|
+
const {done,tracker}=pair('committed',false,'unknown');
|
|
45
|
+
assert.match(done,/FAILED_AFTER_UNKNOWN_EFFECT/);
|
|
46
|
+
assert.match(tracker.summary(),/1 unknown/);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('R69 human console always retains the operation location in terminal result',()=>{
|
|
50
|
+
const {start,done}=pair('denied');
|
|
51
|
+
const absolute='D:\\TECHNICAL\\ProgramingLangPJ\\tmp\\gfx_r3_dev\\runtime\\gfx\\dbyte_gfx3d.dby [root=local_d]';
|
|
52
|
+
assert.ok(start.includes(absolute));
|
|
53
|
+
assert.ok(done.includes(absolute));
|
|
54
|
+
assert.match(done,/ERR status=denied/);
|
|
55
|
+
assert.doesNotMatch(done,/SUCCEEDED/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('R69 compact audit flags status failure or pending even with is_error=false',()=>{
|
|
59
|
+
assert.match(formatCompactAuditEvent({event_type:'tool.result',tool:'host_exec',outcome:{is_error:false,status:'denied'}}),/ERR/);
|
|
60
|
+
assert.match(formatCompactAuditEvent({event_type:'tool.result',tool:'host_exec',outcome:{is_error:false,status:'input_required'}}),/PENDING/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('R69 TTY writer obeys runtime terminal resize without rewriting a wrapped start line',()=>{
|
|
64
|
+
const writes=[];
|
|
65
|
+
const stream={isTTY:true,columns:32,write(value){writes.push(value);return true;}};
|
|
66
|
+
const writer=createLiveTimelineWriter({stream,displayMode:'ascii'});
|
|
67
|
+
writer.write('START',{event_type:'tool.call',request_id:'resize'});
|
|
68
|
+
stream.columns=5;
|
|
69
|
+
writer.write('TOO LONG RESULT',{event_type:'tool.result',request_id:'resize'});
|
|
70
|
+
assert.deepEqual(writes,['START','\n','TOO LONG RESULT\n']);
|
|
71
|
+
assert.equal(writer.pending(),null);
|
|
72
|
+
stream.columns=80;
|
|
73
|
+
writer.write('RUN',{event_type:'tool.call',request_id:'wide'});
|
|
74
|
+
writer.write('OK',{event_type:'tool.result',request_id:'wide'});
|
|
75
|
+
assert.equal(writes.at(-1),'\r\x1b[2KOK\n');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
test('R69 live latency uses fractional milliseconds instead of printing a false 0ms',()=>{
|
|
80
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii'});
|
|
81
|
+
tracker.observe({event_type:'tool.request',tool:'machine_status',request_id:'subms'});
|
|
82
|
+
const done=tracker.observe({event_type:'tool.result',tool:'machine_status',request_id:'subms',
|
|
83
|
+
outcome:{is_error:false,duration_ms:0.125}});
|
|
84
|
+
assert.ok(done.includes('0.125ms'));
|
|
85
|
+
assert.doesNotMatch(done,/ 0ms /);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('R69 latency summary includes p99 and discloses bounded sample coverage',()=>{
|
|
89
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii'});
|
|
90
|
+
for(let i=1;i<=100;i++){
|
|
91
|
+
const id='sample-'+i;
|
|
92
|
+
tracker.observe({event_type:'tool.request',tool:'machine_status',request_id:id});
|
|
93
|
+
tracker.observe({event_type:'tool.result',tool:'machine_status',request_id:id,
|
|
94
|
+
outcome:{is_error:false,duration_ms:i}});
|
|
95
|
+
}
|
|
96
|
+
const summary=tracker.summary();
|
|
97
|
+
assert.ok(summary.includes('p50 51ms'));
|
|
98
|
+
assert.ok(summary.includes('p95 95ms'));
|
|
99
|
+
assert.ok(summary.includes('p99 99ms'));
|
|
100
|
+
assert.ok(summary.includes('sample 100/100'));
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('R69 filter matches status-only errors independent of is_error=false',()=>{
|
|
104
|
+
const filter=createLiveTimelineFilter('status=error');
|
|
105
|
+
filter.accept({event_type:'tool.request',tool:'host_exec',request_id:'r69-e',args:{}});
|
|
106
|
+
assert.equal(filter.accept({event_type:'tool.result',tool:'host_exec',request_id:'r69-e',outcome:{status:'denied',is_error:false}}),true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('R69 mismatched terminal tool cannot inherit a mutating START or claim success',()=>{
|
|
110
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii'});
|
|
111
|
+
const start=tracker.observe({event_type:'tool.request',tool:'coding_file_write',request_id:'r69-mismatch',args:{root_id:'core',path:'scratch.txt'}});
|
|
112
|
+
assert.match(start,/START/);
|
|
113
|
+
const terminal=tracker.observe({event_type:'tool.result',tool:'machine_ping',request_id:'r69-mismatch',
|
|
114
|
+
outcome:{status:'ok',is_error:false,duration_ms:1,receipt_sha256s:['a'.repeat(64)]}});
|
|
115
|
+
assert.match(terminal,/CORRELATION_MISMATCH/);
|
|
116
|
+
assert.doesNotMatch(terminal,/SUCCEEDED|RECEIPT=/);
|
|
117
|
+
assert.match(tracker.summary(),/0 ok \| 0 errors \| 1 unknown/);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('R69 status filter cannot hide a mismatched terminal identity as successful',()=>{
|
|
121
|
+
const unknown=createLiveTimelineFilter('status=unknown');
|
|
122
|
+
unknown.accept({event_type:'tool.request',tool:'coding_file_write',request_id:'r69-filter-mismatch',args:{}});
|
|
123
|
+
assert.equal(unknown.accept({event_type:'tool.result',tool:'machine_ping',request_id:'r69-filter-mismatch',
|
|
124
|
+
outcome:{status:'ok',is_error:false}}),true);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('R69 remote replay projection does not record unavailable as ok or input_required as complete',async()=>{
|
|
128
|
+
const source=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
|
|
129
|
+
const start=source.indexOf('function auditTimelineRecord(');
|
|
130
|
+
const end=source.indexOf('async function replayRemoteResults(',start);
|
|
131
|
+
assert.ok(start>=0&&end>start);
|
|
132
|
+
const record=new Function('createHash','parseAuditLogLine','classifyRemoteAuditOutcome',`${source.slice(start,end)};return auditTimelineRecord;`)(createHash,()=>null,classifyRemoteAuditOutcome);
|
|
133
|
+
const base={event_type:'tool.result',request_id:'r69-projection',tool:'coding_file_write',ts:'2026-10-13T00:00:00.000Z'};
|
|
134
|
+
assert.equal(record('audit.log','bounded-line',{...base,outcome:{status:'unavailable',is_error:false}}).status,'error');
|
|
135
|
+
assert.equal(record('audit.log','bounded-line',{...base,outcome:{status:'input_required',is_error:false}}).status,'pending');
|
|
136
|
+
});
|
|
137
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {mkdtemp,readFile,rm,writeFile} from 'node:fs/promises';
|
|
4
|
+
import {spawnSync} from 'node:child_process';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import * as auto from '../src/autonomous-policy.mjs';
|
|
8
|
+
|
|
9
|
+
const H=c=>c.repeat(64);
|
|
10
|
+
const controller=new URL('../controller/deadbyte-controller.ps1',import.meta.url);
|
|
11
|
+
const quote=s=>`'${String(s).replaceAll("'","''")}'`;
|
|
12
|
+
const issued=Date.parse('2026-10-13T03:00:00.000Z');
|
|
13
|
+
const when=n=>new Date(issued+n).toISOString();
|
|
14
|
+
|
|
15
|
+
test('R70 signed standing grant expiry is bounded, canonical and fail-closed before authority decision',()=>{
|
|
16
|
+
assert.equal(typeof auto.inspectAutonomousStandingWindow,'function');
|
|
17
|
+
const base={granted_at_utc:when(0),expires_at_utc:when(1_800_000)};
|
|
18
|
+
assert.deepEqual(auto.inspectAutonomousStandingWindow(base,new Date(when(300_000))),
|
|
19
|
+
{ok:true,reason:null,expires_at_utc:when(1_800_000),remaining_ms:1_500_000});
|
|
20
|
+
for(const [claim,reason,now] of [
|
|
21
|
+
[{...base,expires_at_utc:when(0)},'expiry-window-invalid',when(30_000)],
|
|
22
|
+
[{...base,expires_at_utc:when(3_600_001)},'expiry-window-invalid',when(30_000)],
|
|
23
|
+
[{...base,expires_at_utc:'bad'},'expiry-invalid',when(30_000)],
|
|
24
|
+
[{...base,expires_at_utc:when(1_800_000)},'expired',when(1_800_000)],
|
|
25
|
+
[{...base,granted_at_utc:when(700_000)},'not-yet-valid',when(300_000)]
|
|
26
|
+
]){
|
|
27
|
+
const result=auto.inspectAutonomousStandingWindow(claim,new Date(now));
|
|
28
|
+
assert.equal(result.ok,false);
|
|
29
|
+
assert.equal(result.reason,reason);
|
|
30
|
+
}
|
|
31
|
+
assert.deepEqual(auto.inspectAutonomousStandingWindow({granted_at_utc:when(0)},new Date(when(300_000))),
|
|
32
|
+
{ok:true,reason:null,expires_at_utc:null,remaining_ms:null});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('R70 runtime rejects a v2 grant whose Coding policy digest is missing or stale',async()=>{
|
|
36
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-coding-lease-'));
|
|
37
|
+
const leaseFile=path.join(root,'grant.json');
|
|
38
|
+
try{
|
|
39
|
+
const policy={policy_sha256:H('a'),coding_policy_sha256:H('b'),root_ids:['core'],
|
|
40
|
+
lease_file:leaseFile,policy_path:path.join(root,'autonomous-policy.json')};
|
|
41
|
+
const base={schema:'deadbyte.autonomous-grant.v2',policy_sha256:H('a'),
|
|
42
|
+
instance_nonce:H('c'),root_ids:['core'],granted_at_utc:when(0),
|
|
43
|
+
expires_at_utc:when(1_800_000)};
|
|
44
|
+
for(const candidate of [{...base,coding_policy_sha256:H('d')},base]){
|
|
45
|
+
await writeFile(leaseFile,JSON.stringify(candidate));
|
|
46
|
+
const status=await auto.autonomousSessionStatus(policy,new Date(when(300_000)));
|
|
47
|
+
assert.equal(status.armed,false);
|
|
48
|
+
assert.equal(status.reason,'coding-policy-digest');
|
|
49
|
+
await assert.rejects(auto.recheckAutonomousAuthority(policy,{
|
|
50
|
+
armed:true,instance_nonce:H('c'),root_ids:['core'],standing:true,expires_at_utc:when(1_800_000)
|
|
51
|
+
},'core',new Date(when(300_000))),/coding-policy-digest/);
|
|
52
|
+
}
|
|
53
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('R70 controller must agree with runtime on expired and malformed signed standing grant',async()=>{
|
|
57
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-grant-expiry-'));
|
|
58
|
+
const grantFile=path.join(root,'autonomous-grant.json');
|
|
59
|
+
try{
|
|
60
|
+
const scriptText=await readFile(controller,'utf8');
|
|
61
|
+
const start=scriptText.indexOf('function Get-AutonomousLeaseStatus(');
|
|
62
|
+
const end=scriptText.indexOf('function Arm-Autonomous(',start);
|
|
63
|
+
assert.ok(start>=0&&end>start);
|
|
64
|
+
const block=scriptText.slice(start,end);
|
|
65
|
+
const now=Date.now();
|
|
66
|
+
const records=[
|
|
67
|
+
{name:'expired',grant:new Date(now-3_600_000),expires:new Date(now-1_800_000),reason:'expired',armed:false},
|
|
68
|
+
{name:'oversized',grant:new Date(now-300_000),expires:new Date(now+7_200_000),reason:'expiry-window-invalid',armed:false},
|
|
69
|
+
{name:'valid',grant:new Date(now-300_000),expires:new Date(now+900_000),reason:'standing-grant',armed:true}
|
|
70
|
+
];
|
|
71
|
+
for(const c of records){
|
|
72
|
+
const lease={schema:'deadbyte.autonomous-grant.v2',policy_sha256:H('a'),coding_policy_sha256:H('b'),
|
|
73
|
+
instance_nonce:H('c'),root_ids:['core'],granted_at_utc:c.grant.toISOString(),
|
|
74
|
+
expires_at_utc:c.expires.toISOString()};
|
|
75
|
+
await writeFile(grantFile,JSON.stringify(lease));
|
|
76
|
+
const script=`$ErrorActionPreference='Stop';
|
|
77
|
+
function Get-AutonomousPolicyMetadata($Cfg){return [pscustomobject]@{LeaseFile=${quote(grantFile)};Sha256='${H('a')}';CodingPolicySha256='${H('b')}';RootIds=@('core')}}
|
|
78
|
+
function Get-CodingLeaseStatus($Cfg){return [pscustomobject]@{Armed=$true;RootIds=@('core')}}
|
|
79
|
+
function Get-AuthorityEpochStatus($Cfg,$Plane,$File,$Nonce){return [pscustomobject]@{Trusted=$true;Seq=1;EventSha256='${H('d')}'}}
|
|
80
|
+
${block}
|
|
81
|
+
(Get-AutonomousLeaseStatus @{AutonomousPolicyFile='test-fixture'})|ConvertTo-Json -Compress`;
|
|
82
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
83
|
+
assert.equal(result.status,0,result.stderr);
|
|
84
|
+
const out=JSON.parse(result.stdout.trim());
|
|
85
|
+
assert.equal(out.Armed,c.armed,c.name);
|
|
86
|
+
assert.equal(out.Reason,c.reason,c.name);
|
|
87
|
+
}
|
|
88
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
89
|
+
});
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {createHash,generateKeyPairSync,sign} from 'node:crypto';
|
|
4
|
+
import {mkdir,mkdtemp,readFile,realpath,rm,writeFile} from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import * as update from '../src/runtime-update.mjs';
|
|
8
|
+
import {canonicalJson} from '../src/canonical-json.mjs';
|
|
9
|
+
import {loadAutonomousPolicy} from '../src/autonomous-policy.mjs';
|
|
10
|
+
|
|
11
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
12
|
+
const baseArgs=['--stage','stage','--development-root','dev','--expected-version','0.15.45',
|
|
13
|
+
'--expected-manifest','a'.repeat(64)];
|
|
14
|
+
|
|
15
|
+
test('R70 autonomous policy bootstrap is an exact path and SHA pair',()=>{
|
|
16
|
+
assert.throws(()=>update.parseUpdateArgs([...baseArgs,'--autonomous-policy','policy.json']),/autonomous policy bootstrap requires path plus SHA-256/);
|
|
17
|
+
assert.throws(()=>update.parseUpdateArgs([...baseArgs,'--autonomous-policy-sha256','a'.repeat(64)]),/autonomous policy bootstrap requires path plus SHA-256/);
|
|
18
|
+
const parsed=update.parseUpdateArgs([...baseArgs,'--autonomous-policy','policy.json','--autonomous-policy-sha256','b'.repeat(64),
|
|
19
|
+
'--owner-approval','approval.json','--owner-approval-sha256','c'.repeat(64)]);
|
|
20
|
+
assert.deepEqual(parsed.autonomousPolicyBootstrap,{path:path.resolve('policy.json'),sha256:'b'.repeat(64)});
|
|
21
|
+
assert.deepEqual(parsed.ownerApprovalBootstrap,{path:path.resolve('approval.json'),sha256:'c'.repeat(64)});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('R70 autonomous policy bootstrap cannot be parsed without pinned owner approval',()=>{
|
|
25
|
+
assert.throws(()=>update.parseUpdateArgs([...baseArgs,'--autonomous-policy','policy.json',
|
|
26
|
+
'--autonomous-policy-sha256','b'.repeat(64)]),/owner approval/i);
|
|
27
|
+
assert.throws(()=>update.parseUpdateArgs([...baseArgs,'--owner-approval','approval.json',
|
|
28
|
+
'--owner-approval-sha256','c'.repeat(64)]),/autonomous policy/i);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('R70 pinned autonomous policy rejects changed bytes and roots outside Coding policy',async()=>{
|
|
32
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-policy-'));
|
|
33
|
+
try{
|
|
34
|
+
const file=path.join(root,'autonomous-policy.json');
|
|
35
|
+
const bytes=Buffer.from(JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
|
|
36
|
+
lease_file:path.join(root,'grant.json'),evidence_dir:path.join(root,'evidence'),
|
|
37
|
+
coding_policy_sha256:'a'.repeat(64),root_ids:['gfx_project'],planner:{backend:'client_sampling',max_tokens:2048},
|
|
38
|
+
profiles:{},limits:{max_files_per_diff:8}}));
|
|
39
|
+
await writeFile(file,bytes);
|
|
40
|
+
const pinned={path:file,sha256:sha(bytes)};
|
|
41
|
+
const prepared=await update.prepareAutonomousPolicyBootstrap(pinned);
|
|
42
|
+
assert.deepEqual(prepared.policy.root_ids,['gfx_project']);
|
|
43
|
+
assert.doesNotThrow(()=>update.assertAutonomousBootstrapRoots(prepared.policy,{roots:{gfx_project:{path:root}}},'a'.repeat(64)));
|
|
44
|
+
assert.throws(()=>update.assertAutonomousBootstrapRoots(prepared.policy,{roots:{core:{path:root}}},'a'.repeat(64)),/outside selected coding policy/);
|
|
45
|
+
assert.throws(()=>update.assertAutonomousBootstrapRoots(prepared.policy,{roots:{gfx_project:{path:root}}},'b'.repeat(64)),/coding policy SHA-256 mismatch/);
|
|
46
|
+
await writeFile(file,Buffer.concat([bytes,Buffer.from('\n')]));
|
|
47
|
+
await assert.rejects(update.prepareAutonomousPolicyBootstrap(pinned),/SHA-256 mismatch/);
|
|
48
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('R70 selected autonomous root must resolve to an existing real directory before update mutation',async()=>{
|
|
52
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-realroot-'));
|
|
53
|
+
try{
|
|
54
|
+
const policy={root_ids:['gfx_project'],coding_policy_sha256:'a'.repeat(64)};
|
|
55
|
+
assert.throws(()=>update.assertAutonomousBootstrapRoots(policy,{roots:{gfx_project:{path:path.join(root,'missing')}}},'a'.repeat(64)),/real directory/);
|
|
56
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('R70 autonomous bootstrap cannot treat a whole drive as a project root',()=>{
|
|
60
|
+
if(process.platform!=='win32') return;
|
|
61
|
+
const drive=path.parse('D:\\').root;
|
|
62
|
+
const policy={root_ids:['local_d'],coding_policy_sha256:'a'.repeat(64)};
|
|
63
|
+
assert.throws(()=>update.assertAutonomousBootstrapRoots(policy,{roots:{local_d:{path:drive}}},'a'.repeat(64)),/project-scoped root/);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('R70 project bootstrap rejects a Coding policy that still exposes a whole drive',async()=>{
|
|
67
|
+
if(process.platform!=='win32') return;
|
|
68
|
+
const project=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-narrow-policy-'));
|
|
69
|
+
try{
|
|
70
|
+
const autonomous={root_ids:['gfx_project'],coding_policy_sha256:'a'.repeat(64)};
|
|
71
|
+
const coding={roots:{
|
|
72
|
+
gfx_project:{path:project,read:true,write:true,exec:false,deny_paths:[]},
|
|
73
|
+
local_c:{path:'C:\\',read:true,write:true,exec:true,deny_paths:[]}
|
|
74
|
+
}};
|
|
75
|
+
assert.throws(()=>update.assertAutonomousBootstrapRoots(autonomous,coding,'a'.repeat(64)),/coding policy contains a broad filesystem root/);
|
|
76
|
+
}finally{await rm(project,{recursive:true,force:true});}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('R70 pinned JSON hash and parsed policy come from one read',async()=>{
|
|
80
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-single-read-'));
|
|
81
|
+
try{
|
|
82
|
+
const file=path.join(root,'policy.json');
|
|
83
|
+
const approved=Buffer.from('{"schema":"approved"}');
|
|
84
|
+
const replacement=Buffer.from('{"schema":"replacement"}');
|
|
85
|
+
await writeFile(file,approved);
|
|
86
|
+
let reads=0;
|
|
87
|
+
const prepared=await update.readPinnedJsonPolicy({path:file,sha256:sha(approved)},'test policy',async()=>{
|
|
88
|
+
reads++;
|
|
89
|
+
return reads===1?approved:replacement;
|
|
90
|
+
});
|
|
91
|
+
assert.equal(reads,1);
|
|
92
|
+
assert.equal(prepared.sha256,sha(approved));
|
|
93
|
+
assert.equal(prepared.policy.schema,'approved');
|
|
94
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('R70 preflight and runtime reject profiles outside approved Autonomous roots',async()=>{
|
|
98
|
+
const state=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-profile-scope-'));
|
|
99
|
+
try{
|
|
100
|
+
const project=path.join(state,'project'),other=path.join(state,'other');
|
|
101
|
+
await mkdir(project);await mkdir(other);
|
|
102
|
+
const digest='a'.repeat(64);
|
|
103
|
+
const codingPolicy={policy_sha256:digest,roots:{gfx_project:{path:project},other_project:{path:other}},
|
|
104
|
+
commands:{script:{}}};
|
|
105
|
+
const bad={schema:'deadbyte.autonomous-policy.v1',enabled:true,lease_file:path.join(state,'grant.json'),
|
|
106
|
+
evidence_dir:path.join(state,'evidence'),coding_policy_sha256:digest,root_ids:['gfx_project'],
|
|
107
|
+
planner:{backend:'client_sampling',max_tokens:2048},
|
|
108
|
+
profiles:{unsafe:{kind:'command',root_id:'other_project',command_id:'script',
|
|
109
|
+
script_path:'verify.ps1',script_sha256:'f'.repeat(64)}}};
|
|
110
|
+
assert.throws(()=>update.assertAutonomousBootstrapRoots(bad,codingPolicy,digest),/profile|autonomous roots/i);
|
|
111
|
+
const file=path.join(state,'autonomous.json');
|
|
112
|
+
await writeFile(file,JSON.stringify(bad));
|
|
113
|
+
await assert.rejects(loadAutonomousPolicy(file,codingPolicy),/profile.*root invalid/i);
|
|
114
|
+
}finally{await rm(state,{recursive:true,force:true});}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('R70 update preflight verifies pinned owner signature against the manifest and selected policies',async()=>{
|
|
118
|
+
const state=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-owner-bootstrap-'));
|
|
119
|
+
try{
|
|
120
|
+
const root=await realpath(path.join(state,'project').replace(/project$/,'')).then(async()=>{
|
|
121
|
+
const project=path.join(state,'project');await mkdir(project);return realpath(project);
|
|
122
|
+
});
|
|
123
|
+
const trust=path.join(state,'trust');await mkdir(trust);
|
|
124
|
+
const {privateKey,publicKey}=generateKeyPairSync('ed25519');
|
|
125
|
+
await writeFile(path.join(trust,'r70-owner-public.pem'),publicKey.export({type:'spki',format:'pem'}));
|
|
126
|
+
const manifest='c'.repeat(64),coding='a'.repeat(64),autonomous='b'.repeat(64);
|
|
127
|
+
const subject={schema:'deadbyte.project-authority-subject.r70.v1',scope:'coding_autonomous_native_diff',
|
|
128
|
+
root_id:'gfx_project',project_root:root,coding_policy_sha256:coding,autonomous_policy_sha256:autonomous,
|
|
129
|
+
reviewed_artifact_sha256:manifest,issued_at_utc:'2026-10-13T00:00:00.000Z',expires_at_utc:'2026-10-13T00:30:00.000Z'};
|
|
130
|
+
const subjectSha=sha(Buffer.from(canonicalJson(subject)));
|
|
131
|
+
const signed={schema:'deadbyte.project-owner-approval.r70.v1',subject_sha256:subjectSha,
|
|
132
|
+
owner_key_id:sha(publicKey.export({type:'spki',format:'der'}))};
|
|
133
|
+
const approval={...signed,subject,signature_base64:sign(null,Buffer.concat([
|
|
134
|
+
Buffer.from('DEADBYTE-R70-PROJECT-OWNER-APPROVAL\0'),Buffer.from(canonicalJson(signed))]),privateKey).toString('base64')};
|
|
135
|
+
const approvalPath=path.join(state,'approval.json'),bytes=Buffer.from(JSON.stringify(approval));
|
|
136
|
+
await writeFile(approvalPath,bytes);
|
|
137
|
+
const input={stateRoot:state,bootstrap:{path:approvalPath,sha256:sha(bytes)},
|
|
138
|
+
autonomousPolicy:{root_ids:['gfx_project'],coding_policy_sha256:coding},codingPolicy:{roots:{gfx_project:{path:root,read:true,write:true}}},
|
|
139
|
+
codingPolicySha256:coding,autonomousPolicySha256:autonomous,expectedManifest:manifest,
|
|
140
|
+
now:new Date('2026-10-13T00:05:00.000Z')};
|
|
141
|
+
const verified=await update.verifyAutonomousOwnerBootstrap(input);
|
|
142
|
+
assert.equal(verified.subject_sha256,subjectSha);
|
|
143
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap({...input,expectedManifest:'d'.repeat(64)}),/artifact/i);
|
|
144
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap({...input,now:new Date('2026-10-13T00:30:00.000Z')}),/expired/i);
|
|
145
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap({
|
|
146
|
+
...input,codingPolicy:{roots:{...input.codingPolicy.roots,trust_writer:{path:trust,write:true}}}
|
|
147
|
+
}),/owner trust key is writable/i);
|
|
148
|
+
await assert.rejects(update.performSlotUpdate({
|
|
149
|
+
stage:path.join(state,'unverified-stage'),developmentRoot:path.join(state,'unverified-dev'),
|
|
150
|
+
expectedVersion:'0.15.45',expectedManifest:manifest,stateRoot:state,
|
|
151
|
+
autonomousPolicyBootstrap:{path:'not-loaded',sha256:autonomous}
|
|
152
|
+
}),/owner approval/i);
|
|
153
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap({
|
|
154
|
+
...input,codingPolicy:{roots:{gfx_project:{...input.codingPolicy.roots.gfx_project,exec:true}}}
|
|
155
|
+
}),/unsandboxed Coding execution/i);
|
|
156
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap({
|
|
157
|
+
...input,codingPolicy:{roots:{...input.codingPolicy.roots,
|
|
158
|
+
command_root:{path:root,read:true,write:false,exec:true}}}
|
|
159
|
+
}),/unsandboxed Coding execution/i);
|
|
160
|
+
const attacker=generateKeyPairSync('ed25519').publicKey;
|
|
161
|
+
await writeFile(path.join(trust,'r70-owner-public.pem'),attacker.export({type:'spki',format:'pem'}));
|
|
162
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap(input),/key identity|signature/i);
|
|
163
|
+
await writeFile(approvalPath,Buffer.concat([bytes,Buffer.from('\\n')]));
|
|
164
|
+
await assert.rejects(update.verifyAutonomousOwnerBootstrap(input),/SHA-256 mismatch/i);
|
|
165
|
+
}finally{await rm(state,{recursive:true,force:true});}
|
|
166
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {mkdtemp,readFile,rm,symlink,unlink,writeFile} from 'node:fs/promises';
|
|
4
|
+
import {spawnSync} from 'node:child_process';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
const controllerPath=new URL('../controller/deadbyte-controller.ps1',import.meta.url);
|
|
9
|
+
const quote=value=>`'${String(value).replaceAll("'","''")}'`;
|
|
10
|
+
|
|
11
|
+
test('R70 controller rejects Autonomous roots outside selected Coding roots',async()=>{
|
|
12
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-controller-root-'));
|
|
13
|
+
try{
|
|
14
|
+
const runtime=path.join(root,'runtime'),policyFile=path.join(root,'autonomous.json');
|
|
15
|
+
await writeFile(policyFile,JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
|
|
16
|
+
lease_file:path.join(runtime,'autonomous-grant.json'),coding_policy_sha256:'a'.repeat(64),root_ids:['outside']}));
|
|
17
|
+
const source=await readFile(controllerPath,'utf8');
|
|
18
|
+
const start=source.indexOf('function Get-AutonomousPolicyMetadata(');
|
|
19
|
+
const end=source.indexOf('function Get-AutonomousLeaseStatus(',start);
|
|
20
|
+
assert.ok(start>=0&&end>start);
|
|
21
|
+
const helperStart=source.indexOf('function Read-ControllerPolicySnapshot(');
|
|
22
|
+
const helperEnd=source.indexOf('function Get-CodingPolicyMetadata(',helperStart);
|
|
23
|
+
assert.ok(helperStart>=0&&helperEnd>helperStart);
|
|
24
|
+
const block=source.slice(helperStart,helperEnd)+source.slice(start,end);
|
|
25
|
+
const script=`$ErrorActionPreference='Stop';$RuntimeDir=${quote(runtime)};function Fail([string]$m){throw $m};function Get-ExecutableHash($p){return 'b'.PadLeft(64,'b')};function Get-CodingPolicyMetadata($Cfg){return [pscustomobject]@{Sha256='a'.PadLeft(64,'a');RootIds=@('project');RootPaths=@{project=${quote(root)}};RootAccess=@{project=@{read=$true;write=$true;exec=$false}}}};${block};try{Get-AutonomousPolicyMetadata @{AutonomousPolicyFile=${quote(policyFile)}}|Out-Null;Write-Output 'UNEXPECTED_PASS'}catch{Write-Output $_.Exception.Message}`;
|
|
26
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
27
|
+
assert.equal(result.status,0,result.stderr);
|
|
28
|
+
assert.match(result.stdout,/autonomous policy root 'outside' outside coding policy/);
|
|
29
|
+
await writeFile(policyFile,JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
|
|
30
|
+
lease_file:path.join(runtime,'autonomous-grant.json'),coding_policy_sha256:'a'.repeat(64),root_ids:['project']}));
|
|
31
|
+
const accepted=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
32
|
+
assert.equal(accepted.status,0,accepted.stderr);
|
|
33
|
+
assert.match(accepted.stdout,/UNEXPECTED_PASS/);
|
|
34
|
+
assert.doesNotMatch(accepted.stdout,/outside coding policy/);
|
|
35
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('R70 controller refuses a direct Autonomous whole-drive policy root',async()=>{
|
|
39
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-controller-drive-'));
|
|
40
|
+
try{
|
|
41
|
+
const runtime=path.join(root,'runtime'),policyFile=path.join(root,'autonomous.json');
|
|
42
|
+
const drive=path.parse(root).root;
|
|
43
|
+
await writeFile(policyFile,JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
|
|
44
|
+
lease_file:path.join(runtime,'autonomous-grant.json'),coding_policy_sha256:'a'.repeat(64),root_ids:['project']}));
|
|
45
|
+
const source=await readFile(controllerPath,'utf8');
|
|
46
|
+
const helperStart=source.indexOf('function Read-ControllerPolicySnapshot(');
|
|
47
|
+
const helperEnd=source.indexOf('function Get-CodingPolicyMetadata(',helperStart);
|
|
48
|
+
const start=source.indexOf('function Get-AutonomousPolicyMetadata(');
|
|
49
|
+
const end=source.indexOf('function Get-AutonomousLeaseStatus(',start);
|
|
50
|
+
assert.ok(helperStart>=0&&helperEnd>helperStart&&start>=0&&end>start);
|
|
51
|
+
const block=source.slice(helperStart,helperEnd)+source.slice(start,end);
|
|
52
|
+
const script=`$ErrorActionPreference='Stop';$RuntimeDir=${quote(runtime)};function Fail([string]$m){throw $m};function Get-CodingPolicyMetadata($Cfg){return [pscustomobject]@{Sha256='a'.PadLeft(64,'a');RootIds=@('project');RootPaths=@{project=${quote(drive)}};RootAccess=@{project=@{read=$true;write=$true;exec=$false}}}};${block};try{Get-AutonomousPolicyMetadata @{AutonomousPolicyFile=${quote(policyFile)}}|Out-Null;Write-Output 'UNEXPECTED_PASS'}catch{Write-Output $_.Exception.Message}`;
|
|
53
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
54
|
+
assert.equal(result.status,0,result.stderr);
|
|
55
|
+
assert.match(result.stdout,/project-scoped root/);
|
|
56
|
+
assert.doesNotMatch(result.stdout,/UNEXPECTED_PASS/);
|
|
57
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('R70 controller refuses a project-looking junction to a whole drive',async()=>{
|
|
61
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-controller-junction-'));
|
|
62
|
+
const link=path.join(root,'project-link');
|
|
63
|
+
try{
|
|
64
|
+
const runtime=path.join(root,'runtime'),policyFile=path.join(root,'autonomous.json');
|
|
65
|
+
await symlink(path.parse(root).root,link,'junction');
|
|
66
|
+
await writeFile(policyFile,JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
|
|
67
|
+
lease_file:path.join(runtime,'autonomous-grant.json'),coding_policy_sha256:'a'.repeat(64),root_ids:['project']}));
|
|
68
|
+
const source=await readFile(controllerPath,'utf8');
|
|
69
|
+
const helperStart=source.indexOf('function Read-ControllerPolicySnapshot(');
|
|
70
|
+
const helperEnd=source.indexOf('function Get-CodingPolicyMetadata(',helperStart);
|
|
71
|
+
const start=source.indexOf('function Get-AutonomousPolicyMetadata(');
|
|
72
|
+
const end=source.indexOf('function Get-AutonomousLeaseStatus(',start);
|
|
73
|
+
const block=source.slice(helperStart,helperEnd)+source.slice(start,end);
|
|
74
|
+
const script=`$ErrorActionPreference='Stop';$RuntimeDir=${quote(runtime)};function Fail([string]$m){throw $m};function Get-CodingPolicyMetadata($Cfg){return [pscustomobject]@{Sha256='a'.PadLeft(64,'a');RootIds=@('project');RootPaths=@{project=${quote(link)}};RootAccess=@{project=@{read=$true;write=$true;exec=$false}}}};${block};try{Get-AutonomousPolicyMetadata @{AutonomousPolicyFile=${quote(policyFile)}}|Out-Null;Write-Output 'UNEXPECTED_PASS'}catch{Write-Output $_.Exception.Message}`;
|
|
75
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
76
|
+
assert.equal(result.status,0,result.stderr);
|
|
77
|
+
assert.match(result.stdout,/real project directory/);
|
|
78
|
+
assert.doesNotMatch(result.stdout,/UNEXPECTED_PASS/);
|
|
79
|
+
}finally{
|
|
80
|
+
await unlink(link).catch(error=>{if(error.code!=='ENOENT')throw error;});
|
|
81
|
+
await rm(root,{recursive:true,force:true});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test('R70 controller refuses a narrow Autonomous root when Coding still empowers a whole drive',async()=>{
|
|
86
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-controller-coding-drive-'));
|
|
87
|
+
try{
|
|
88
|
+
const runtime=path.join(root,'runtime'),policyFile=path.join(root,'autonomous.json');
|
|
89
|
+
const drive=path.parse(root).root;
|
|
90
|
+
await writeFile(policyFile,JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
|
|
91
|
+
lease_file:path.join(runtime,'autonomous-grant.json'),coding_policy_sha256:'a'.repeat(64),root_ids:['project']}));
|
|
92
|
+
const source=await readFile(controllerPath,'utf8');
|
|
93
|
+
const helperStart=source.indexOf('function Read-ControllerPolicySnapshot(');
|
|
94
|
+
const helperEnd=source.indexOf('function Get-CodingPolicyMetadata(',helperStart);
|
|
95
|
+
const start=source.indexOf('function Get-AutonomousPolicyMetadata(');
|
|
96
|
+
const end=source.indexOf('function Get-AutonomousLeaseStatus(',start);
|
|
97
|
+
const block=source.slice(helperStart,helperEnd)+source.slice(start,end);
|
|
98
|
+
const script=`$ErrorActionPreference='Stop';$RuntimeDir=${quote(runtime)};function Fail([string]$m){throw $m};function Get-CodingPolicyMetadata($Cfg){return [pscustomobject]@{Sha256='a'.PadLeft(64,'a');RootIds=@('project','local_drive');RootPaths=@{project=${quote(root)};local_drive=${quote(drive)}};RootAccess=@{project=@{read=$true;write=$true;exec=$false};local_drive=@{read=$true;write=$true;exec=$true}}}};${block};try{Get-AutonomousPolicyMetadata @{AutonomousPolicyFile=${quote(policyFile)}}|Out-Null;Write-Output 'UNEXPECTED_PASS'}catch{Write-Output $_.Exception.Message}`;
|
|
99
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
100
|
+
assert.equal(result.status,0,result.stderr);
|
|
101
|
+
assert.match(result.stdout,/coding policy contains a broad filesystem root/);
|
|
102
|
+
assert.doesNotMatch(result.stdout,/UNEXPECTED_PASS/);
|
|
103
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
104
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {mkdtemp,readFile,rm,writeFile} from 'node:fs/promises';
|
|
4
|
+
import {spawnSync} from 'node:child_process';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
const controllerPath=new URL('../controller/deadbyte-controller.ps1',import.meta.url);
|
|
9
|
+
const quote=value=>`'${String(value).replaceAll("'","''")}'`;
|
|
10
|
+
|
|
11
|
+
test('R70 Autonomous status cannot exceed effective Coding grant roots',async()=>{
|
|
12
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-grant-subset-'));
|
|
13
|
+
try{
|
|
14
|
+
const grant=path.join(root,'autonomous-grant.json');
|
|
15
|
+
await writeFile(grant,JSON.stringify({schema:'deadbyte.autonomous-grant.v2',policy_sha256:'a'.repeat(64),
|
|
16
|
+
coding_policy_sha256:'b'.repeat(64),instance_nonce:'c'.repeat(64),root_ids:['other']}));
|
|
17
|
+
const source=await readFile(controllerPath,'utf8');
|
|
18
|
+
const start=source.indexOf('function Get-AutonomousLeaseStatus('),end=source.indexOf('function Arm-Autonomous(',start);
|
|
19
|
+
assert.ok(start>=0&&end>start);
|
|
20
|
+
const block=source.slice(start,end);
|
|
21
|
+
const script=`$ErrorActionPreference='Stop';function Get-AutonomousPolicyMetadata($Cfg){return [pscustomobject]@{LeaseFile=${quote(grant)};Sha256='a'.PadLeft(64,'a');CodingPolicySha256='b'.PadLeft(64,'b');RootIds=@('project','other')}};function Get-CodingLeaseStatus($Cfg){return [pscustomobject]@{Armed=$true;RootIds=@('project')}};function Get-AuthorityEpochStatus($Cfg,$Plane,$Grant,$Nonce){return [pscustomobject]@{Trusted=$true;Seq=1;EventSha256='d'.PadLeft(64,'d')}};${block};$s=Get-AutonomousLeaseStatus @{AutonomousPolicyFile='fixture'};$s|ConvertTo-Json -Compress`;
|
|
22
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
23
|
+
assert.equal(result.status,0,result.stderr);
|
|
24
|
+
const state=JSON.parse(result.stdout.trim());
|
|
25
|
+
assert.equal(state.Armed,false);
|
|
26
|
+
assert.equal(state.Reason,'coding-roots');
|
|
27
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
28
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {mkdtemp,readFile,rm} from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import {spawnSync} from 'node:child_process';
|
|
7
|
+
|
|
8
|
+
const controllerPath=new URL('../controller/deadbyte-controller.ps1',import.meta.url);
|
|
9
|
+
const LEGACY='6274492644c303b38117541cc22a59e88e6ff5fdef7051a5d57ad336f45765f5';
|
|
10
|
+
const H=c=>c.repeat(64);
|
|
11
|
+
|
|
12
|
+
async function probe(policySha,rootId){
|
|
13
|
+
const source=await readFile(controllerPath,'utf8');
|
|
14
|
+
const start=source.indexOf('function Arm-Autonomous(');
|
|
15
|
+
const end=source.indexOf('function Disarm-Autonomous(',start);
|
|
16
|
+
assert.ok(start>=0&&end>start,'controller arm function must be present');
|
|
17
|
+
const slice=source.slice(start,end);
|
|
18
|
+
const script=`$ErrorActionPreference='Stop';
|
|
19
|
+
function Fail([string]$m){throw $m}
|
|
20
|
+
function Get-CodingLeaseStatus($Cfg){return [pscustomobject]@{Armed=$true;RootIds=@('core','gfx_project')}}
|
|
21
|
+
function Get-AutonomousPolicyMetadata($Cfg){return [pscustomobject]@{Sha256='${policySha}';RootIds=@('${rootId}');CodingPolicySha256='${H('a')}'}}
|
|
22
|
+
function Ensure-Directory($d){Write-Output 'MUTATION_REACHED';throw 'TEST_STUB_NO_GRANT'}
|
|
23
|
+
$RuntimeDir='fixture-only'
|
|
24
|
+
${slice}
|
|
25
|
+
try{Arm-Autonomous @{};Write-Output 'UNEXPECTED_PASS'}catch{Write-Output ('GATE_ERROR '+$_.Exception.Message)}
|
|
26
|
+
`;
|
|
27
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
28
|
+
assert.equal(result.status,0,result.stderr);
|
|
29
|
+
return result.stdout;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
test('R70 controller must reject unapproved successor Autonomous policy before grant I/O',async()=>{
|
|
33
|
+
for(const [sha,id] of [[H('b'),'gfx_project'],[H('b'),'core'],[LEGACY,'gfx_project']]){
|
|
34
|
+
const output=await probe(sha,id);
|
|
35
|
+
assert.match(output,/R70_OWNER_ENROLLMENT_REQUIRED/,output);
|
|
36
|
+
assert.doesNotMatch(output,/MUTATION_REACHED|UNEXPECTED_PASS/,output);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('R70 newly issued legacy-core grant includes bounded expiry before signing',async()=>{
|
|
41
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r70-finite-grant-'));
|
|
42
|
+
const leaseFile=path.join(root,'grant.json');
|
|
43
|
+
const quote=s=>`'${s.replaceAll("'","''")}'`;
|
|
44
|
+
try{
|
|
45
|
+
const source=await readFile(controllerPath,'utf8');
|
|
46
|
+
const start=source.indexOf('function Arm-Autonomous(');
|
|
47
|
+
const end=source.indexOf('function Disarm-Autonomous(',start);
|
|
48
|
+
assert.ok(start>=0&&end>start);
|
|
49
|
+
const script=`$ErrorActionPreference='Stop';
|
|
50
|
+
function Fail([string]$m){throw $m}
|
|
51
|
+
function Get-CodingLeaseStatus($Cfg){return [pscustomobject]@{Armed=$true;RootIds=@('core')}}
|
|
52
|
+
function Get-AutonomousPolicyMetadata($Cfg){return [pscustomobject]@{Sha256='${LEGACY}';RootIds=@('core');CodingPolicySha256='${H('a')}';LeaseFile=${quote(leaseFile)}}}
|
|
53
|
+
function Ensure-Directory($p){}
|
|
54
|
+
function Invoke-AuthorityEpochCommand($Cfg,$Plane,$Action,$File){return 'TEST_ONLY_EPOCH'}
|
|
55
|
+
$RuntimeDir=${quote(root)}
|
|
56
|
+
${source.slice(start,end)}
|
|
57
|
+
Arm-Autonomous @{};
|
|
58
|
+
`;
|
|
59
|
+
const before=Date.now();
|
|
60
|
+
const result=spawnSync('powershell',['-NoLogo','-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',timeout:15000});
|
|
61
|
+
const after=Date.now();
|
|
62
|
+
assert.equal(result.status,0,result.stderr);
|
|
63
|
+
const grant=JSON.parse((await readFile(leaseFile,'utf8')).replace(/^\uFEFF/,''));
|
|
64
|
+
assert.equal(grant.schema,'deadbyte.autonomous-grant.v2');
|
|
65
|
+
assert.equal(grant.policy_sha256,LEGACY);
|
|
66
|
+
assert.equal(grant.coding_policy_sha256,H('a'));
|
|
67
|
+
assert.deepEqual(grant.root_ids,['core']);
|
|
68
|
+
const issued=Date.parse(grant.granted_at_utc),expires=Date.parse(grant.expires_at_utc);
|
|
69
|
+
assert.ok(Number.isFinite(issued)&&Number.isFinite(expires),'grant must include valid UTC times');
|
|
70
|
+
assert.ok(issued>=before-1000&&issued<=after+1000,'signed grant issued_at must be current');
|
|
71
|
+
assert.equal(expires-issued,3_600_000,'new grant must expire within exactly one hour');
|
|
72
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('R70 exact known-good core policy keeps existing explicit manual arm route',async()=>{
|
|
76
|
+
const output=await probe(LEGACY,'core');
|
|
77
|
+
assert.match(output,/MUTATION_REACHED/,output);
|
|
78
|
+
assert.match(output,/TEST_STUB_NO_GRANT/,output);
|
|
79
|
+
assert.doesNotMatch(output,/UNEXPECTED_PASS/,output);
|
|
80
|
+
});
|