deadbyte-mcp 0.15.52 → 0.15.54

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.
Files changed (33) hide show
  1. package/MANIFEST.SHA256 +32 -25
  2. package/PROVENANCE.json +27 -8
  3. package/README.txt +18 -18
  4. package/RELEASE.json +33 -6
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +32 -2
  7. package/bridge/src/remote-call-claims-r60.mjs +5 -0
  8. package/controller/deadbyte-process-policy.json +4 -4
  9. package/package.json +1 -1
  10. package/scripts/deploy-r48.mjs +51 -5
  11. package/src/activation-preflight-r65.mjs +35 -5
  12. package/src/commander-remote-bridge-r47.mjs +20 -2
  13. package/src/commander-remote-relay-r47.mjs +13 -2
  14. package/src/deadbyte-cli.mjs +10 -2
  15. package/src/legacy-offline-policy-proof-r146.mjs +204 -0
  16. package/src/release-generation.mjs +20 -1
  17. package/src/remote-device-r44.mjs +1 -1
  18. package/src/remote-live-log.mjs +43 -7
  19. package/src/version.mjs +1 -1
  20. package/test/commander-remote-bridge-r47.test.mjs +20 -1
  21. package/test/commander-remote-plane-r47.test.mjs +11 -0
  22. package/test/r130-release-security-contract.test.mjs +8 -8
  23. package/test/r132-release-identity.test.mjs +9 -9
  24. package/test/r144-claim-terminal-history.test.mjs +55 -0
  25. package/test/r144-controller-broad-roots-cleanup.test.mjs +54 -0
  26. package/test/r146-generation-scope-narrowing.test.mjs +64 -0
  27. package/test/r146-legacy-offline-policy-proof.test.mjs +199 -0
  28. package/test/r146-livelog-backpressure.test.mjs +105 -0
  29. package/test/r147-remote-request-hash.test.mjs +54 -0
  30. package/test/r59-tool-surface-compat.test.mjs +1 -1
  31. package/test/r65-activation-orchestration.test.mjs +53 -0
  32. package/test/r74-prepublish-contract.test.mjs +2 -2
  33. package/test/release-generation.test.mjs +8 -1
@@ -0,0 +1,54 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {registerCommanderRemoteBridge} from '../src/commander-remote-bridge-r47.mjs';
5
+
6
+ function canonical(value) {
7
+ if(Array.isArray(value)) return value.map(canonical);
8
+ if(value&&typeof value==='object')
9
+ return Object.fromEntries(Object.keys(value).sort((a,b)=>a.localeCompare(b,'en')).map(key=>[key,canonical(value[key])]));
10
+ return value;
11
+ }
12
+ const hashRequest=v=>createHash('sha256').update(JSON.stringify(canonical(v)),'utf8').digest('hex');
13
+ function server(){
14
+ const tools=new Map();
15
+ return {tools,registerTool(name,meta,handler){tools.set(name,{meta,handler});}};
16
+ }
17
+ const id='a'.repeat(64),request='b'.repeat(64),epoch=4,cap='machine.status';
18
+ const payload={z:4,a:{inner:1}};
19
+ const digest=hashRequest({device_id:id,epoch,capability_id:cap,payload});
20
+
21
+ test('R147 native relay request_sha256 passes strict remote_mcp schema',()=>{
22
+ const app=server();registerCommanderRemoteBridge(app,{});
23
+ const validation=app.tools.get('remote_mcp').meta.inputSchema.safeParse({
24
+ device_id:id,epoch,capability_id:cap,payload,request_id:request,request_sha256:digest
25
+ });
26
+ assert.equal(validation.success,true,'native relay sends request_sha256 and strict server must accept it');
27
+ });
28
+
29
+ test('R147 remote_mcp rejects a conflicting claimed payload hash before dispatch',async()=>{
30
+ const app=server(),calls=[];
31
+ registerCommanderRemoteBridge(app,{remoteDevicePlane:{async dispatch(value){calls.push(value);return {state:'completed',result_sha256:digest};}}});
32
+ const input={device_id:id,epoch,capability_id:cap,payload,request_id:request,request_sha256:'f'.repeat(64)};
33
+ await assert.rejects(app.tools.get('remote_mcp').handler(input),/request.*hash.*mismatch/i);
34
+ assert.equal(calls.length,0);
35
+ });
36
+
37
+ test('R147 remote_mcp binds matching digest and retains original dispatch contract',async()=>{
38
+ const app=server(),calls=[];
39
+ registerCommanderRemoteBridge(app,{remoteDevicePlane:{async dispatch(value){calls.push(value);return {state:'completed',result_sha256:digest};}}});
40
+ const input={device_id:id,epoch,capability_id:cap,payload,request_id:request,request_sha256:digest};
41
+ const result=await app.tools.get('remote_mcp').handler(input);
42
+ assert.equal(result.state,'completed');
43
+ assert.deepEqual(calls,[{deviceId:id,epoch,capabilityId:cap,payload,requestId:request}]);
44
+ });
45
+
46
+ test('R147 remote_mcp remains backward-compatible with correctly scoped legacy call',async()=>{
47
+ const app=server(),calls=[];
48
+ registerCommanderRemoteBridge(app,{remoteDevicePlane:{async dispatch(v){calls.push(v);return {state:'completed'};}}});
49
+ const result=await app.tools.get('remote_mcp').handler({
50
+ device_id:id,epoch,capability_id:cap,payload,request_id:request
51
+ });
52
+ assert.equal(result.state,'completed');
53
+ assert.equal(calls.length,1);
54
+ });
@@ -83,7 +83,7 @@ test('R72 compact baseline permits only R64 read offset and authorized coding-on
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','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49','0.15.50','0.15.51','0.15.52'].includes(packageVersion)){
86
+ if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49','0.15.50','0.15.51','0.15.52','0.15.53','0.15.54'].includes(packageVersion)){
87
87
  assert.deepEqual([...diff.schema_changed].sort(),['machine_fs','native_diff_preview']);
88
88
  assert.equal(diff.unchanged.length,41);
89
89
  const prior=baseline.tools.find(tool=>tool.name==='machine_fs');
@@ -178,3 +178,56 @@ test('terminal activation outcome is persisted before activation claim release',
178
178
  assert.equal(result.state,'ACTIVATED');
179
179
  assert.deepEqual(order,['claim','activate-start','activate-end','record','release']);
180
180
  });
