deadbyte-mcp 0.15.1 → 0.15.3

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 (96) hide show
  1. package/MANIFEST.SHA256 +95 -64
  2. package/PROVENANCE.json +6 -5
  3. package/README.txt +36 -20
  4. package/RELEASE.json +24 -8
  5. package/SBOM.cdx.json +3 -3
  6. package/controller/README.TXT +2 -2
  7. package/controller/deadbyte-controller.ps1 +50 -2
  8. package/controller/deadbyte-process-policy.json +63 -1
  9. package/docs/ARCHITECTURE.md +3 -4
  10. package/package.json +88 -86
  11. package/scripts/autonomous-build.ps1 +1 -0
  12. package/scripts/autonomous-tests.ps1 +1 -0
  13. package/scripts/check-agent-backend-r46.mjs +77 -0
  14. package/scripts/check-atomic-resource-r46.mjs +84 -0
  15. package/scripts/check-autonomous-race-r46.mjs +160 -0
  16. package/scripts/check-coding-task-deadline-r46.mjs +59 -0
  17. package/scripts/check-deadline-cancellation-r46.mjs +49 -0
  18. package/scripts/check-process-deadline-r46.mjs +52 -0
  19. package/scripts/check-r46-background.mjs +5 -0
  20. package/scripts/deferred-slot-operation-r46.mjs +126 -0
  21. package/scripts/extract-r46-failures.mjs +5 -0
  22. package/scripts/final-closure-r46.mjs +98 -0
  23. package/scripts/final-closure-verify-r46.mjs +119 -0
  24. package/scripts/full-regression-r46.mjs +28 -0
  25. package/scripts/gate-windows-r46.ps1 +58 -0
  26. package/scripts/inspect-r46-active.mjs +2 -0
  27. package/scripts/r47-core-failures.mjs +1 -0
  28. package/scripts/refresh-process-policy.mjs +64 -7
  29. package/scripts/release-manifest.mjs +1 -1
  30. package/scripts/release-parity-r46.mjs +187 -0
  31. package/scripts/run-r46-full-regression-background.mjs +7 -0
  32. package/scripts/run-r46-windows-gate-background.mjs +6 -0
  33. package/scripts/run-r46-windows-gate-background.ps1 +10 -0
  34. package/scripts/windows-gate-evidence-r46.mjs +111 -0
  35. package/scripts/workload-contract-regression-r47.mjs +14 -0
  36. package/scripts/workload-stream-regression.mjs +16 -0
  37. package/scripts/workload-substrate-r47-regression.mjs +12 -0
  38. package/src/agent-backend-r44.mjs +75 -10
  39. package/src/atomic-mutation.mjs +55 -0
  40. package/src/autonomous-mcp-tools.mjs +4 -3
  41. package/src/autonomous-output-contracts.mjs +16 -3
  42. package/src/autonomous-runtime.mjs +83 -30
  43. package/src/capability-ledger.mjs +1 -0
  44. package/src/coding-mcp-tools.mjs +2 -2
  45. package/src/coding-output-contracts.mjs +18 -4
  46. package/src/coding-plane.mjs +3 -24
  47. package/src/coding-search.mjs +11 -2
  48. package/src/coding-task-runtime.mjs +41 -6
  49. package/src/compact-gateway-mcp-tools.mjs +7 -5
  50. package/src/deadbyte-cli.mjs +7 -3
  51. package/src/deadline-cancellation.mjs +83 -0
  52. package/src/machine-fs-mcp-tools.mjs +3 -3
  53. package/src/machine-fs-output-contracts.mjs +1 -1
  54. package/src/machine-fs-read-worker.mjs +46 -0
  55. package/src/machine-fs-smoke-client.mjs +1 -1
  56. package/src/machine-fs.mjs +66 -33
  57. package/src/mcp-server.mjs +10 -0
  58. package/src/mcp-smoke-client.mjs +4 -1
  59. package/src/observation-runtime.mjs +25 -4
  60. package/src/observation-smoke-client.mjs +1 -1
  61. package/src/process-mcp-tools.mjs +29 -8
  62. package/src/process-output-contracts.mjs +43 -3
  63. package/src/process-policy.mjs +3 -1
  64. package/src/process-runtime.mjs +152 -23
  65. package/src/process-smoke-client.mjs +67 -22
  66. package/src/release-generation.mjs +22 -3
  67. package/src/remote-device-r44.mjs +53 -15
  68. package/src/remote-mcp-smoke-client.mjs +1 -1
  69. package/src/resource-identity.mjs +59 -0
  70. package/src/runtime-update.mjs +526 -162
  71. package/src/stdio-console-guard.mjs +24 -0
  72. package/src/version.mjs +1 -1
  73. package/src/workload-substrate.mjs +87 -0
  74. package/test/cli-entrypoint.test.mjs +3 -3
  75. package/test/coding-runtime.test.mjs +12 -0
  76. package/test/coding-search-r36.test.mjs +7 -0
  77. package/test/compact-gateway-r36.test.mjs +28 -0
  78. package/test/core.test.mjs +1 -1
  79. package/test/full-max-catalog-r46.test.mjs +92 -0
  80. package/test/helpers/autonomous-r34-fixture.mjs +10 -1
  81. package/test/machine-fs-mcp-tools.test.mjs +4 -1
  82. package/test/machine-fs-runtime.test.mjs +18 -2
  83. package/test/observation-runtime.test.mjs +29 -2
  84. package/test/process-mcp-tools.test.mjs +27 -6
  85. package/test/process-policy-refresh.test.mjs +87 -10
  86. package/test/process-runtime.test.mjs +129 -2
  87. package/test/process-supervision.test.mjs +4 -2
  88. package/test/production-docs.test.mjs +3 -3
  89. package/test/r33-finalization.test.mjs +3 -3
  90. package/test/r45-finalization.test.mjs +1 -1
  91. package/test/release-generation.test.mjs +25 -11
  92. package/test/release-version.test.mjs +99 -44
  93. package/test/remote-device-r44.test.mjs +75 -0
  94. package/test/remote-r24-catalog.test.mjs +2 -2
  95. package/test/runtime-self-update.test.mjs +118 -1
  96. package/test/workload-substrate.test.mjs +22 -0
