deadbyte-mcp 0.15.0 → 0.15.2
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 +109 -64
- package/PROVENANCE.json +11 -0
- package/R45-PARENT.json +18 -0
- package/README.txt +36 -20
- package/RELEASE.json +53 -0
- package/SBOM.cdx.json +46 -0
- package/TEST-MATRIX.json +31 -0
- package/bin/deadbyte-hardware-observer-r45.exe +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/controller/README.TXT +2 -2
- package/controller/deadbyte-controller.ps1 +51 -3
- package/controller/deadbyte-process-policy.json +63 -1
- package/docs/ARCHITECTURE.md +3 -4
- package/native/deadbyte-hardware-observer.cpp +308 -0
- package/package.json +14 -7
- package/scripts/autonomous-tests.ps1 +2 -2
- package/scripts/build-hardware-r45.ps1 +71 -0
- package/scripts/deferred-slot-operation-r45.mjs +126 -0
- package/scripts/deferred-slot-operation-r46.mjs +126 -0
- package/scripts/derive-r45-parent.mjs +24 -0
- package/scripts/derive-r45-release.mjs +72 -0
- package/scripts/derive-r45-tests.mjs +20 -0
- package/scripts/final-closure-r45.mjs +121 -0
- package/scripts/final-closure-r46.mjs +98 -0
- package/scripts/final-closure-verify-r45.mjs +220 -0
- package/scripts/final-closure-verify-r46.mjs +119 -0
- package/scripts/finalize-r45.mjs +219 -0
- package/scripts/full-regression-r45.mjs +20 -0
- package/scripts/full-regression-r46.mjs +20 -0
- package/scripts/full-regression-summary-r45.mjs +14 -0
- package/scripts/gate-windows-r45.ps1 +44 -0
- package/scripts/gate-windows-r46.ps1 +56 -0
- package/scripts/init-host-policy.ps1 +39 -1
- package/scripts/inspect-active-release-r45.mjs +20 -0
- package/scripts/refresh-process-policy.mjs +64 -7
- package/scripts/release-manifest.mjs +3 -1
- package/scripts/release-parity-r45.mjs +253 -0
- package/scripts/release-parity-r46.mjs +187 -0
- package/scripts/release-parity-tests-r45.ps1 +8 -0
- package/scripts/verify-r45-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r45.mjs +60 -0
- package/scripts/windows-gate-evidence-r46.mjs +110 -0
- package/src/autonomous-runtime.mjs +12 -7
- package/src/capability-ledger.mjs +2 -0
- package/src/compact-gateway-mcp-tools.mjs +11 -7
- package/src/deadbyte-cli.mjs +24 -12
- package/src/doctor-r45.mjs +65 -0
- package/src/host-plane.mjs +133 -85
- package/src/machine-fs-mcp-tools.mjs +3 -3
- package/src/machine-fs-output-contracts.mjs +1 -1
- package/src/machine-fs-read-worker.mjs +46 -0
- package/src/machine-fs.mjs +63 -10
- package/src/mcp-server.mjs +68 -23
- package/src/mcp-smoke-client.mjs +4 -1
- package/src/native-diff-v2.mjs +9 -4
- package/src/native-diff.mjs +29 -7
- package/src/observation-mcp-tools.mjs +5 -1
- package/src/observation-output-contracts.mjs +8 -0
- package/src/observation-runtime.mjs +57 -5
- package/src/observation-smoke-client.mjs +6 -2
- package/src/output-contracts.mjs +27 -11
- package/src/process-mcp-tools.mjs +18 -5
- package/src/process-output-contracts.mjs +20 -3
- package/src/process-policy.mjs +3 -1
- package/src/process-runtime.mjs +99 -19
- package/src/process-smoke-client.mjs +67 -22
- package/src/r45-compact-disarmed-probe.mjs +74 -0
- package/src/r45-full-surface-probe.mjs +34 -0
- package/src/release-generation.mjs +23 -3
- package/src/remote-device-r44.mjs +53 -15
- package/src/remote-mcp-r45-parity-client.mjs +206 -0
- package/src/remote-mcp-smoke-client.mjs +1 -1
- package/src/runtime-update.mjs +36 -8
- package/src/stdio-console-guard.mjs +24 -0
- package/src/version.mjs +1 -1
- package/test/agent-runtime.test.mjs +1 -0
- package/test/autonomous-loop.test.mjs +24 -0
- package/test/autonomous-runtime.test.mjs +1 -0
- package/test/cli-entrypoint.test.mjs +4 -4
- package/test/coding-plane.test.mjs +1 -0
- package/test/compact-gateway-r36.test.mjs +28 -0
- package/test/compact-max-catalog-r45.test.mjs +99 -0
- package/test/contained.test.mjs +23 -11
- package/test/controller.test.mjs +5 -1
- package/test/core.test.mjs +1 -1
- package/test/full-max-catalog-r45.test.mjs +91 -0
- package/test/full-max-catalog-r46.test.mjs +92 -0
- package/test/hardware-observation-r45.test.mjs +44 -0
- package/test/host-inline-r45.test.mjs +67 -0
- package/test/machine-fs-mcp-tools.test.mjs +4 -1
- package/test/machine-fs-runtime.test.mjs +18 -2
- package/test/machine-mcp-integration.test.mjs +1 -0
- package/test/observation-mcp-tools.test.mjs +4 -3
- package/test/observation-runtime.test.mjs +29 -2
- package/test/output-schema.test.mjs +1 -0
- package/test/package-boundary.test.mjs +1 -1
- package/test/process-mcp-tools.test.mjs +23 -5
- package/test/process-policy-refresh.test.mjs +87 -10
- package/test/process-runtime.test.mjs +111 -1
- package/test/process-supervision.test.mjs +4 -2
- package/test/production-docs.test.mjs +3 -3
- package/test/r33-closeout-regression.test.mjs +20 -19
- package/test/r33-finalization.test.mjs +3 -3
- package/test/r45-autonomous-quick-test.test.mjs +10 -0
- package/test/r45-finalization.test.mjs +84 -0
- package/test/release-generation.test.mjs +26 -11
- package/test/release-version.test.mjs +112 -46
- package/test/remote-device-r44.test.mjs +75 -0
- package/test/remote-r24-catalog.test.mjs +2 -2
- package/test/runtime-host-bootstrap-r45.test.mjs +46 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateFinalizerAuthorityStatus, validateWindowsGateEvidence } from '../scripts/finalize-r45.mjs';
|
|
5
|
+
import { R45_PREDECESSOR_RELEASE_ID, R45_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r45.mjs';
|
|
6
|
+
|
|
7
|
+
const manifest='a'.repeat(64);
|
|
8
|
+
const parent={
|
|
9
|
+
release_id:'v0.15.0-c15fa41719be61b3',
|
|
10
|
+
manifest_sha256:'c15fa41719be61b3186e49b2367a5f4c057365cfb465102dbefb7d7355f45483',
|
|
11
|
+
generation_manifest_sha256:'6d7429c050b7fe893492e102f00282019116e0c9e54e4f25a5791defa1661d30',
|
|
12
|
+
closure_sha256:'533b7e0ff9ded04086dd90ed34e3b87bc427acc3c55c25bb9f4ec66cb448e667'
|
|
13
|
+
};
|
|
14
|
+
const features=()=>({
|
|
15
|
+
skill_integrity:true,agent_backend_persistence:true,codex_protocol_contract:true,
|
|
16
|
+
remote_device_identity:true,durable_job_supervisor:true,real_external_supervisor_smoke:true,
|
|
17
|
+
full_regression_required:true,codex_live_binary_required:false,
|
|
18
|
+
host_inline_native:true,native_hardware_observation:true,doctor_release_truth:true
|
|
19
|
+
});
|
|
20
|
+
const valid=()=>({
|
|
21
|
+
schema:'deadbyte.r45-windows-gate.v1',status:'passed',exit_code:0,version:'0.15.1',
|
|
22
|
+
marker:'DEADBYTE V0.15.1 / R45 MACHINE FREEDOM WINDOWS BATCH GATE: PASS',
|
|
23
|
+
manifest_sha256:manifest,
|
|
24
|
+
parent:{release_id:parent.release_id,manifest_sha256:parent.manifest_sha256,
|
|
25
|
+
generation_manifest_sha256:parent.generation_manifest_sha256,final_closure_sha256:parent.closure_sha256},
|
|
26
|
+
features:features()
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('R45 detached finalizer requires Process+Coding+Autonomous and Desktop+Host DISARMED',()=>{
|
|
30
|
+
assert.equal(validateFinalizerAuthorityStatus({process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false}),true);
|
|
31
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({process_armed:false,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false}),/Process standing grant/);
|
|
32
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:true,host_armed:false}),/Desktop DISARMED/);
|
|
33
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:true}),/Host DISARMED/);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('R45 finalizer binds exact R44 parent and all Machine Freedom gate proofs',()=>{
|
|
37
|
+
assert.equal(validateWindowsGateEvidence(valid(),manifest,parent),true);
|
|
38
|
+
for(const key of ['host_inline_native','native_hardware_observation','doctor_release_truth']){
|
|
39
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),features:{...features(),[key]:false}},manifest,parent),new RegExp(key));
|
|
40
|
+
}
|
|
41
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),manifest_sha256:'b'.repeat(64)},manifest,parent),/candidate mismatch/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('R45 release machinery binds 0.15.1, 82/43 surfaces, Host v2 bootstrap and FINAL closure',async()=>{
|
|
45
|
+
const root=new URL('../',import.meta.url);
|
|
46
|
+
const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
47
|
+
const [gate,parity,compactClient,writer,verifier,finalizer,evidence,manifestSource]=await Promise.all([
|
|
48
|
+
text('scripts/gate-windows-r45.ps1'),text('scripts/release-parity-r45.mjs'),text('src/remote-mcp-r45-parity-client.mjs'),text('scripts/final-closure-r45.mjs'),
|
|
49
|
+
text('scripts/final-closure-verify-r45.mjs'),text('scripts/finalize-r45.mjs'),text('scripts/windows-gate-evidence-r45.mjs'),text('scripts/release-manifest.mjs')
|
|
50
|
+
]);
|
|
51
|
+
assert.equal(R45_PREDECESSOR_RELEASE_ID,parent.release_id);
|
|
52
|
+
assert.equal(R45_PREDECESSOR_MANIFEST,parent.manifest_sha256);
|
|
53
|
+
assert.match(gate,/host-policy-refresh/);assert.match(gate,/doctor/);assert.match(gate,/hardware-build/);
|
|
54
|
+
const hermetic=gate.indexOf('host-policy-hermetic-clean');
|
|
55
|
+
const focused=gate.indexOf('r45-feature-focused');
|
|
56
|
+
const regression=gate.indexOf("Invoke-GateStep -Name 'full-regression'");
|
|
57
|
+
const agentSmoke=gate.indexOf("Invoke-GateStep -Name 'mcp-agent-smoke'");
|
|
58
|
+
const containedSmoke=gate.indexOf("Invoke-GateStep -Name 'mcp-contained-smoke'");
|
|
59
|
+
const hostRefresh=gate.indexOf("Invoke-GateStep -Name 'host-policy-refresh'");
|
|
60
|
+
const manifestWrite=gate.indexOf("Invoke-GateStep -Name 'release-manifest-write'");
|
|
61
|
+
const hostSmoke=gate.indexOf("Invoke-GateStep -Name 'mcp-host-smoke'");
|
|
62
|
+
assert.ok(hermetic>=0&&focused>hermetic&®ression>focused&&agentSmoke>regression&&containedSmoke>agentSmoke&&hostRefresh>containedSmoke&&manifestWrite>hostRefresh&&hostSmoke>manifestWrite,'R45 gate must keep generated Host policy out of hermetic regression and non-Host smoke surfaces');
|
|
63
|
+
assert.match(gate,/DEADBYTE V0\.15\.1 \/ R45 MACHINE FREEDOM WINDOWS BATCH GATE: PASS/);
|
|
64
|
+
assert.match(parity,/tool_count===82/);assert.match(parity,/tool_count===43/);assert.match(compactClient,/hardware_query/);
|
|
65
|
+
assert.match(parity,/waitForExactPointer/);
|
|
66
|
+
assert.match(parity,/rollbackPair\.completed\.active_release===R45_PREDECESSOR_RELEASE_ID/);
|
|
67
|
+
assert.match(parity,/version:'0\.15\.0',manifestSha256:R45_PREDECESSOR_MANIFEST/);
|
|
68
|
+
assert.match(parity,/restorePair\.completed\.active_release===active\.release_id/);
|
|
69
|
+
assert.match(parity,/version:'0\.15\.1',manifestSha256:candidateManifest/);
|
|
70
|
+
assert.match(parity,/predecessor_disarmed\?\.tool_count===43/);
|
|
71
|
+
assert.doesNotMatch(parity,/predecessor_disarmed\?\.tool_count===42/);
|
|
72
|
+
assert.doesNotMatch(parity,/R45 exact R44 predecessor identity mismatch[^\n]*0\.14\.1/);
|
|
73
|
+
for(const source of [writer,verifier]){
|
|
74
|
+
assert.match(source,/DEADBYTE-R45-FINAL-CLOSURE-V1/);
|
|
75
|
+
assert.match(source,/deadbyte\.r45-final-closure\.v1/);
|
|
76
|
+
assert.match(source,/R45 MACHINE FREEDOM FINAL BASELINE/);
|
|
77
|
+
}
|
|
78
|
+
assert.match(finalizer,/--host-policy/);assert.match(finalizer,/--host-policy-sha256/);
|
|
79
|
+
assert.match(finalizer,/host_inline_native/);assert.match(finalizer,/native_hardware_observation/);assert.match(finalizer,/doctor_release_truth/);
|
|
80
|
+
assert.match(evidence,/host_inline_native:true/);assert.match(evidence,/native_hardware_observation:true/);assert.match(evidence,/doctor_release_truth:true/);
|
|
81
|
+
assert.match(manifestSource,/excludedPackagePrefixes = \[[^\]]*'tmp\/'[^\]]*'\.deadbyte-machine-fs-recovery\/'[^\]]*\]/);
|
|
82
|
+
assert.match(manifestSource,/excludedPackagePaths = new Set\(\['controller\/deadbyte-host-policy\.json'\]\)/);
|
|
83
|
+
assert.match(manifestSource,/excludedPackagePrefixes\.some\(prefix => rel\.startsWith\(prefix\)\)/);
|
|
84
|
+
});
|
|
@@ -16,7 +16,12 @@ function command(executable='C:/Windows/System32/cmd.exe'){
|
|
|
16
16
|
test('R27 generation bundle rebinds authority and mutable state outside the release slot', async () => {
|
|
17
17
|
const base=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r27-generation-'));
|
|
18
18
|
const state=path.join(base,'state'),release=path.join(base,'release'),workspace=path.join(base,'workspace');
|
|
19
|
-
|
|
19
|
+
const systemRoot=path.join(base,'Windows'),system32=path.join(systemRoot,'System32');
|
|
20
|
+
const powershellDir=path.join(system32,'WindowsPowerShell','v1.0');
|
|
21
|
+
await mkdir(path.join(release,'scripts'),{recursive:true}); await mkdir(path.join(release,'bin'),{recursive:true}); await mkdir(workspace,{recursive:true}); await mkdir(powershellDir,{recursive:true});
|
|
22
|
+
const cmdPath=path.join(system32,'cmd.exe'),cmdBytes=Buffer.from('target-cmd-bytes\\n');
|
|
23
|
+
const powershellPath=path.join(powershellDir,'powershell.exe'),powershellBytes=Buffer.from('target-powershell-bytes\\n');
|
|
24
|
+
await writeFile(cmdPath,cmdBytes); await writeFile(powershellPath,powershellBytes);
|
|
20
25
|
await writeFile(path.join(release,'scripts','gate.ps1'),'Write-Output gate\n');
|
|
21
26
|
await writeFile(path.join(release,'bin','deadbyte-process-host.exe'),'process-host-bytes\n');
|
|
22
27
|
const desktopObserver=Buffer.from('desktop-observer-bytes\n');
|
|
@@ -47,7 +52,10 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
47
52
|
const processPolicy={schema:'deadbyte.process-policy.v1',enabled:true,grant_file:'C:/old/process-grant.json',state_dir:'C:/old/process-state',
|
|
48
53
|
native_host:{path:'C:/old/deadbyte-process-host.exe',sha256:'0'.repeat(64)},
|
|
49
54
|
roots:{core:{path:'C:/old/core',deny_paths:['node_modules']}},
|
|
50
|
-
profiles:{
|
|
55
|
+
profiles:{
|
|
56
|
+
ping_hold:{executable:'C:/stale/cmd.exe',executable_sha256:EXE,root_ids:['core'],prefix_args:['/d','/q'],transport:'pipe',max_args:0,max_arg_bytes:256,max_sessions:1,max_input_bytes:4096,max_retained_output_bytes:65536,env_allow:['PATH','TEMP','TMP'],input_actions:{ping:'echo DEADBYTE_ACTION_PING\\r\\n'}},
|
|
57
|
+
powershell:{executable:'C:/stale/powershell.exe',executable_sha256:EXE,root_ids:['core'],prefix_args:['-NoLogo','-NoProfile','-NonInteractive','-Command'],transport:'pipe',max_args:1,max_arg_bytes:8192,max_sessions:4,max_input_bytes:65536,max_retained_output_bytes:1048576,env_allow:['PATH','TEMP','TMP','SystemRoot','WINDIR','USERPROFILE','PSModulePath','COMSPEC','PATHEXT'],input_actions:{}}
|
|
58
|
+
}};
|
|
51
59
|
const desktopPolicy={schema:'deadbyte.desktop-policy.v1',enabled:true,grant_file:'C:/old/desktop-grant.json',evidence_dir:'C:/old/desktop-evidence',
|
|
52
60
|
allowed_input_desktops:['Default'],allowed_actions:['click_primary','key_chord'],
|
|
53
61
|
limits:{max_frame_age_ms:2000,max_frame_bytes:8388608,capture_timeout_ms:5000,input_timeout_ms:2000,ground_timeout_ms:5000,post_observe_timeout_ms:5000,max_preview_bytes:1048576,max_text_bytes:4096},
|
|
@@ -59,7 +67,8 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
59
67
|
await writeFile(path.join(development,'scripts','gate-windows-old.ps1'),'Write-Output old-gate\n');
|
|
60
68
|
await writeFile(path.join(development,'scripts','gate-windows-current.ps1'),'Write-Output current-gate\n');
|
|
61
69
|
await writeFile(path.join(development,'package.json'),JSON.stringify({scripts:{'gate:windows':'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-current.ps1'}}));
|
|
62
|
-
const
|
|
70
|
+
const build=args=>createGenerationBundle({...args,systemRoot});
|
|
71
|
+
const result=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
63
72
|
const verified=await verifyGenerationBundle(result.generation_root,result.generation_manifest_sha256);
|
|
64
73
|
assert.equal(verified.files,7);
|
|
65
74
|
const generatedProcess=JSON.parse(await readFile(result.process_policy_path,'utf8'));
|
|
@@ -68,6 +77,11 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
68
77
|
assert.equal(generatedProcess.roots.core.path,path.resolve(development));
|
|
69
78
|
assert.equal(generatedProcess.native_host.path,path.join(path.resolve(release),'bin','deadbyte-process-host.exe'));
|
|
70
79
|
assert.equal(generatedProcess.native_host.sha256,sha(Buffer.from('process-host-bytes\n')));
|
|
80
|
+
assert.equal(generatedProcess.profiles.ping_hold.executable,cmdPath);
|
|
81
|
+
assert.equal(generatedProcess.profiles.ping_hold.executable_sha256,sha(cmdBytes));
|
|
82
|
+
assert.equal(generatedProcess.profiles.powershell.executable,powershellPath);
|
|
83
|
+
assert.equal(generatedProcess.profiles.powershell.executable_sha256,sha(powershellBytes));
|
|
84
|
+
assert.deepEqual(generatedProcess.profiles.powershell.prefix_args,['-NoLogo','-NoProfile','-NonInteractive','-Command']);
|
|
71
85
|
const generatedDesktop=JSON.parse(await readFile(result.desktop_policy_path,'utf8'));
|
|
72
86
|
assert.equal(generatedDesktop.grant_file,path.join(path.resolve(state),'runtime','desktop-grant.json'));
|
|
73
87
|
assert.equal(generatedDesktop.evidence_dir,path.join(path.resolve(state),'runtime','desktop-evidence'));
|
|
@@ -92,6 +106,7 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
92
106
|
assert.equal(generatedAuto.profiles.gate.script_sha256,sha(Buffer.from('Write-Output gate\n')));
|
|
93
107
|
assert.equal(generatedAuto.profiles['windows-release'].script_path,'scripts/gate-windows-current.ps1');
|
|
94
108
|
assert.equal(generatedAuto.profiles['windows-release'].script_sha256,sha(Buffer.from('Write-Output current-gate\n')));
|
|
109
|
+
assert.equal(generatedAuto.profiles['windows-release'].timeout_ms,600000);
|
|
95
110
|
assert.equal(generatedAuto.profiles['windows-release'].description,'Full Windows target release gate; runs only when finish is requested.');
|
|
96
111
|
const generatedHost=JSON.parse(await readFile(result.host_policy_path,'utf8'));
|
|
97
112
|
assert.equal(generatedHost.roots.core.path,path.resolve(development));
|
|
@@ -128,44 +143,44 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
128
143
|
assert.match(path.basename(result.generation_root),/^v0\.8\.3-aaaaaaaaaaaaaaaa-g[0-9a-f]{16}$/);
|
|
129
144
|
const changedConfig=structuredClone(currentConfig);
|
|
130
145
|
changedConfig.Bridge.Arguments='bridge-v2.mjs';
|
|
131
|
-
const second=await
|
|
146
|
+
const second=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:changedConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
132
147
|
assert.notEqual(second.generation_root,result.generation_root);
|
|
133
148
|
assert.notEqual(second.generation_seed_sha256,result.generation_seed_sha256);
|
|
134
149
|
const endpointChanged=structuredClone(currentConfig);
|
|
135
150
|
endpointChanged.McpUrlFileSha256='2'.repeat(64);
|
|
136
|
-
const third=await
|
|
151
|
+
const third=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:endpointChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
137
152
|
assert.notEqual(third.generation_root,result.generation_root);
|
|
138
153
|
assert.notEqual(third.generation_seed_sha256,result.generation_seed_sha256);
|
|
139
154
|
const machineDisabled=structuredClone(currentConfig);
|
|
140
155
|
machineDisabled.MachineRuntimeEnabled=false;
|
|
141
|
-
const fourth=await
|
|
156
|
+
const fourth=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:machineDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
142
157
|
assert.notEqual(fourth.generation_root,result.generation_root);
|
|
143
158
|
assert.notEqual(fourth.generation_seed_sha256,result.generation_seed_sha256);
|
|
144
159
|
const machineFsDisabled=structuredClone(currentConfig);
|
|
145
160
|
machineFsDisabled.MachineFsRuntimeEnabled=false;
|
|
146
|
-
const fifth=await
|
|
161
|
+
const fifth=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:machineFsDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
147
162
|
assert.notEqual(fifth.generation_root,result.generation_root);
|
|
148
163
|
assert.notEqual(fifth.generation_seed_sha256,result.generation_seed_sha256);
|
|
149
164
|
const observationDisabled=structuredClone(currentConfig);
|
|
150
165
|
observationDisabled.ObservationRuntimeEnabled=false;
|
|
151
|
-
const sixth=await
|
|
166
|
+
const sixth=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:observationDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
152
167
|
assert.notEqual(sixth.generation_root,result.generation_root);
|
|
153
168
|
assert.notEqual(sixth.generation_seed_sha256,result.generation_seed_sha256);
|
|
154
169
|
const desktopDisabled=structuredClone(currentConfig);
|
|
155
170
|
desktopDisabled.DesktopRuntimeEnabled=false;
|
|
156
|
-
const desktopVariant=await
|
|
171
|
+
const desktopVariant=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:desktopDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
157
172
|
assert.notEqual(desktopVariant.generation_root,result.generation_root);
|
|
158
173
|
assert.notEqual(desktopVariant.generation_seed_sha256,result.generation_seed_sha256);
|
|
159
174
|
const desktopTampered=structuredClone(desktopPolicy);
|
|
160
175
|
desktopTampered.input.sha256='f'.repeat(64);
|
|
161
|
-
await assert.rejects(
|
|
176
|
+
await assert.rejects(build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy:desktopTampered}),/desktop input helper SHA-256 mismatch/);
|
|
162
177
|
const semanticConfig2Path=path.join(base,'semantic-lsp-v2.json');
|
|
163
178
|
const semanticConfig2Bytes=Buffer.from(JSON.stringify({schema:'deadbyte.semantic-lsp-config.v1',servers:[{id:'changed'}]})+'\n','utf8');
|
|
164
179
|
await writeFile(semanticConfig2Path,semanticConfig2Bytes);
|
|
165
180
|
const semanticChanged=structuredClone(currentConfig);
|
|
166
181
|
semanticChanged.SemanticLspConfigFile=semanticConfig2Path;
|
|
167
182
|
semanticChanged.SemanticLspConfigSha256=sha(semanticConfig2Bytes);
|
|
168
|
-
const seventh=await
|
|
183
|
+
const seventh=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:semanticChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
169
184
|
assert.notEqual(seventh.generation_root,result.generation_root);
|
|
170
185
|
assert.notEqual(seventh.generation_seed_sha256,result.generation_seed_sha256);
|
|
171
186
|
await verifyGenerationBundle(result.generation_root,result.generation_manifest_sha256);
|
|
@@ -2,58 +2,124 @@ import test from 'node:test';
|
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { readFile } from 'node:fs/promises';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
|
-
const root=new URL('../',import.meta.url);const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
6
|
-
const PARENT_RELEASE='v0.14.1-0a5a833892593283';
|
|
7
|
-
const PARENT_MANIFEST='0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9';
|
|
8
|
-
const PARENT_CLOSURE='2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b';
|
|
9
5
|
|
|
10
|
-
|
|
6
|
+
const root=new URL('../',import.meta.url);
|
|
7
|
+
const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
8
|
+
const PARENT_RELEASE='v0.15.1-d55f00b5144dc31a';
|
|
9
|
+
const PARENT_MANIFEST='d55f00b5144dc31a7fe39e4dc60d640a94780da6aaeca0918e87636b816d7854';
|
|
10
|
+
const PARENT_GENERATION='00cde7bf540cc2804d679a39040d5b07193c5f8a0d49cac3b882402f8f4e6ad8';
|
|
11
|
+
|
|
12
|
+
test('R46 current authority agrees on V0.15.2 and preserves exact R45 parent identity',async()=>{
|
|
11
13
|
const pkg=JSON.parse(await text('package.json'));
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
text('
|
|
15
|
-
text('
|
|
16
|
-
text('scripts/
|
|
17
|
-
text('
|
|
14
|
+
const release=JSON.parse(await text('RELEASE.json'));
|
|
15
|
+
const [version,controller,gate,readme,architecture,controllerReadme,deferred,parity,closure,closureVerify,windowsGate,processPolicy]=await Promise.all([
|
|
16
|
+
text('src/version.mjs'),
|
|
17
|
+
text('controller/deadbyte-controller.ps1'),
|
|
18
|
+
text('scripts/gate-windows-r46.ps1'),
|
|
19
|
+
text('README.txt'),
|
|
20
|
+
text('docs/ARCHITECTURE.md'),
|
|
21
|
+
text('controller/README.TXT'),
|
|
22
|
+
text('scripts/deferred-slot-operation-r46.mjs'),
|
|
23
|
+
text('scripts/release-parity-r46.mjs'),
|
|
24
|
+
text('scripts/final-closure-r46.mjs'),
|
|
25
|
+
text('scripts/final-closure-verify-r46.mjs'),
|
|
26
|
+
text('scripts/windows-gate-evidence-r46.mjs'),
|
|
27
|
+
text('controller/deadbyte-process-policy.json')
|
|
18
28
|
]);
|
|
19
|
-
|
|
20
|
-
assert.equal(pkg.
|
|
21
|
-
assert.equal(pkg.scripts['
|
|
22
|
-
assert.equal(pkg.scripts['
|
|
23
|
-
assert.equal(pkg.scripts['
|
|
24
|
-
assert.equal(pkg.scripts['release:
|
|
25
|
-
assert.equal(pkg.scripts['release:final:
|
|
26
|
-
assert.equal(pkg.scripts['
|
|
27
|
-
assert.equal(pkg.scripts['
|
|
28
|
-
|
|
29
|
-
assert.match(
|
|
30
|
-
assert.match(
|
|
31
|
-
assert.match(
|
|
32
|
-
assert.match(
|
|
33
|
-
assert.match(
|
|
34
|
-
assert.match(
|
|
35
|
-
assert.match(
|
|
36
|
-
assert.match(
|
|
37
|
-
assert.match(
|
|
38
|
-
assert.match(
|
|
39
|
-
assert.match(
|
|
40
|
-
|
|
41
|
-
assert.
|
|
42
|
-
assert.
|
|
43
|
-
assert.match(
|
|
44
|
-
assert.match(
|
|
29
|
+
|
|
30
|
+
assert.equal(pkg.version,'0.15.2');
|
|
31
|
+
assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r46.ps1');
|
|
32
|
+
assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r46.mjs');
|
|
33
|
+
assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r46.mjs');
|
|
34
|
+
assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r46.mjs');
|
|
35
|
+
assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r46.mjs');
|
|
36
|
+
assert.equal(pkg.scripts['r46:fileless:test'],"node --test --test-concurrency=1 test/process-policy.test.mjs test/process-policy-refresh.test.mjs test/release-generation.test.mjs test/process-runtime.test.mjs test/process-mcp-tools.test.mjs test/compact-gateway-r36.test.mjs test/capability-ledger-r36.test.mjs test/remote-device-r44.test.mjs test/observation-runtime.test.mjs test/observation-mcp-tools.test.mjs");
|
|
37
|
+
assert.equal(pkg.scripts['r46:full:test'],'node scripts/full-regression-r46.mjs');
|
|
38
|
+
|
|
39
|
+
assert.match(version,/DEADBYTE_VERSION = '0\.15\.2'/);
|
|
40
|
+
assert.match(controller,/CONTROLLER V0\.15\.2 \/ R46/);
|
|
41
|
+
assert.match(gate,/DEADBYTE V0\.15\.2 \/ R46 FILELESS POWERSHELL WINDOWS BATCH GATE: PASS/);
|
|
42
|
+
assert.match(readme,/^DEADBYTE MCP V0\.15\.2 \/ R46 FILELESS POWERSHELL PRODUCT BASELINE$/m);
|
|
43
|
+
assert.match(readme,/powershell\.exe -Command <source>/);
|
|
44
|
+
assert.match(architecture,/^# DEADBYTE MCP V0\.15\.2 \/ R46 ARCHITECTURE$/m);
|
|
45
|
+
assert.match(controllerReadme,/^DEADBYTE MCP V0\.15\.2 \/ R46 CONTROLLER$/m);
|
|
46
|
+
assert.match(deferred,/--expected-version','0\.15\.2'/);
|
|
47
|
+
assert.match(parity,/deadbyte\.r46-parity\.v1/);
|
|
48
|
+
assert.match(parity,/DB_R46_FILELESS_PARITY/);
|
|
49
|
+
assert.match(parity,/target_repin_verified:true/);
|
|
50
|
+
assert.match(parity,/DB_R46_REPL_VALUE=42/);
|
|
51
|
+
assert.match(parity,/raw_input_not_journaled:true/);
|
|
52
|
+
assert.match(parity,/eviction_verified:true/);
|
|
53
|
+
assert.match(windowsGate,/full_tool_count:83/);
|
|
54
|
+
assert.match(windowsGate,/remote_reachability_ttl:true/);
|
|
55
|
+
assert.match(windowsGate,/observation_search_terminal_ttl:true/);
|
|
56
|
+
assert.match(windowsGate,/observation_search_hard_cap:128/);
|
|
57
|
+
assert.match(closure,/deadbyte\.r46-final-closure\.v1/);
|
|
58
|
+
assert.match(closure,/DEADBYTE-R46-FINAL-CLOSURE-V1/);
|
|
59
|
+
assert.match(closureVerify,/DEADBYTE-R46-FINAL-CLOSURE-V1/);
|
|
60
|
+
assert.match(windowsGate,/deadbyte\.r46-windows-gate\.v1/);
|
|
61
|
+
|
|
62
|
+
assert.equal(release.version,'0.15.2');
|
|
63
|
+
assert.equal(release.train,'R46');
|
|
64
|
+
assert.equal(release.label,'FILELESS POWERSHELL PRODUCT BASELINE');
|
|
65
|
+
assert.equal(release.parent.release_id,PARENT_RELEASE);
|
|
66
|
+
assert.equal(release.parent.manifest_sha256,PARENT_MANIFEST);
|
|
67
|
+
assert.equal(release.parent.generation_manifest_sha256,PARENT_GENERATION);
|
|
68
|
+
assert.deepEqual(release.capabilities.process_profiles,['ping_hold','powershell','powershell_repl']);
|
|
69
|
+
assert.equal(release.capabilities.full_tool_count,83);
|
|
70
|
+
assert.equal(release.capabilities.compact_tool_count,43);
|
|
71
|
+
assert.equal(release.capabilities.powershell_persistent_repl,true);
|
|
72
|
+
assert.equal(release.capabilities.process_raw_input_profile_opt_in,true);
|
|
73
|
+
assert.equal(release.capabilities.powershell_fileless,true);
|
|
74
|
+
assert.equal(release.capabilities.powershell_source_max_arg_bytes,8192);
|
|
75
|
+
|
|
76
|
+
const policy=JSON.parse(processPolicy);
|
|
77
|
+
assert.ok(policy.profiles.ping_hold);
|
|
78
|
+
assert.ok(policy.profiles.powershell);
|
|
79
|
+
assert.ok(policy.profiles.powershell_repl);
|
|
80
|
+
assert.equal(policy.profiles.powershell_repl.allow_raw_input,true);
|
|
81
|
+
assert.deepEqual(policy.profiles.powershell_repl.prefix_args,['-NoLogo','-NoProfile','-NonInteractive']);
|
|
82
|
+
assert.deepEqual(policy.profiles.powershell.prefix_args,['-NoLogo','-NoProfile','-NonInteractive','-Command']);
|
|
83
|
+
assert.equal(policy.profiles.powershell.max_args,1);
|
|
84
|
+
assert.equal(policy.profiles.powershell.max_arg_bytes,8192);
|
|
85
|
+
assert.equal(policy.profiles.powershell.transport,'pipe');
|
|
45
86
|
});
|
|
46
87
|
|
|
47
|
-
test('
|
|
48
|
-
const [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
88
|
+
test('R46 leaves sealed R45 release artifacts historical and unchanged in identity',async()=>{
|
|
89
|
+
const [gate,deferred,parity,closure,closureVerify,finalizer,parent]=await Promise.all([
|
|
90
|
+
text('scripts/gate-windows-r45.ps1'),
|
|
91
|
+
text('scripts/deferred-slot-operation-r45.mjs'),
|
|
92
|
+
text('scripts/release-parity-r45.mjs'),
|
|
93
|
+
text('scripts/final-closure-r45.mjs'),
|
|
94
|
+
text('scripts/final-closure-verify-r45.mjs'),
|
|
95
|
+
text('scripts/finalize-r45.mjs'),
|
|
96
|
+
text('R45-PARENT.json')
|
|
97
|
+
]);
|
|
98
|
+
assert.match(gate,/DEADBYTE V0\.15\.1 \/ R45 MACHINE FREEDOM WINDOWS BATCH GATE: PASS/);
|
|
99
|
+
assert.match(deferred,/--expected-version','0\.15\.1'/);
|
|
100
|
+
assert.match(parity,/deadbyte\.r45-parity\.v1/);
|
|
101
|
+
assert.match(closure,/version:'0\.15\.1'/);
|
|
102
|
+
assert.match(closure,/DEADBYTE-R45-FINAL-CLOSURE-V1/);
|
|
103
|
+
assert.match(closureVerify,/R45_FULL_TOOL_COUNT=82/);
|
|
104
|
+
assert.match(finalizer,/EXPECTED_VERSION='0\.15\.1'/);
|
|
105
|
+
const parentRecord=JSON.parse(parent);
|
|
106
|
+
assert.equal(parentRecord.parent_release_id,'v0.15.0-c15fa41719be61b3');
|
|
54
107
|
});
|
|
55
108
|
|
|
56
|
-
test('
|
|
57
|
-
const semantic=await
|
|
109
|
+
test('R46 keeps ONLINE reuse, explicit Desktop authority, and semantic config pin',async()=>{
|
|
110
|
+
const [cli,controller,semantic]=await Promise.all([
|
|
111
|
+
text('src/deadbyte-cli.mjs'),
|
|
112
|
+
text('controller/deadbyte-controller.ps1'),
|
|
113
|
+
text('controller/deadbyte-semantic-lsp-config.json')
|
|
114
|
+
]);
|
|
115
|
+
assert.match(cli,/controllerRuntimeReady/);
|
|
116
|
+
assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
|
|
117
|
+
const start=controller.indexOf('function Recover-AutonomousSupervisor'),end=controller.indexOf('function Show-State',start);
|
|
118
|
+
assert.ok(start>=0&&end>start);
|
|
119
|
+
const block=controller.slice(start,end);
|
|
120
|
+
assert.doesNotMatch(block,/\$host\s*=/i);
|
|
121
|
+
assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);
|
|
122
|
+
assert.match(controller,/armdesktop/);
|
|
123
|
+
assert.match(controller,/disarmdesktop/);
|
|
58
124
|
assert.equal(createHash('sha256').update(Buffer.from(semantic,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');
|
|
59
125
|
});
|
|
@@ -102,3 +102,78 @@ test('R44 remote state corruption fails closed',async()=>{
|
|
|
102
102
|
await assert.rejects(createRemoteDevicePlaneR44({stateDir:root,relay:new FakeRelay(),authorizeCapability:async()=>true}),/state JSON invalid/);
|
|
103
103
|
}finally{await rm(root,{recursive:true,force:true});}
|
|
104
104
|
});
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
test('R46 remote readiness probe retries only the idempotent probe and remains bounded by timeout',async()=>{
|
|
108
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r46-remote-probe-timeout-'));
|
|
109
|
+
const key=deviceKey();
|
|
110
|
+
let attempts=0;
|
|
111
|
+
const relay={
|
|
112
|
+
requests:[],
|
|
113
|
+
async probe(value){
|
|
114
|
+
attempts+=1;
|
|
115
|
+
if(attempts===1) return await new Promise(()=>{});
|
|
116
|
+
return {device_id:value.device_id,epoch:value.epoch,nonce:value.nonce,ready:true};
|
|
117
|
+
},
|
|
118
|
+
async request(value){this.requests.push(value);return {ack:'accepted',request_id:value.request_id,terminal:{status:'completed',result_sha256:'a'.repeat(64)}};}
|
|
119
|
+
};
|
|
120
|
+
try{
|
|
121
|
+
const plane=await createRemoteDevicePlaneR44({
|
|
122
|
+
stateDir:root,relay,authorizeCapability:async()=>true,
|
|
123
|
+
relayTimeoutMs:100,probeRetries:1,reachableTtlMs:5000
|
|
124
|
+
});
|
|
125
|
+
await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
126
|
+
await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'retry-c'});
|
|
127
|
+
const ready=await plane.probe({deviceId:key.deviceId,epoch:1});
|
|
128
|
+
assert.equal(attempts,2);
|
|
129
|
+
assert.equal(ready.reachable,true);
|
|
130
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('R46 remote reachability expires after the bounded probe freshness window',async()=>{
|
|
134
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r46-remote-stale-'));
|
|
135
|
+
const relay=new FakeRelay(),key=deviceKey();
|
|
136
|
+
try{
|
|
137
|
+
const plane=await createRemoteDevicePlaneR44({
|
|
138
|
+
stateDir:root,relay,authorizeCapability:async()=>true,
|
|
139
|
+
relayTimeoutMs:1000,probeRetries:0,reachableTtlMs:1000
|
|
140
|
+
});
|
|
141
|
+
await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
142
|
+
await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'stale-c'});
|
|
143
|
+
await plane.probe({deviceId:key.deviceId,epoch:1});
|
|
144
|
+
assert.equal((await plane.status({deviceId:key.deviceId})).reachable,true);
|
|
145
|
+
await new Promise(resolve=>setTimeout(resolve,1100));
|
|
146
|
+
assert.equal((await plane.status({deviceId:key.deviceId})).reachable,false);
|
|
147
|
+
await assert.rejects(
|
|
148
|
+
plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'machine.status',payload:{},requestId:'8'.repeat(64)}),
|
|
149
|
+
/not reachable|stale/i
|
|
150
|
+
);
|
|
151
|
+
assert.equal(relay.requests.length,0);
|
|
152
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('R46 remote dispatch timeout is not retried and downgrades reachability',async()=>{
|
|
156
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r46-remote-dispatch-timeout-'));
|
|
157
|
+
const key=deviceKey();
|
|
158
|
+
let requestCount=0;
|
|
159
|
+
const relay={
|
|
160
|
+
async probe(value){return {device_id:value.device_id,epoch:value.epoch,nonce:value.nonce,ready:true};},
|
|
161
|
+
async request(){requestCount+=1;return await new Promise(()=>{});}
|
|
162
|
+
};
|
|
163
|
+
try{
|
|
164
|
+
const plane=await createRemoteDevicePlaneR44({
|
|
165
|
+
stateDir:root,relay,authorizeCapability:async()=>true,
|
|
166
|
+
relayTimeoutMs:100,probeRetries:0,reachableTtlMs:5000
|
|
167
|
+
});
|
|
168
|
+
await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
169
|
+
await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'dispatch-c'});
|
|
170
|
+
await plane.probe({deviceId:key.deviceId,epoch:1});
|
|
171
|
+
const result=await plane.dispatch({
|
|
172
|
+
deviceId:key.deviceId,epoch:1,capabilityId:'coding.file_read',payload:{path:'README.md'},requestId:'9'.repeat(64)
|
|
173
|
+
});
|
|
174
|
+
assert.equal(result.state,'failed');
|
|
175
|
+
assert.equal(result.error_code,'transport_error');
|
|
176
|
+
assert.equal(requestCount,1,'side-effecting dispatch must never auto-retry');
|
|
177
|
+
assert.equal((await plane.status({deviceId:key.deviceId})).reachable,false);
|
|
178
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
179
|
+
});
|
|
@@ -32,10 +32,10 @@ test('R29 remote gate accepts machine plane as an exact optional catalog dimensi
|
|
|
32
32
|
assert.match(source, /if \(machine\) items\.push\(\.\.\.machineTools\)/);
|
|
33
33
|
assert.match(source, /machine_runtime: machineRuntime/);
|
|
34
34
|
});
|
|
35
|
-
test('
|
|
35
|
+
test('R46 remote gate accepts seven-tool process supervision as one exact optional catalog dimension', async () => {
|
|
36
36
|
const source = await readFile(sourcePath, 'utf8');
|
|
37
37
|
assert.match(source, /const processTools = \[/);
|
|
38
|
-
for (const name of ['process_session_start','process_session_read','process_session_status','process_session_list','process_session_terminate','process_session_action']) {
|
|
38
|
+
for (const name of ['process_session_start','process_session_read','process_session_status','process_session_list','process_session_terminate','process_session_action','process_session_write']) {
|
|
39
39
|
assert.match(source, new RegExp(`'${name}'`));
|
|
40
40
|
}
|
|
41
41
|
assert.match(source, /for \(const processPlane of \[false, true\]\)/);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { mkdtemp, readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { parseUpdateArgs, prepareHostPolicyBootstrap } from '../scripts/runtime-self-update.mjs';
|
|
8
|
+
|
|
9
|
+
const hex=ch=>ch.repeat(64);
|
|
10
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
|
|
12
|
+
test('R45 slot-update CLI binds Host policy bootstrap as one exact path plus SHA-256 pair',()=>{
|
|
13
|
+
const base=['--stage','stage','--development-root','dev','--expected-version','0.15.1','--expected-manifest',hex('a')];
|
|
14
|
+
assert.throws(()=>parseUpdateArgs([...base,'--host-policy','C:/candidate/host.json']),/host policy.*pair/i);
|
|
15
|
+
assert.throws(()=>parseUpdateArgs([...base,'--host-policy-sha256',hex('b')]),/host policy.*pair/i);
|
|
16
|
+
const parsed=parseUpdateArgs([...base,'--host-policy','C:/candidate/host.json','--host-policy-sha256',hex('b')]);
|
|
17
|
+
assert.equal(parsed.hostPolicyBootstrap.path,path.resolve('C:/candidate/host.json'));
|
|
18
|
+
assert.equal(parsed.hostPolicyBootstrap.sha256,hex('b'));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('R45 Host policy bootstrap accepts exact v2 bytes and rejects hash or native contract drift',async()=>{
|
|
22
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r45-host-bootstrap-'));
|
|
23
|
+
const file=path.join(root,'host.json');
|
|
24
|
+
const policy={
|
|
25
|
+
schema:'deadbyte.host-policy.v2',enabled:true,arm_file:'C:/state/host-grant.json',
|
|
26
|
+
roots:{core:{path:'C:/core',read:true,write:true,exec:true}},
|
|
27
|
+
commands:{node_inline:{kind:'inline',executable:'C:/node.exe',executable_sha256:hex('1'),root_ids:['core'],prefix_args:['-e'],timeout_ms:1000,max_output_bytes:4096,max_command_chars:1024}},
|
|
28
|
+
native_exec:{enabled:true,root_ids:['core'],timeout_ms:1000,max_output_bytes:4096,max_args:8,max_arg_chars:1024}
|
|
29
|
+
};
|
|
30
|
+
const bytes=Buffer.from(JSON.stringify(policy)+'\n','utf8'); await writeFile(file,bytes);
|
|
31
|
+
const accepted=await prepareHostPolicyBootstrap({path:file,sha256:sha(bytes)});
|
|
32
|
+
assert.equal(accepted.sha256,sha(bytes)); assert.deepEqual(accepted.policy,policy);
|
|
33
|
+
await assert.rejects(prepareHostPolicyBootstrap({path:file,sha256:hex('f')}),/host policy.*SHA-256 mismatch/i);
|
|
34
|
+
const bad=path.join(root,'bad.json');
|
|
35
|
+
const badBytes=Buffer.from(JSON.stringify({...policy,native_exec:{...policy.native_exec,enabled:false}})+'\n','utf8');
|
|
36
|
+
await writeFile(bad,badBytes);
|
|
37
|
+
await assert.rejects(prepareHostPolicyBootstrap({path:bad,sha256:sha(await readFile(bad))}),/native_exec contract/i);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('R45 updater threads the bootstrapped Host v2 policy into successor generation',async()=>{
|
|
41
|
+
const source=await readFile(new URL('../src/runtime-update.mjs',import.meta.url),'utf8');
|
|
42
|
+
assert.match(source,/prepareHostPolicyBootstrap\(hostPolicyBootstrap\)/);
|
|
43
|
+
assert.match(source,/control\.hostPolicy=hostBootstrap\.policy/);
|
|
44
|
+
assert.match(source,/hostPolicy:control\.hostPolicy/);
|
|
45
|
+
assert.match(source,/hostPolicyBootstrap:args\.hostPolicyBootstrap/);
|
|
46
|
+
});
|