deadbyte-mcp 0.15.44 → 0.15.45
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 +69 -131
- package/PROVENANCE.json +257 -243
- package/README.txt +18 -18
- package/RELEASE.json +348 -334
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +503 -491
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +1857 -1769
- package/controller/deadbyte-desktop-policy.json +6 -6
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R68-COMPAT-HOST-EXEC-CANDIDATE.md +63 -0
- package/docs/R69-LIVE-OUTCOME-R70-POLICY-TRANSFER.md +136 -0
- package/docs/R70-CODING-DIGEST-SUPERVISOR-CHECKPOINT-20261013.md +42 -0
- package/docs/R70-FINITE-GRANT-OWNER-BOUNDARY-20261013.md +80 -0
- package/docs/R70-OWNER-BOOTSTRAP-CHECKPOINT-20261013.md +60 -0
- package/docs/R70-REFERENCE-MECHANISMS.json +95 -0
- package/docs/R70-TRUST-GUARD-EXPIRY-CHECKPOINT-20261013.md +47 -0
- package/package.json +2 -2
- package/scripts/benchmark-l0-r71.mjs +76 -0
- package/scripts/gate-windows-r71.ps1 +64 -0
- package/scripts/npm-release-r48.mjs +2 -0
- package/scripts/npm-release-readiness-r71.mjs +21 -0
- package/scripts/verify-r70-full-regression.ps1 +72 -0
- package/src/authority-continuity-r65.mjs +28 -8
- package/src/autonomous-mcp-tools.mjs +1 -1
- package/src/autonomous-output-contracts.mjs +4 -1
- package/src/autonomous-policy.mjs +54 -7
- package/src/capability-ledger.mjs +1 -1
- package/src/capability-resolver.mjs +2 -1
- package/src/commander-compat-runtime.mjs +30 -2
- package/src/deadbyte-cli.mjs +8 -6
- package/src/native-diff-v2.mjs +18 -5
- package/src/native-diff.mjs +21 -5
- package/src/r70-owner-approval.mjs +78 -0
- package/src/remote-live-log.mjs +48 -14
- package/src/remote-result-journal.mjs +1 -1
- package/src/runtime-update.mjs +2051 -1891
- package/src/tool-audit.mjs +2 -0
- package/src/version.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +2 -1
- package/test/autonomous-output-contract.test.mjs +17 -1
- package/test/autonomous-supervisor-integration.test.mjs +2 -1
- package/test/capability-resolver.test.mjs +17 -0
- package/test/codex-autonomous-r44.test.mjs +1 -1
- package/test/commander-compat-runtime.test.mjs +42 -0
- package/test/controller-policy-preflight-r59.test.mjs +1 -0
- package/test/native-diff-topology-r36.test.mjs +35 -2
- package/test/native-diff.test.mjs +83 -3
- package/test/r59-tool-surface-compat.test.mjs +9 -5
- package/test/r65-authority-runtime-epoch.test.mjs +9 -1
- package/test/r67-isolated-slot-rollback-restore.test.mjs +2 -1
- package/test/r67-npm-publish-gate.test.mjs +4 -2
- package/test/r67-release-contract.test.mjs +8 -7
- package/test/r69-live-outcome.test.mjs +137 -0
- package/test/r70-autonomous-grant-expiry.test.mjs +89 -0
- package/test/r70-autonomous-policy-bootstrap.test.mjs +166 -0
- package/test/r70-controller-autonomous-root.test.mjs +104 -0
- package/test/r70-controller-grant-subset.test.mjs +28 -0
- package/test/r70-controller-owner-issue-boundary.test.mjs +80 -0
- package/test/r70-controller-policy-snapshot.test.mjs +66 -0
- package/test/r70-owner-approval.test.mjs +67 -0
- package/test/r71-full-verifier-artifact.test.mjs +28 -0
- package/test/r71-isolated-slot-rollback-restore.test.mjs +62 -0
- package/test/r71-native-diff-mcp-wire.test.mjs +75 -0
- package/test/r71-publish-fence.test.mjs +38 -0
- package/test/r71-release-identity.test.mjs +31 -0
- package/test/remote-result-journal.test.mjs +12 -0
- package/test/remote-session-cli.test.mjs +2 -1
- package/test/standing-grants.test.mjs +2 -2
- package/test/tool-audit.test.mjs +14 -0
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-desktop-input-r40.obj +0 -0
- package/bin/deadbyte-desktop-observer-r40.obj +0 -0
- package/bin/deadbyte-desktop-uia-r40.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/bin/deadbyte-native-inspect-r67.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/conpty-input-observer.obj +0 -0
- package/miniconpty.obj +0 -0
- package/proof/CONTAINMENT-BUILD.txt +0 -163
- package/proof/MCP-SMOKE-STATUS.txt +0 -9
- package/proof/NODE-SYNTAX.txt +0 -4
- package/proof/PROOF.txt +0 -6
- package/proof/R34-TASK8-SUPERVISOR-CHECKPOINT.json +0 -29
- package/proof/R34-TASK9-MCP-SURFACE-CHECKPOINT.json +0 -28
- package/proof/SECRET-SCAN.txt +0 -4
- package/proof/SOURCE-GATES.txt +0 -16
- package/proof/STATUS.txt +0 -11
- package/proof/TARGET-V0313-CONTAINMENT-PASS.sha256 +0 -1
- package/proof/TARGET-V0313-CONTAINMENT-PASS.txt +0 -215
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.sha256 +0 -1
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.txt +0 -299
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.txt +0 -311
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.txt +0 -313
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.txt +0 -308
- package/proof/TARGET-V044-CONTAINED-PASS.sha256 +0 -1
- package/proof/TARGET-V044-CONTAINED-PASS.txt +0 -432
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.sha256 +0 -1
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.txt +0 -481
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.sha256 +0 -1
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.txt +0 -610
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.sha256 +0 -1
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.txt +0 -642
- package/proof/TARGET-V050-BATCH-GATE-PASS.sha256 +0 -1
- package/proof/TARGET-V050-BATCH-GATE-PASS.txt +0 -713
- package/proof/TESTS.txt +0 -686
- package/proof/TRUST-EPHEMERAL.txt +0 -4
- package/proof/V03-FREEZE.txt +0 -27
- package/proof/V041-IPC-HOTFIX.txt +0 -16
- package/proof/V042-ENV-HOTFIX.txt +0 -15
- package/proof/V043-DRIVE-CWD-HOTFIX.txt +0 -14
- package/proof/V044-LOCALAPPDATA-HOTFIX.txt +0 -18
- package/proof/V045-OPERATION-REGISTRY.txt +0 -7
- package/proof/V046-WORKER-REGISTRY.txt +0 -12
- package/proof/V047-WORKER-MANIFEST.txt +0 -18
- package/proof/V050-BATCH-TRUST-CLOSURE.txt +0 -21
- package/proof/V060-ACTIVE-NETWORK-AUTHORITY.txt +0 -29
- package/proof/V070-NODE-SYNTAX.txt +0 -36
- package/proof/V070-NODE-TESTS.txt +0 -752
- package/proof/V070-PACK-DRY-RUN.txt +0 -126
- package/proof/V070-SOURCE-GATE.txt +0 -30
- package/proof/V070-STATIC-SCAN.txt +0 -4
- package/proof/V070-WINDOWS-GATE-PENDING.txt +0 -25
- package/proof/V071-NODE-SYNTAX.txt +0 -1
- package/proof/V071-NODE-TESTS.txt +0 -796
- package/proof/V071-PACK-DRY-RUN.json +0 -656
- package/proof/V071-SOURCE-GATE.txt +0 -16
- package/proof/V071-WINDOWS-GATE-PENDING.txt +0 -24
- package/proof/V073-NODE-SYNTAX.txt +0 -4
- package/proof/V073-SOURCE-GATE.txt +0 -21
- package/proof/V073-STATIC-SCAN.txt +0 -10
- package/proof/V073-WINDOWS-GATE-PENDING.txt +0 -5
- package/proof/VERIFY.txt +0 -7
- package/proof/WINDOWS-CONTAINED-STATUS.txt +0 -5
- package/proof/WINDOWS-CONTAINMENT-STATUS.txt +0 -3
- package/proof/commander-closure-20260927/CONTINUATION.json +0 -43
- package/proof/commander-closure-20260927/RESULT.json +0 -30
- package/proof/commander-closure-20260927/SEARCH-CONTINUATION.json +0 -30
- package/proof/commander-closure-20260927/XLS-REFERENCE-PROBE.json +0 -13
- package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +0 -122
- package/proof/r59-full-regression-current.json +0 -13
- package/proof/r59-full-regression-current.stderr.log +0 -0
- package/proof/r59-full-regression-current.stdout.log +0 -1268
package/src/tool-audit.mjs
CHANGED
|
@@ -116,11 +116,13 @@ function summarizeOutcome(result,error,durationMs){
|
|
|
116
116
|
const structured=result?.structuredContent;
|
|
117
117
|
const status=typeof structured?.status==='string'?structured.status:(result?.isError===true?'error':'ok');
|
|
118
118
|
const isError=result?.isError===true;
|
|
119
|
+
const unknownSideEffect=structured?.side_effect_state==='unknown'||structured?.result?.side_effect_state==='unknown';
|
|
119
120
|
const capability=structured?.result;
|
|
120
121
|
const snapshot=capability?.schema==='deadbyte.capability-manifest.v3'&&HEX64.test(String(capability.snapshot_id??''))&&
|
|
121
122
|
Number.isInteger(capability.state_epoch)&&capability.state_epoch>0
|
|
122
123
|
?{snapshot_id:capability.snapshot_id,state_epoch:capability.state_epoch}:{};
|
|
123
124
|
return {status:String(status).slice(0,128),is_error:isError,duration_ms:duration,receipt_sha256s:outcomeReceiptHashes(result),
|
|
125
|
+
...(unknownSideEffect?{side_effect_state:'unknown'}:{}),
|
|
124
126
|
...snapshot,
|
|
125
127
|
...(isError?{reason:resultOutcomeReason(result)}:{})};
|
|
126
128
|
}
|
package/src/version.mjs
CHANGED
|
@@ -53,7 +53,8 @@ async function createProviderHostFixture(){
|
|
|
53
53
|
planner:{backend:'openai_compatible',endpoint:`http://127.0.0.1:${planner.address().port}/v1/chat/completions`,model:'r34-host-test',max_tokens:2048,timeout_ms:30000,max_response_bytes:262144},
|
|
54
54
|
limits:{max_iterations:8,max_mutations:8,max_wall_ms:null,max_context_bytes:262144,max_diff_bytes:262144,max_files_per_diff:4},profiles:{}}));
|
|
55
55
|
const autonomousPolicy=await loadAutonomousPolicy(autonomousPath,codingPolicy);
|
|
56
|
-
await writeBoundStandingGrant('autonomous', autonomousPolicy.lease_file, {schema:'deadbyte.autonomous-grant.v2',policy_sha256:autonomousPolicy.policy_sha256,
|
|
56
|
+
await writeBoundStandingGrant('autonomous', autonomousPolicy.lease_file, {schema:'deadbyte.autonomous-grant.v2',policy_sha256:autonomousPolicy.policy_sha256,
|
|
57
|
+
coding_policy_sha256:codingPolicy.policy_sha256,
|
|
57
58
|
instance_nonce:nonce(),root_ids:['project'],granted_at_utc:new Date().toISOString()});
|
|
58
59
|
const codingRuntime=createCodingRuntime({policy:codingPolicy,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
|
|
59
60
|
const nativeDiffRuntime=createNativeDiffRuntime({policy:autonomousPolicy,codingRuntime,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
|
|
@@ -2,10 +2,26 @@ import test from 'node:test';
|
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import {
|
|
4
4
|
autonomousGoalApproveOutputSchema, autonomousGoalRunOutputSchema, autonomousGoalStatusOutputSchema,
|
|
5
|
-
autonomousGoalVerifyOutputSchema,
|
|
5
|
+
autonomousGoalVerifyOutputSchema, nativeDiffPreviewOutputSchema,
|
|
6
6
|
autonomousStructuredResult
|
|
7
7
|
} from '../src/autonomous-output-contracts.mjs';
|
|
8
8
|
|
|
9
|
+
test('R71 preview-only MCP output cannot masquerade as a signed ready-to-apply diff',()=>{
|
|
10
|
+
const base={root_id:'preview',operation_count:1,payload_bytes:0,paths:['a.txt'],
|
|
11
|
+
operations:[{kind:'delete',path:'a.txt',expected_sha256:'a'.repeat(64)}]};
|
|
12
|
+
const unsigned=autonomousStructuredResult(nativeDiffPreviewOutputSchema,{
|
|
13
|
+
status:'preview_only',schema:'deadbyte.native-diff.v1',...base
|
|
14
|
+
});
|
|
15
|
+
assert.equal(unsigned.structuredContent.status,'preview_only');
|
|
16
|
+
assert.equal(unsigned.structuredContent.diff_id,undefined);
|
|
17
|
+
assert.throws(()=>autonomousStructuredResult(nativeDiffPreviewOutputSchema,{
|
|
18
|
+
status:'preview_only',diff_id:'b'.repeat(64),...base
|
|
19
|
+
}),/autonomous output contract violation/);
|
|
20
|
+
assert.throws(()=>autonomousStructuredResult(nativeDiffPreviewOutputSchema,{
|
|
21
|
+
status:'ready',...base
|
|
22
|
+
}),/autonomous output contract violation/);
|
|
23
|
+
});
|
|
24
|
+
|
|
9
25
|
test('autonomous_goal_verify structured contract preserves delegated action evidence count', () => {
|
|
10
26
|
const value = {
|
|
11
27
|
ok:true,
|
|
@@ -73,7 +73,8 @@ async function startPlanner() {
|
|
|
73
73
|
}));
|
|
74
74
|
const autonomousSha = sha(await readFile(autonomousPath));
|
|
75
75
|
await writeBoundStandingGrant('autonomous', path.join(root, 'runtime', 'autonomous-grant.json'), {
|
|
76
|
-
schema:'deadbyte.autonomous-grant.v2', policy_sha256:autonomousSha,
|
|
76
|
+
schema:'deadbyte.autonomous-grant.v2', policy_sha256:autonomousSha,
|
|
77
|
+
coding_policy_sha256:codingSha,
|
|
77
78
|
instance_nonce:nonce(), root_ids:['project'], granted_at_utc:new Date().toISOString()
|
|
78
79
|
});
|
|
79
80
|
const client = new Client({ name:'deadbyte-supervisor-integration', version:'0.8.0' },
|
|
@@ -37,6 +37,10 @@ test('R59 live plane state can only reduce signed capability availability', asyn
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
test('deriveCapabilityRequirements maps dependencies accurately', () => {
|
|
40
|
+
const preview=R36_CAPABILITY_LEDGER.entries.find(item=>item.id==='native_diff.preview');
|
|
41
|
+
assert.equal(preview.authority,'coding');
|
|
42
|
+
assert.equal(preview.mutating,false);
|
|
43
|
+
assert.deepEqual(deriveCapabilityRequirements(preview),['DEADBYTE_AUTONOMOUS_RUNTIME','coding_session.armed']);
|
|
40
44
|
const reqCodingRead = deriveCapabilityRequirements({
|
|
41
45
|
id: 'coding.search',
|
|
42
46
|
authority: 'coding',
|
|
@@ -61,6 +65,19 @@ test('deriveCapabilityRequirements maps dependencies accurately', () => {
|
|
|
61
65
|
assert.deepEqual(reqSkill, ['skill_plane.valid']);
|
|
62
66
|
});
|
|
63
67
|
|
|
68
|
+
test('Native Diff preview is available under Coding read while apply remains Autonomous denied',async()=>{
|
|
69
|
+
const preview=R36_CAPABILITY_LEDGER.entries.find(item=>item.id==='native_diff.preview');
|
|
70
|
+
const apply=R36_CAPABILITY_LEDGER.entries.find(item=>item.id==='native_diff.apply');
|
|
71
|
+
const result=await resolveCapabilityStates({ledger:{entries:[preview,apply]},
|
|
72
|
+
toolCatalog:['native_diff_preview','native_diff_apply'],profile:'full',
|
|
73
|
+
env:{DEADBYTE_AUTONOMOUS_RUNTIME:'1'},
|
|
74
|
+
codingRuntime:{sessionStatus:async()=>({armed:true,root_ids:['project']})},
|
|
75
|
+
autonomousRuntime:{sessionStatus:async()=>({armed:false,reason:'disarmed'})}});
|
|
76
|
+
const byId=id=>result.capabilities.find(item=>item.id===id);
|
|
77
|
+
assert.equal(byId('native_diff.preview').state,CAPABILITY_STATES.AVAILABLE);
|
|
78
|
+
assert.equal(byId('native_diff.apply').state,CAPABILITY_STATES.DENIED);
|
|
79
|
+
});
|
|
80
|
+
|
|
64
81
|
test('resolveCapabilityStates resolves all 5 states correctly', async () => {
|
|
65
82
|
const allCompactTools = [
|
|
66
83
|
'capability_manifest',
|
|
@@ -38,7 +38,7 @@ async function fixture(){
|
|
|
38
38
|
const policy=await loadAutonomousPolicy(autonomousPath,codingPolicy);
|
|
39
39
|
await writeBoundStandingGrant('coding', codingPolicy.lease_file, {schema:'deadbyte.coding-grant.v2',policy_sha256:codingPolicy.policy_sha256,
|
|
40
40
|
instance_nonce:nonce(),root_ids:['project'],armed_at_utc:new Date().toISOString()});
|
|
41
|
-
await writeBoundStandingGrant('autonomous', policy.lease_file, {schema:'deadbyte.autonomous-grant.v2',policy_sha256:policy.policy_sha256,
|
|
41
|
+
await writeBoundStandingGrant('autonomous', policy.lease_file, {schema:'deadbyte.autonomous-grant.v2',policy_sha256:policy.policy_sha256,coding_policy_sha256:codingPolicy.policy_sha256,
|
|
42
42
|
instance_nonce:nonce(),root_ids:['project'],armed_at_utc:new Date().toISOString()});
|
|
43
43
|
const codingRuntime=createCodingRuntime({policy:codingPolicy,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
|
|
44
44
|
const nativeDiffRuntime=createNativeDiffRuntime({policy,codingRuntime,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
|
|
@@ -32,3 +32,45 @@ test('native source rejects a Commander package dependency', () => {
|
|
|
32
32
|
assertNoCommanderDependency("import x from './machine-fs.mjs';");
|
|
33
33
|
assert.throws(()=>assertNoCommanderDependency("import x from '@wonderwhy-er/desktop-commander';"),/must not depend/);
|
|
34
34
|
});
|
|
35
|
+
|
|
36
|
+
test('host_exec script, inline, and native have independent required fields', () => {
|
|
37
|
+
const sha='a'.repeat(64);
|
|
38
|
+
const script={root_id:'core',command_id:'powershell_script',script_path:'scripts/check.ps1',script_sha256:sha};
|
|
39
|
+
const inline={mode:'inline',root_id:'core',command_id:'powershell_inline',command:'Write-Output ok'};
|
|
40
|
+
const native={mode:'native',root_id:'core',executable:'C:\\Windows\\System32\\whoami.exe',executable_sha256:sha};
|
|
41
|
+
for(const args of [script,inline,native]){
|
|
42
|
+
const validated=validateCommanderRequest('host_exec',args);
|
|
43
|
+
assert.equal(validated.native_tool,'host.exec');
|
|
44
|
+
assert.deepEqual(validated.args,args);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('compat adapter routes only validated host_exec modes to the native operation', async () => {
|
|
49
|
+
const calls=[];
|
|
50
|
+
const rt=createCommanderCompatibilityRuntime({
|
|
51
|
+
invoke:async(native,args)=>{calls.push({native,args});return {status:'passed',mode:args.mode};}
|
|
52
|
+
});
|
|
53
|
+
const inline={mode:'inline',root_id:'core',command_id:'powershell_inline',command:'Write-Output ok'};
|
|
54
|
+
const result=await rt.call('host_exec',inline);
|
|
55
|
+
assert.equal(result.status,'ok');
|
|
56
|
+
assert.equal(calls.length,1);
|
|
57
|
+
assert.deepEqual(calls[0],{native:'host.exec',args:inline});
|
|
58
|
+
await assert.rejects(()=>rt.call('host_exec',{...inline,script_path:'stray.ps1'}),/unexpected fields/);
|
|
59
|
+
assert.equal(calls.length,1,'rejected requests must never reach native invoke');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('host_exec rejects cross-mode parameters and malformed authority inputs', () => {
|
|
63
|
+
const sha='a'.repeat(64);
|
|
64
|
+
const inline={mode:'inline',root_id:'core',command_id:'powershell_inline',command:'Write-Output ok'};
|
|
65
|
+
const native={mode:'native',root_id:'core',executable:'C:\\Windows\\System32\\whoami.exe',executable_sha256:sha};
|
|
66
|
+
const reject=args=>assert.throws(()=>validateCommanderRequest('host_exec',args));
|
|
67
|
+
reject({...inline,script_sha256:sha});
|
|
68
|
+
reject({...native,command_id:'powershell_inline'});
|
|
69
|
+
reject({...native,executable_sha256:'bad'});
|
|
70
|
+
reject({...inline,command:'a'+String.fromCharCode(0)+'b'});
|
|
71
|
+
reject({...inline,command:''});
|
|
72
|
+
reject({mode:'inline',root_id:'core',command_id:'powershell_inline'});
|
|
73
|
+
reject({mode:'native',root_id:'core',executable:'x.exe'});
|
|
74
|
+
reject({mode:'superuser',root_id:'core',command:'x'});
|
|
75
|
+
reject({root_id:'core',command_id:'powershell_script',script_path:'scripts/check.ps1',script_sha256:'bad'});
|
|
76
|
+
});
|
|
@@ -26,6 +26,7 @@ test('R59 controller refuses to arm process or coding policy with a missing root
|
|
|
26
26
|
const source=await readFile(controllerPath,'utf8');
|
|
27
27
|
const blocks=[functionBlock(source,'Assert-PolicyRootsAvailable','Get-HostPolicyMetadata'),
|
|
28
28
|
functionBlock(source,'Get-ProcessPolicyMetadata','Get-ProcessGrantStatus'),
|
|
29
|
+
functionBlock(source,'Read-ControllerPolicySnapshot','Get-CodingPolicyMetadata'),
|
|
29
30
|
functionBlock(source,'Get-CodingPolicyMetadata','Get-CodingLeaseStatus')].join('\n');
|
|
30
31
|
const script=`$ErrorActionPreference='Stop';$RuntimeDir=${quote(runtime)};function Fail([string]$m){throw $m};function Get-ExecutableHash($p){return '${'a'.repeat(64)}'};${blocks};`+
|
|
31
32
|
`$errors=@();foreach($case in @(@{kind='process';cfg=@{ProcessPolicyFile=${quote(processPolicy)}}},@{kind='coding';cfg=@{CodingPolicyFile=${quote(coding)}}})){try{if($case.kind -eq 'process'){Get-ProcessPolicyMetadata $case.cfg|Out-Null}else{Get-CodingPolicyMetadata $case.cfg|Out-Null};throw 'unexpected pass'}catch{$errors+=$_.Exception.Message}};$errors|ConvertTo-Json -Compress`;
|
|
@@ -18,9 +18,9 @@ async function fixture(){
|
|
|
18
18
|
await mkdir(project); await mkdir(trust);
|
|
19
19
|
const keys=await generateTrustKeypair({privateKeyPath:path.join(trust,'private.pem'),publicKeyPath:path.join(trust,'public.pem')});
|
|
20
20
|
const codingPath=path.join(root,'coding-policy.json');
|
|
21
|
-
await writeFile(codingPath,JSON.stringify({schema:'deadbyte.coding-policy.v1',enabled:true,lease_file:path.join(root,'coding-lease.json'),evidence_dir:path.join(root,'coding-evidence'),roots:{project:{path:project,read:true,write:true,exec:false,deny_paths:[]}},commands:{},max_read_bytes:524288,max_write_bytes:2097152}));
|
|
21
|
+
await writeFile(codingPath,JSON.stringify({schema:'deadbyte.coding-policy.v1',enabled:true,lease_file:path.join(root,'coding-lease.json'),evidence_dir:path.join(root,'coding-evidence'),roots:{project:{path:project,read:true,write:true,exec:false,deny_paths:[]},preview:{path:project,read:true,write:false,exec:false,deny_paths:[]}},commands:{},max_read_bytes:524288,max_write_bytes:2097152}));
|
|
22
22
|
const codingPolicy=await loadCodingPolicy(codingPath);
|
|
23
|
-
await writeFile(codingPolicy.lease_file,JSON.stringify({schema:'deadbyte.coding-lease.v1',policy_sha256:codingPolicy.policy_sha256,instance_nonce:randomBytes(32).toString('hex'),root_ids:['project'],armed_at_utc:new Date().toISOString(),expires_at_utc:new Date(Date.now()+3600000).toISOString()}));
|
|
23
|
+
await writeFile(codingPolicy.lease_file,JSON.stringify({schema:'deadbyte.coding-lease.v1',policy_sha256:codingPolicy.policy_sha256,instance_nonce:randomBytes(32).toString('hex'),root_ids:['project','preview'],armed_at_utc:new Date().toISOString(),expires_at_utc:new Date(Date.now()+3600000).toISOString()}));
|
|
24
24
|
const autoPath=path.join(root,'autonomous-policy.json');
|
|
25
25
|
await writeFile(autoPath,JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,lease_file:path.join(root,'auto-lease.json'),evidence_dir:path.join(root,'auto-evidence'),root_ids:['project'],coding_policy_sha256:codingPolicy.policy_sha256,planner:{backend:'client_sampling',max_tokens:2048},profiles:{},limits:{max_files_per_diff:12,max_diff_bytes:1048576}}));
|
|
26
26
|
const policy=await loadAutonomousPolicy(autoPath,codingPolicy);
|
|
@@ -31,6 +31,39 @@ async function fixture(){
|
|
|
31
31
|
return {root,project,keys,policy,codingRuntime,machineFsRuntime,nativeDiff};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
test('R71 Native Diff V2 Coding-only topology preview is non-applicable',async()=>{
|
|
35
|
+
const f=await fixture();
|
|
36
|
+
try{
|
|
37
|
+
const preview=await f.nativeDiff.preview({rootId:'preview',title:'read-only topology',operations:[
|
|
38
|
+
{kind:'mkdir',path:'candidate/newdir'}
|
|
39
|
+
]});
|
|
40
|
+
assert.equal(preview.status,'preview_only');
|
|
41
|
+
assert.equal(preview.schema,NATIVE_DIFF_V2_SCHEMA);
|
|
42
|
+
assert.equal(preview.diff_id,undefined);
|
|
43
|
+
assert.equal(preview.root_id,'preview');
|
|
44
|
+
assert.equal(preview.operation_count,1);
|
|
45
|
+
assert.equal(await exists(path.join(f.project,'candidate')),false);
|
|
46
|
+
assert.equal(await exists(path.join(f.policy.evidence_dir,'native-diffs')),false);
|
|
47
|
+
await assert.rejects(f.nativeDiff.apply({diffId:'0'.repeat(64)}));
|
|
48
|
+
await rm(f.codingRuntime.policy.lease_file);
|
|
49
|
+
await assert.rejects(f.nativeDiff.preview({rootId:'preview',operations:[
|
|
50
|
+
{kind:'mkdir',path:'after-revoke'}
|
|
51
|
+
]}),/coding plane is disarmed/);
|
|
52
|
+
}finally{await rm(f.root,{recursive:true,force:true});}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('V2 topology preview on an Autonomous root remains non-applicable after Autonomous revocation',async()=>{
|
|
56
|
+
const f=await fixture();
|
|
57
|
+
try{
|
|
58
|
+
await rm(f.policy.lease_file);
|
|
59
|
+
const preview=await f.nativeDiff.preview({rootId:'project',operations:[{kind:'mkdir',path:'still-read-only'}]});
|
|
60
|
+
assert.equal(preview.status,'preview_only');
|
|
61
|
+
assert.equal(preview.diff_id,undefined);
|
|
62
|
+
assert.equal(await exists(path.join(f.project,'still-read-only')),false);
|
|
63
|
+
assert.equal(await exists(path.join(f.policy.evidence_dir,'native-diffs')),false);
|
|
64
|
+
}finally{await rm(f.root,{recursive:true,force:true});}
|
|
65
|
+
});
|
|
66
|
+
|
|
34
67
|
test('R36 Native Diff V2 commits mkdir write move and independently verifies mixed receipts',async()=>{
|
|
35
68
|
const f=await fixture(); try{
|
|
36
69
|
await writeFile(path.join(f.project,'seed.txt'),'seed\n');
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { createHash, randomBytes } from 'node:crypto';
|
|
4
|
-
import { access, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { access, mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises';
|
|
5
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import { generateTrustKeypair } from '../src/trust.mjs';
|
|
8
8
|
import { createCodingRuntime, loadCodingPolicy } from '../src/coding-plane.mjs';
|
|
9
9
|
import { loadAutonomousPolicy } from '../src/autonomous-policy.mjs';
|
|
10
10
|
import { createNativeDiffRuntime } from '../src/native-diff.mjs';
|
|
11
|
+
import { registerAutonomousTools } from '../src/autonomous-mcp-tools.mjs';
|
|
11
12
|
|
|
12
13
|
const sha = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
13
14
|
const exists = file => access(file).then(() => true, () => false);
|
|
@@ -19,10 +20,11 @@ async function fixture() {
|
|
|
19
20
|
const codingPolicyPath = path.join(root, 'coding-policy.json');
|
|
20
21
|
await writeFile(codingPolicyPath, JSON.stringify({ schema:'deadbyte.coding-policy.v1', enabled:true,
|
|
21
22
|
lease_file:path.join(root,'coding-lease.json'), evidence_dir:path.join(root,'coding-evidence'),
|
|
22
|
-
roots:{ project:{ path:project, read:true, write:true, exec:true, deny_paths:[] }
|
|
23
|
+
roots:{ project:{ path:project, read:true, write:true, exec:true, deny_paths:[] },
|
|
24
|
+
preview:{ path:project, read:true, write:false, exec:false, deny_paths:[] } }, commands:{} }, null, 2));
|
|
23
25
|
const codingPolicy = await loadCodingPolicy(codingPolicyPath);
|
|
24
26
|
await writeFile(codingPolicy.lease_file, JSON.stringify({ schema:'deadbyte.coding-lease.v1', policy_sha256:codingPolicy.policy_sha256,
|
|
25
|
-
instance_nonce:randomBytes(32).toString('hex'), root_ids:['project'], armed_at_utc:new Date().toISOString(),
|
|
27
|
+
instance_nonce:randomBytes(32).toString('hex'), root_ids:['project','preview'], armed_at_utc:new Date().toISOString(),
|
|
26
28
|
expires_at_utc:new Date(Date.now()+3600000).toISOString() }));
|
|
27
29
|
const autonomousPolicyPath = path.join(root, 'autonomous-policy.json');
|
|
28
30
|
await writeFile(autonomousPolicyPath, JSON.stringify({ schema:'deadbyte.autonomous-policy.v1', enabled:true,
|
|
@@ -38,6 +40,84 @@ async function fixture() {
|
|
|
38
40
|
return { root, project, keys, policy, codingRuntime, nativeDiff };
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
test('R71 Coding-only native_diff_preview does not create an applicable signed diff',async()=>{
|
|
44
|
+
const f=await fixture();
|
|
45
|
+
try{
|
|
46
|
+
const file=path.join(f.project,'only-preview.txt');
|
|
47
|
+
await writeFile(file,'original text\n');
|
|
48
|
+
const before=sha(await readFile(file));
|
|
49
|
+
const preview=await f.nativeDiff.preview({rootId:'preview',title:'read-only project preview',operations:[
|
|
50
|
+
{kind:'replace',path:'only-preview.txt',expected_sha256:before,old_string:'original',new_string:'updated',expected_replacements:1}
|
|
51
|
+
]});
|
|
52
|
+
assert.equal(preview.status,'preview_only');
|
|
53
|
+
assert.equal(preview.diff_id,undefined);
|
|
54
|
+
assert.equal(preview.root_id,'preview');
|
|
55
|
+
assert.equal(preview.operation_count,1);
|
|
56
|
+
assert.equal((await readFile(file,'utf8')),'original text\n');
|
|
57
|
+
assert.equal(await exists(path.join(f.policy.evidence_dir,'native-diffs')),false);
|
|
58
|
+
await assert.rejects(f.nativeDiff.apply({diffId:'0'.repeat(64)}));
|
|
59
|
+
await assert.rejects(f.nativeDiff.preview({rootId:'ungranted',operations:[
|
|
60
|
+
{kind:'write',path:'not-allowed.txt',content:'abc',expected_sha256:'absent'}
|
|
61
|
+
]}),/not allowed|disarmed|denied|root/);
|
|
62
|
+
await rm(f.codingRuntime.policy.lease_file);
|
|
63
|
+
await assert.rejects(f.nativeDiff.preview({rootId:'preview',operations:[
|
|
64
|
+
{kind:'replace',path:'only-preview.txt',expected_sha256:before,old_string:'original',new_string:'updated'}
|
|
65
|
+
]}),/coding plane is disarmed/);
|
|
66
|
+
}finally{await rm(f.root,{recursive:true,force:true});}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('MCP preview on an Autonomous-policy root remains read-only with only Coding authority',async()=>{
|
|
70
|
+
const f=await fixture();
|
|
71
|
+
try{
|
|
72
|
+
const file=path.join(f.project,'mcp-preview.txt');
|
|
73
|
+
await writeFile(file,'old\n');
|
|
74
|
+
const before=sha(await readFile(file));
|
|
75
|
+
await rm(f.policy.lease_file);
|
|
76
|
+
const handlers=new Map();
|
|
77
|
+
const contracts=new Map();
|
|
78
|
+
registerAutonomousTools({registerTool:(name,contract,handler)=>{handlers.set(name,handler);contracts.set(name,contract);}},
|
|
79
|
+
{autonomousRuntime:{},nativeDiffRuntime:f.nativeDiff});
|
|
80
|
+
assert.match(contracts.get('native_diff_preview').description,/Coding read authority/i);
|
|
81
|
+
assert.match(contracts.get('native_diff_preview').description,/preview.only/i);
|
|
82
|
+
const response=await handlers.get('native_diff_preview')({root_id:'project',title:'read only',operations:[
|
|
83
|
+
{kind:'replace',path:'mcp-preview.txt',expected_sha256:before,old_string:'old',new_string:'new',expected_replacements:1}
|
|
84
|
+
]});
|
|
85
|
+
assert.equal(response.isError,false);
|
|
86
|
+
assert.equal(response.structuredContent.status,'preview_only');
|
|
87
|
+
assert.equal(response.structuredContent.diff_id,undefined);
|
|
88
|
+
assert.equal(sha(await readFile(file)),before);
|
|
89
|
+
assert.equal(await exists(path.join(f.policy.evidence_dir,'native-diffs')),false);
|
|
90
|
+
}finally{await rm(f.root,{recursive:true,force:true});}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('Coding-only preview denies escaped, reparse, and expired authority without changing targets',async()=>{
|
|
94
|
+
const f=await fixture();
|
|
95
|
+
try{
|
|
96
|
+
await rm(f.policy.lease_file);
|
|
97
|
+
const outside=path.join(f.root,'outside.txt');
|
|
98
|
+
await writeFile(outside,'outside\n');
|
|
99
|
+
const outsideSha=sha(await readFile(outside));
|
|
100
|
+
await assert.rejects(f.nativeDiff.preview({rootId:'project',operations:[
|
|
101
|
+
{kind:'replace',path:'../outside.txt',expected_sha256:outsideSha,old_string:'outside',new_string:'changed'}
|
|
102
|
+
]}),/path|escape|outside|relative/i);
|
|
103
|
+
const link=path.join(f.project,'linked');
|
|
104
|
+
const target=path.join(f.root,'external');
|
|
105
|
+
await mkdir(target);
|
|
106
|
+
await writeFile(path.join(target,'target.txt'),'outside\n');
|
|
107
|
+
await symlink(target,link,process.platform==='win32'?'junction':'dir');
|
|
108
|
+
await assert.rejects(f.nativeDiff.preview({rootId:'project',operations:[
|
|
109
|
+
{kind:'replace',path:'linked/target.txt',expected_sha256:outsideSha,old_string:'outside',new_string:'changed'}
|
|
110
|
+
]}),/reparse|symlink|path|outside|root/i);
|
|
111
|
+
const lease=JSON.parse(await readFile(f.codingRuntime.policy.lease_file,'utf8'));
|
|
112
|
+
await writeFile(f.codingRuntime.policy.lease_file,JSON.stringify({...lease,expires_at_utc:new Date(Date.now()-1000).toISOString()}));
|
|
113
|
+
await assert.rejects(f.nativeDiff.preview({rootId:'project',operations:[
|
|
114
|
+
{kind:'write',path:'new.txt',content:'new',expected_sha256:'absent'}
|
|
115
|
+
]}),/coding plane is disarmed: expired/);
|
|
116
|
+
assert.equal(sha(await readFile(outside)),outsideSha);
|
|
117
|
+
assert.equal(sha(await readFile(path.join(target,'target.txt'))),outsideSha);
|
|
118
|
+
}finally{await rm(f.root,{recursive:true,force:true});}
|
|
119
|
+
});
|
|
120
|
+
|
|
41
121
|
test('native diff commits exact preconditioned edits and independently verifies coding receipts', async () => {
|
|
42
122
|
const f = await fixture();
|
|
43
123
|
try {
|
|
@@ -71,7 +71,7 @@ async function captureCurrentSurface(){
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
test('
|
|
74
|
+
test('R71 compact baseline permits only R64 read offset and authorized coding-only preview output',async()=>{
|
|
75
75
|
const raw=JSON.parse(await readFile(fixturePath,'utf8'));
|
|
76
76
|
assert.equal(raw.schema,'deadbyte.tool-surface-baseline.v1');
|
|
77
77
|
assert.equal(raw.release_id,'v0.15.35-1b5715b276facbc0');
|
|
@@ -83,13 +83,17 @@ test('R59 compact baseline changes only at the explicitly authorized R64 read-of
|
|
|
83
83
|
assert.deepEqual(diff.added,[]);
|
|
84
84
|
assert.deepEqual(diff.removed,[]);
|
|
85
85
|
const packageVersion=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8')).version;
|
|
86
|
-
if(['0.15.41','0.15.42','0.15.43','0.15.44'].includes(packageVersion)){
|
|
87
|
-
assert.deepEqual(diff.schema_changed,['machine_fs']);
|
|
88
|
-
assert.equal(diff.unchanged.length,
|
|
86
|
+
if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45'].includes(packageVersion)){
|
|
87
|
+
assert.deepEqual([...diff.schema_changed].sort(),['machine_fs','native_diff_preview']);
|
|
88
|
+
assert.equal(diff.unchanged.length,41);
|
|
89
89
|
const prior=baseline.tools.find(tool=>tool.name==='machine_fs');
|
|
90
90
|
const present=current.tools.find(tool=>tool.name==='machine_fs');
|
|
91
|
-
assert.equal(present.output_sha256,prior.output_sha256,'output contract must remain unchanged');
|
|
91
|
+
assert.equal(present.output_sha256,prior.output_sha256,'machine_fs output contract must remain unchanged');
|
|
92
92
|
assert.notEqual(present.input_sha256,prior.input_sha256,'R64 must expose the widened read offset');
|
|
93
|
+
const previewBefore=baseline.tools.find(tool=>tool.name==='native_diff_preview');
|
|
94
|
+
const previewAfter=current.tools.find(tool=>tool.name==='native_diff_preview');
|
|
95
|
+
assert.equal(previewAfter.input_sha256,previewBefore.input_sha256,'preview-only must not change input permissions or tool selection');
|
|
96
|
+
assert.notEqual(previewAfter.output_sha256,previewBefore.output_sha256,'preview-only output must be declared in MCP schema');
|
|
93
97
|
}else{
|
|
94
98
|
assert.deepEqual(diff.schema_changed,[]);
|
|
95
99
|
assert.equal(diff.unchanged.length,43);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import {mkdtemp,mkdir,rm,writeFile,readFile} from 'node:fs/promises';
|
|
4
|
-
import {createHash} from 'node:crypto';
|
|
4
|
+
import {createHash,generateKeyPairSync} from 'node:crypto';
|
|
5
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import {loadCodingPolicy,codingSessionStatus} from '../src/coding-plane.mjs';
|
|
@@ -37,6 +37,14 @@ test('R65 standing Coding grant is disarmed until the durable epoch binds the ex
|
|
|
37
37
|
assert.equal(trusted.armed,true);
|
|
38
38
|
assert.equal(trusted.reason,'standing-grant');
|
|
39
39
|
assert.equal(trusted.instance_nonce,grant.instance_nonce);
|
|
40
|
+
const publicPath=path.join(root,'trust','ed25519-public.pem');
|
|
41
|
+
const originalPublic=await readFile(publicPath);
|
|
42
|
+
const rotated=generateKeyPairSync('ed25519').publicKey.export({format:'pem',type:'spki'});
|
|
43
|
+
await writeFile(publicPath,rotated);
|
|
44
|
+
const denied=await codingSessionStatus(policy);
|
|
45
|
+
assert.equal(denied.armed,false,'changed trust bytes must not reuse the cached parsed key');
|
|
46
|
+
await writeFile(publicPath,originalPublic);
|
|
47
|
+
assert.equal((await codingSessionStatus(policy)).armed,true);
|
|
40
48
|
}finally{
|
|
41
49
|
await rm(root,{recursive:true,force:true});
|
|
42
50
|
}
|
|
@@ -22,7 +22,8 @@ async function generation(state,label){
|
|
|
22
22
|
return {root,manifest_sha256:sha(manifest),config_path:path.join(root,'controller-config.psd1')};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
const historicalR67=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8')).version==='0.15.44';
|
|
26
|
+
test('R67 isolated immutable slot activates, rolls back exact R66, and restores the same R67 bytes with no authority',{skip:historicalR67?false:'Historical R67 regression applies only to package version 0.15.44; R71 test is separate'},async()=>{
|
|
26
27
|
const base=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r67-slot-parity-'));
|
|
27
28
|
const state=path.join(base,'state');
|
|
28
29
|
try{
|
|
@@ -3,10 +3,12 @@ import assert from 'node:assert/strict';
|
|
|
3
3
|
import {readFile} from 'node:fs/promises';
|
|
4
4
|
import {fileURLToPath} from 'node:url';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
6
7
|
import {assertR67NpmPublishReady} from '../scripts/npm-release-readiness-r67.mjs';
|
|
7
8
|
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
8
|
-
test('
|
|
9
|
-
const
|
|
9
|
+
test('sealed R67 predecessor retains its exact npm publish-readiness metadata gate',async()=>{
|
|
10
|
+
const sealed=path.join(os.homedir(),'.deadbyte-mcp','releases','v0.15.44-9f500af433df3e77');
|
|
11
|
+
const release=JSON.parse(await readFile(path.join(sealed,'RELEASE.json'),'utf8'));
|
|
10
12
|
assert.equal(release.r67_native_observation.status,'CANDIDATE_SEALED');
|
|
11
13
|
assert.doesNotThrow(()=>assertR67NpmPublishReady(release));
|
|
12
14
|
});
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import {readFile} from 'node:fs/promises';
|
|
4
|
-
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
const sealedRoot=path.join(os.homedir(),'.deadbyte-mcp','releases','v0.15.44-9f500af433df3e77');
|
|
7
|
+
const get=async rel=>JSON.parse(await readFile(path.join(sealedRoot,rel),'utf8'));
|
|
5
8
|
const parent={
|
|
6
9
|
release_id:'v0.15.43-4c4a64a4c8e9f5a6',
|
|
7
10
|
manifest_sha256:'4c4a64a4c8e9f5a6e9eecce85fd0007ebcac99121b29c07f1a1fc81d1643cd33',
|
|
8
11
|
generation_manifest_sha256:'ef3b041e2a87c2e143d4733a98a52d9db80cd16ad7007e112fcb5202e70c77c3'
|
|
9
12
|
};
|
|
10
|
-
test('R67 release version,
|
|
11
|
-
const [pkg,
|
|
12
|
-
get('package.json'),get('
|
|
13
|
+
test('sealed R67 predecessor preserves its release version, lineage and prepublish evidence',async()=>{
|
|
14
|
+
const [pkg,bridge,release,prov,matrix,sbom,version]=await Promise.all([
|
|
15
|
+
get('package.json'),get('bridge/package.json'),
|
|
13
16
|
get('RELEASE.json'),get('PROVENANCE.json'),get('TEST-MATRIX.json'),get('SBOM.cdx.json'),
|
|
14
|
-
readFile(
|
|
17
|
+
readFile(path.join(sealedRoot,'src','version.mjs'),'utf8')
|
|
15
18
|
]);
|
|
16
19
|
assert.equal(pkg.version,'0.15.44');
|
|
17
|
-
assert.equal(lock.version,pkg.version);
|
|
18
|
-
assert.equal(lock.packages[''].version,pkg.version);
|
|
19
20
|
assert.equal(bridge.version,pkg.version);
|
|
20
21
|
assert.match(version,/DEADBYTE_VERSION = '0\.15\.44'/);
|
|
21
22
|
assert.equal(release.version,pkg.version);
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import {readFile} from 'node:fs/promises';
|
|
5
|
+
import {classifyRemoteAuditOutcome,createLiveTimelineTracker,createLiveTimelineFilter,createLiveTimelineWriter,formatCompactAuditEvent} from '../src/remote-live-log.mjs';
|
|
6
|
+
|
|
7
|
+
function pair(status,is_error=false,side_effect_state=null){
|
|
8
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii',rootPaths:{local_d:'D:\\'}});
|
|
9
|
+
const args={root_id:'local_d',path:'TECHNICAL/ProgramingLangPJ/tmp/gfx_r3_dev/runtime/gfx/dbyte_gfx3d.dby'};
|
|
10
|
+
const start=tracker.observe({event_type:'tool.request',tool:'coding_file_write',request_id:'r69-example-1',args});
|
|
11
|
+
const done=tracker.observe({event_type:'tool.result',tool:'coding_file_write',request_id:'r69-example-1',
|
|
12
|
+
outcome:{status,is_error,side_effect_state,duration_ms:1}});
|
|
13
|
+
return {tracker,start,done};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
test('R69 failed, denied and observed_failure never produce a false SUCCEEDED line',()=>{
|
|
17
|
+
for(const status of ['failed','denied','rejected','blocked','observed_failure','cancelled']){
|
|
18
|
+
const {tracker,done}=pair(status);
|
|
19
|
+
assert.match(done,/ERR status=/,status);
|
|
20
|
+
assert.doesNotMatch(done,/SUCCEEDED|\bOK\b/,status);
|
|
21
|
+
assert.match(tracker.summary(),/0 ok \| 1 error/,status);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('R69 unavailable and unsupported result envelopes never print mutation SUCCEEDED',()=>{
|
|
26
|
+
for(const status of ['unavailable','unsupported']){
|
|
27
|
+
const {tracker,done}=pair(status);
|
|
28
|
+
assert.match(done,/ERR status=/,status);
|
|
29
|
+
assert.doesNotMatch(done,/SUCCEEDED/,status);
|
|
30
|
+
assert.match(tracker.summary(),/0 ok \| 1 error/,status);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('R69 pending tool result requires continuation, never implies effect committed',()=>{
|
|
35
|
+
for(const status of ['pending','running','input_required','paused','processing','accepted']){
|
|
36
|
+
const {tracker,done}=pair(status);
|
|
37
|
+
assert.match(done,/PENDING status=/,status);
|
|
38
|
+
assert.doesNotMatch(done,/SUCCEEDED|\bOK\b/,status);
|
|
39
|
+
assert.match(tracker.summary(),/0 ok \| 0 errors \| 0 unknown \| 1 pending/,status);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('R69 unknown side-effect outranks every status; no retry claim',()=>{
|
|
44
|
+
const {done,tracker}=pair('committed',false,'unknown');
|
|
45
|
+
assert.match(done,/FAILED_AFTER_UNKNOWN_EFFECT/);
|
|
46
|
+
assert.match(tracker.summary(),/1 unknown/);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('R69 human console always retains the operation location in terminal result',()=>{
|
|
50
|
+
const {start,done}=pair('denied');
|
|
51
|
+
const absolute='D:\\TECHNICAL\\ProgramingLangPJ\\tmp\\gfx_r3_dev\\runtime\\gfx\\dbyte_gfx3d.dby [root=local_d]';
|
|
52
|
+
assert.ok(start.includes(absolute));
|
|
53
|
+
assert.ok(done.includes(absolute));
|
|
54
|
+
assert.match(done,/ERR status=denied/);
|
|
55
|
+
assert.doesNotMatch(done,/SUCCEEDED/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('R69 compact audit flags status failure or pending even with is_error=false',()=>{
|
|
59
|
+
assert.match(formatCompactAuditEvent({event_type:'tool.result',tool:'host_exec',outcome:{is_error:false,status:'denied'}}),/ERR/);
|
|
60
|
+
assert.match(formatCompactAuditEvent({event_type:'tool.result',tool:'host_exec',outcome:{is_error:false,status:'input_required'}}),/PENDING/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('R69 TTY writer obeys runtime terminal resize without rewriting a wrapped start line',()=>{
|
|
64
|
+
const writes=[];
|
|
65
|
+
const stream={isTTY:true,columns:32,write(value){writes.push(value);return true;}};
|
|
66
|
+
const writer=createLiveTimelineWriter({stream,displayMode:'ascii'});
|
|
67
|
+
writer.write('START',{event_type:'tool.call',request_id:'resize'});
|
|
68
|
+
stream.columns=5;
|
|
69
|
+
writer.write('TOO LONG RESULT',{event_type:'tool.result',request_id:'resize'});
|
|
70
|
+
assert.deepEqual(writes,['START','\n','TOO LONG RESULT\n']);
|
|
71
|
+
assert.equal(writer.pending(),null);
|
|
72
|
+
stream.columns=80;
|
|
73
|
+
writer.write('RUN',{event_type:'tool.call',request_id:'wide'});
|
|
74
|
+
writer.write('OK',{event_type:'tool.result',request_id:'wide'});
|
|
75
|
+
assert.equal(writes.at(-1),'\r\x1b[2KOK\n');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
test('R69 live latency uses fractional milliseconds instead of printing a false 0ms',()=>{
|
|
80
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii'});
|
|
81
|
+
tracker.observe({event_type:'tool.request',tool:'machine_status',request_id:'subms'});
|
|
82
|
+
const done=tracker.observe({event_type:'tool.result',tool:'machine_status',request_id:'subms',
|
|
83
|
+
outcome:{is_error:false,duration_ms:0.125}});
|
|
84
|
+
assert.ok(done.includes('0.125ms'));
|
|
85
|
+
assert.doesNotMatch(done,/ 0ms /);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('R69 latency summary includes p99 and discloses bounded sample coverage',()=>{
|
|
89
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii'});
|
|
90
|
+
for(let i=1;i<=100;i++){
|
|
91
|
+
const id='sample-'+i;
|
|
92
|
+
tracker.observe({event_type:'tool.request',tool:'machine_status',request_id:id});
|
|
93
|
+
tracker.observe({event_type:'tool.result',tool:'machine_status',request_id:id,
|
|
94
|
+
outcome:{is_error:false,duration_ms:i}});
|
|
95
|
+
}
|
|
96
|
+
const summary=tracker.summary();
|
|
97
|
+
assert.ok(summary.includes('p50 51ms'));
|
|
98
|
+
assert.ok(summary.includes('p95 95ms'));
|
|
99
|
+
assert.ok(summary.includes('p99 99ms'));
|
|
100
|
+
assert.ok(summary.includes('sample 100/100'));
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('R69 filter matches status-only errors independent of is_error=false',()=>{
|
|
104
|
+
const filter=createLiveTimelineFilter('status=error');
|
|
105
|
+
filter.accept({event_type:'tool.request',tool:'host_exec',request_id:'r69-e',args:{}});
|
|
106
|
+
assert.equal(filter.accept({event_type:'tool.result',tool:'host_exec',request_id:'r69-e',outcome:{status:'denied',is_error:false}}),true);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('R69 mismatched terminal tool cannot inherit a mutating START or claim success',()=>{
|
|
110
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000,displayMode:'ascii'});
|
|
111
|
+
const start=tracker.observe({event_type:'tool.request',tool:'coding_file_write',request_id:'r69-mismatch',args:{root_id:'core',path:'scratch.txt'}});
|
|
112
|
+
assert.match(start,/START/);
|
|
113
|
+
const terminal=tracker.observe({event_type:'tool.result',tool:'machine_ping',request_id:'r69-mismatch',
|
|
114
|
+
outcome:{status:'ok',is_error:false,duration_ms:1,receipt_sha256s:['a'.repeat(64)]}});
|
|
115
|
+
assert.match(terminal,/CORRELATION_MISMATCH/);
|
|
116
|
+
assert.doesNotMatch(terminal,/SUCCEEDED|RECEIPT=/);
|
|
117
|
+
assert.match(tracker.summary(),/0 ok \| 0 errors \| 1 unknown/);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('R69 status filter cannot hide a mismatched terminal identity as successful',()=>{
|
|
121
|
+
const unknown=createLiveTimelineFilter('status=unknown');
|
|
122
|
+
unknown.accept({event_type:'tool.request',tool:'coding_file_write',request_id:'r69-filter-mismatch',args:{}});
|
|
123
|
+
assert.equal(unknown.accept({event_type:'tool.result',tool:'machine_ping',request_id:'r69-filter-mismatch',
|
|
124
|
+
outcome:{status:'ok',is_error:false}}),true);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('R69 remote replay projection does not record unavailable as ok or input_required as complete',async()=>{
|
|
128
|
+
const source=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
|
|
129
|
+
const start=source.indexOf('function auditTimelineRecord(');
|
|
130
|
+
const end=source.indexOf('async function replayRemoteResults(',start);
|
|
131
|
+
assert.ok(start>=0&&end>start);
|
|
132
|
+
const record=new Function('createHash','parseAuditLogLine','classifyRemoteAuditOutcome',`${source.slice(start,end)};return auditTimelineRecord;`)(createHash,()=>null,classifyRemoteAuditOutcome);
|
|
133
|
+
const base={event_type:'tool.result',request_id:'r69-projection',tool:'coding_file_write',ts:'2026-10-13T00:00:00.000Z'};
|
|
134
|
+
assert.equal(record('audit.log','bounded-line',{...base,outcome:{status:'unavailable',is_error:false}}).status,'error');
|
|
135
|
+
assert.equal(record('audit.log','bounded-line',{...base,outcome:{status:'input_required',is_error:false}}).status,'pending');
|
|
136
|
+
});
|
|
137
|
+
|