deadbyte-mcp 0.15.29 → 0.15.31

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 (65) hide show
  1. package/MANIFEST.SHA256 +64 -48
  2. package/PROVENANCE.json +28 -18
  3. package/README.txt +18 -14
  4. package/RELEASE.json +35 -17
  5. package/SBOM.cdx.json +3 -3
  6. package/STABILIZATION-PROGRESS.md +60 -0
  7. package/TEST-MATRIX.json +52 -118
  8. package/bin/appcontainer-stage.obj +0 -0
  9. package/bin/bootstrap-advapi32.obj +0 -0
  10. package/bin/bootstrap-exitcode.obj +0 -0
  11. package/bin/bootstrap-kernel32.obj +0 -0
  12. package/bin/child-control-probe.obj +0 -0
  13. package/bin/child-control-stage.obj +0 -0
  14. package/bin/contained-reverse-worker.obj +0 -0
  15. package/bin/contained-transform-worker.obj +0 -0
  16. package/bin/containment-probe.obj +0 -0
  17. package/bin/deadbyte-contain.obj +0 -0
  18. package/bin/deadbyte-exec.obj +0 -0
  19. package/bin/deadbyte-hardware-observer-r45.obj +0 -0
  20. package/bin/deadbyte-process-host.obj +0 -0
  21. package/bin/deadbyte-tunnel-host.obj +0 -0
  22. package/controller/deadbyte-desktop-policy.json +5 -5
  23. package/controller/deadbyte-process-policy.json +4 -4
  24. package/package.json +5 -3
  25. package/proof/CONTAINMENT-BUILD.txt +6 -6
  26. package/scripts/gate-windows-r53.ps1 +58 -0
  27. package/scripts/gate-windows-r54.ps1 +26 -0
  28. package/scripts/verify-r42-parent.mjs +1 -1
  29. package/scripts/verify-r43-parent.mjs +1 -1
  30. package/scripts/verify-r44-parent.mjs +1 -1
  31. package/scripts/verify-r45-parent.mjs +1 -1
  32. package/scripts/windows-gate-evidence-r53.mjs +102 -0
  33. package/scripts/windows-gate-evidence-r54.mjs +76 -0
  34. package/src/authority-smoke.mjs +1 -0
  35. package/src/deadbyte-cli.mjs +4 -2
  36. package/src/doctor-r45.mjs +2 -1
  37. package/src/machine-fs-smoke-client.mjs +1 -0
  38. package/src/mcp-contained-smoke-client.mjs +1 -0
  39. package/src/mcp-host-smoke-client.mjs +1 -0
  40. package/src/mcp-smoke-client.mjs +1 -0
  41. package/src/process-smoke-client.mjs +1 -0
  42. package/src/release-slot.mjs +5 -2
  43. package/src/remote-session-guardian.mjs +12 -4
  44. package/src/runtime-coherence.mjs +13 -4
  45. package/src/runtime-update.mjs +51 -13
  46. package/src/state-root.mjs +8 -0
  47. package/src/trust.mjs +2 -1
  48. package/src/tunnel-stdio-compat-smoke.mjs +1 -0
  49. package/src/version.mjs +1 -1
  50. package/test/commander-biff-reference-r48.test.mjs +1 -1
  51. package/test/r44-finalizer.test.mjs +4 -3
  52. package/test/r49-windows-gate.test.mjs +36 -27
  53. package/test/r52-release-contract.test.mjs +9 -3
  54. package/test/r53-release-contract.test.mjs +68 -0
  55. package/test/r54-offline-predecessor-self-exclusion.test.mjs +56 -0
  56. package/test/r54-release-contract.test.mjs +59 -0
  57. package/test/release-slot.test.mjs +2 -1
  58. package/test/skill-mcp-r44.test.mjs +3 -0
  59. package/test/stabilization-guardian.test.mjs +25 -0
  60. package/test/stabilization-parent-context.test.mjs +18 -0
  61. package/test/stabilization-powershell.test.mjs +26 -0
  62. package/test/stabilization-semver.test.mjs +23 -0
  63. package/test/stabilization-smoke-root.test.mjs +23 -0
  64. package/test/stabilization-state-root.test.mjs +60 -0
  65. package/test/stabilization-update-child-root.test.mjs +20 -0