@@ -0,0 +1,119 @@
1
+ import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const DOMAIN=Buffer.from('DEADBYTE-R46-FINAL-CLOSURE-V1\0','utf8');
8
+ const here=path.dirname(fileURLToPath(import.meta.url));
9
+ const packageRoot=path.resolve(here,'..');
10
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
11
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
12
+ const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
13
+ ?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
14
+ const canonicalJson=value=>JSON.stringify(canonical(value));
15
+ function insist(ok,message){if(!ok)throw new Error(message);}
16
+
17
+ export async function verifyFinalClosureObject(envelope,{root=packageRoot,runtimeStateRoot=stateRoot}={}){
18
+ const candidate=path.resolve(root),state=path.resolve(runtimeStateRoot);
19
+ insist(envelope&&typeof envelope==='object'&&!Array.isArray(envelope),'R46 closure envelope invalid');
20
+ insist(envelope.body?.schema==='deadbyte.r46-final-closure.v1','R46 closure schema mismatch');
21
+ insist(envelope.body?.version==='0.15.2'&&envelope.body?.train==='R46','R46 closure version/train mismatch');
22
+ insist(envelope.body?.release_label==='FILELESS POWERSHELL PRODUCT BASELINE','R46 closure label mismatch');
23
+
24
+ const bodyBytes=Buffer.from(canonicalJson(envelope.body),'utf8');
25
+ insist(envelope.body_sha256===sha256(bodyBytes),'R46 closure body SHA-256 mismatch');
26
+ insist(envelope.attestation?.algorithm==='ed25519'&&envelope.attestation?.domain==='DEADBYTE-R46-FINAL-CLOSURE-V1','R46 closure attestation contract mismatch');
27
+ const publicKey=createPublicKey(await readFile(path.join(state,'trust','ed25519-public.pem')));
28
+ insist(publicKey.asymmetricKeyType==='ed25519','R46 closure verify key must be Ed25519');
29
+ const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
30
+ insist(envelope.attestation.key_id===keyId,'R46 closure signer key mismatch');
31
+ insist(typeof envelope.attestation.signature_base64==='string'&&cryptoVerify(
32
+ null,Buffer.concat([DOMAIN,bodyBytes]),publicKey,Buffer.from(envelope.attestation.signature_base64,'base64')
33
+ ),'R46 closure signature invalid');
34
+
35
+ const unsigned={body:envelope.body,body_sha256:envelope.body_sha256,attestation:envelope.attestation};
36
+ const closureSha256=sha256(Buffer.from(canonicalJson(unsigned),'utf8'));
37
+ insist(envelope.closure_sha256===closureSha256,'R46 closure digest mismatch');
38
+
39
+ const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
40
+ const manifestSha256=sha256(manifestBytes);
41
+ const pointer=JSON.parse(await readFile(path.join(state,'active-release.json'),'utf8'));
42
+ insist(pointer.version==='0.15.2'&&pointer.manifest_sha256===manifestSha256,'R46 active pointer/candidate mismatch');
43
+ insist(pointer.release_id===`v0.15.2-${manifestSha256.slice(0,16)}`,'R46 active release id mismatch');
44
+ insist(envelope.body.active_pointer?.release_id===pointer.release_id&&
45
+ envelope.body.active_pointer?.manifest_sha256===pointer.manifest_sha256&&
46
+ envelope.body.active_pointer?.generation_manifest_sha256===pointer.generation_manifest_sha256,
47
+ 'R46 closure active pointer drift');
48
+
49
+ const gateRef=envelope.body.evidence?.windows_gate;
50
+ const parityRef=envelope.body.evidence?.parity;
51
+ for(const [label,ref] of [['windows gate',gateRef],['parity',parityRef]]){
52
+ insist(ref&&typeof ref.path==='string'&&/^[0-9a-f]{64}$/.test(String(ref.sha256??'')),`R46 ${label} evidence reference invalid`);
53
+ const bytes=await readFile(path.resolve(ref.path));
54
+ insist(sha256(bytes)===ref.sha256,`R46 ${label} evidence hash mismatch`);
55
+ }
56
+ const gate=JSON.parse(await readFile(path.resolve(gateRef.path),'utf8'));
57
+ const parity=JSON.parse(await readFile(path.resolve(parityRef.path),'utf8'));
58
+ insist(gate.schema==='deadbyte.r46-windows-gate.v1'&&gate.status==='passed'&&gate.version==='0.15.2','R46 gate evidence invalid');
59
+ insist(gate.manifest_sha256===manifestSha256,'R46 gate candidate mismatch');
60
+ insist(gate.parent?.release_id==='v0.15.1-d55f00b5144dc31a'&&gate.parent?.manifest_sha256==='d55f00b5144dc31a7fe39e4dc60d640a94780da6aaeca0918e87636b816d7854','R46 sealed parent identity invalid');
61
+ insist(gate.runtime_predecessor?.release_id==='v0.15.2-0fb46542f6a4345f'&&gate.runtime_predecessor?.manifest_sha256==='0fb46542f6a4345f1c527565d06bf6e9b8e283260e47bf684fb70a60308fcf34','R46 reopened runtime predecessor identity invalid');
62
+ insist(envelope.body.runtime_predecessor?.release_id===gate.runtime_predecessor.release_id&&envelope.body.runtime_predecessor?.manifest_sha256===gate.runtime_predecessor.manifest_sha256,'R46 closure runtime predecessor mismatch');
63
+ insist(parity.schema==='deadbyte.r46-parity.v1'&&parity.status==='passed'&&parity.version==='0.15.2','R46 parity evidence invalid');
64
+ insist(parity.candidate?.release_id===pointer.release_id&&
65
+ parity.candidate?.manifest_sha256===pointer.manifest_sha256&&
66
+ parity.candidate?.generation_manifest_sha256===pointer.generation_manifest_sha256,
67
+ 'R46 parity active generation mismatch');
68
+ insist(parity.process_policy?.target_repin_verified===true,'R46 target-machine process repin proof missing');
69
+ insist(parity.fileless_powershell?.exit_code===0&&
70
+ parity.fileless_powershell?.pscommandpath_empty===true&&
71
+ parity.fileless_powershell?.invocation_path_empty===true&&
72
+ parity.fileless_powershell?.new_temp_ps1_count===0,
73
+ 'R46 fileless PowerShell proof invalid');
74
+ insist(parity.persistent_powershell_repl?.state_persisted===true&&
75
+ parity.persistent_powershell_repl?.observed_value===42&&
76
+ parity.persistent_powershell_repl?.wait_for_verified===true&&
77
+ parity.persistent_powershell_repl?.tail_read_verified===true&&
78
+ parity.persistent_powershell_repl?.raw_input_not_journaled===true,
79
+ 'R46 persistent PowerShell REPL proof invalid');
80
+ insist(parity.retained_output_ring?.eviction_verified===true&&
81
+ parity.retained_output_ring?.tail_marker_verified===true&&
82
+ parity.retained_output_ring?.earliest_offset>0,
83
+ 'R46 retained-output ring proof invalid');
84
+ insist(envelope.body.process_policy?.target_repin_verified===true,'R46 closure process repin proof invalid');
85
+ insist(envelope.body.fileless_powershell?.exit_code===0&&
86
+ envelope.body.fileless_powershell?.new_temp_ps1_count===0,
87
+ 'R46 closure fileless proof invalid');
88
+ insist(envelope.body.persistent_powershell_repl?.state_persisted===true&&
89
+ envelope.body.persistent_powershell_repl?.observed_value===42&&
90
+ envelope.body.persistent_powershell_repl?.raw_input_not_journaled===true,
91
+ 'R46 closure persistent REPL proof invalid');
92
+ insist(envelope.body.retained_output_ring?.eviction_verified===true&&
93
+ envelope.body.retained_output_ring?.tail_marker_verified===true,
94
+ 'R46 closure retained-output ring proof invalid');
95
+
96
+ return {
97
+ ok:true,status:'passed',version:'0.15.2',train:'R46',
98
+ release_id:pointer.release_id,
99
+ manifest_sha256:pointer.manifest_sha256,
100
+ generation_manifest_sha256:pointer.generation_manifest_sha256,
101
+ closure_sha256:envelope.closure_sha256,
102
+ signer_key_id:keyId,
103
+ fileless_powershell:true,
104
+ target_machine_process_repin:true
105
+ };
106
+ }
107
+
108
+ export async function verifyFinalClosure({file=null,root=packageRoot,runtimeStateRoot=stateRoot}={}){
109
+ const state=path.resolve(runtimeStateRoot),candidate=path.resolve(root);
110
+ const manifestSha256=sha256(await readFile(path.join(candidate,'MANIFEST.SHA256')));
111
+ const target=file?path.resolve(file):path.join(state,'evidence','release',`r46-final-${manifestSha256.slice(0,16)}.json`);
112
+ const envelope=JSON.parse(await readFile(target,'utf8'));
113
+ return {...await verifyFinalClosureObject(envelope,{root:candidate,runtimeStateRoot:state}),path:target};
114
+ }
115
+
116
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
117
+ if(invoked)verifyFinalClosure({file:process.argv[2]??null})
118
+ .then(value=>console.log(JSON.stringify(value,null,2)))
119
+ .catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
@@ -0,0 +1,28 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { readdir, stat } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const here=path.dirname(fileURLToPath(import.meta.url));
7
+ const root=path.resolve(here,'..');
8
+ const testDir=path.join(root,'test');
9
+ const excluded=new Set(['full-max-catalog-r44.test.mjs','full-max-catalog-r45.test.mjs']);
10
+ const files=(await readdir(testDir,{withFileTypes:true}))
11
+ .filter(entry=>entry.isFile()&&entry.name.endsWith('.test.mjs')&&!excluded.has(entry.name));
12
+ const weighted=[];
13
+ for(const entry of files) weighted.push({path:path.join('test',entry.name),size:(await stat(path.join(testDir,entry.name))).size});
14
+ weighted.sort((a,b)=>b.size-a.size||a.path.localeCompare(b.path,'en'));
15
+ const batchCount=8;
16
+ const batches=Array.from({length:batchCount},()=>[]);
17
+ weighted.forEach((entry,index)=>batches[index%batchCount].push(entry.path));
18
+ let total=0;
19
+ for(let index=0;index<batchCount;index++){
20
+ const batch=batches[index].sort((a,b)=>a.localeCompare(b,'en'));
21
+ console.log(`R47-BOUNDED-REGRESSION batch=${index+1}/${batchCount} files=${batch.length}`);
22
+ const result=spawnSync(process.execPath,['--test','--test-concurrency=1',...batch],{cwd:root,stdio:'inherit',windowsHide:true,shell:false});
23
+ if(result.error) throw result.error;
24
+ if(result.signal) throw new Error(`regression batch ${index} terminated by ${result.signal}`);
25
+ if(result.status!==0) throw new Error(`regression batch ${index} failed with exit code ${result.status}`);
26
+ total+=batch.length;
27
+ }
28
+ console.log(`R47-BOUNDED-REGRESSION PASS files=${total} batches=${batchCount}`);
@@ -0,0 +1,58 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version 2.0
3
+
4
+ function Invoke-GateStep {
5
+ param(
6
+ [Parameter(Mandatory = $true)][string]$Name,
7
+ [Parameter(Mandatory = $true)][string[]]$NpmArgs
8
+ )
9
+ Write-Host "==== $Name ===="
10
+ $LASTEXITCODE = 0
11
+ & npm.cmd @NpmArgs
12
+ if ($LASTEXITCODE -ne 0) {
13
+ throw "DEADBYTE V0.15.2 / R46 gate failed at $Name with exit code $LASTEXITCODE"
14
+ }
15
+ }
16
+
17
+ Invoke-GateStep -Name 'containment-build' -NpmArgs @('run','containment:build')
18
+ Invoke-GateStep -Name 'process-policy-refresh' -NpmArgs @('run','process:policy:refresh')
19
+ Invoke-GateStep -Name 'desktop-policy-refresh' -NpmArgs @('run','desktop:policy:refresh')
20
+ Invoke-GateStep -Name 'hardware-build' -NpmArgs @('run','hardware:build')
21
+
22
+ Write-Host '==== host-policy-hermetic-clean ===='
23
+ $HostPolicyPath = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
24
+ Remove-Item -LiteralPath $HostPolicyPath -Force -ErrorAction SilentlyContinue
25
+ if (Test-Path -LiteralPath $HostPolicyPath) {
26
+ throw "DEADBYTE V0.15.2 / R46 gate could not remove machine-local Host policy before hermetic regression"
27
+ }
28
+ Write-Host 'HOST_POLICY_HERMETIC_ABSENT'
29
+
30
+ Invoke-GateStep -Name 'r46-fileless-focused' -NpmArgs @('run','r46:fileless:test')
31
+ Invoke-GateStep -Name 'full-regression' -NpmArgs @('run','r46:full:test')
32
+ Invoke-GateStep -Name 'mcp-smoke' -NpmArgs @('run','mcp:smoke')
33
+ Invoke-GateStep -Name 'mcp-agent-smoke' -NpmArgs @('run','mcp:agent:smoke')
34
+ Invoke-GateStep -Name 'mcp-coding-smoke' -NpmArgs @('run','mcp:coding:smoke')
35
+ Invoke-GateStep -Name 'mcp-machine-fs-smoke' -NpmArgs @('run','mcp:machine-fs:smoke')
36
+ Invoke-GateStep -Name 'mcp-observation-smoke' -NpmArgs @('run','mcp:observation:smoke')
37
+ Invoke-GateStep -Name 'mcp-process-smoke' -NpmArgs @('run','mcp:process:smoke')
38
+ Invoke-GateStep -Name 'mcp-autonomous-smoke' -NpmArgs @('run','mcp:autonomous:smoke')
39
+ Invoke-GateStep -Name 'tunnel-stdio-compat-smoke' -NpmArgs @('run','mcp:tunnel-compat:smoke')
40
+ Invoke-GateStep -Name 'containment-smoke' -NpmArgs @('run','containment:smoke')
41
+ Invoke-GateStep -Name 'contained-smoke' -NpmArgs @('run','contained:smoke')
42
+ Invoke-GateStep -Name 'mcp-contained-smoke' -NpmArgs @('run','mcp:contained:smoke')
43
+
44
+ Invoke-GateStep -Name 'host-policy-refresh' -NpmArgs @('run','host:policy:init')
45
+ Invoke-GateStep -Name 'release-manifest-write' -NpmArgs @('run','manifest:write')
46
+ Invoke-GateStep -Name 'release-manifest' -NpmArgs @('run','manifest:verify')
47
+ Invoke-GateStep -Name 'doctor' -NpmArgs @('run','doctor')
48
+ Invoke-GateStep -Name 'mcp-host-smoke' -NpmArgs @('run','mcp:host:smoke')
49
+ Invoke-GateStep -Name 'authority-smoke' -NpmArgs @('run','authority:smoke')
50
+ Invoke-GateStep -Name 'release-manifest-final' -NpmArgs @('run','manifest:verify')
51
+
52
+ Write-Host '==== windows-gate-evidence ===='
53
+ $LASTEXITCODE = 0
54
+ & node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r46.mjs')
55
+ if ($LASTEXITCODE -ne 0) {
56
+ throw "DEADBYTE V0.15.2 / R46 gate failed at windows-gate-evidence with exit code $LASTEXITCODE"
57
+ }
58
+ Write-Host '==== DEADBYTE V0.15.2 / R46 FILELESS POWERSHELL WINDOWS BATCH GATE: PASS ===='
@@ -0,0 +1,2 @@
1
+ import { readFile } from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path';
2
+ const p=path.join(os.homedir(),'.deadbyte-mcp','active-release.json'); console.log(JSON.stringify({cwd:process.cwd(),state:p,active:JSON.parse(await readFile(p,'utf8'))},null,2));
@@ -0,0 +1 @@
1
+ import {spawnSync} from 'node:child_process'; const files=["test/autonomous-r34-e2e.test.mjs","test/autonomous-capability-r36.test.mjs","test/desktop-runtime-r40.test.mjs","test/coding-runtime.test.mjs"]; const r=spawnSync(process.execPath,['--test','--test-concurrency=1',...files],{stdio:'inherit',shell:false,windowsHide:true}); process.exit(r.status??1);
@@ -1,5 +1,5 @@
1
1
  import { createHash, randomBytes } from 'node:crypto';