181
+
182
+ test('R146 legacy offline scope repair is claimed, owner-bound and reproved immediately before activation',async()=>{
183
+ const order=[];
184
+ const disarmed=plane=>({configured:true,armed:false,reason:plane==='autonomous'?'unverified':'disarmed'});
185
+ const proof=plane=>({state:plane==='autonomous'?'UNVERIFIED':'VERIFIED_DISARMED',policy_sha256:policies[plane],grant_absent:true});
186
+ let current={state:'OFFLINE',local_ready:false,bridge:{alive:false},core:{alive:false},cloud:{alive:false},supervisor:{running:false},
187
+ authority:Object.fromEntries(Object.keys(policies).map(plane=>[plane,disarmed(plane)])),
188
+ authority_proof:Object.fromEntries(Object.keys(policies).map(plane=>[plane,proof(plane)])),policy_sha256:policies,
189
+ active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,
190
+ active_generation_manifest_sha256:parent.generation_manifest_sha256};
191
+ const observe=async()=>current;
192
+ const claim=async subject=>{order.push('claim:'+subject);return async()=>order.push('release');};
193
+ const legacyOfflineRecovery=async({phase,preflight_subject_sha256,candidate:boundCandidate})=>{
194
+ order.push('proof:'+phase);
195
+ assert.match(preflight_subject_sha256,/^[0-9a-f]{64}$/);
196
+ assert.equal(boundCandidate.manifest_sha256,candidate.manifest_sha256);
197
+ return {state:'VERIFIED_OFFLINE_LEGACY_SCOPE_REPAIR',preflight_subject_sha256,
198
+ candidate_manifest_sha256:candidate.manifest_sha256,owner_approval_verified:true,subject_sha256:'7'.repeat(64)};
199
+ };
200
+ const activate=async()=>{
201
+ order.push('activate');
202
+ current={...current,state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},
203
+ authority:Object.fromEntries(Object.keys(policies).map(plane=>[plane,legacyEntry(false)])),
204
+ authority_proof:Object.fromEntries(Object.keys(policies).map(plane=>[plane,{state:'VERIFIED_DISARMED',policy_sha256:policies[plane],grant_absent:true}]))};
205
+ return {verified:true,release_id:'v0.15.42-new'};
206
+ };
207
+ const recordOutcome=async outcome=>{order.push('record:'+outcome.state);};
208
+ const result=await orchestrateActivation({pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,
209
+ observe,command:async()=>{throw new Error('no authority command expected');},activate,claim,recordOutcome,legacyOfflineRecovery});
210
+ assert.equal(result.state,'ACTIVATED');
211
+ assert.equal(result.authority_continuity,'LEGACY_SCOPE_REPAIRED_DISARMED');
212
+ assert.deepEqual(order.map(x=>x.replace(/:.*$/,'')),['claim','proof','proof','activate','record','release']);
213
+ });
214
+
215
+ test('R146 legacy offline scope proof drift after claim never dispatches activation',async()=>{
216
+ const authority=Object.fromEntries(Object.keys(policies).map(plane=>[plane,{configured:true,armed:false,reason:plane==='autonomous'?'unverified':'disarmed'}]));
217
+ const authority_proof=Object.fromEntries(Object.keys(policies).map(plane=>[plane,{state:plane==='autonomous'?'UNVERIFIED':'VERIFIED_DISARMED',policy_sha256:policies[plane],grant_absent:true}]));
218
+ const observation={state:'OFFLINE',local_ready:false,bridge:{alive:false},core:{alive:false},cloud:{alive:false},supervisor:{running:false},authority,authority_proof,policy_sha256:policies,
219
+ active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,active_generation_manifest_sha256:parent.generation_manifest_sha256};
220
+ let proofs=0,activated=false,released=false;
221
+ const result=await orchestrateActivation({pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,
222
+ observe:async()=>observation,command:async()=>{},activate:async()=>{activated=true;return {verified:true};},
223
+ claim:async()=>async()=>{released=true;},recordOutcome:async()=>{},
224
+ legacyOfflineRecovery:async({preflight_subject_sha256})=>{
225
+ proofs++;
226
+ if(proofs===2)throw new Error('legacy policy bytes changed');
227
+ return {state:'VERIFIED_OFFLINE_LEGACY_SCOPE_REPAIR',preflight_subject_sha256,
228
+ candidate_manifest_sha256:candidate.manifest_sha256,owner_approval_verified:true,subject_sha256:'7'.repeat(64)};
229
+ }});
230
+ assert.equal(result.state,'ACTIVATION_REJECTED');
231
+ assert.equal(activated,false);
232
+ assert.equal(released,true);
233
+ });
@@ -21,8 +21,8 @@ test('R74 prepublish contract: positive path succeeds and verifies identities',
21
21
  assert.equal(result.checks.no_self_referential_tarball_hash, true);
22
22
  assert.equal(result.identities.package_name, 'deadbyte-mcp');
23
23
  // R74 component contract retains its train-specific source and predecessor assertions;
24
- // the containing R143 package must report its actual immutable package version.
25
- assert.equal(result.identities.package_version, '0.15.52');
24
+ // the containing R144 package must report its actual immutable package version.
25
+ assert.equal(result.identities.package_version, '0.15.54');
26
26
  assert.equal(result.identities.target_train, 'R74');
27
27
  assert.equal(result.identities.published_source_predecessor, '0.15.46');
28
28
  assert.notEqual(result.identities.published_source_predecessor, result.identities.runtime_predecessor);
@@ -41,7 +41,10 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
41
41
  ]},
