deadbyte-mcp 0.14.0 → 0.15.1
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/AGENTS.md +11 -18
- package/CONTEXT.md +3 -3
- package/MANIFEST.SHA256 +156 -70
- package/PROVENANCE.json +10 -0
- package/R43-PARENT.json +20 -0
- package/R44-DONORS.json +99 -0
- package/R44-PARENT.json +18 -0
- package/R45-PARENT.json +18 -0
- package/README.txt +19 -14
- package/RELEASE.json +37 -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 +5 -6
- package/controller/deadbyte-controller.ps1 +2 -2
- package/docs/ARCHITECTURE.md +8 -1
- package/docs/R44-ARCHITECTURE.md +37 -0
- package/native/deadbyte-hardware-observer.cpp +308 -0
- package/package.json +18 -8
- package/scripts/autonomous-tests.ps1 +2 -2
- package/scripts/build-hardware-r45.ps1 +71 -0
- package/scripts/deferred-slot-operation-r43.mjs +126 -0
- package/scripts/deferred-slot-operation-r44.mjs +126 -0
- package/scripts/deferred-slot-operation-r45.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-r43.mjs +115 -0
- package/scripts/final-closure-r44.mjs +121 -0
- package/scripts/final-closure-r45.mjs +121 -0
- package/scripts/final-closure-verify-r43.mjs +213 -0
- package/scripts/final-closure-verify-r44.mjs +220 -0
- package/scripts/final-closure-verify-r45.mjs +220 -0
- package/scripts/finalize-r43.mjs +217 -0
- package/scripts/finalize-r44.mjs +217 -0
- package/scripts/finalize-r45.mjs +219 -0
- package/scripts/full-regression-r43.mjs +20 -0
- package/scripts/full-regression-r44.mjs +20 -0
- package/scripts/full-regression-r45.mjs +20 -0
- package/scripts/full-regression-summary-r45.mjs +14 -0
- package/scripts/gate-windows-r43.ps1 +36 -0
- package/scripts/gate-windows-r44.ps1 +36 -0
- package/scripts/gate-windows-r45.ps1 +44 -0
- package/scripts/init-host-policy.ps1 +39 -1
- package/scripts/inspect-active-release-r45.mjs +20 -0
- package/scripts/release-manifest.mjs +3 -1
- package/scripts/release-parity-r43.mjs +218 -0
- package/scripts/release-parity-r44.mjs +242 -0
- package/scripts/release-parity-r45.mjs +253 -0
- package/scripts/release-parity-tests-r43.ps1 +8 -0
- package/scripts/release-parity-tests-r44.ps1 +8 -0
- package/scripts/release-parity-tests-r45.ps1 +8 -0
- package/scripts/verify-r43-parent.mjs +126 -0
- package/scripts/verify-r44-parent.mjs +142 -0
- package/scripts/verify-r45-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r43.mjs +55 -0
- package/scripts/windows-gate-evidence-r44.mjs +55 -0
- package/scripts/windows-gate-evidence-r45.mjs +60 -0
- package/src/agent-backend-r44.mjs +254 -0
- package/src/autonomous-output-contracts.mjs +1 -1
- package/src/autonomous-policy.mjs +41 -4
- package/src/autonomous-runtime.mjs +37 -19
- package/src/autonomous-supervisor-host.mjs +12 -2
- package/src/capability-ledger.mjs +3 -1
- package/src/codex-app-server-r44.mjs +154 -0
- package/src/coding-plane.mjs +66 -19
- package/src/compact-gateway-mcp-tools.mjs +4 -2
- package/src/deadbyte-cli.mjs +17 -9
- package/src/doctor-r45.mjs +65 -0
- package/src/durable-job-r44.mjs +145 -0
- package/src/external-job-provider-r44.mjs +126 -0
- package/src/host-plane.mjs +156 -87
- package/src/job-supervisor-host-r44.mjs +112 -0
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +21 -10
- package/src/mcp-host-smoke-client.mjs +1 -1
- package/src/mcp-server.mjs +84 -26
- package/src/mcp-smoke-client.mjs +1 -1
- package/src/native-diff-v2.mjs +12 -7
- package/src/native-diff.mjs +32 -9
- package/src/observation-mcp-tools.mjs +5 -1
- package/src/observation-output-contracts.mjs +8 -0
- package/src/observation-runtime.mjs +33 -2
- package/src/observation-smoke-client.mjs +7 -3
- package/src/operator-surface.mjs +2 -2
- package/src/output-contracts.mjs +27 -11
- package/src/process-policy.mjs +19 -0
- package/src/process-runtime.mjs +5 -2
- package/src/process-smoke-client.mjs +2 -2
- package/src/provider-circuit.mjs +8 -2
- package/src/r44-compact-disarmed-probe.mjs +74 -0
- package/src/r44-full-surface-probe.mjs +34 -0
- package/src/r45-compact-disarmed-probe.mjs +74 -0
- package/src/r45-full-surface-probe.mjs +34 -0
- package/src/release-generation.mjs +1 -0
- package/src/remote-device-r44.mjs +205 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +4 -4
- package/src/remote-mcp-r44-parity-client.mjs +203 -0
- package/src/remote-mcp-r45-parity-client.mjs +206 -0
- package/src/remote-mcp-smoke-client.mjs +7 -4
- package/src/runtime-update.mjs +100 -39
- package/src/skill-mcp-tools-r44.mjs +37 -0
- package/src/skill-plane-r44.mjs +203 -0
- package/src/tunnel-stdio-compat-smoke.mjs +1 -1
- package/src/version.mjs +1 -1
- package/test/agent-backend-r44.test.mjs +115 -0
- package/test/agent-runtime.test.mjs +4 -3
- package/test/autonomous-loop.test.mjs +121 -11
- package/test/autonomous-runtime.test.mjs +3 -2
- package/test/capability-ledger-r36.test.mjs +3 -3
- package/test/cli-entrypoint.test.mjs +4 -4
- package/test/codex-app-server-r44.test.mjs +115 -0
- package/test/codex-autonomous-r44.test.mjs +87 -0
- package/test/coding-plane.test.mjs +3 -2
- package/test/coding-runtime.test.mjs +36 -1
- package/test/compact-catalog-r36.test.mjs +3 -3
- package/test/compact-max-catalog-r40.test.mjs +4 -2
- package/test/compact-max-catalog-r44.test.mjs +97 -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/durable-job-r44.test.mjs +75 -0
- package/test/external-job-provider-r44.test.mjs +46 -0
- package/test/full-max-catalog-r40.test.mjs +5 -3
- package/test/full-max-catalog-r44.test.mjs +91 -0
- package/test/full-max-catalog-r45.test.mjs +91 -0
- package/test/hardware-observation-r45.test.mjs +44 -0
- package/test/host-inline-r45.test.mjs +67 -0
- package/test/host-plane.test.mjs +15 -1
- package/test/machine-mcp-integration.test.mjs +1 -0
- package/test/native-diff.test.mjs +28 -0
- package/test/observation-mcp-tools.test.mjs +4 -3
- package/test/output-schema.test.mjs +3 -2
- package/test/package-boundary.test.mjs +1 -1
- package/test/process-policy.test.mjs +22 -1
- package/test/production-docs.test.mjs +3 -3
- package/test/prompts-resources.test.mjs +1 -1
- package/test/r33-closeout-regression.test.mjs +20 -36
- package/test/r33-finalization.test.mjs +7 -7
- package/test/r43-finalization.test.mjs +31 -0
- package/test/r43-finalizer.test.mjs +34 -0
- package/test/r43-parent.test.mjs +29 -0
- package/test/r44-finalization.test.mjs +58 -0
- package/test/r44-finalizer.test.mjs +48 -0
- package/test/r44-parent.test.mjs +25 -0
- package/test/r45-autonomous-quick-test.test.mjs +10 -0
- package/test/r45-finalization.test.mjs +84 -0
- package/test/release-generation.test.mjs +1 -0
- package/test/release-version.test.mjs +65 -20
- package/test/remote-device-r44.test.mjs +104 -0
- package/test/runtime-host-bootstrap-r45.test.mjs +46 -0
- package/test/runtime-self-update.test.mjs +42 -0
- package/test/skill-mcp-r44.test.mjs +38 -0
- package/test/skill-plane-r44.test.mjs +93 -0
- package/test/standing-grants.test.mjs +5 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateParityEvidence,R44_PREDECESSOR_RELEASE_ID,R44_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r44.mjs';
|
|
5
|
+
import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r44.mjs';
|
|
6
|
+
|
|
7
|
+
const root=new URL('../',import.meta.url);const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
8
|
+
const featureGate=manifest=>({schema:'deadbyte.r44-windows-gate.v1',status:'passed',exit_code:0,version:'0.15.0',
|
|
9
|
+
marker:'DEADBYTE V0.15.0 / R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS',manifest_sha256:manifest,
|
|
10
|
+
features:{skill_integrity:true,agent_backend_persistence:true,codex_protocol_contract:true,remote_device_identity:true,
|
|
11
|
+
durable_job_supervisor:true,real_external_supervisor_smoke:true,full_regression_required:true,codex_live_binary_required:false}});
|
|
12
|
+
function parity(){
|
|
13
|
+
const manifest='a'.repeat(64),gate=featureGate(manifest);
|
|
14
|
+
const requirements=Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy',
|
|
15
|
+
'interrupted_recovery','evidence_verification','compact_closure','full_surface','desktop_readonly','desktop_guarded_input','deterministic_memory',
|
|
16
|
+
'skill_integrity','agent_backend_persistence','codex_protocol_contract','remote_device_identity','durable_job_supervisor','real_external_supervisor_smoke'].map(key=>[key,true]));
|
|
17
|
+
return {schema:'deadbyte.r44-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
|
|
18
|
+
candidate:{release_id:`v0.15.0-${manifest.slice(0,16)}`,version:'0.15.0',manifest_sha256:manifest},
|
|
19
|
+
immutable_slot:{protected:true,release_root:'C:/immutable/r44',development_root:'D:/Projects/deadbyte-mcp/development/deadbyte-mcp-r42-agentic-dev'},
|
|
20
|
+
local_full:{status:'passed',tool_count:81,strict_output_schemas:true},
|
|
21
|
+
public_compact:{status:'passed',tool_count:43,capability_closure:true,gateway_count:6,skill_catalog_verified:true,
|
|
22
|
+
desktop_armed:false,desktop_observation_receipt_verified:true,desktop_grounding_receipt_verified:true},
|
|
23
|
+
autonomous:{status:'passed',signed_release_verified:true},desktop_guarded:{status:'passed',native_injected:true,replay_performed:false,
|
|
24
|
+
predispatch_retry_count:0,observation_receipts_verified:1,action_receipts_verified:3},
|
|
25
|
+
deterministic_memory:{status:'passed',goal_count:1,snapshot_count:1,index_count:1},
|
|
26
|
+
feature_gate:gate,feature_gate_sha256:'f'.repeat(64),
|
|
27
|
+
before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
28
|
+
rollback:{state:'completed'},restore:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},
|
|
29
|
+
predecessor:{release_id:R44_PREDECESSOR_RELEASE_ID,version:'0.14.1',manifest_sha256:R44_PREDECESSOR_MANIFEST},
|
|
30
|
+
predecessor_disarmed:{status:'passed',tool_count:42,capability_closure:true},
|
|
31
|
+
successor:{release_id:`v0.15.0-${manifest.slice(0,16)}`,version:'0.15.0',manifest_sha256:manifest},
|
|
32
|
+
successor_disarmed:{status:'passed',tool_count:43,capability_closure:true,skill_catalog_verified:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
33
|
+
requirements};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test('R44 parity requires exact R43 predecessor, 81/43 surface and feature contract',()=>{
|
|
37
|
+
const value=parity();assert.equal(validateParityEvidence(value),true);
|
|
38
|
+
assert.throws(()=>validateParityEvidence({...value,predecessor:{...value.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
|
|
39
|
+
assert.throws(()=>validateParityEvidence({...value,local_full:{...value.local_full,tool_count:80}}),/81-tool/i);
|
|
40
|
+
assert.throws(()=>validateParityEvidence({...value,public_compact:{...value.public_compact,tool_count:42}}),/compact/i);
|
|
41
|
+
assert.throws(()=>validateParityEvidence({...value,feature_gate:{...value.feature_gate,features:{...value.feature_gate.features,codex_protocol_contract:false}}}),/codex_protocol_contract/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('R44 release machinery is isolated from R43 and binds 0.15.0 signed closure domains',async()=>{
|
|
45
|
+
const [gate,deferred,paritySource,writer,verifier,evidence,suite,finalizer,parent]=await Promise.all([
|
|
46
|
+
text('scripts/gate-windows-r44.ps1'),text('scripts/deferred-slot-operation-r44.mjs'),text('scripts/release-parity-r44.mjs'),
|
|
47
|
+
text('scripts/final-closure-r44.mjs'),text('scripts/final-closure-verify-r44.mjs'),text('scripts/windows-gate-evidence-r44.mjs'),
|
|
48
|
+
text('scripts/release-parity-tests-r44.ps1'),text('scripts/finalize-r44.mjs'),text('R44-PARENT.json')]);
|
|
49
|
+
assert.equal(R44_PREDECESSOR_RELEASE_ID,'v0.14.1-0a5a833892593283');
|
|
50
|
+
assert.equal(R44_PREDECESSOR_MANIFEST,'0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9');
|
|
51
|
+
assert.match(gate,/r44-parent-verify/);assert.match(gate,/r44:full:test/);assert.match(gate,/DEADBYTE V0\.15\.0 \/ R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS/);
|
|
52
|
+
assert.match(deferred,/--expected-version','0\.15\.0'/);assert.match(paritySource,/deadbyte\.r44-parity\.v1/);assert.match(paritySource,/tool_count===81/);assert.match(paritySource,/tool_count===43/);
|
|
53
|
+
for(const source of [writer,verifier]){assert.match(source,/DEADBYTE-R44-FINAL-CLOSURE-V1/);assert.match(source,/deadbyte\.r44-final-closure\.v1/);assert.match(source,/R44 REMOTE AGENT SKILL BASELINE/);}
|
|
54
|
+
assert.equal(typeof verifyFinalClosureObject,'function');assert.match(evidence,/deadbyte\.r44-windows-gate\.v1/);assert.match(evidence,/final_closure_sha256/);
|
|
55
|
+
assert.match(suite,/skill-plane-r44\.test\.mjs/);assert.match(suite,/codex-app-server-r44\.test\.mjs/);assert.match(suite,/external-job-provider-r44\.test\.mjs/);
|
|
56
|
+
assert.match(finalizer,/--restore-standing-grants/);assert.match(finalizer,/runReleaseParity/);assert.match(finalizer,/writeFinalClosure/);assert.match(finalizer,/verifyFinalClosureObject/);assert.match(finalizer,/--rollback-receipt/);
|
|
57
|
+
const parentRecord=JSON.parse(parent);assert.equal(parentRecord.parent_final_closure_sha256,'2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b');
|
|
58
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { validateFinalizerAuthorityStatus, validateWindowsGateEvidence } from '../scripts/finalize-r44.mjs';
|
|
4
|
+
import { windowsPowerShellEnvironment } from '../src/runtime-update.mjs';
|
|
5
|
+
|
|
6
|
+
const manifest='a'.repeat(64);
|
|
7
|
+
const parent={
|
|
8
|
+
release_id:'v0.14.1-0a5a833892593283',
|
|
9
|
+
manifest_sha256:'0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9',
|
|
10
|
+
generation_manifest_sha256:'fcfcb5a47d55039b7bb5d42faa0739b57b13d8a420d4418ae09d96d2862967cb',
|
|
11
|
+
closure_sha256:'2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b'
|
|
12
|
+
};
|
|
13
|
+
const features=()=>({skill_integrity:true,agent_backend_persistence:true,codex_protocol_contract:true,
|
|
14
|
+
remote_device_identity:true,durable_job_supervisor:true,real_external_supervisor_smoke:true,full_regression_required:true,
|
|
15
|
+
codex_live_binary_required:false});
|
|
16
|
+
const valid=()=>({schema:'deadbyte.r44-windows-gate.v1',status:'passed',exit_code:0,version:'0.15.0',
|
|
17
|
+
marker:'DEADBYTE V0.15.0 / R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS',manifest_sha256:manifest,
|
|
18
|
+
parent:{release_id:parent.release_id,manifest_sha256:parent.manifest_sha256,
|
|
19
|
+
generation_manifest_sha256:parent.generation_manifest_sha256,final_closure_sha256:parent.closure_sha256},
|
|
20
|
+
features:features()});
|
|
21
|
+
|
|
22
|
+
test('R44 detached finalizer requires Process+Coding+Autonomous and Desktop+Host DISARMED',()=>{
|
|
23
|
+
assert.equal(validateFinalizerAuthorityStatus({process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false}),true);
|
|
24
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({process_armed:false,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false}),/Process standing grant/);
|
|
25
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:true,host_armed:false}),/Desktop DISARMED/);
|
|
26
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:true}),/Host DISARMED/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('R44 detached finalizer accepts only exact signed-R43-parent feature gate evidence',()=>{
|
|
30
|
+
assert.equal(validateWindowsGateEvidence(valid(),manifest,parent),true);
|
|
31
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),manifest_sha256:'b'.repeat(64)},manifest,parent),/candidate mismatch/);
|
|
32
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),parent:{...valid().parent,release_id:'v0.14.1-bad'}},manifest,parent),/parent mismatch/);
|
|
33
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),parent:{...valid().parent,final_closure_sha256:'b'.repeat(64)}},manifest,parent),/parent/);
|
|
34
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),features:{...features(),skill_integrity:false}},manifest,parent),/skill_integrity/);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('R44 detached finalizer isolates Windows PowerShell modules from the parent runtime',()=>{
|
|
38
|
+
const env=windowsPowerShellEnvironment({
|
|
39
|
+
SystemRoot:'C:\\Windows',USERPROFILE:'C:\\Users\\operator',ProgramFiles:'C:\\Program Files',
|
|
40
|
+
PSModulePath:'C:\\poisoned-runtime-modules'
|
|
41
|
+
});
|
|
42
|
+
assert.equal(env.PSModulePath,[
|
|
43
|
+
'C:\\Users\\operator\\Documents\\WindowsPowerShell\\Modules',
|
|
44
|
+
'C:\\Program Files\\WindowsPowerShell\\Modules',
|
|
45
|
+
'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\Modules'
|
|
46
|
+
].join(';'));
|
|
47
|
+
assert.doesNotMatch(env.PSModulePath,/poisoned-runtime-modules/);
|
|
48
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { verifyR44Parent } from '../scripts/verify-r44-parent.mjs';
|
|
6
|
+
|
|
7
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const root=path.resolve(here,'..');
|
|
9
|
+
|
|
10
|
+
test('R44 parent is exact sealed R43 final baseline',async()=>{
|
|
11
|
+
const result=await verifyR44Parent(path.join(root,'R44-PARENT.json'));
|
|
12
|
+
assert.equal(result.ok,true);
|
|
13
|
+
assert.equal(result.release_id,'v0.14.1-0a5a833892593283');
|
|
14
|
+
assert.equal(result.manifest_sha256,'0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9');
|
|
15
|
+
assert.equal(result.generation_manifest_sha256,'fcfcb5a47d55039b7bb5d42faa0739b57b13d8a420d4418ae09d96d2862967cb');
|
|
16
|
+
assert.equal(result.release_files,1834);
|
|
17
|
+
assert.equal(result.generation_files,7);
|
|
18
|
+
assert.equal(result.closure_sha256,'2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b');
|
|
19
|
+
assert.equal(result.recorded_all_disarmed,true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('R44 parent proof is historical and does not require current grants to remain absent',async()=>{
|
|
23
|
+
const result=await verifyR44Parent(path.join(root,'R44-PARENT.json'));
|
|
24
|
+
assert.equal(result.proof_class,'immutable-slot+generation+signed-final-closure');
|
|
25
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
test('R45 autonomous quick-test is fixture-scoped and does not invoke legacy npm test matrix', async () => {
|
|
6
|
+
const text=await readFile(new URL('../scripts/autonomous-tests.ps1',import.meta.url),'utf8');
|
|
7
|
+
assert.match(text,/node\.exe --test test\/autonomous-live-fixture\.test\.mjs/);
|
|
8
|
+
assert.doesNotMatch(text,/npm\.cmd test/);
|
|
9
|
+
assert.match(text,/R24 QUICK TEST PASS/);
|
|
10
|
+
});
|
|
@@ -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
|
+
});
|
|
@@ -92,6 +92,7 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
92
92
|
assert.equal(generatedAuto.profiles.gate.script_sha256,sha(Buffer.from('Write-Output gate\n')));
|
|
93
93
|
assert.equal(generatedAuto.profiles['windows-release'].script_path,'scripts/gate-windows-current.ps1');
|
|
94
94
|
assert.equal(generatedAuto.profiles['windows-release'].script_sha256,sha(Buffer.from('Write-Output current-gate\n')));
|
|
95
|
+
assert.equal(generatedAuto.profiles['windows-release'].timeout_ms,600000);
|
|
95
96
|
assert.equal(generatedAuto.profiles['windows-release'].description,'Full Windows target release gate; runs only when finish is requested.');
|
|
96
97
|
const generatedHost=JSON.parse(await readFile(result.host_policy_path,'utf8'));
|
|
97
98
|
assert.equal(generatedHost.roots.core.path,path.resolve(development));
|
|
@@ -2,24 +2,69 @@ 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
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
|
|
6
|
+
const root=new URL('../',import.meta.url);
|
|
7
|
+
const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
8
|
+
const PARENT_RELEASE='v0.15.0-c15fa41719be61b3';
|
|
9
|
+
const PARENT_MANIFEST='c15fa41719be61b3186e49b2367a5f4c057365cfb465102dbefb7d7355f45483';
|
|
10
|
+
const PARENT_GENERATION='6d7429c050b7fe893492e102f00282019116e0c9e54e4f25a5791defa1661d30';
|
|
11
|
+
const PARENT_CLOSURE='533b7e0ff9ded04086dd90ed34e3b87bc427acc3c55c25bb9f4ec66cb448e667';
|
|
12
|
+
|
|
13
|
+
test('R45 current authority agrees on V0.15.1 and preserves exact sealed R44 parent',async()=>{
|
|
14
|
+
const pkg=JSON.parse(await text('package.json'));
|
|
15
|
+
const [version,controller,gate,readme,architecture,controllerReadme,deferred,parity,closure,closureVerify,windowsGate,parent,r44Gate,r44Parity,r44Closure]=await Promise.all([
|
|
16
|
+
text('src/version.mjs'),text('controller/deadbyte-controller.ps1'),text('scripts/gate-windows-r45.ps1'),text('README.txt'),
|
|
17
|
+
text('docs/ARCHITECTURE.md'),text('controller/README.TXT'),text('scripts/deferred-slot-operation-r45.mjs'),
|
|
18
|
+
text('scripts/release-parity-r45.mjs'),text('scripts/final-closure-r45.mjs'),text('scripts/final-closure-verify-r45.mjs'),
|
|
19
|
+
text('scripts/windows-gate-evidence-r45.mjs'),text('R45-PARENT.json'),
|
|
20
|
+
text('scripts/gate-windows-r44.ps1'),text('scripts/release-parity-r44.mjs'),text('scripts/final-closure-r44.mjs')
|
|
21
|
+
]);
|
|
22
|
+
assert.equal(pkg.version,'0.15.1');
|
|
23
|
+
assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r45.ps1');
|
|
24
|
+
assert.equal(pkg.scripts['r45:parent:verify'],'node scripts/verify-r45-parent.mjs');
|
|
25
|
+
assert.equal(pkg.scripts['r45:full:test'],'node scripts/full-regression-r45.mjs');
|
|
26
|
+
assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r45.mjs');
|
|
27
|
+
assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r45.mjs');
|
|
28
|
+
assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r45.mjs');
|
|
29
|
+
assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r45.mjs');
|
|
30
|
+
assert.equal(pkg.scripts['finalize:r45'],'node scripts/finalize-r45.mjs');
|
|
31
|
+
assert.match(version,/DEADBYTE_VERSION = '0\.15\.1'/);
|
|
32
|
+
assert.match(controller,/CONTROLLER V0\.15\.1 \/ R45/);
|
|
33
|
+
assert.match(gate,/DEADBYTE V0\.15\.1 \/ R45 MACHINE FREEDOM WINDOWS BATCH GATE: PASS/);
|
|
34
|
+
assert.match(readme,/^DEADBYTE MCP V0\.15\.1 \/ R45 MACHINE FREEDOM FINAL BASELINE$/m);
|
|
35
|
+
assert.match(architecture,/^# DEADBYTE MCP V0\.15\.1 \/ R45 ARCHITECTURE$/m);
|
|
36
|
+
assert.match(controllerReadme,/^DEADBYTE MCP V0\.15\.1 \/ R45 CONTROLLER$/m);
|
|
37
|
+
assert.match(deferred,/--expected-version','0\.15\.1'/);
|
|
38
|
+
assert.match(parity,/R45_PREDECESSOR_RELEASE_ID='v0\.15\.0-c15fa41719be61b3'/);
|
|
39
|
+
assert.match(parity,new RegExp(PARENT_MANIFEST));
|
|
40
|
+
assert.match(parity,/tool_count===82/);assert.match(parity,/tool_count===43/);
|
|
41
|
+
assert.match(closure,/version:'0\.15\.1'/);assert.match(closure,/DEADBYTE-R45-FINAL-CLOSURE-V1/);
|
|
42
|
+
assert.match(closureVerify,/R45_FULL_TOOL_COUNT=82/);assert.match(closureVerify,/R45_COMPACT_TOOL_COUNT=43/);
|
|
43
|
+
assert.match(windowsGate,/deadbyte\.r45-windows-gate\.v1/);
|
|
44
|
+
const parentRecord=JSON.parse(parent);
|
|
45
|
+
assert.equal(parentRecord.parent_release_id,PARENT_RELEASE);
|
|
46
|
+
assert.equal(parentRecord.parent_manifest_sha256,PARENT_MANIFEST);
|
|
47
|
+
assert.equal(parentRecord.parent_generation_manifest_sha256,PARENT_GENERATION);
|
|
48
|
+
assert.equal(parentRecord.parent_final_closure_sha256,PARENT_CLOSURE);
|
|
49
|
+
assert.match(r44Gate,/DEADBYTE V0\.15\.0 \/ R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS/);
|
|
50
|
+
assert.match(r44Parity,/deadbyte\.r44-parity\.v1/);
|
|
51
|
+
assert.match(r44Closure,/version:'0\.15\.0'/);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('R45 keeps ONLINE reuse and explicit Desktop authority',async()=>{
|
|
55
|
+
const [cli,controller]=await Promise.all([text('src/deadbyte-cli.mjs'),text('controller/deadbyte-controller.ps1')]);
|
|
56
|
+
assert.match(cli,/controllerRuntimeReady/);
|
|
57
|
+
assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
|
|
58
|
+
const start=controller.indexOf('function Recover-AutonomousSupervisor'),end=controller.indexOf('function Show-State',start);
|
|
59
|
+
assert.ok(start>=0&&end>start);
|
|
60
|
+
const block=controller.slice(start,end);
|
|
61
|
+
assert.doesNotMatch(block,/\$host\s*=/i);
|
|
62
|
+
assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);
|
|
63
|
+
assert.match(controller,/armdesktop/);
|
|
64
|
+
assert.match(controller,/disarmdesktop/);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('semantic config remains byte-pinned across R45 machine-freedom work',async()=>{
|
|
68
|
+
const semantic=await text('controller/deadbyte-semantic-lsp-config.json');
|
|
69
|
+
assert.equal(createHash('sha256').update(Buffer.from(semantic,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');
|
|
22
70
|
});
|
|
23
|
-
test('R40 keeps ONLINE reuse and PowerShell Host collision fix while Desktop stays explicit',async()=>{const [cli,controller]=await Promise.all([text('src/deadbyte-cli.mjs'),text('controller/deadbyte-controller.ps1')]);assert.match(cli,/controllerRuntimeReady/);assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);const start=controller.indexOf('function Recover-AutonomousSupervisor'),end=controller.indexOf('function Show-State',start);assert.ok(start>=0&&end>start);const block=controller.slice(start,end);assert.doesNotMatch(block,/\$host\s*=/i);assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);assert.match(controller,/armdesktop/);assert.match(controller,/disarmdesktop/);});
|
|
24
|
-
test('sealed R39 tooling remains historical 0.11.3 authority with exact 0.11.2 predecessor',async()=>{const [parity,gate,closure]=await Promise.all([text('scripts/release-parity-r39.mjs'),text('scripts/gate-windows-r39.ps1'),text('scripts/final-closure-r39.mjs')]);assert.match(parity,/R39_PREDECESSOR_RELEASE_ID='v0\.11\.2-058605dfccaa3035'/);assert.match(parity,/version==='0\.11\.3'|version:'0\.11\.3'/);assert.match(gate,/DEADBYTE V0\.11\.3 \/ R39 WINDOWS BATCH GATE: PASS/);assert.match(closure,/version:'0\.11\.3'/);});
|
|
25
|
-
test('sealed R37 tooling remains historical 0.11.1 authority',async()=>{const [parity,gate,closure]=await Promise.all([text('scripts/release-parity.mjs'),text('scripts/gate-windows.ps1'),text('scripts/final-closure.mjs')]);assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);assert.match(closure,/version:'0\.11\.1'/);});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { generateKeyPairSync, createHash } from 'node:crypto';
|
|
4
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { createRemoteDevicePlaneR44 } from '../src/remote-device-r44.mjs';
|
|
8
|
+
|
|
9
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
10
|
+
function deviceKey(){
|
|
11
|
+
const {publicKey}=generateKeyPairSync('ed25519');
|
|
12
|
+
const der=Buffer.from(publicKey.export({type:'spki',format:'der'}));
|
|
13
|
+
return {spki:der.toString('base64'),deviceId:sha(der)};
|
|
14
|
+
}
|
|
15
|
+
class FakeRelay{
|
|
16
|
+
constructor(){this.probes=[];this.requests=[];this.drop=false;}
|
|
17
|
+
async probe(value){this.probes.push(structuredClone(value));return {device_id:value.device_id,epoch:value.epoch,nonce:value.nonce,ready:true};}
|
|
18
|
+
async request(value){this.requests.push(structuredClone(value));if(this.drop)return null;return {ack:'accepted',request_id:value.request_id,terminal:{status:'completed',result_sha256:'a'.repeat(64)}};}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
test('R44 remote device reported online is not reachable until identity-bound probe ACK',async()=>{
|
|
22
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-remote-'));
|
|
23
|
+
const relay=new FakeRelay(), key=deviceKey();
|
|
24
|
+
try{
|
|
25
|
+
const plane=await createRemoteDevicePlaneR44({stateDir:root,relay,authorizeCapability:async()=>true});
|
|
26
|
+
const paired=await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
27
|
+
assert.equal(paired.device_id,key.deviceId);assert.equal(paired.epoch,1);
|
|
28
|
+
await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'conn-1'});
|
|
29
|
+
assert.equal((await plane.status({deviceId:key.deviceId})).reachable,false);
|
|
30
|
+
await assert.rejects(plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'coding.search',payload:{q:'x'},requestId:'1'.repeat(64)}),/not reachable/);
|
|
31
|
+
const ready=await plane.probe({deviceId:key.deviceId,epoch:1});
|
|
32
|
+
assert.equal(ready.reachable,true);assert.equal(relay.probes.length,1);
|
|
33
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('R44 remote dispatch is durable-before-send, replay-idempotent and silent drop is terminal',async()=>{
|
|
37
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-remote-dispatch-'));
|
|
38
|
+
const relay=new FakeRelay(), key=deviceKey();
|
|
39
|
+
try{
|
|
40
|
+
const plane=await createRemoteDevicePlaneR44({stateDir:root,relay,authorizeCapability:async()=>true});
|
|
41
|
+
await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
42
|
+
await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'c'});
|
|
43
|
+
await plane.probe({deviceId:key.deviceId,epoch:1});
|
|
44
|
+
const requestId='2'.repeat(64), payload={path:'README.md'};
|
|
45
|
+
const done=await plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'coding.file_read',payload,requestId});
|
|
46
|
+
assert.equal(done.state,'completed');assert.equal(relay.requests.length,1);
|
|
47
|
+
const stored=JSON.parse(await readFile(path.join(root,'remote-devices.json'),'utf8'));
|
|
48
|
+
assert.equal(stored.requests[requestId].state,'completed');
|
|
49
|
+
const replay=await plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'coding.file_read',payload,requestId});
|
|
50
|
+
assert.equal(replay.replay,true);assert.equal(relay.requests.length,1);
|
|
51
|
+
await assert.rejects(plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'coding.file_read',payload:{path:'other'},requestId}),/request id conflict/);
|
|
52
|
+
|
|
53
|
+
relay.drop=true;
|
|
54
|
+
const droppedId='3'.repeat(64);
|
|
55
|
+
const dropped=await plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'coding.file_read',payload,requestId:droppedId});
|
|
56
|
+
assert.equal(dropped.state,'failed');assert.equal(dropped.error_code,'transport_no_ack');
|
|
57
|
+
const after=JSON.parse(await readFile(path.join(root,'remote-devices.json'),'utf8'));
|
|
58
|
+
assert.equal(after.requests[droppedId].state,'failed');
|
|
59
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('R44 remote routing requires local capability authorization and revoke invalidates epoch',async()=>{
|
|
63
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-remote-auth-'));
|
|
64
|
+
const relay=new FakeRelay(), key=deviceKey();
|
|
65
|
+
try{
|
|
66
|
+
const plane=await createRemoteDevicePlaneR44({stateDir:root,relay,authorizeCapability:async({capabilityId})=>capabilityId==='machine.status'});
|
|
67
|
+
await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
68
|
+
await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'c'});await plane.probe({deviceId:key.deviceId,epoch:1});
|
|
69
|
+
await assert.rejects(plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'host.exec',payload:{},requestId:'4'.repeat(64)}),/capability denied/);
|
|
70
|
+
assert.equal(relay.requests.length,0);
|
|
71
|
+
const revoked=await plane.revoke({deviceId:key.deviceId,epoch:1});
|
|
72
|
+
assert.equal(revoked.revoked,true);
|
|
73
|
+
await assert.rejects(plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'new'}),/revoked|epoch/i);
|
|
74
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('R44 credential rotation commits encrypted replacement before supersede callback',async()=>{
|
|
78
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-remote-rotate-'));
|
|
79
|
+
const relay=new FakeRelay(), key=deviceKey(), observed=[];
|
|
80
|
+
try{
|
|
81
|
+
const plane=await createRemoteDevicePlaneR44({stateDir:root,relay,authorizeCapability:async()=>true,
|
|
82
|
+
onCredentialSuperseded:async info=>{
|
|
83
|
+
const current=JSON.parse(await readFile(path.join(root,'credentials',`${key.deviceId}.json`),'utf8'));
|
|
84
|
+
observed.push({info,current});
|
|
85
|
+
}});
|
|
86
|
+
await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
|
|
87
|
+
const one=Buffer.from('encrypted-token-one').toString('base64');
|
|
88
|
+
const first=await plane.rotateCredential({deviceId:key.deviceId,epoch:1,encryptedBundleBase64:one,expectedPreviousSha256:null});
|
|
89
|
+
const two=Buffer.from('encrypted-token-two').toString('base64');
|
|
90
|
+
const second=await plane.rotateCredential({deviceId:key.deviceId,epoch:1,encryptedBundleBase64:two,expectedPreviousSha256:first.credential_sha256});
|
|
91
|
+
assert.notEqual(second.credential_sha256,first.credential_sha256);
|
|
92
|
+
assert.equal(observed.length,1);
|
|
93
|
+
assert.equal(observed[0].current.credential_sha256,second.credential_sha256,'new credential must be durable before supersede');
|
|
94
|
+
await assert.rejects(plane.rotateCredential({deviceId:key.deviceId,epoch:1,encryptedBundleBase64:one,expectedPreviousSha256:first.credential_sha256}),/precondition/);
|
|
95
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('R44 remote state corruption fails closed',async()=>{
|
|
99
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-remote-corrupt-'));
|
|
100
|
+
try{
|
|
101
|
+
await writeFile(path.join(root,'remote-devices.json'),'{"schema":','utf8');
|
|
102
|
+
await assert.rejects(createRemoteDevicePlaneR44({stateDir:root,relay:new FakeRelay(),authorizeCapability:async()=>true}),/state JSON invalid/);
|
|
103
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
104
|
+
});
|
|
@@ -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
|
+
});
|
|
@@ -53,6 +53,29 @@ test('R27 slot-update CLI requires exact stage/development/version/manifest bind
|
|
|
53
53
|
assert.ok(path.isAbsolute(parsed.developmentRoot));
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
+
test('R43 slot authority restore plan carries prior Process grant without restoring Desktop or Host', () => {
|
|
57
|
+
assert.equal(typeof runtimeUpdate.standingAuthorityRestorePlan,'function');
|
|
58
|
+
const parsed=runtimeUpdate.parseControllerStatus([
|
|
59
|
+
'DEADBYTE MCP = ONLINE',
|
|
60
|
+
'Process plane : ARMED [standing-grant]',
|
|
61
|
+
'Coding plane : ARMED [standing-grant]',
|
|
62
|
+
'Autonomous : ARMED [standing-grant]',
|
|
63
|
+
'Desktop plane : ARMED [standing-grant]',
|
|
64
|
+
'Host plane : DISARMED [disarmed]'
|
|
65
|
+
].join('\n'));
|
|
66
|
+
assert.equal(parsed.process_armed,true);
|
|
67
|
+
const plan=runtimeUpdate.standingAuthorityRestorePlan(parsed,true);
|
|
68
|
+
assert.deepEqual(plan.commands,['armcoding','armautonomous','armprocess']);
|
|
69
|
+
assert.deepEqual(plan.expected,{
|
|
70
|
+
process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false
|
|
71
|
+
});
|
|
72
|
+
const disabled=runtimeUpdate.standingAuthorityRestorePlan(parsed,false);
|
|
73
|
+
assert.deepEqual(disabled.commands,[]);
|
|
74
|
+
assert.deepEqual(disabled.expected,{
|
|
75
|
+
process_armed:false,coding_armed:false,autonomous_armed:false,desktop_armed:false,host_armed:false
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
56
79
|
test('R27 development root is outside immutable/runtime state stores', async () => {
|
|
57
80
|
const state=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r27-state-'));
|
|
58
81
|
const dev=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r27-dev-'));
|
|
@@ -410,6 +433,25 @@ test('R29 bridge bootstrap rebinds only the pinned external bridge script', asyn
|
|
|
410
433
|
await assert.rejects(runtimeUpdate.prepareBridgeSpec(config,{root,scriptSha256:hex('f')}),/bridge script SHA-256 mismatch/i);
|
|
411
434
|
});
|
|
412
435
|
|
|
436
|
+
test('R44 downstream core selection accepts only one exact visible or one opaque child of the verified Bridge', () => {
|
|
437
|
+
assert.equal(typeof runtimeUpdate.selectCoreProcess,'function');
|
|
438
|
+
const root=path.resolve('C:/release'),bridgePid=1200;
|
|
439
|
+
const visible={ProcessId:1300,ParentProcessId:bridgePid,CreationDate:'20260921010000.000000+000',
|
|
440
|
+
ExecutablePath:'C:\\Program Files\\nodejs\\node.exe',CommandLine:`node "${path.join(root,'src','mcp-server.mjs')}"`};
|
|
441
|
+
const exact=runtimeUpdate.selectCoreProcess([visible],root,bridgePid);
|
|
442
|
+
assert.equal(exact.pid,1300);
|
|
443
|
+
assert.equal(exact.identity_basis,'command_line');
|
|
444
|
+
const opaque={ProcessId:1301,ParentProcessId:bridgePid,CreationDate:'20260921010100.000000+000',ExecutablePath:null,CommandLine:null};
|
|
445
|
+
const verifiedBridge={component:'bridge',pid:bridgePid,script_path:'C:\\bridge\\src\\bridge.mjs',script_sha256:hex('a')};
|
|
446
|
+
const fallback=runtimeUpdate.selectCoreProcess([opaque],root,bridgePid,verifiedBridge);
|
|
447
|
+
assert.equal(fallback.pid,1301);
|
|
448
|
+
assert.equal(fallback.identity_basis,'verified_bridge_single_opaque_node_child');
|
|
449
|
+
assert.throws(()=>runtimeUpdate.selectCoreProcess([opaque],root,bridgePid),/requires verified Bridge script binding/i);
|
|
450
|
+
assert.throws(()=>runtimeUpdate.selectCoreProcess([opaque,{...opaque,ProcessId:1302}],root,bridgePid,verifiedBridge),/unambiguous downstream core/i);
|
|
451
|
+
assert.throws(()=>runtimeUpdate.selectCoreProcess([{...visible,CommandLine:'node C:\\other\\server.mjs'}],root,bridgePid),/unambiguous downstream core/i);
|
|
452
|
+
assert.throws(()=>runtimeUpdate.selectCoreProcess([{...opaque,CreationDate:''}],root,bridgePid,verifiedBridge),/identity incomplete/i);
|
|
453
|
+
});
|
|
454
|
+
|
|
413
455
|
test('R31 updater threads pinned process policy and machine-FS enable into successor generation', async () => {
|
|
414
456
|
const source=await readFile(new URL('../src/runtime-update.mjs',import.meta.url),'utf8');
|
|
415
457
|
assert.match(source,/prepareProcessPolicyBootstrap\(processPolicyBootstrap\)/);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
4
|
+
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
|
|
5
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const repoRoot=path.resolve(here,'..');
|
|
12
|
+
const serverPath=path.join(repoRoot,'src','mcp-server.mjs');
|
|
13
|
+
|
|
14
|
+
test('R44 compact surface exposes one read-only skill_catalog without authority',async()=>{
|
|
15
|
+
const state=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-skill-mcp-'));
|
|
16
|
+
const client=new Client({name:'deadbyte-r44-skill-mcp',version:'0.15.0-dev'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
|
|
17
|
+
const env={...getDefaultEnvironment(),DEADBYTE_STATE_ROOT:state,DEADBYTE_CAPABILITY_PROFILE:'compact',
|
|
18
|
+
DEADBYTE_AUDIT_RUNTIME:'0',DEADBYTE_MACHINE_RUNTIME:'0',DEADBYTE_AGENT_RUNTIME:'0',
|
|
19
|
+
DEADBYTE_PROCESS_RUNTIME:'0',DEADBYTE_CODING_RUNTIME:'0',DEADBYTE_MACHINE_FS_RUNTIME:'0',
|
|
20
|
+
DEADBYTE_OBSERVATION_RUNTIME:'0',DEADBYTE_DESKTOP_RUNTIME:'0',DEADBYTE_AUTONOMOUS_RUNTIME:'0'};
|
|
21
|
+
const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
|
|
22
|
+
try{
|
|
23
|
+
await client.connect(transport);
|
|
24
|
+
const names=(await client.listTools()).tools.map(t=>t.name).sort();
|
|
25
|
+
assert.ok(names.includes('skill_catalog'),'R44 skill_catalog missing from compact surface');
|
|
26
|
+
assert.equal(names.filter(name=>name.startsWith('skill_')).length,1,'skill plane must remain one-tool surface');
|
|
27
|
+
const listed=await client.callTool({name:'skill_catalog',arguments:{op:'list'}});
|
|
28
|
+
assert.equal(listed.isError,false,JSON.stringify(listed));
|
|
29
|
+
assert.equal(listed.structuredContent.status,'ok');
|
|
30
|
+
assert.equal(listed.structuredContent.op,'list');
|
|
31
|
+
assert.deepEqual(listed.structuredContent.result.skills,[]);
|
|
32
|
+
assert.match(listed.structuredContent.result.registry_sha256,/^[0-9a-f]{64}$/);
|
|
33
|
+
const manifest=await client.callTool({name:'capability_manifest',arguments:{}});
|
|
34
|
+
const cap=manifest.structuredContent.result.capabilities.find(x=>x.id==='skill.catalog');
|
|
35
|
+
assert.ok(cap,'skill.catalog capability missing');
|
|
36
|
+
assert.equal(cap.authority,'none');assert.equal(cap.mutating,false);assert.equal(cap.compact_tool,'skill_catalog');
|
|
37
|
+
}finally{await client.close().catch(()=>{});await rm(state,{recursive:true,force:true});}
|
|
38
|
+
});
|