2
- import { open, readFile, rename, rm } from 'node:fs/promises';
2
+ import { lstat, open, readFile, rename, rm } from 'node:fs/promises';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath, pathToFileURL } from 'node:url';
5
5
 
@@ -14,7 +14,35 @@ function samePath(a, b) {
14
14
  : left === right;
15
15
  }
16
16
 
17
- export async function refreshProcessPolicy({ repoRoot, policyPath }) {
17
+ async function regularPinnedExecutable(file, label) {
18
+ const info = await lstat(file);
19
+ if (!info.isFile() || info.isSymbolicLink()) throw new Error(`${label} must be a regular non-symlink file`);
20
+ return sha256(await readFile(file));
21
+ }
22
+
23
+ function resolveSystemRoot(explicit) {
24
+ const value = explicit ?? process.env.SystemRoot ?? process.env.WINDIR ?? null;
25
+ if (typeof value !== 'string' || value.length < 1) {
26
+ throw new Error('process policy Windows system profiles require SystemRoot/WINDIR');
27
+ }
28
+ return path.resolve(value);
29
+ }
30
+
31
+ async function refreshSystemProfile(policy, id, expectedExecutable) {
32
+ const profile = policy?.profiles?.[id];
33
+ if (!profile || typeof profile !== 'object' || Array.isArray(profile)) {
34
+ throw new Error(`process policy profile '${id}' missing`);
35
+ }
36
+ if (typeof profile.executable !== 'string' || !samePath(profile.executable, expectedExecutable)) {
37
+ throw new Error(`process policy profile '${id}' executable path mismatch`);
38
+ }
39
+ const digest = await regularPinnedExecutable(expectedExecutable, `process profile '${id}'`);
40
+ profile.executable = expectedExecutable;
41
+ profile.executable_sha256 = digest;
42
+ return digest;
43
+ }
44
+
45
+ export async function refreshProcessPolicy({ repoRoot, policyPath, systemRoot = null }) {
18
46
  const root = path.resolve(repoRoot);
19
47
  const file = path.resolve(policyPath);
20
48
  const rawBytes = await readFile(file);
@@ -29,9 +57,16 @@ export async function refreshProcessPolicy({ repoRoot, policyPath }) {
29
57
  if (!samePath(policy.native_host.path, expectedHost)) {
30
58
  throw new Error('process policy native_host path must equal candidate bin/deadbyte-process-host.exe');
31
59
  }
32
- const hostBytes = await readFile(expectedHost);
33
- const hostSha = sha256(hostBytes);
60
+ const hostSha = await regularPinnedExecutable(expectedHost, 'process native host');
34
61
  policy.native_host.sha256 = hostSha;
62
+
63
+ const windowsRoot = resolveSystemRoot(systemRoot);
64
+ const cmdPath = path.join(windowsRoot, 'System32', 'cmd.exe');
65
+ const powershellPath = path.join(windowsRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
66
+ const cmdSha = await refreshSystemProfile(policy, 'ping_hold', cmdPath);
67
+ const powershellSha = await refreshSystemProfile(policy, 'powershell', powershellPath);
68
+ const powershellReplSha = await refreshSystemProfile(policy, 'powershell_repl', powershellPath);
69
+
35
70
  const output = Buffer.from(`${JSON.stringify(policy, null, 2)}\n`, 'utf8');
36
71
  const temp = `${file}.tmp-${process.pid}-${randomBytes(4).toString('hex')}`;
37
72
  const handle = await open(temp, 'wx');
@@ -47,8 +82,30 @@ export async function refreshProcessPolicy({ repoRoot, policyPath }) {
47
82
  await rm(temp, { force: true }).catch(() => {});
48
83
  throw error;
49
84
  }
50
- if (sha256(await readFile(expectedHost)) !== hostSha) throw new Error('process native host changed during policy refresh');
51
- return { policy_path: file, native_host_path: expectedHost, native_host_sha256: hostSha };
85
+
86
+ if (await regularPinnedExecutable(expectedHost, 'process native host') !== hostSha) {
87
+ throw new Error('process native host changed during policy refresh');
88
+ }
89
+ if (await regularPinnedExecutable(cmdPath, "process profile 'ping_hold'") !== cmdSha) {
90
+ throw new Error("process profile 'ping_hold' changed during policy refresh");
91
+ }
92
+ if (await regularPinnedExecutable(powershellPath, "process profile 'powershell'") !== powershellSha) {
93
+ throw new Error("process profile 'powershell' changed during policy refresh");
94
+ }
95
+ if (await regularPinnedExecutable(powershellPath, "process profile 'powershell_repl'") !== powershellReplSha) {
96
+ throw new Error("process profile 'powershell_repl' changed during policy refresh");
97
+ }
98
+
99
+ return {
100
+ policy_path: file,
101
+ native_host_path: expectedHost,
102
+ native_host_sha256: hostSha,
103
+ cmd_executable: cmdPath,
104
+ cmd_executable_sha256: cmdSha,
105
+ powershell_executable: powershellPath,
106
+ powershell_executable_sha256: powershellSha,
107
+ powershell_repl_executable_sha256: powershellReplSha
108
+ };
52
109
  }
53
110
 
54
111
  const invoked = process.argv[1] && pathToFileURL(path.resolve(process.argv[1])).href === import.meta.url;
@@ -60,7 +117,7 @@ if (invoked) {
60
117
  : path.join(root, 'controller', 'deadbyte-process-policy.json');
61
118
  try {
62
119
  const result = await refreshProcessPolicy({ repoRoot: root, policyPath });
63
- console.log(`PROCESS_POLICY_REFRESH_OK sha256=${result.native_host_sha256}`);
120
+ console.log(`PROCESS_POLICY_REFRESH_OK native=${result.native_host_sha256} cmd=${result.cmd_executable_sha256} powershell=${result.powershell_executable_sha256} powershell_repl=${result.powershell_repl_executable_sha256}`);
64
121
  } catch (error) {
65
122
  console.error(`PROCESS_POLICY_REFRESH_FAIL ${error?.message ?? error}`);
66
123
  process.exitCode = 1;
@@ -27,7 +27,7 @@ const requiredBundledDependencyRoots = [
27
27
  'node_modules/zod/package.json'
28
28
  ];
29
29
  const excludedPackagePrefixes = ['tmp/','.deadbyte-machine-fs-recovery/'];
30
- const excludedPackagePaths = new Set(['controller/deadbyte-host-policy.json']);
30
+ const excludedPackagePaths = new Set(['controller/deadbyte-host-policy.json','controller/deadbyte-coding-policy.json']);
31
31
  const allowedWorkspacePayload = new Set([
32
32
  'workspaces/autonomous-live/fixture.txt',
33
33
  'workspaces/demo/input.txt'
@@ -0,0 +1,187 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, open, readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { verifyGenerationBundle } from '../src/release-generation.mjs';
7
+ import { loadProcessPolicy, processSessionStatus } from '../src/process-policy.mjs';
8
+ import { createProcessRuntime } from '../src/process-runtime.mjs';
9
+
10
+ const here=path.dirname(fileURLToPath(import.meta.url));
11
+ const packageRoot=path.resolve(here,'..');
12
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
13
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
14
+ const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
15
+ function insist(ok,message){if(!ok)throw new Error(message);}
16
+ function samePath(a,b){return path.resolve(String(a)).toLowerCase()===path.resolve(String(b)).toLowerCase();}
17
+
18
+ async function waitForExit(runtime,sessionId,timeoutMs=10000){
19
+ const deadline=Date.now()+timeoutMs;
20
+ let page=null,text='';
21
+ while(Date.now()<deadline){
22
+ page=await runtime.read({sessionId,offset:0,maxBytes:65536});
23
+ text=Buffer.from(page.data_base64,'base64').toString('utf8');
24
+ if(page.state==='exited'||page.state==='terminated') return {page,text};
25
+ await sleep(50);
26
+ }
27
+ throw new Error('R46 PowerShell parity timed out');
28
+ }
29
+
30
+ export async function runReleaseParity({
31
+ root=packageRoot,
32
+ runtimeStateRoot=stateRoot,
33
+ clock=()=>new Date()
34
+ }={}){
35
+ const candidate=path.resolve(root);
36
+ const state=path.resolve(runtimeStateRoot);
37
+ const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
38
+ const manifestSha256=sha256(manifestBytes);
39
+ const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
40
+ insist(pkg.version==='0.15.2','R46 parity requires package version 0.15.2');
41
+
42
+ const pointer=JSON.parse(await readFile(path.join(state,'active-release.json'),'utf8'));
43
+ insist(pointer.version==='0.15.2'&&pointer.manifest_sha256===manifestSha256,'R46 active pointer candidate mismatch');
44
+ insist(pointer.release_id===`v0.15.2-${manifestSha256.slice(0,16)}`,'R46 active release id mismatch');
45
+ const releaseManifest=await readFile(path.join(pointer.release_root,'MANIFEST.SHA256'));
46
+ insist(sha256(releaseManifest)===manifestSha256,'R46 immutable release manifest mismatch');
47
+
48
+ const generation=await verifyGenerationBundle(pointer.generation_root,pointer.generation_manifest_sha256);
49
+ const processPolicyPath=path.join(pointer.generation_root,'process-policy.json');
50
+ const policy=await loadProcessPolicy(processPolicyPath);
51
+ const status=await processSessionStatus(policy);
52
+ insist(status.armed===true&&status.reason==='standing-grant','R46 parity requires restored Process standing grant');
53
+ insist(status.profile_ids.includes('powershell')&&status.root_ids.includes('core'),'R46 parity Process grant missing powershell/core');
54
+
55
+ const systemRoot=process.env.SystemRoot||process.env.WINDIR;
56
+ insist(typeof systemRoot==='string'&&systemRoot.length>0,'R46 parity requires SystemRoot/WINDIR');
57
+ const expectedPowerShell=path.join(systemRoot,'System32','WindowsPowerShell','v1.0','powershell.exe');
58
+ const expectedCmd=path.join(systemRoot,'System32','cmd.exe');
59
+ insist(samePath(policy.profiles?.powershell?.executable,expectedPowerShell),'R46 generated PowerShell path is not target-bound');
60
+ insist(samePath(policy.profiles?.ping_hold?.executable,expectedCmd),'R46 generated cmd path is not target-bound');
61
+ insist(policy.profiles.powershell.executable_sha256===sha256(await readFile(expectedPowerShell)),'R46 generated PowerShell digest mismatch');
62
+ insist(policy.profiles.ping_hold.executable_sha256===sha256(await readFile(expectedCmd)),'R46 generated cmd digest mismatch');
63
+ insist(JSON.stringify(policy.profiles.powershell.prefix_args)===JSON.stringify(['-NoLogo','-NoProfile','-NonInteractive','-Command']),'R46 PowerShell prefix contract mismatch');
64
+ insist(policy.profiles.powershell.max_args===1&&policy.profiles.powershell.max_arg_bytes===8192,'R46 PowerShell argument bounds mismatch');
65
+
66
+ const runtime=createProcessRuntime({
67
+ policy,
68
+ signingKeyPath:path.join(state,'trust','ed25519-private.pem'),
69
+ verifyKeyPath:path.join(state,'trust','ed25519-public.pem')
70
+ });
71
+ const source="$ErrorActionPreference='Stop';$before=@(Get-ChildItem -LiteralPath $env:TEMP -Filter '*.ps1' -File -ErrorAction SilentlyContinue|ForEach-Object{$_.FullName});[Console]::WriteLine('DB_R46_FILELESS_PARITY');[Console]::WriteLine('PSCommandPath=' + [string]$PSCommandPath);[Console]::WriteLine('InvocationPath=' + [string]$MyInvocation.MyCommand.Path);$after=@(Get-ChildItem -LiteralPath $env:TEMP -Filter '*.ps1' -File -ErrorAction SilentlyContinue|ForEach-Object{$_.FullName});$new=@($after|Where-Object{$_ -notin $before});[Console]::WriteLine('NEW_TEMP_PS1_COUNT=' + $new.Count)";
72
+ const started=await runtime.start({profileId:'powershell',rootId:'core',cwd:'.',args:[source]});
73
+ const observed=await waitForExit(runtime,started.session_id);
74
+ insist(observed.page.state==='exited'&&observed.page.exit_code===0,'R46 PowerShell parity process did not exit cleanly');
75
+ insist(/DB_R46_FILELESS_PARITY/.test(observed.text),'R46 PowerShell parity marker missing');
76
+ insist(/PSCommandPath=\r?\n/.test(observed.text),'R46 PowerShell unexpectedly materialized PSCommandPath');
77
+ insist(/InvocationPath=\r?\n/.test(observed.text),'R46 PowerShell invocation path is not fileless');
78
+ insist(/NEW_TEMP_PS1_COUNT=0/.test(observed.text),'R46 PowerShell parity created a temp ps1');
79
+ const journal=await runtime.verifyEventJournal({sessionId:started.session_id});
80
+ insist(journal.ok===true,'R46 PowerShell process journal verification failed');
81
+
82
+
83
+ insist(status.profile_ids.includes('powershell_repl'),'R46 parity Process grant missing powershell_repl');
84
+ insist(samePath(policy.profiles?.powershell_repl?.executable,expectedPowerShell),'R46 generated PowerShell REPL path is not target-bound');
85
+ insist(policy.profiles.powershell_repl.executable_sha256===sha256(await readFile(expectedPowerShell)),'R46 generated PowerShell REPL digest mismatch');
86
+ insist(policy.profiles.powershell_repl.allow_raw_input===true&&policy.profiles.powershell_repl.transport==='pipe','R46 PowerShell REPL raw-input contract mismatch');
87
+
88
+ const repl=await runtime.start({profileId:'powershell_repl',rootId:'core',cwd:'.',args:[]});
89
+ const firstWrite=await runtime.write({sessionId:repl.session_id,input:"$x=41;[Console]::WriteLine('DB_R46_REPL_SET')",appendNewline:true});
90
+ insist(firstWrite.session.state==='running','R46 PowerShell REPL did not remain running after first write');
91
+ const firstRead=await runtime.read({sessionId:repl.session_id,offset:0,maxBytes:65536,waitMs:5000,waitFor:'DB_R46_REPL_SET'});
92
+ insist(firstRead.wait_satisfied===true,'R46 PowerShell REPL first wait was not satisfied');
93
+ const beforeSecond=(await runtime.status({sessionId:repl.session_id})).stream_head;
94
+ await runtime.write({sessionId:repl.session_id,input:"[Console]::WriteLine('DB_R46_REPL_VALUE=' + ($x+1))",appendNewline:true});
95
+ const secondRead=await runtime.read({sessionId:repl.session_id,offset:beforeSecond,maxBytes:65536,waitMs:5000,waitFor:'DB_R46_REPL_VALUE=42'});
96
+ const secondText=Buffer.from(secondRead.data_base64,'base64').toString('utf8');
97
+ insist(secondRead.wait_satisfied===true&&/DB_R46_REPL_VALUE=42/.test(secondText),'R46 PowerShell REPL state did not persist across writes');
98
+ const tailRead=await runtime.read({sessionId:repl.session_id,offset:-4096,maxBytes:4096});
99
+ insist(/DB_R46_REPL_VALUE=42/.test(Buffer.from(tailRead.data_base64,'base64').toString('utf8')),'R46 PowerShell REPL tail read missing state proof');
100
+ await runtime.terminate({sessionId:repl.session_id});
101
+ const replJournal=await runtime.verifyEventJournal({sessionId:repl.session_id});
102
+ insist(replJournal.ok===true,'R46 PowerShell REPL journal verification failed');
103
+ const replJournalText=await readFile(path.join(policy.state_dir,`${repl.session_id}.jsonl`),'utf8');
104
+ insist(!replJournalText.includes('$x=41')&&!replJournalText.includes('DB_R46_REPL_VALUE'),'R46 raw process input leaked into signed journal');
105
+
106
+ const ringSource="[Console]::Write(('A'*2097152));[Console]::WriteLine('DB_R46_RING_TAIL')";
107
+ const ring=await runtime.start({profileId:'powershell',rootId:'core',cwd:'.',args:[ringSource]});
108
+ const ringObserved=await waitForExit(runtime,ring.session_id,15000);
109
+ const ringStatus=await runtime.status({sessionId:ring.session_id});
110
+ insist(ringObserved.page.exit_code===0&&ringStatus.earliest_offset>0,'R46 retained-output ring did not evict under heavy output');
111
+ const ringTail=await runtime.read({sessionId:ring.session_id,offset:-4096,maxBytes:4096});
112
+ insist(/DB_R46_RING_TAIL/.test(Buffer.from(ringTail.data_base64,'base64').toString('utf8')),'R46 retained-output ring lost tail marker');
113
+
114
+ const completed=clock();
115
+ insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'R46 parity clock invalid');
116
+ const evidence={
117
+ schema:'deadbyte.r46-parity.v1',
118
+ status:'passed',
119
+ version:'0.15.2',
120
+ completed_at_utc:completed.toISOString(),
121
+ candidate:{
122
+ release_id:pointer.release_id,
123
+ manifest_sha256:pointer.manifest_sha256,
124
+ generation_manifest_sha256:pointer.generation_manifest_sha256
125
+ },
126
+ generation:{files:generation.files,generation_manifest_sha256:generation.generation_manifest_sha256},
127
+ process_policy:{
128
+ sha256:policy.policy_sha256,
129
+ profile_ids:Object.keys(policy.profiles).sort(),
130
+ powershell_executable:policy.profiles.powershell.executable,
131
+ powershell_executable_sha256:policy.profiles.powershell.executable_sha256,
132
+ cmd_executable:policy.profiles.ping_hold.executable,
133
+ cmd_executable_sha256:policy.profiles.ping_hold.executable_sha256,
134
+ target_repin_verified:true
135
+ },
136
+ fileless_powershell:{
137
+ session_id:started.session_id,
138
+ child_pid:started.child_pid,
139
+ exit_code:observed.page.exit_code,
140
+ stream_sha256:observed.page.stream_sha256,
141
+ pscommandpath_empty:true,
142
+ invocation_path_empty:true,
143
+ new_temp_ps1_count:0,
144
+ journal_head_sha256:journal.head_sha256,
145
+ journal_event_count:journal.event_count
146
+ },
147
+ persistent_powershell_repl:{
148
+ session_id:repl.session_id,
149
+ child_pid:repl.child_pid,
150
+ state_persisted:true,
151
+ observed_value:42,
152
+ wait_for_verified:true,
153
+ tail_read_verified:true,
154
+ raw_input_not_journaled:true,
155
+ journal_head_sha256:replJournal.head_sha256,
156
+ journal_event_count:replJournal.event_count
157
+ },
158
+ retained_output_ring:{
159
+ session_id:ring.session_id,
160
+ stream_head:ringStatus.stream_head,
161
+ earliest_offset:ringStatus.earliest_offset,
162
+ eviction_verified:true,
163
+ tail_marker_verified:true
164
+ },
165
+ execution_provider:'deadbyte_mcp',
166
+ rdc_operation_count:0
167
+ };
168
+ const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
169
+ const dir=path.join(state,'evidence','release');
170
+ await mkdir(dir,{recursive:true});
171
+ const file=path.join(dir,`r46-parity-${manifestSha256.slice(0,16)}.json`);
172
+ try{
173
+ const handle=await open(file,'wx',0o600);
174
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
175
+ return {status:'written',evidence_path:file,evidence_sha256:sha256(bytes),evidence};
176
+ }catch(error){
177
+ if(error?.code!=='EEXIST')throw error;
178
+ const existingBytes=await readFile(file);
179
+ const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
180
+ insist(existing.schema===evidence.schema&&existing.status==='passed','existing R46 parity evidence invalid');
181
+ insist(existing.candidate?.manifest_sha256===manifestSha256,'existing R46 parity candidate mismatch');
182
+ return {status:'existing',evidence_path:file,evidence_sha256:sha256(existingBytes),evidence:existing};
183
+ }
184
+ }
185
+
186
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
187
+ if(invoked)runReleaseParity().then(value=>console.log(JSON.stringify(value))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
@@ -0,0 +1,7 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { openSync } from 'node:fs';
3
+ const out=openSync('proof/r46-full-regression-background.log','w');
4
+ const err=openSync('proof/r46-full-regression-background.err.log','w');
5
+ const p=spawn(process.execPath,['scripts/full-regression-r46.mjs'],{cwd:process.cwd(),detached:true,stdio:['ignore',out,err],windowsHide:true});
6
+ p.unref();
7
+ console.log(JSON.stringify({pid:p.pid}));
@@ -0,0 +1,6 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { writeFile } from 'node:fs/promises';
3
+ const child=spawn('powershell.exe',['-NoProfile','-ExecutionPolicy','Bypass','-File','scripts/gate-windows-r46.ps1'],{cwd:process.cwd(),detached:true,stdio:'ignore',windowsHide:true});
4
+ await writeFile('proof/r46-windows-gate-background.pid.json',JSON.stringify({pid:child.pid,started_at_utc:new Date().toISOString()}));
5
+ child.unref();
6
+ console.log(JSON.stringify({status:'started',pid:child.pid}));
@@ -0,0 +1,10 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ $root = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
3
+ $log = Join-Path $root 'proof/r46-windows-gate-background.log'
4
+ $err = Join-Path $root 'proof/r46-windows-gate-background.err.log'
5
+ $done = Join-Path $root 'proof/r46-windows-gate-background.done'
6
+ Remove-Item -LiteralPath $done -Force -ErrorAction SilentlyContinue
7
+ Remove-Item -LiteralPath $log -Force -ErrorAction SilentlyContinue
8
+ Remove-Item -LiteralPath $err -Force -ErrorAction SilentlyContinue
9
+ $p = Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile','-ExecutionPolicy','Bypass','-File',(Join-Path $PSScriptRoot 'gate-windows-r46.ps1')) -WorkingDirectory $root -RedirectStandardOutput $log -RedirectStandardError $err -PassThru
10
+ @{ pid=$p.Id; started_at_utc=(Get-Date).ToUniversalTime().ToString('o') } | ConvertTo-Json -Compress | Set-Content -LiteralPath $done -Encoding utf8