42
42
  LocalReadyUri:'http://127.0.0.1:8787/healthz',UrlRegex:'https://x',McpUrlFile:'C:/mcp-url.txt',McpUrlFileSha256:EXE,McpPathFile:'C:/token.txt',StartTimeoutSeconds:30,ProbeTimeoutSeconds:3};
43
43
  const coding={schema:'deadbyte.coding-policy.v1',enabled:true,lease_file:'C:/old/coding.json',evidence_dir:'C:/old/evidence',
44
- roots:{core:{path:'C:/old/core',read:true,write:true,exec:true,deny_paths:['node_modules']}},commands:{tests:command(),powershell_script:command()},max_read_bytes:524288,max_write_bytes:2097152};
44
+ roots:{core:{path:'C:/old/core',read:true,write:true,exec:true,deny_paths:['node_modules']},
45
+ local_c:{path:'C:\\',read:true,write:true,exec:true,deny_paths:[]},
46
+ local_d:{path:'D:\\',read:true,write:true,exec:true,deny_paths:[]}},
47
+ commands:{tests:command(),powershell_script:{...command(),root_ids:['core','local_c','local_d']}},max_read_bytes:524288,max_write_bytes:2097152};
45
48
  const autonomous={schema:'deadbyte.autonomous-policy.v1',enabled:true,lease_file:'C:/old/auto.json',evidence_dir:'C:/old/auto-evidence',coding_policy_sha256:'0'.repeat(64),root_ids:['core'],planner:{backend:'client_sampling',max_tokens:4096},
46
49
  profiles:{
47
50
  gate:{kind:'command',root_id:'core',command_id:'tests',script_path:'scripts/gate.ps1',script_sha256:'0'.repeat(64),args:[],cwd:'.',timeout_ms:120000,expect_exit_code:0,required_for_release:true,run_after_mutation:true,description:'gate'},
@@ -97,6 +100,10 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
97
100
  const generatedCoding=JSON.parse(await readFile(result.coding_policy_path,'utf8'));
98
101
  assert.equal(generatedCoding.roots.core.path,path.resolve(development));
99
102
  assert.notEqual(generatedCoding.roots.core.path,path.resolve(release));
103
+ assert.equal(Object.hasOwn(generatedCoding.roots,'local_c'),false);
104
+ assert.equal(Object.hasOwn(generatedCoding.roots,'local_d'),false);
105
+ assert.deepEqual(generatedCoding.commands.powershell_script.root_ids,['core']);
106
+ assert.ok(Object.hasOwn(coding.roots,'local_c'),'predecessor policy must remain untouched');
100
107
  const parityScratch=path.join(path.resolve(state),'runtime','r33-parity-scratch');
101
108
  assert.deepEqual(generatedCoding.roots.parity_scratch,{path:parityScratch,read:true,write:true,exec:false,deny_paths:[]});
102
109
  await access(parityScratch);