@@ -0,0 +1,68 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const root=new URL('../',import.meta.url);
6
+ const read=rel=>readFile(new URL(rel,root),'utf8');
7
+ const json=rel=>read(rel).then(JSON.parse);
8
+ const currentPackage=await json('package.json');
9
+ const r53test=currentPackage.version==='0.15.30'?test:test.skip;
10
+
11
+ r53test('R53 current release identity is coherent across package lock source metadata SBOM and gate',async()=>{
12
+ const [pkg,lock,release,provenance,matrix,sbom,versionSource]=await Promise.all([
13
+ json('package.json'),json('package-lock.json'),json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs')
14
+ ]);
15
+ assert.equal(pkg.version,'0.15.30');
16
+ assert.equal(lock.version,pkg.version);
17
+ assert.equal(lock.packages[''].version,pkg.version);
18
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.30'/);
19
+ assert.equal(release.version,pkg.version);
20
+ assert.equal(release.train,'R53');
21
+ assert.equal(provenance.version,pkg.version);
22
+ assert.equal(matrix.version,pkg.version);
23
+ assert.equal(matrix.train,'R53');
24
+ assert.equal(sbom.metadata.component.version,pkg.version);
25
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r53:0.15.30');
26
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r53\.ps1/);
27
+ assert.match(pkg.scripts['r53:focused:test'],/stabilization-semver\.test\.mjs/);
28
+ });
29
+
30
+ r53test('R53 lineage binds exact published 0.15.29 as parent and runtime predecessor',async()=>{
31
+ const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
32
+ const parent={
33
+ release_id:'v0.15.29-f74eaa1b3d00e6fb',
34
+ manifest_sha256:'f74eaa1b3d00e6fb5a36b2358efb815e3686c9fe9dbd3b84d25a713ef957748c',
35
+ generation_manifest_sha256:'289b4fc065de0681da6864cc1bbe09aab198ca804945ffc27c786438dad13f5a'
36
+ };
37
+ assert.deepEqual(release.runtime_predecessor,parent);
38
+ assert.equal(release.parent.version,'0.15.29');
39
+ assert.equal(release.parent.release_id,parent.release_id);
40
+ assert.equal(release.parent.manifest_sha256,parent.manifest_sha256);
41
+ assert.equal(release.parent.generation_manifest_sha256,parent.generation_manifest_sha256);
42
+ assert.equal(release.parent.tarball_sha256,'f535d7121a384bed106d34bc7525afa9d4048c7e290f270699e25136d1e82eeb');
43
+ assert.equal(release.source_predecessor.version,'0.15.29');
44
+ assert.equal(release.source_predecessor.tarball_sha256,release.parent.tarball_sha256);
45
+ assert.equal(release.source_predecessor.manifest_file_sha256,release.parent.manifest_sha256);
46
+ assert.equal(release.source_predecessor.generation_manifest_sha256,release.parent.generation_manifest_sha256);
47
+ assert.equal(provenance.parent_release_id,parent.release_id);
48
+ assert.equal(provenance.parent_manifest_sha256,parent.manifest_sha256);
49
+ assert.equal(provenance.parent_generation_manifest_sha256,parent.generation_manifest_sha256);
50
+ assert.equal(provenance.parent_tarball_sha256,release.parent.tarball_sha256);
51
+ assert.deepEqual(provenance.runtime_predecessor,parent);
52
+ });
53
+
54
+ r53test('R53 records stabilization evidence and explicit soak bypass without STABLE/FINAL claim',async()=>{
55
+ const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
56
+ assert.equal(release.stabilization.semver_strict_validation,true);
57
+ assert.equal(release.stabilization.powershell_child_environment_normalized,true);
58
+ assert.equal(release.stabilization.explicit_state_root_propagation,true);
59
+ assert.equal(release.stabilization.guardian_cleanup_fail_closed,true);
60
+ assert.equal(release.stabilization.local_isolated_state_acceptance,'PASS');
61
+ assert.equal(release.stabilization.full_regression,'PASS');
62
+ assert.equal(release.stabilization.four_hour_soak,'NOT_COMPLETED_OPERATOR_BYPASS');
63
+ assert.equal(release.stabilization.stable_final_claim,false);
64
+ assert.equal(provenance.operator_override.four_hour_soak,'NOT_COMPLETED');
65
+ assert.equal(provenance.operator_override.stable_final_claim,false);
66
+ assert.equal(matrix.operator_override.four_hour_soak,'NOT_COMPLETED');
67
+ assert.equal(matrix.operator_override.stable_final_claim,false);
68
+ });
@@ -0,0 +1,56 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { pathToFileURL } from 'node:url';
4
+ import path from 'node:path';
5
+
6
+ const target=process.env.R54_RUNTIME_UPDATE_PATH
7
+ ? path.resolve(process.env.R54_RUNTIME_UPDATE_PATH)
8
+ : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
9
+ const runtimeUpdate=await import(pathToFileURL(target).href+'?r54='+Date.now());
10
+
11
+ test('R54 exposes behavior-testable offline recovery blocker selection',()=>{
12
+ assert.equal(typeof runtimeUpdate.selectOfflineRecoveryBlockers,'function');
13
+ });
14
+
15
+ test('R54 excludes only the current activation ancestry across non-Node wrapper processes',()=>{
16
+ const processes=[
17
+ {ProcessId:100,ParentProcessId:50,Name:'node.exe',CommandLine:'node npm-cli.js exec -- deadbyte-mcp@latest remote'},
18
+ {ProcessId:200,ParentProcessId:100,Name:'cmd.exe',CommandLine:'cmd /d /s /c deadbyte-mcp remote'},
19
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
20
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
21
+ {ProcessId:900,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\mcp-server.mjs'}
22
+ ];
23
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
24
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[900]);
25
+ });
26
+
27
+ test('R54 does not exempt a sibling stale DEADBYTE runtime',()=>{
28
+ const processes=[
29
+ {ProcessId:100,ParentProcessId:50,Name:'node.exe',CommandLine:'node npm-cli.js exec -- deadbyte-mcp@latest remote'},
30
+ {ProcessId:200,ParentProcessId:100,Name:'cmd.exe',CommandLine:'cmd /d /s /c deadbyte-mcp remote'},
31
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
32
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
33
+ {ProcessId:700,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\mcp-server.mjs'}
34
+ ];
35
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
36
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[700]);
37
+ });
38
+
39
+ test('R54 still blocks unrelated stale guardian, tunnel, and cloud DEADBYTE processes',()=>{
40
+ const processes=[
41
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
42
+ {ProcessId:910,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\remote-session-guardian.mjs'},
43
+ {ProcessId:920,ParentProcessId:1,Name:'deadbyte-tunnel-host.exe',CommandLine:'C:\\stale\\deadbyte-tunnel-host.exe'},
44
+ {ProcessId:930,ParentProcessId:1,Name:'cloudflared.exe',CommandLine:'cloudflared tunnel --config C:\\deadbyte-mcp\\cloud.yml run'}
45
+ ];
46
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
47
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[910,920,930]);
48
+ });
49
+
50
+ test('R54 ignores unrelated Node processes without DEADBYTE runtime identity',()=>{
51
+ const processes=[
52
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
53
+ {ProcessId:950,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\work\\unrelated-app\\server.js'}
54
+ ];
55
+ assert.deepEqual(runtimeUpdate.selectOfflineRecoveryBlockers(processes,400),[]);
56
+ });
@@ -0,0 +1,59 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const root=new URL('../',import.meta.url);
6
+ const read=rel=>readFile(new URL(rel,root),'utf8');
7
+ const json=rel=>read(rel).then(JSON.parse);
8
+
9
+ test('R54 release identity is coherent across package lock source metadata SBOM and gate',async()=>{
10
+ const [pkg,lock,release,provenance,matrix,sbom,versionSource]=await Promise.all([
11
+ json('package.json'),json('package-lock.json'),json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs')
12
+ ]);
13
+ assert.equal(pkg.version,'0.15.31');
14
+ assert.equal(lock.version,pkg.version);
15
+ assert.equal(lock.packages[''].version,pkg.version);
16
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.31'/);
17
+ assert.equal(release.version,pkg.version);
18
+ assert.equal(release.train,'R54');
19
+ assert.equal(provenance.version,pkg.version);
20
+ assert.equal(matrix.version,pkg.version);
21
+ assert.equal(matrix.train,'R54');
22
+ assert.equal(sbom.metadata.component.version,pkg.version);
23
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r54:0.15.31');
24
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r54\.ps1/);
25
+ assert.match(pkg.scripts['r54:focused:test'],/r54-offline-predecessor-self-exclusion\.test\.mjs/);
26
+ });
27
+
28
+ test('R54 source predecessor is exact immutable published 0.15.30 while runtime predecessor remains exact 0.15.29',async()=>{
29
+ const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
30
+ assert.equal(release.parent.version,'0.15.30');
31
+ assert.equal(release.parent.release_id,'v0.15.30-ddf7c7338d9a371f');
32
+ assert.equal(release.parent.manifest_sha256,'ddf7c7338d9a371f5667d7b138695e7f9cfced553d14073ac5a44fd2fe0a0399');
33
+ assert.equal(release.parent.tarball_sha256,'72881981bf76eb45527946b310caed8387943e2ca8e37ea6e606c32189dd5a70');
34
+ assert.equal(release.parent.activation_status,'PUBLISHED_NOT_ACTIVATED');
35
+ assert.equal(release.source_predecessor.version,'0.15.30');
36
+ assert.equal(release.source_predecessor.tarball_sha256,release.parent.tarball_sha256);
37
+ assert.equal(release.source_predecessor.manifest_file_sha256,release.parent.manifest_sha256);
38
+ assert.deepEqual(release.runtime_predecessor,{
39
+ release_id:'v0.15.29-f74eaa1b3d00e6fb',
40
+ manifest_sha256:'f74eaa1b3d00e6fb5a36b2358efb815e3686c9fe9dbd3b84d25a713ef957748c',
41
+ generation_manifest_sha256:'289b4fc065de0681da6864cc1bbe09aab198ca804945ffc27c786438dad13f5a'
42
+ });
43
+ assert.equal(provenance.parent_manifest_sha256,release.parent.manifest_sha256);
44
+ assert.deepEqual(provenance.runtime_predecessor,release.runtime_predecessor);
45
+ });
46
+
47
+ test('R54 records surgical activation recovery fix and preserves explicit non-final claim',async()=>{
48
+ const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
49
+ assert.equal(release.hotfix.activation_ancestry_excluded,true);
50
+ assert.equal(release.hotfix.unrelated_stale_runtime_fail_closed,true);
51
+ assert.equal(release.hotfix.red_parent_0_15_30,'FAIL_5_OF_5');
52
+ assert.equal(release.hotfix.green_r54_candidate,'PASS_5_OF_5');
53
+ assert.equal(release.hotfix.stable_final_claim,false);
54
+ assert.equal(release.stabilization.four_hour_soak,'NOT_COMPLETED_OPERATOR_BYPASS');
55
+ assert.equal(provenance.operator_override.four_hour_soak,'NOT_COMPLETED');
56
+ assert.equal(provenance.operator_override.stable_final_claim,false);
57
+ assert.equal(matrix.operator_override.four_hour_soak,'NOT_COMPLETED');
58
+ assert.equal(matrix.operator_override.stable_final_claim,false);
59
+ });
@@ -104,7 +104,8 @@ test('R27 active pointer is schema bound and atomically replaceable', async () =
104
104
  test('R27 stable launcher resolves only the active pointer, not a release hardcode', () => {
105
105
  const cmd=renderStableLauncherCmd();
106
106
  const ps1=renderStableLauncherPs1();
107
- assert.match(cmd,/\.deadbyte-mcp\\bin\\DEADBYTE-MCP\.ps1/i);
107
+ assert.match(cmd,/if not defined DEADBYTE_STATE_ROOT set "DEADBYTE_STATE_ROOT=%USERPROFILE%\\\.deadbyte-mcp"/i);
108
+ assert.match(cmd,/%DEADBYTE_STATE_ROOT%\\bin\\DEADBYTE-MCP\.ps1/i);
108
109
  assert.doesNotMatch(cmd,/deadbyte-mcp-v0\.6\.0/i);
109
110
  assert.match(ps1,/active-release\.json/);
110
111
  assert.match(ps1,/DEADBYTE_CONTROLLER_CONFIG/);
@@ -6,6 +6,7 @@ import { mkdtemp, rm } from 'node:fs/promises';
6
6
  import os from 'node:os';
7
7
  import path from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
+ import { generateTrustKeypair } from '../src/trust.mjs';
9
10
 
10
11
  const here=path.dirname(fileURLToPath(import.meta.url));
11
12
  const repoRoot=path.resolve(here,'..');
@@ -13,8 +14,10 @@ const serverPath=path.join(repoRoot,'src','mcp-server.mjs');
13
14
 
14
15
  test('R44 compact surface exposes one read-only skill_catalog without authority',async()=>{
15
16
  const state=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-skill-mcp-'));
17
+ const keys=await generateTrustKeypair({privateKeyPath:path.join(state,'trust','private.pem'),publicKeyPath:path.join(state,'trust','public.pem')});
16
18
  const client=new Client({name:'deadbyte-r44-skill-mcp',version:'0.15.0-dev'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
17
19
  const env={...getDefaultEnvironment(),DEADBYTE_STATE_ROOT:state,DEADBYTE_CAPABILITY_PROFILE:'compact',
20
+ DEADBYTE_SIGNING_KEY:keys.privateKeyPath,DEADBYTE_VERIFY_KEY:keys.publicKeyPath,
18
21
  DEADBYTE_AUDIT_RUNTIME:'0',DEADBYTE_MACHINE_RUNTIME:'0',DEADBYTE_AGENT_RUNTIME:'0',
19
22
  DEADBYTE_PROCESS_RUNTIME:'0',DEADBYTE_CODING_RUNTIME:'0',DEADBYTE_MACHINE_FS_RUNTIME:'0',
20
23
  DEADBYTE_OBSERVATION_RUNTIME:'0',DEADBYTE_DESKTOP_RUNTIME:'0',DEADBYTE_AUTONOMOUS_RUNTIME:'0'};
@@ -0,0 +1,25 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdir,mkdtemp,writeFile,readFile} from 'node:fs/promises';
4
+ import {spawnSync} from 'node:child_process';
5
+ import path from 'node:path';
6
+
7
+ test('failed guardian cleanup preserves ownership evidence and reports failure',async()=>{
8
+ const base='D:/Projects/deadbyte-mcp/testing/0.15.30';
9
+ await mkdir(base,{recursive:true});
10
+ const root=await mkdtemp(path.join(base,'guardian-failure-'));
11
+ await mkdir(path.join(root,'bin'),{recursive:true});
12
+ await mkdir(path.join(root,'runtime'),{recursive:true});
13
+ const observedRoot=path.join(root,'observed-root.txt');
14
+ await writeFile(path.join(root,'bin','DEADBYTE-MCP.ps1'),`[IO.File]::WriteAllText('${observedRoot.replaceAll("'","''")}',[string]$env:DEADBYTE_STATE_ROOT)\nexit 1\n`);
15
+ const owner=spawnSync(process.execPath,['-e','process.exit(0)']);
16
+ assert.equal(owner.status,0);
17
+ const marker={schema:'deadbyte.remote-session.v2',owner_pid:owner.pid,session_nonce:'a'.repeat(64)};
18
+ const markerPath=path.join(root,'runtime','remote-session.json');
19
+ await writeFile(markerPath,JSON.stringify(marker));
20
+ const result=spawnSync(process.execPath,['src/remote-session-guardian.mjs','--state-root',root,'--owner-pid',String(owner.pid),'--session-nonce',marker.session_nonce],{encoding:'utf8',timeout:20000,env:{...process.env,DEADBYTE_STATE_ROOT:path.join(base,'different-guardian-parent')}});
21
+ assert.equal(result.error,undefined,String(result.error));
22
+ assert.notEqual(result.status,0,'cleanup failure must not report success');
23
+ assert.deepEqual(JSON.parse(await readFile(markerPath,'utf8')),marker);
24
+ assert.equal(await readFile(observedRoot,'utf8'),root);
25
+ });
@@ -0,0 +1,18 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdir,mkdtemp} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {generateTrustKeypair} from '../src/trust.mjs';
6
+ import {verifyR43Parent} from '../scripts/verify-r43-parent.mjs';
7
+
8
+ test('historical parent verifier rejects a different explicit public key',async()=>{
9
+ const base='D:/Projects/deadbyte-mcp/testing/0.15.30';
10
+ await mkdir(base,{recursive:true});
11
+ const root=await mkdtemp(path.join(base,'historical-key-context-'));
12
+ const keys=await generateTrustKeypair({privateKeyPath:path.join(root,'private.pem'),publicKeyPath:path.join(root,'public.pem')});
13
+ const prior=process.env.DEADBYTE_PARENT_VERIFY_KEY;
14
+ try{
15
+ process.env.DEADBYTE_PARENT_VERIFY_KEY=keys.publicKeyPath;
16
+ await assert.rejects(verifyR43Parent(new URL('../R43-PARENT.json',import.meta.url)),/activation signer mismatch/);
17
+ }finally{if(prior===undefined)delete process.env.DEADBYTE_PARENT_VERIFY_KEY;else process.env.DEADBYTE_PARENT_VERIFY_KEY=prior;}
18
+ });
@@ -0,0 +1,26 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {spawnSync} from 'node:child_process';
4
+ import path from 'node:path';
5
+ import {windowsPowerShellEnvironment} from '../src/runtime-update.mjs';
6
+
7
+ test('child normalization preserves custom module paths and unrelated environment',()=>{
8
+ const base={...process.env,PSModulePath:'D:\\custom-modules;D:\\other-modules',STABILIZATION_SENTINEL:'preserved'};
9
+ const normalized=windowsPowerShellEnvironment(base);
10
+ assert.ok(normalized.PSModulePath.split(';').includes('D:\\custom-modules'));
11
+ assert.ok(normalized.PSModulePath.split(';').includes('D:\\other-modules'));
12
+ assert.equal(normalized.STABILIZATION_SENTINEL,'preserved');
13
+ assert.equal(base.PSModulePath,'D:\\custom-modules;D:\\other-modules');
14
+ });
15
+ test('normalized Windows PowerShell resolves native Get-FileHash for inherited, missing and custom paths',()=>{
16
+ assert.equal(process.platform,'win32','this acceptance test requires Windows');
17
+ const executable=path.join(process.env.SystemRoot,'System32','WindowsPowerShell','v1.0','powershell.exe');
18
+ for(const value of [process.env.PSModulePath,undefined,'D:\\custom-modules']){
19
+ const base={...process.env};
20
+ if(value===undefined) delete base.PSModulePath; else base.PSModulePath=value;
21
+ const result=spawnSync(executable,['-NoProfile','-Command',"$ErrorActionPreference='Stop'; $c=Get-Command Get-FileHash; $c.Name; $c.Module.Path"],{encoding:'utf8',timeout:20000,env:windowsPowerShellEnvironment(base)});
22
+ assert.equal(result.status,0,result.stderr);
23
+ assert.match(result.stdout,/Get-FileHash/);
24
+ assert.ok(result.stdout.toLowerCase().includes(path.join(process.env.SystemRoot,'System32','WindowsPowerShell','v1.0','Modules').toLowerCase()),result.stdout);
25
+ }
26
+ });
@@ -0,0 +1,23 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {compareRuntimeVersions as compare,ensureRuntimeCoherence} from '../src/runtime-coherence.mjs';
4
+
5
+ test('strict SemVer grammar',()=>{
6
+ for(const v of ['01.0.0','1.00.0','1.0.00','1.0.0-01','1.0.0-alpha..1','1.0.0+.','1.0.0-','1.0.0+','1.0.0\n']) assert.throws(()=>compare(v,v),/invalid/,v);
7
+ for(const v of ['1.0.0','1.0.0-0','1.0.0-alpha.1','1.0.0+001','1.0.0-x-y']) assert.equal(compare(v,v),0);
8
+ });
9
+ test('ASCII, arbitrary precision and SemVer precedence laws',()=>{
10
+ const ordered=['1.0.0-0','1.0.0-1','1.0.0-A','1.0.0-a','1.0.0-alpha','1.0.0-alpha.1','1.0.0-alpha.beta','1.0.0-beta','1.0.0-beta.2','1.0.0-beta.11','1.0.0-rc.1','1.0.0','1.0.1','2.0.0'];
11
+ for(let i=0;i<ordered.length;i++) for(let j=0;j<ordered.length;j++){
12
+ assert.equal(compare(ordered[i],ordered[j]),Math.sign(i-j));
13
+ for(let k=j;k<ordered.length;k++) if(i<=j) assert.ok(compare(ordered[i],ordered[k])<=0);
14
+ }
15
+ assert.equal(compare('9007199254740992.0.0','9007199254740993.0.0'),-1);
16
+ assert.equal(compare('1.0.0-9007199254740992','1.0.0-9007199254740993'),-1);
17
+ assert.equal(compare('1.0.0+a','1.0.0+b'),0);
18
+ });
19
+ test('ASCII downgrade never dispatches authority or activation',async()=>{
20
+ let calls=0;
21
+ await assert.rejects(ensureRuntimeCoherence({cliVersion:'1.0.0-A',packageManifestSha256:'b'.repeat(64),readActive:async()=>({version:'1.0.0-a',manifest_sha256:'a'.repeat(64)}),disarmPrivileged:async()=>{calls++;},activateCurrentPackage:async()=>{calls++;}}),/refusing automatic downgrade/);
22
+ assert.equal(calls,0);
23
+ });
@@ -0,0 +1,23 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdir,mkdtemp,writeFile,readFile} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {spawnSync} from 'node:child_process';
6
+
7
+ test('MCP smoke preserves caller state root across SDK stdio transport',async()=>{
8
+ const base='D:/Projects/deadbyte-mcp/testing/0.15.30';
9
+ await mkdir(base,{recursive:true});
10
+ const root=await mkdtemp(path.join(base,'smoke-root-'));
11
+ const state=path.join(root,'isolated'),profile=path.join(root,'profile'),temp=path.join(root,'temp');
12
+ for(const dir of [path.join(state,'evidence','updates'),path.join(profile,'.deadbyte-mcp'),temp])await mkdir(dir,{recursive:true});
13
+ await writeFile(path.join(state,'active-release.json'),'INVALID_ISOLATED_POINTER');
14
+ const result=spawnSync(process.execPath,['src/mcp-smoke-client.mjs'],{encoding:'utf8',timeout:30000,env:{...process.env,DEADBYTE_STATE_ROOT:state,USERPROFILE:profile,TEMP:temp,TMP:temp}});
15
+ assert.notEqual(result.status,0,'smoke ignored corrupt explicitly-selected state');
16
+ assert.equal(result.error,undefined,String(result.error));
17
+ assert.match(result.stderr,/JSON|Unexpected token|connection closed/i);
18
+ });
19
+ test('release smoke child environments explicitly bind state root',async()=>{
20
+ for(const name of ['mcp-smoke-client','mcp-contained-smoke-client','process-smoke-client','machine-fs-smoke-client','authority-smoke','mcp-host-smoke-client']){
21
+ assert.match(await readFile(new URL('../src/'+name+'.mjs',import.meta.url),'utf8'),/DEADBYTE_STATE_ROOT\s*:/,name);
22
+ }
23
+ });
@@ -0,0 +1,60 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdtemp,mkdir,writeFile,readFile} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {spawnSync} from 'node:child_process';
6
+ import {renderStableLauncherPs1,renderStableLauncherCmd} from '../src/release-slot.mjs';
7
+ import {windowsPowerShellEnvironment} from '../src/runtime-update.mjs';
8
+ import {resolveStateRoot} from '../src/state-root.mjs';
9
+
10
+ const base='D:/Projects/deadbyte-mcp/testing/0.15.30';
11
+ test('trust default follows explicit environment in a fresh child',()=>{
12
+ const root=path.join(base,'trust-isolated');
13
+ const r=spawnSync(process.execPath,['--input-type=module','-e',"import {defaultTrustDir} from './src/trust.mjs'; console.log(defaultTrustDir());"],{encoding:'utf8',env:{...process.env,DEADBYTE_STATE_ROOT:root}});
14
+ assert.equal(r.status,0,r.stderr);
15
+ assert.equal(r.stdout.trim(),path.resolve(root,'trust'));
16
+ });
17
+ test('updater recovery reads the isolated pointer, not production',async()=>{
18
+ await mkdir(base,{recursive:true});
19
+ const root=await mkdtemp(path.join(base,'recovery-root-'));
20
+ await mkdir(path.join(root,'evidence','updates'),{recursive:true});
21
+ await writeFile(path.join(root,'active-release.json'),'INVALID_ISOLATED_POINTER');
22
+ const r=spawnSync(process.execPath,['scripts/runtime-self-update.mjs','--recover-interrupted'],{encoding:'utf8',env:{...process.env,DEADBYTE_STATE_ROOT:root},timeout:20000});
23
+ assert.notEqual(r.status,0);
24
+ assert.match(r.stderr,/JSON|Unexpected token/);
25
+ });
26
+ test('root precedence, default and invalid explicit roots',()=>{
27
+ assert.equal(resolveStateRoot('D:/explicit',{DEADBYTE_STATE_ROOT:'D:/environment'}),path.resolve('D:/explicit'));
28
+ assert.equal(resolveStateRoot(undefined,{DEADBYTE_STATE_ROOT:'D:/environment'}),path.resolve('D:/environment'));
29
+ assert.match(resolveStateRoot(undefined,{}),/\.deadbyte-mcp$/);
30
+ assert.throws(()=>resolveStateRoot(''),/invalid/);
31
+ assert.throws(()=>resolveStateRoot(null),/invalid/);
32
+ assert.throws(()=>resolveStateRoot('D:/bad\0'),/invalid/);
33
+ });
34
+ test('PS launcher selects isolated missing pointer rather than decoy production pointer',async()=>{
35
+ await mkdir(base,{recursive:true});
36
+ const fixture=await mkdtemp(path.join(base,'root-red-'));
37
+ const profile=path.join(fixture,'profile'),isolated=path.join(fixture,'isolated');
38
+ await mkdir(path.join(profile,'.deadbyte-mcp'),{recursive:true});
39
+ const decoy=path.join(profile,'.deadbyte-mcp','active-release.json');
40
+ await writeFile(decoy,'{"schema":"DECOY_PRODUCTION"}');
41
+ const launcher=path.join(fixture,'launcher.ps1');
42
+ await writeFile(launcher,renderStableLauncherPs1());
43
+ const r=spawnSync(path.join(process.env.SystemRoot,'System32','WindowsPowerShell','v1.0','powershell.exe'),['-NoProfile','-File',launcher,'status'],{encoding:'utf8',timeout:20000,env:windowsPowerShellEnvironment({...process.env,USERPROFILE:profile,DEADBYTE_STATE_ROOT:isolated})});
44
+ assert.notEqual(r.status,0);
45
+ assert.match(r.stderr,/active release pointer missing/);
46
+ assert.doesNotMatch(r.stderr,/schema mismatch/);
47
+ assert.equal(await readFile(decoy,'utf8'),'{"schema":"DECOY_PRODUCTION"}');
48
+ });
49
+ test('CMD launcher transports explicit root with spaces to nested Node child',async()=>{
50
+ await mkdir(base,{recursive:true});
51
+ const fixture=await mkdtemp(path.join(base,'cmd-red-'));
52
+ const isolated=path.join(fixture,'isolated with spaces');
53
+ await mkdir(path.join(isolated,'bin'),{recursive:true});
54
+ await writeFile(path.join(isolated,'bin','DEADBYTE-MCP.ps1'),`& '${process.execPath.replaceAll("'","''")}' -e 'console.log(process.env.DEADBYTE_STATE_ROOT)'\nexit $LASTEXITCODE\n`);
55
+ const cmd=path.join(fixture,'launcher.cmd');
56
+ await writeFile(cmd,renderStableLauncherCmd());
57
+ const r=spawnSync(process.env.ComSpec,['/d','/c',cmd,'status'],{encoding:'utf8',timeout:20000,env:windowsPowerShellEnvironment({...process.env,DEADBYTE_STATE_ROOT:isolated,USERPROFILE:fixture})});
58
+ assert.equal(r.status,0,r.stderr);
59
+ assert.equal(r.stdout.trim(),isolated);
60
+ });
@@ -0,0 +1,20 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdir,mkdtemp,writeFile,readFile} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {runControllerStartNoCapture} from '../src/runtime-update.mjs';
6
+
7
+ test('explicit updater context root overrides inherited root for controller child',async()=>{
8
+ const base='D:/Projects/deadbyte-mcp/testing/0.15.30';
9
+ await mkdir(base,{recursive:true});
10
+ const root=await mkdtemp(path.join(base,'explicit-child-root-'));
11
+ const output=path.join(root,'observed-root.txt'),controller=path.join(root,'controller.ps1');
12
+ await writeFile(controller,`[IO.File]::WriteAllText('${output.replaceAll("'","''")}',[string]$env:DEADBYTE_STATE_ROOT)\nexit 0\n`);
13
+ const old=process.env.DEADBYTE_STATE_ROOT;
14
+ try{
15
+ process.env.DEADBYTE_STATE_ROOT=path.join(base,'different-parent-root');
16
+ const result=runControllerStartNoCapture({kind:'slot',state_root:root,controller_path:controller,cwd:root,runtime_root:path.join(root,'runtime'),pointer:{config_path:path.join(root,'config.psd1')}},10000);
17
+ assert.equal(result.status,0);
18
+ assert.equal(await readFile(output,'utf8'),root);
19
+ }finally{if(old===undefined)delete process.env.DEADBYTE_STATE_ROOT;else process.env.DEADBYTE_STATE_ROOT=old;}
20
+ });