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
|
@@ -12,6 +12,15 @@ const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
|
12
12
|
const cliPath=path.join(root,'src','deadbyte-cli.mjs');
|
|
13
13
|
const isWindows=process.platform==='win32';
|
|
14
14
|
const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
|
|
15
|
+
const fixtureTimeoutMs=30000;
|
|
16
|
+
async function boundedCompletion(promise,timeoutMs=fixtureTimeoutMs){
|
|
17
|
+
let timer;
|
|
18
|
+
try{return await Promise.race([promise,new Promise(resolve=>{
|
|
19
|
+
timer=setTimeout(()=>resolve({timeout:true}),timeoutMs);
|
|
20
|
+
timer.unref?.();
|
|
21
|
+
})]);}
|
|
22
|
+
finally{clearTimeout(timer);}
|
|
23
|
+
}
|
|
15
24
|
|
|
16
25
|
async function fixture({failCommand='',statusOnline=false}={}){
|
|
17
26
|
const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-remote-session-'));
|
|
@@ -45,7 +54,7 @@ async function traceCommands(file,{read=readFile,retryDelayMs=10,maxAttempts=20}
|
|
|
45
54
|
}
|
|
46
55
|
return [];
|
|
47
56
|
}
|
|
48
|
-
async function waitFor(file,predicate,{timeoutMs=
|
|
57
|
+
async function waitFor(file,predicate,{timeoutMs=fixtureTimeoutMs}={}){
|
|
49
58
|
const deadline=Date.now()+timeoutMs;
|
|
50
59
|
while(Date.now()<deadline){
|
|
51
60
|
const commands=await traceCommands(file);
|
|
@@ -73,6 +82,17 @@ async function collect(child){
|
|
|
73
82
|
const closed=new Promise(resolve=>child.once('close',(code,signal)=>resolve({code,signal})));
|
|
74
83
|
return {closed,get stdout(){return stdout;},get stderr(){return stderr;}};
|
|
75
84
|
}
|
|
85
|
+
// Windows: SIGKILL leaves PowerShell child holding a handle on the .ps1 fixture
|
|
86
|
+
// for a short window; retry rm() until it succeeds or gives up.
|
|
87
|
+
async function safeRm(dir,{maxAttempts=10,retryDelayMs=200}={}){
|
|
88
|
+
for(let i=0;i<maxAttempts;i++){
|
|
89
|
+
try{await rm(dir,{recursive:true,force:true});return;}
|
|
90
|
+
catch(err){
|
|
91
|
+
if(err?.code==='EBUSY'&&i<maxAttempts-1){await sleep(retryDelayMs);continue;}
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
76
96
|
|
|
77
97
|
const winTest=isWindows?test:test.skip;
|
|
78
98
|
|
|
@@ -80,14 +100,14 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
|
|
|
80
100
|
const fx=await fixture({failCommand:'start',statusOnline:true});
|
|
81
101
|
let child=null;
|
|
82
102
|
try{
|
|
83
|
-
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
103
|
+
child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
84
104
|
const output=await collect(child);
|
|
85
|
-
const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=3,{timeoutMs:
|
|
105
|
+
const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=3,{timeoutMs:fixtureTimeoutMs});
|
|
86
106
|
assert.deepEqual(ready.slice(0,6),['status','status','armprocess','armcoding','armautonomous','status'],output.stderr);
|
|
87
107
|
assert.doesNotMatch(ready.join(','),/(^|,)start(,|$)/);
|
|
88
108
|
assert.equal(child.exitCode,null,'remote session must remain foreground after reusing ONLINE runtime');
|
|
89
109
|
assert.match(output.stdout,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
|
|
90
|
-
const authDeadline=Date.now()+
|
|
110
|
+
const authDeadline=Date.now()+fixtureTimeoutMs;
|
|
91
111
|
while(Date.now()<authDeadline&&!/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/.test(output.stdout)) await sleep(50);
|
|
92
112
|
assert.match(output.stdout,/\[DISPLAY\] ASCII fallback: stdout_not_tty/);
|
|
93
113
|
assert.match(output.stdout,/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/);
|
|
@@ -95,7 +115,31 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
|
|
|
95
115
|
await output.closed;
|
|
96
116
|
}finally{
|
|
97
117
|
if(child&&child.exitCode===null) child.kill('SIGKILL');
|
|
98
|
-
await
|
|
118
|
+
await safeRm(fx.dir);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
winTest('R72 bare remote reaches READY with every authority disarmed and never arms a plane',async()=>{
|
|
123
|
+
const fx=await fixture({statusOnline:true});
|
|
124
|
+
let child=null;
|
|
125
|
+
try{
|
|
126
|
+
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
127
|
+
const output=await collect(child);
|
|
128
|
+
const deadline=Date.now()+fixtureTimeoutMs;
|
|
129
|
+
while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)&&child.exitCode===null)await sleep(50);
|
|
130
|
+
assert.match(output.stdout,/\[READY\]/,output.stderr);
|
|
131
|
+
assert.match(output.stdout,/\[AUTH\] process DISARMED \| coding DISARMED \| autonomous DISARMED \| desktop DISARMED \| host DISARMED/);
|
|
132
|
+
const before=await traceCommands(fx.trace);
|
|
133
|
+
assert.deepEqual(before.slice(0,6),['status','status','disarmautonomous','disarmcoding','disarmprocess','status']);
|
|
134
|
+
assert.equal(before.filter(x=>/^arm(?:process|coding|autonomous|host|desktop)$/.test(x)).length,0,'bare remote must issue zero ARM commands');
|
|
135
|
+
child.stdin.end();
|
|
136
|
+
const ended=await boundedCompletion(output.closed);
|
|
137
|
+
assert.equal(ended.timeout,undefined,'bare remote did not stop');
|
|
138
|
+
assert.equal(ended.code,0,output.stderr);
|
|
139
|
+
assert.equal((await traceCommands(fx.trace)).at(-1),'park');
|
|
140
|
+
}finally{
|
|
141
|
+
if(child?.exitCode===null)child.kill('SIGKILL');
|
|
142
|
+
await safeRm(fx.dir);
|
|
99
143
|
}
|
|
100
144
|
});
|
|
101
145
|
|
|
@@ -106,16 +150,16 @@ winTest('bounded remote disarms a stale standing Host grant before READY',async(
|
|
|
106
150
|
try{
|
|
107
151
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
108
152
|
const output=await collect(child);
|
|
109
|
-
const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3,{timeoutMs:
|
|
153
|
+
const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3,{timeoutMs:fixtureTimeoutMs});
|
|
110
154
|
assert.ok(commands.indexOf('disarmhost')>commands.indexOf('status'));
|
|
111
|
-
const deadline=Date.now()+
|
|
155
|
+
const deadline=Date.now()+fixtureTimeoutMs;
|
|
112
156
|
while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
|
|
113
157
|
assert.match(output.stdout,/\[READY\]/,output.stderr);
|
|
114
158
|
child.stdin.end();
|
|
115
159
|
assert.equal((await output.closed).code,0,output.stderr);
|
|
116
160
|
}finally{
|
|
117
161
|
if(child&&child.exitCode===null) child.kill('SIGKILL');
|
|
118
|
-
await
|
|
162
|
+
await safeRm(fx.dir);
|
|
119
163
|
}
|
|
120
164
|
});
|
|
121
165
|
|
|
@@ -125,7 +169,7 @@ winTest('remote --full verifies all five planes before READY and revokes them on
|
|
|
125
169
|
try{
|
|
126
170
|
child=spawn(process.execPath,[cliPath,'remote','--full'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
127
171
|
const output=await collect(child);
|
|
128
|
-
const deadline=Date.now()+
|
|
172
|
+
const deadline=Date.now()+fixtureTimeoutMs;
|
|
129
173
|
while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
|
|
130
174
|
assert.match(output.stdout,/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop ARMED \| host ARMED/,output.stderr);
|
|
131
175
|
assert.match(output.stdout,/\[READY\]/);
|
|
@@ -137,7 +181,7 @@ winTest('remote --full verifies all five planes before READY and revokes them on
|
|
|
137
181
|
assert.deepEqual(after.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
|
|
138
182
|
}finally{
|
|
139
183
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
140
|
-
await
|
|
184
|
+
await safeRm(fx.dir);
|
|
141
185
|
}
|
|
142
186
|
});
|
|
143
187
|
|
|
@@ -148,7 +192,7 @@ for(const [flag,armedPlane,disarmedPlane] of [['--desktop','desktop','host'],['-
|
|
|
148
192
|
try{
|
|
149
193
|
child=spawn(process.execPath,[cliPath,'remote',flag],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
150
194
|
const output=await collect(child);
|
|
151
|
-
const deadline=Date.now()+
|
|
195
|
+
const deadline=Date.now()+fixtureTimeoutMs;
|
|
152
196
|
while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
|
|
153
197
|
assert.match(output.stdout,/\[READY\]/,output.stderr);
|
|
154
198
|
assert.match(output.stdout,new RegExp(`${armedPlane} ARMED`));
|
|
@@ -160,7 +204,7 @@ for(const [flag,armedPlane,disarmedPlane] of [['--desktop','desktop','host'],['-
|
|
|
160
204
|
assert.equal((await output.closed).code,0,output.stderr);
|
|
161
205
|
}finally{
|
|
162
206
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
163
|
-
await
|
|
207
|
+
await safeRm(fx.dir);
|
|
164
208
|
}
|
|
165
209
|
});
|
|
166
210
|
}
|
|
@@ -173,7 +217,7 @@ winTest('conflicting remote authority modes fail before controller mutation',asy
|
|
|
173
217
|
assert.notEqual((await output.closed).code,0);
|
|
174
218
|
assert.match(output.stderr,/mutually exclusive/);
|
|
175
219
|
assert.deepEqual(await traceCommands(fx.trace),[]);
|
|
176
|
-
}finally{await
|
|
220
|
+
}finally{await safeRm(fx.dir);}
|
|
177
221
|
});
|
|
178
222
|
|
|
179
223
|
winTest('remote refuses READY when public signed MCP execution probe fails',async()=>{
|
|
@@ -182,14 +226,14 @@ winTest('remote refuses READY when public signed MCP execution probe fails',asyn
|
|
|
182
226
|
try{
|
|
183
227
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
184
228
|
const output=await collect(child);
|
|
185
|
-
const ended=await
|
|
229
|
+
const ended=await boundedCompletion(output.closed);
|
|
186
230
|
assert.equal(ended.timeout,undefined,'remote did not fail closed after execution probe failure');
|
|
187
231
|
assert.notEqual(ended.code,0);
|
|
188
232
|
assert.doesNotMatch(output.stdout,/\[READY\]|\[OK\] ONLINE/);
|
|
189
233
|
assert.match(output.stderr,/machinetest|execution probe/i);
|
|
190
234
|
}finally{
|
|
191
235
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
192
|
-
await
|
|
236
|
+
await safeRm(fx.dir);
|
|
193
237
|
}
|
|
194
238
|
});
|
|
195
239
|
|
|
@@ -201,14 +245,14 @@ winTest('remote refuses READY when controller snapshot lies about Host enforceme
|
|
|
201
245
|
try{
|
|
202
246
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
203
247
|
const output=await collect(child);
|
|
204
|
-
const ended=await
|
|
248
|
+
const ended=await boundedCompletion(output.closed);
|
|
205
249
|
assert.equal(ended.timeout,undefined,`remote did not reject split authority truth; stdout=${output.stdout.slice(-1200)} stderr=${output.stderr.slice(-1200)} trace=${(await traceCommands(fx.trace)).join(',')}`);
|
|
206
250
|
assert.notEqual(ended.code,0);
|
|
207
251
|
assert.doesNotMatch(output.stdout,/\[READY\]|\[OK\] ONLINE/);
|
|
208
252
|
assert.match(output.stderr,/machinetest|enforcement/i);
|
|
209
253
|
}finally{
|
|
210
254
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
211
|
-
await
|
|
255
|
+
await safeRm(fx.dir);
|
|
212
256
|
}
|
|
213
257
|
});
|
|
214
258
|
|
|
@@ -220,7 +264,7 @@ winTest('foreground cleanup retains ownership when status lies about a no-op Hos
|
|
|
220
264
|
try{
|
|
221
265
|
child=spawn(process.execPath,[cliPath,'remote','--full'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
222
266
|
const output=await collect(child);
|
|
223
|
-
const deadline=Date.now()+
|
|
267
|
+
const deadline=Date.now()+fixtureTimeoutMs;
|
|
224
268
|
while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
|
|
225
269
|
assert.match(output.stdout,/\[READY\]/,output.stderr);
|
|
226
270
|
child.stdin.end();
|
|
@@ -230,7 +274,7 @@ winTest('foreground cleanup retains ownership when status lies about a no-op Hos
|
|
|
230
274
|
assert.ok(!(await traceCommands(fx.trace)).includes('park'));
|
|
231
275
|
}finally{
|
|
232
276
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
233
|
-
await
|
|
277
|
+
await safeRm(fx.dir);
|
|
234
278
|
}
|
|
235
279
|
});
|
|
236
280
|
|
|
@@ -240,26 +284,28 @@ winTest('bare remote PARKED startup does not wait for a long-lived child holding
|
|
|
240
284
|
let child=null;
|
|
241
285
|
try{
|
|
242
286
|
const startedAt=Date.now();
|
|
243
|
-
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
287
|
+
child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
244
288
|
const output=await collect(child);
|
|
245
|
-
const
|
|
289
|
+
const afterStart=await waitFor(fx.trace,commands=>commands.length>=3,{timeoutMs:15000});
|
|
246
290
|
const elapsed=Date.now()-startedAt;
|
|
291
|
+
assert.deepEqual(afterStart.slice(0,3),['status','start','status']);
|
|
292
|
+
assert.ok(elapsed<12000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
|
|
293
|
+
const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4,{timeoutMs:fixtureTimeoutMs});
|
|
247
294
|
assert.deepEqual(ready.slice(0,8),['status','start','status','status','armprocess','armcoding','armautonomous','status']);
|
|
248
|
-
assert.ok(elapsed<7000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
|
|
249
295
|
assert.equal(child.exitCode,null,'remote session must remain foreground after PARKED startup');
|
|
250
296
|
assert.match(output.stdout,/\[BOOT\] Starting bridge\/runtime\.\.\./);
|
|
251
|
-
const readyDeadline=Date.now()+
|
|
297
|
+
const readyDeadline=Date.now()+fixtureTimeoutMs;
|
|
252
298
|
while(Date.now()<readyDeadline&&!/\[OK\] ONLINE/.test(output.stdout)) await sleep(50);
|
|
253
299
|
assert.match(output.stdout,/\[OK\] ONLINE/);
|
|
254
300
|
child.stdin.end();
|
|
255
|
-
const ended=await
|
|
301
|
+
const ended=await boundedCompletion(output.closed);
|
|
256
302
|
assert.equal(ended.timeout,undefined,'remote session did not exit after PARKED startup proof');
|
|
257
303
|
assert.equal(ended.code,0,output.stderr);
|
|
258
304
|
}finally{
|
|
259
305
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
260
306
|
try{const pid=Number((await readFile(fx.spawnedPid,'utf8')).trim());if(Number.isInteger(pid)&&pid>0) process.kill(pid,'SIGKILL');}catch{}
|
|
261
307
|
await sleep(100);
|
|
262
|
-
await
|
|
308
|
+
await safeRm(fx.dir);
|
|
263
309
|
}
|
|
264
310
|
});
|
|
265
311
|
|
|
@@ -267,13 +313,14 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
267
313
|
const fx=await fixture();
|
|
268
314
|
let child=null;
|
|
269
315
|
try{
|
|
270
|
-
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
316
|
+
child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
271
317
|
const output=await collect(child);
|
|
272
318
|
const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4);
|
|
273
319
|
assert.deepEqual(ready.slice(0,8),['status','start','status','status','armprocess','armcoding','armautonomous','status']);
|
|
274
320
|
assert.equal(child.exitCode,null,'remote session must remain foreground after becoming ready');
|
|
275
|
-
const tailDeadline=Date.now()+
|
|
276
|
-
while(Date.now()<tailDeadline
|
|
321
|
+
const tailDeadline=Date.now()+fixtureTimeoutMs;
|
|
322
|
+
while(Date.now()<tailDeadline&&(!/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/.test(output.stdout)||
|
|
323
|
+
!/\[READY\] DEADBYTE MCP online/.test(output.stdout))) await sleep(50);
|
|
277
324
|
assert.match(output.stdout,/\[DISPLAY\] ASCII fallback: stdout_not_tty/);
|
|
278
325
|
assert.match(output.stdout,/\[DEVICE\] Starting DEADBYTE MCP/);
|
|
279
326
|
assert.match(output.stdout,/\[BRIDGE\] Local bridge connected/);
|
|
@@ -305,7 +352,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
305
352
|
'[TOOL OUT] 2026-09-16T00:00:00.001Z #000001 coding_tree {"is_error":false}',
|
|
306
353
|
'[TOOL OUT] 2026-09-16T00:00:00.002Z #000002 coding_file_read {"is_error":true}'
|
|
307
354
|
].join('\n')+'\n','utf8');
|
|
308
|
-
const logDeadline=Date.now()+
|
|
355
|
+
const logDeadline=Date.now()+fixtureTimeoutMs;
|
|
309
356
|
while(Date.now()<logDeadline&&!/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s \[SLOW\] ERR$/m.test(output.stdout)) await sleep(50);
|
|
310
357
|
assert.doesNotMatch(output.stdout,/\| Arguments:/,'default human view must not print request JSON');
|
|
311
358
|
assert.match(output.stdout,/^S .*#2 \[abcdef12\] coding_tree projects:src 42ms OK$/m);
|
|
@@ -325,7 +372,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
325
372
|
assert.doesNotMatch(output.stdout,/\[TOOL IN \]|\[TOOL OUT\]/);
|
|
326
373
|
assert.doesNotMatch(output.stdout,/payload bytes=/);
|
|
327
374
|
child.stdin.end();
|
|
328
|
-
const ended=await
|
|
375
|
+
const ended=await boundedCompletion(output.closed);
|
|
329
376
|
assert.equal(ended.timeout,undefined,'remote session did not exit after foreground input closed');
|
|
330
377
|
const commands=await traceCommands(fx.trace);
|
|
331
378
|
assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
|
|
@@ -336,7 +383,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
336
383
|
assert.doesNotMatch(output.stdout,/\p{Extended_Pictographic}/u,'piped Windows fallback must remain ASCII-safe');
|
|
337
384
|
}finally{
|
|
338
385
|
if(child?.exitCode===null) child.kill();
|
|
339
|
-
await
|
|
386
|
+
await safeRm(fx.dir);
|
|
340
387
|
}
|
|
341
388
|
});
|
|
342
389
|
|
|
@@ -373,7 +420,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
|
|
|
373
420
|
deadline=Date.now()+3000;
|
|
374
421
|
while(Date.now()<deadline&&!/^R .*#4 \[resume-r\] coding_file_read projects:src\/deadbyte-cli\.mjs.*OK$/m.test(firstOutput.stdout)) await sleep(50);
|
|
375
422
|
first.stdin.end();
|
|
376
|
-
const firstEnded=await
|
|
423
|
+
const firstEnded=await boundedCompletion(firstOutput.closed);
|
|
377
424
|
assert.equal(firstEnded.timeout,undefined);
|
|
378
425
|
|
|
379
426
|
second=spawn(process.execPath,[cliPath,'remote','--resume',cursor1],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
@@ -394,12 +441,12 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
|
|
|
394
441
|
const liveIndex=secondOutput.stdout.indexOf('[LOG] Human live timeline');
|
|
395
442
|
assert.ok(callReplayIndex>=0&&resultReplayIndex>callReplayIndex&&liveIndex>resultReplayIndex,'resume ordering must be call -> result -> live tail');
|
|
396
443
|
second.stdin.end();
|
|
397
|
-
const secondEnded=await
|
|
444
|
+
const secondEnded=await boundedCompletion(secondOutput.closed);
|
|
398
445
|
assert.equal(secondEnded.timeout,undefined);
|
|
399
446
|
assert.equal(secondEnded.code,0,secondOutput.stderr);
|
|
400
447
|
}finally{
|
|
401
448
|
if(first?.exitCode===null) first.kill();if(second?.exitCode===null) second.kill();
|
|
402
|
-
await
|
|
449
|
+
await safeRm(fx.dir);
|
|
403
450
|
}
|
|
404
451
|
});
|
|
405
452
|
|
|
@@ -423,14 +470,14 @@ winTest('remote --verbose enables sanitized request detail while preserving fore
|
|
|
423
470
|
assert.match(output.stdout,/coding_tree\s+\| Arguments: .*"path":"src".*"root_id":"projects"/);
|
|
424
471
|
assert.doesNotMatch(output.stdout,/DO_NOT_PRINT_VERBOSE_SECRET/);
|
|
425
472
|
child.stdin.end();
|
|
426
|
-
const ended=await
|
|
473
|
+
const ended=await boundedCompletion(output.closed);
|
|
427
474
|
assert.equal(ended.timeout,undefined);
|
|
428
475
|
assert.equal(ended.code,0,output.stderr);
|
|
429
476
|
const commands=await traceCommands(fx.trace);
|
|
430
477
|
assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
|
|
431
478
|
}finally{
|
|
432
479
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
433
|
-
await
|
|
480
|
+
await safeRm(fx.dir);
|
|
434
481
|
}
|
|
435
482
|
});
|
|
436
483
|
|
|
@@ -438,7 +485,7 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
|
|
|
438
485
|
const fx=await fixture();
|
|
439
486
|
let child=null;
|
|
440
487
|
try{
|
|
441
|
-
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
488
|
+
child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
442
489
|
const output=await collect(child);
|
|
443
490
|
const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4);
|
|
444
491
|
assert.deepEqual(ready.slice(0,8),['status','start','status','status','armprocess','armcoding','armautonomous','status']);
|
|
@@ -469,7 +516,7 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
|
|
|
469
516
|
assert.equal(markerGone,true,'guardian left stale remote-session marker after hard kill');
|
|
470
517
|
}finally{
|
|
471
518
|
if(child?.exitCode===null) child.kill();
|
|
472
|
-
await
|
|
519
|
+
await safeRm(fx.dir);
|
|
473
520
|
}
|
|
474
521
|
});
|
|
475
522
|
|
|
@@ -480,12 +527,12 @@ winTest('guardian retains ownership marker when disarm exits zero but Host remai
|
|
|
480
527
|
try{
|
|
481
528
|
child=spawn(process.execPath,[cliPath,'remote','--full'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
482
529
|
const output=await collect(child);
|
|
483
|
-
const deadline=Date.now()+
|
|
530
|
+
const deadline=Date.now()+fixtureTimeoutMs;
|
|
484
531
|
while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
|
|
485
532
|
assert.match(output.stdout,/\[READY\]/,output.stderr);
|
|
486
533
|
child.kill('SIGKILL');
|
|
487
534
|
await output.closed;
|
|
488
|
-
await waitFor(fx.trace,commands=>commands.includes('disarmhost'),{timeoutMs:
|
|
535
|
+
await waitFor(fx.trace,commands=>commands.includes('disarmhost'),{timeoutMs:fixtureTimeoutMs});
|
|
489
536
|
await sleep(750);
|
|
490
537
|
const marker=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-session.json'),'utf8'));
|
|
491
538
|
assert.equal(marker.schema,'deadbyte.remote-session.v2');
|
|
@@ -493,23 +540,23 @@ winTest('guardian retains ownership marker when disarm exits zero but Host remai
|
|
|
493
540
|
assert.ok(!commands.includes('park'),'guardian must not park after unverified revocation');
|
|
494
541
|
}finally{
|
|
495
542
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
496
|
-
await
|
|
543
|
+
await safeRm(fx.dir);
|
|
497
544
|
}
|
|
498
545
|
});
|
|
499
546
|
|
|
500
547
|
winTest('bare remote rolls back authority and parks if one plane fails to arm',async()=>{
|
|
501
548
|
const fx=await fixture({failCommand:'armcoding'});
|
|
502
549
|
try{
|
|
503
|
-
const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
550
|
+
const child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
504
551
|
const output=await collect(child);
|
|
505
|
-
const ended=await
|
|
552
|
+
const ended=await boundedCompletion(output.closed);
|
|
506
553
|
assert.equal(ended.timeout,undefined,`failed startup did not terminate; stdout=${output.stdout.slice(-1200)} stderr=${output.stderr.slice(-1200)} trace=${(await traceCommands(fx.trace)).join(',')}`);
|
|
507
554
|
assert.notEqual(ended.code,0);
|
|
508
555
|
const commands=await traceCommands(fx.trace);
|
|
509
556
|
assert.deepEqual(commands.slice(0,6),['status','start','status','status','armprocess','armcoding']);
|
|
510
557
|
assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
|
|
511
558
|
assert.doesNotMatch(output.stdout,/Live logs/i);
|
|
512
|
-
}finally{await
|
|
559
|
+
}finally{await safeRm(fx.dir);}
|
|
513
560
|
});
|
|
514
561
|
|
|
515
562
|
winTest('bare remote recovers a stale crashed session before arming a new one',async()=>{
|
|
@@ -521,18 +568,18 @@ winTest('bare remote recovers a stale crashed session before arming a new one',a
|
|
|
521
568
|
await writeFile(path.join(runtime,'remote-session.json'),JSON.stringify({schema:'deadbyte.remote-session.v1',pid:2147483000,started_at_utc:'2026-01-01T00:00:00.000Z'}),'utf8');
|
|
522
569
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
523
570
|
const output=await collect(child);
|
|
524
|
-
const ready=await waitFor(fx.trace,commands=>commands.
|
|
571
|
+
const ready=await waitFor(fx.trace,commands=>commands.length>=10&&commands[9]==='start');
|
|
525
572
|
assert.deepEqual(ready.slice(0,8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
|
|
526
573
|
assert.equal(ready[8],'status');
|
|
527
574
|
assert.equal(ready[9],'start');
|
|
528
575
|
assert.match(output.stdout,/\[RECOVERY\] Stale remote session pid=2147483000; revoking authority before restart\./);
|
|
529
576
|
child.stdin.end();
|
|
530
|
-
const ended=await
|
|
577
|
+
const ended=await boundedCompletion(output.closed);
|
|
531
578
|
assert.equal(ended.timeout,undefined);
|
|
532
579
|
assert.equal(ended.code,0,output.stderr);
|
|
533
580
|
}finally{
|
|
534
581
|
if(child?.exitCode===null) child.kill();
|
|
535
|
-
await
|
|
582
|
+
await safeRm(fx.dir);
|
|
536
583
|
}
|
|
537
584
|
});
|
|
538
585
|
|
|
@@ -546,13 +593,13 @@ winTest('remote warning lines use deterministic ASCII fallback on piped Windows
|
|
|
546
593
|
const markerPath=path.join(fx.state,'runtime','remote-session.json');
|
|
547
594
|
await writeFile(markerPath,'{invalid-json\n','utf8');
|
|
548
595
|
child.stdin.end();
|
|
549
|
-
const ended=await
|
|
596
|
+
const ended=await boundedCompletion(output.closed);
|
|
550
597
|
assert.equal(ended.timeout,undefined,'remote session did not exit after warning fixture');
|
|
551
598
|
assert.match(output.stderr,/^\[WARN\] remote session marker cleanup:/m);
|
|
552
599
|
assert.doesNotMatch(output.stderr,/\p{Extended_Pictographic}/u);
|
|
553
600
|
}finally{
|
|
554
601
|
if(child?.exitCode===null) child.kill();
|
|
555
|
-
await
|
|
602
|
+
await safeRm(fx.dir);
|
|
556
603
|
}
|
|
557
604
|
});
|
|
558
605
|
|
|
@@ -560,7 +607,7 @@ winTest('R58 concurrent cold remote claims have one winner and no loser cleanup'
|
|
|
560
607
|
const fx=await fixture({statusOnline:true});const children=[],outputs=[];
|
|
561
608
|
try{
|
|
562
609
|
for(let i=0;i<3;i++){
|
|
563
|
-
const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
610
|
+
const child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
564
611
|
children.push(child);outputs.push(await collect(child));
|
|
565
612
|
}
|
|
566
613
|
const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3);
|
|
@@ -578,18 +625,18 @@ winTest('R58 concurrent cold remote claims have one winner and no loser cleanup'
|
|
|
578
625
|
live[0].stdin.end();assert.equal((await outputs[children.indexOf(live[0])].closed).code,0);
|
|
579
626
|
}finally{
|
|
580
627
|
for(const child of children)if(child.exitCode===null)child.kill();
|
|
581
|
-
await
|
|
628
|
+
await safeRm(fx.dir);
|
|
582
629
|
}
|
|
583
630
|
});
|
|
584
631
|
|
|
585
632
|
winTest('R58 duplicate remote verifies the real live owner and leaves its authority untouched',async()=>{
|
|
586
633
|
const fx=await fixture({statusOnline:true});let first=null,second=null;
|
|
587
634
|
try{
|
|
588
|
-
first=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
635
|
+
first=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
589
636
|
const firstOutput=await collect(first);
|
|
590
637
|
const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3);
|
|
591
638
|
assert.ok(commands.filter(x=>x==='status').length>=3,firstOutput.stderr);
|
|
592
|
-
const ownerReadyDeadline=Date.now()+
|
|
639
|
+
const ownerReadyDeadline=Date.now()+fixtureTimeoutMs;
|
|
593
640
|
while(Date.now()<ownerReadyDeadline&&!/\[READY\]/.test(firstOutput.stdout)) await sleep(50);
|
|
594
641
|
assert.match(firstOutput.stdout,/\[READY\]/,firstOutput.stderr);
|
|
595
642
|
const before=await traceCommands(fx.trace);
|
|
@@ -597,7 +644,7 @@ winTest('R58 duplicate remote verifies the real live owner and leaves its author
|
|
|
597
644
|
const marker=JSON.parse(await readFile(markerPath,'utf8'));
|
|
598
645
|
assert.equal(marker.owner_identity.pid,first.pid);
|
|
599
646
|
assert.equal(marker.guardian_identity.parent_pid,first.pid);
|
|
600
|
-
second=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
647
|
+
second=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
601
648
|
const secondOutput=await collect(second);
|
|
602
649
|
const stopped=await secondOutput.closed;
|
|
603
650
|
assert.notEqual(stopped.code,0);
|
|
@@ -608,7 +655,7 @@ winTest('R58 duplicate remote verifies the real live owner and leaves its author
|
|
|
608
655
|
first.stdin.end();assert.equal((await firstOutput.closed).code,0,firstOutput.stderr);
|
|
609
656
|
}finally{
|
|
610
657
|
if(first?.exitCode===null)first.kill();if(second?.exitCode===null)second.kill();
|
|
611
|
-
await
|
|
658
|
+
await safeRm(fx.dir);
|
|
612
659
|
}
|
|
613
660
|
});
|
|
614
661
|
|
|
@@ -623,14 +670,14 @@ winTest('bare remote refuses unverified legacy ownership without touching author
|
|
|
623
670
|
const output=await collect(child);
|
|
624
671
|
await sleep(500);
|
|
625
672
|
if(child.exitCode===null) child.stdin.end();
|
|
626
|
-
const ended=await
|
|
673
|
+
const ended=await boundedCompletion(output.closed);
|
|
627
674
|
assert.equal(ended.timeout,undefined);
|
|
628
675
|
assert.notEqual(ended.code,0);
|
|
629
676
|
assert.deepEqual(await traceCommands(fx.trace),[]);
|
|
630
677
|
assert.match(output.stderr,/remote session ownership unverified/i);
|
|
631
678
|
}finally{
|
|
632
679
|
if(child?.exitCode===null) child.kill();
|
|
633
|
-
await
|
|
680
|
+
await safeRm(fx.dir);
|
|
634
681
|
}
|
|
635
682
|
});
|
|
636
683
|
|
|
@@ -639,11 +686,11 @@ winTest('explicit remote status remains a one-shot controller command',async()=>
|
|
|
639
686
|
try{
|
|
640
687
|
const child=spawn(process.execPath,[cliPath,'remote','status'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
641
688
|
const output=await collect(child);
|
|
642
|
-
const ended=await
|
|
689
|
+
const ended=await boundedCompletion(output.closed);
|
|
643
690
|
assert.equal(ended.timeout,undefined);
|
|
644
691
|
assert.equal(ended.code,0,output.stderr);
|
|
645
692
|
assert.deepEqual(await traceCommands(fx.trace),['status']);
|
|
646
|
-
}finally{await
|
|
693
|
+
}finally{await safeRm(fx.dir);}
|
|
647
694
|
});
|
|
648
695
|
|
|
649
696
|
winTest('explicit remote status keeps the coherent runtime one-shot and silent',async()=>{
|
|
@@ -658,12 +705,12 @@ winTest('explicit remote status keeps the coherent runtime one-shot and silent',
|
|
|
658
705
|
}),'utf8');
|
|
659
706
|
const child=spawn(process.execPath,[cliPath,'remote','status'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
660
707
|
const output=await collect(child);
|
|
661
|
-
const ended=await
|
|
708
|
+
const ended=await boundedCompletion(output.closed);
|
|
662
709
|
assert.equal(ended.timeout,undefined);
|
|
663
710
|
assert.equal(ended.code,0,output.stderr);
|
|
664
711
|
assert.doesNotMatch(output.stderr,/VERSION SKEW/);
|
|
665
712
|
assert.deepEqual(await traceCommands(fx.trace),['status']);
|
|
666
|
-
}finally{await
|
|
713
|
+
}finally{await safeRm(fx.dir);}
|
|
667
714
|
});
|
|
668
715
|
|
|
669
716
|
winTest('bare remote surfaces bounded controller-start-failure evidence instead of only exit code',async()=>{
|
|
@@ -671,12 +718,12 @@ winTest('bare remote surfaces bounded controller-start-failure evidence instead
|
|
|
671
718
|
try{
|
|
672
719
|
const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
673
720
|
const output=await collect(child);
|
|
674
|
-
const ended=await
|
|
721
|
+
const ended=await boundedCompletion(output.closed);
|
|
675
722
|
assert.equal(ended.timeout,undefined,'failed start did not terminate');
|
|
676
723
|
assert.notEqual(ended.code,0);
|
|
677
724
|
assert.match(output.stderr,/fixture controller evidence detail/);
|
|
678
725
|
assert.match(output.stderr,/controller-start-failure/i);
|
|
679
|
-
}finally{await
|
|
726
|
+
}finally{await safeRm(fx.dir);}
|
|
680
727
|
});
|
|
681
728
|
|
|
682
729
|
|
|
@@ -710,11 +757,11 @@ winTest('remote --trace --filter selects presentation without dropping journaled
|
|
|
710
757
|
const journal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',marker.result_session_id+'.json'),'utf8'));
|
|
711
758
|
assert.equal(journal.events.length,4,'presentation filter must not remove journal evidence');
|
|
712
759
|
child.stdin.end();
|
|
713
|
-
const ended=await
|
|
760
|
+
const ended=await boundedCompletion(output.closed);
|
|
714
761
|
assert.equal(ended.timeout,undefined);
|
|
715
762
|
assert.equal(ended.code,0,output.stderr);
|
|
716
763
|
}finally{
|
|
717
764
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
718
|
-
await
|
|
765
|
+
await safeRm(fx.dir);
|
|
719
766
|
}
|
|
720
767
|
});
|
|
@@ -85,13 +85,13 @@ test('host standing grant remains armed until explicit revocation', async () =>
|
|
|
85
85
|
assert.equal(status.remaining_ms, null);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
test('controller
|
|
88
|
+
test('controller retains coding/host standing grants but issues bounded autonomous expiry', async () => {
|
|
89
89
|
const controller = await import('node:fs/promises').then(fs => fs.readFile(
|
|
90
90
|
new URL('../controller/deadbyte-controller.ps1', import.meta.url), 'utf8'));
|
|
91
91
|
assert.match(controller, /deadbyte\.host-grant\.v2/);
|
|
92
92
|
assert.match(controller, /deadbyte\.coding-grant\.v2/);
|
|
93
93
|
assert.match(controller, /deadbyte\.autonomous-grant\.v2/);
|
|
94
|
-
assert.
|
|
94
|
+
assert.match(controller, /expires_at_utc=\$now\.AddHours\(1\)\.ToString\('o'\)/);
|
|
95
95
|
assert.doesNotMatch(controller, /AddMinutes\((?:15|30|60)\)/);
|
|
96
96
|
assert.doesNotMatch(controller, /expires=/);
|
|
97
97
|
});
|
package/test/tool-audit.test.mjs
CHANGED
|
@@ -71,6 +71,20 @@ test('tool wrapper durably records request before handler and writes correlated
|
|
|
71
71
|
}finally{await rm(root,{recursive:true,force:true});}
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
+
test('R69 audit retains explicit unknown side effect even when a tool envelope says ok',async()=>{
|
|
75
|
+
const root=await temp();
|
|
76
|
+
try{
|
|
77
|
+
const k=await keys(root);
|
|
78
|
+
const audit=await createToolAudit({stateRoot:root,signingKeyPath:k.privateKeyPath,contextProvider:async()=>context()});
|
|
79
|
+
const server=fakeServer();installToolAudit(server,audit);
|
|
80
|
+
server.registerTool('uncertain_write',{},async()=>({isError:false,
|
|
81
|
+
structuredContent:{status:'ok',side_effect_state:'unknown'}}));
|
|
82
|
+
await server.handlers.get('uncertain_write')({path:'scratch.txt'});
|
|
83
|
+
const all=await events(root);
|
|
84
|
+
assert.equal(all.at(-1).outcome.side_effect_state,'unknown');
|
|
85
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
86
|
+
});
|
|
87
|
+
|
|
74
88
|
test('audit failure before request commit prevents handler side effects',async()=>{
|
|
75
89
|
const server=fakeServer();let sideEffect=false;
|
|
76
90
|
installToolAudit(server,{async recordRequest(){throw new Error('audit unavailable');},async recordResult(){throw new Error('unexpected');}});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/deadbyte-contain.obj
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/deadbyte-exec.obj
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/miniconpty.obj
DELETED
|
Binary file
|