deadbyte-mcp 0.15.0 → 0.15.2
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 +109 -64
- package/PROVENANCE.json +11 -0
- package/R45-PARENT.json +18 -0
- package/README.txt +36 -20
- package/RELEASE.json +53 -0
- package/SBOM.cdx.json +46 -0
- package/TEST-MATRIX.json +31 -0
- package/bin/deadbyte-hardware-observer-r45.exe +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/controller/README.TXT +2 -2
- package/controller/deadbyte-controller.ps1 +51 -3
- package/controller/deadbyte-process-policy.json +63 -1
- package/docs/ARCHITECTURE.md +3 -4
- package/native/deadbyte-hardware-observer.cpp +308 -0
- package/package.json +14 -7
- package/scripts/autonomous-tests.ps1 +2 -2
- package/scripts/build-hardware-r45.ps1 +71 -0
- package/scripts/deferred-slot-operation-r45.mjs +126 -0
- package/scripts/deferred-slot-operation-r46.mjs +126 -0
- package/scripts/derive-r45-parent.mjs +24 -0
- package/scripts/derive-r45-release.mjs +72 -0
- package/scripts/derive-r45-tests.mjs +20 -0
- package/scripts/final-closure-r45.mjs +121 -0
- package/scripts/final-closure-r46.mjs +98 -0
- package/scripts/final-closure-verify-r45.mjs +220 -0
- package/scripts/final-closure-verify-r46.mjs +119 -0
- package/scripts/finalize-r45.mjs +219 -0
- package/scripts/full-regression-r45.mjs +20 -0
- package/scripts/full-regression-r46.mjs +20 -0
- package/scripts/full-regression-summary-r45.mjs +14 -0
- package/scripts/gate-windows-r45.ps1 +44 -0
- package/scripts/gate-windows-r46.ps1 +56 -0
- package/scripts/init-host-policy.ps1 +39 -1
- package/scripts/inspect-active-release-r45.mjs +20 -0
- package/scripts/refresh-process-policy.mjs +64 -7
- package/scripts/release-manifest.mjs +3 -1
- package/scripts/release-parity-r45.mjs +253 -0
- package/scripts/release-parity-r46.mjs +187 -0
- package/scripts/release-parity-tests-r45.ps1 +8 -0
- package/scripts/verify-r45-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r45.mjs +60 -0
- package/scripts/windows-gate-evidence-r46.mjs +110 -0
- package/src/autonomous-runtime.mjs +12 -7
- package/src/capability-ledger.mjs +2 -0
- package/src/compact-gateway-mcp-tools.mjs +11 -7
- package/src/deadbyte-cli.mjs +24 -12
- package/src/doctor-r45.mjs +65 -0
- package/src/host-plane.mjs +133 -85
- package/src/machine-fs-mcp-tools.mjs +3 -3
- package/src/machine-fs-output-contracts.mjs +1 -1
- package/src/machine-fs-read-worker.mjs +46 -0
- package/src/machine-fs.mjs +63 -10
- package/src/mcp-server.mjs +68 -23
- package/src/mcp-smoke-client.mjs +4 -1
- package/src/native-diff-v2.mjs +9 -4
- package/src/native-diff.mjs +29 -7
- package/src/observation-mcp-tools.mjs +5 -1
- package/src/observation-output-contracts.mjs +8 -0
- package/src/observation-runtime.mjs +57 -5
- package/src/observation-smoke-client.mjs +6 -2
- package/src/output-contracts.mjs +27 -11
- package/src/process-mcp-tools.mjs +18 -5
- package/src/process-output-contracts.mjs +20 -3
- package/src/process-policy.mjs +3 -1
- package/src/process-runtime.mjs +99 -19
- package/src/process-smoke-client.mjs +67 -22
- package/src/r45-compact-disarmed-probe.mjs +74 -0
- package/src/r45-full-surface-probe.mjs +34 -0
- package/src/release-generation.mjs +23 -3
- package/src/remote-device-r44.mjs +53 -15
- package/src/remote-mcp-r45-parity-client.mjs +206 -0
- package/src/remote-mcp-smoke-client.mjs +1 -1
- package/src/runtime-update.mjs +36 -8
- package/src/stdio-console-guard.mjs +24 -0
- package/src/version.mjs +1 -1
- package/test/agent-runtime.test.mjs +1 -0
- package/test/autonomous-loop.test.mjs +24 -0
- package/test/autonomous-runtime.test.mjs +1 -0
- package/test/cli-entrypoint.test.mjs +4 -4
- package/test/coding-plane.test.mjs +1 -0
- package/test/compact-gateway-r36.test.mjs +28 -0
- package/test/compact-max-catalog-r45.test.mjs +99 -0
- package/test/contained.test.mjs +23 -11
- package/test/controller.test.mjs +5 -1
- package/test/core.test.mjs +1 -1
- package/test/full-max-catalog-r45.test.mjs +91 -0
- package/test/full-max-catalog-r46.test.mjs +92 -0
- package/test/hardware-observation-r45.test.mjs +44 -0
- package/test/host-inline-r45.test.mjs +67 -0
- package/test/machine-fs-mcp-tools.test.mjs +4 -1
- package/test/machine-fs-runtime.test.mjs +18 -2
- package/test/machine-mcp-integration.test.mjs +1 -0
- package/test/observation-mcp-tools.test.mjs +4 -3
- package/test/observation-runtime.test.mjs +29 -2
- package/test/output-schema.test.mjs +1 -0
- package/test/package-boundary.test.mjs +1 -1
- package/test/process-mcp-tools.test.mjs +23 -5
- package/test/process-policy-refresh.test.mjs +87 -10
- package/test/process-runtime.test.mjs +111 -1
- package/test/process-supervision.test.mjs +4 -2
- package/test/production-docs.test.mjs +3 -3
- package/test/r33-closeout-regression.test.mjs +20 -19
- package/test/r33-finalization.test.mjs +3 -3
- package/test/r45-autonomous-quick-test.test.mjs +10 -0
- package/test/r45-finalization.test.mjs +84 -0
- package/test/release-generation.test.mjs +26 -11
- package/test/release-version.test.mjs +112 -46
- package/test/remote-device-r44.test.mjs +75 -0
- package/test/remote-r24-catalog.test.mjs +2 -2
- package/test/runtime-host-bootstrap-r45.test.mjs +46 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createHash, createPublicKey, randomBytes } from 'node:crypto';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { parseActivePointer } from '../src/release-slot.mjs';
|
|
8
|
+
import { loadPowerShellDataFile, runSlotUpdateCli, verifySlotUpdateEnvelope } from '../src/runtime-update.mjs';
|
|
9
|
+
|
|
10
|
+
const HEX64=/^[0-9a-f]{64}$/;
|
|
11
|
+
const RECEIPT_ID=/^r27-[A-Za-z0-9-]+$/;
|
|
12
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const packageRoot=path.resolve(here,'..');
|
|
14
|
+
const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
15
|
+
const evidenceRoot=path.join(stateRoot,'evidence','deferred-slot-operations');
|
|
16
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
17
|
+
const atomicJson=async(file,value)=>{
|
|
18
|
+
await mkdir(path.dirname(file),{recursive:true});
|
|
19
|
+
const temp=`${file}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
|
|
20
|
+
await writeFile(temp,`${JSON.stringify(value,null,2)}\n`,{flag:'wx'});
|
|
21
|
+
await import('node:fs/promises').then(fs=>fs.rename(temp,file));
|
|
22
|
+
};
|
|
23
|
+
function activationArgs(manifestSha){
|
|
24
|
+
if(!HEX64.test(manifestSha??'')) throw new Error('activate requires one lowercase manifest SHA-256');
|
|
25
|
+
return ['--stage',packageRoot,'--development-root',packageRoot,'--expected-version','0.15.2',
|
|
26
|
+
'--expected-manifest',manifestSha,'--process-policy',path.join(packageRoot,'controller','deadbyte-process-policy.json'),
|
|
27
|
+
'--process-policy-sha256',null,'--desktop-policy',path.join(packageRoot,'controller','deadbyte-desktop-policy.json'),
|
|
28
|
+
'--desktop-policy-sha256',null,'--semantic-lsp-config',path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json'),
|
|
29
|
+
'--semantic-lsp-config-sha256',null,'--enable-machine-fs','--enable-observation','--enable-desktop','--enable-autonomous-supervisor'];
|
|
30
|
+
}
|
|
31
|
+
async function bridgeBootstrapArgs(explicitBridgeRoot=null,explicitBridgeSha256=null){
|
|
32
|
+
const hasRoot=typeof explicitBridgeRoot==='string'&&explicitBridgeRoot.length>0;
|
|
33
|
+
const hasSha=typeof explicitBridgeSha256==='string'&&explicitBridgeSha256.length>0;
|
|
34
|
+
if(hasRoot!==hasSha) throw new Error('bridge override requires exact root + SHA pair');
|
|
35
|
+
let bridgeRootRaw,expectedSha256=null;
|
|
36
|
+
if(hasRoot){
|
|
37
|
+
if(!path.isAbsolute(explicitBridgeRoot)||!HEX64.test(explicitBridgeSha256)) throw new Error('bridge override requires exact root + SHA pair');
|
|
38
|
+
bridgeRootRaw=explicitBridgeRoot;expectedSha256=explicitBridgeSha256;
|
|
39
|
+
}else{
|
|
40
|
+
const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
|
|
41
|
+
const config=await loadPowerShellDataFile(pointer.config_path);
|
|
42
|
+
bridgeRootRaw=config?.Bridge?.WorkingDirectory;
|
|
43
|
+
if(typeof bridgeRootRaw!=='string'||!path.isAbsolute(bridgeRootRaw)) throw new Error('active controller Bridge.WorkingDirectory must be absolute');
|
|
44
|
+
}
|
|
45
|
+
const bridgeRoot=await realpath(path.resolve(bridgeRootRaw));
|
|
46
|
+
const packageFile=path.join(bridgeRoot,'package.json');
|
|
47
|
+
const bridgeScript=path.join(bridgeRoot,'src','bridge.mjs');
|
|
48
|
+
const pkg=JSON.parse(await readFile(packageFile,'utf8'));
|
|
49
|
+
if(pkg?.name!=='deadbyte-chatgpt-bridge') throw new Error('active Bridge package identity mismatch');
|
|
50
|
+
const scriptSha256=sha256(await readFile(bridgeScript));
|
|
51
|
+
if(expectedSha256&&scriptSha256!==expectedSha256) throw new Error('bridge override SHA-256 mismatch');
|
|
52
|
+
return ['--bridge-root',bridgeRoot,'--bridge-script-sha256',scriptSha256];
|
|
53
|
+
}
|
|
54
|
+
async function rollbackArgs(receiptPath){
|
|
55
|
+
const resolved=await realpath(path.resolve(receiptPath));
|
|
56
|
+
const allowed=path.join(stateRoot,'evidence','updates')+path.sep;
|
|
57
|
+
if(!resolved.startsWith(allowed)||path.basename(resolved).toLowerCase()!=='receipt.json'||!RECEIPT_ID.test(path.basename(path.dirname(resolved)))) {
|
|
58
|
+
throw new Error('rollback receipt must be one signed activation receipt under the update evidence store');
|
|
59
|
+
}
|
|
60
|
+
const envelope=JSON.parse(await readFile(resolved,'utf8'));
|
|
61
|
+
const publicKey=createPublicKey(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
|
|
62
|
+
if(!verifySlotUpdateEnvelope(envelope,publicKey)||envelope.body?.rollback_performed!==false) throw new Error('rollback activation receipt verification failed');
|
|
63
|
+
const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
|
|
64
|
+
if(pointer.release_id!==envelope.body?.active_pointer?.release_id||pointer.generation_root!==envelope.body?.active_pointer?.generation_root) {
|
|
65
|
+
throw new Error('rollback receipt does not identify the active release generation');
|
|
66
|
+
}
|
|
67
|
+
return ['--rollback-receipt',resolved];
|
|
68
|
+
}
|
|
69
|
+
async function normalizedArgs(mode,value,{explicitBridgeRoot=null,explicitBridgeSha256=null}={}){
|
|
70
|
+
if(mode==='activate'){
|
|
71
|
+
const args=activationArgs(value);
|
|
72
|
+
args[args.indexOf('--process-policy-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-process-policy.json')));
|
|
73
|
+
args[args.indexOf('--desktop-policy-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-desktop-policy.json')));
|
|
74
|
+
args[args.indexOf('--semantic-lsp-config-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json')));
|
|
75
|
+
args.push(...await bridgeBootstrapArgs(explicitBridgeRoot,explicitBridgeSha256));
|
|
76
|
+
return args;
|
|
77
|
+
}
|
|
78
|
+
if(mode==='rollback'){
|
|
79
|
+
if(explicitBridgeRoot||explicitBridgeSha256) throw new Error('rollback does not accept bridge override');
|
|
80
|
+
return rollbackArgs(value);
|
|
81
|
+
}
|
|
82
|
+
throw new Error("operation must be exactly 'activate' or 'rollback'");
|
|
83
|
+
}
|
|
84
|
+
const rawArgs=process.argv.slice(2);
|
|
85
|
+
const mode=rawArgs[0],value=rawArgs[1];
|
|
86
|
+
if(!value||!['activate','rollback'].includes(mode)) throw new Error('usage: deferred-slot-operation-r46.mjs <activate manifest_sha256|rollback activation_receipt> [--bridge-root ABS --bridge-script-sha256 HEX64]');
|
|
87
|
+
let cursor=2,explicitBridgeRoot=null,explicitBridgeSha256=null;
|
|
88
|
+
if(rawArgs[cursor]==='--bridge-root'){
|
|
89
|
+
explicitBridgeRoot=rawArgs[cursor+1]??null;
|
|
90
|
+
if(rawArgs[cursor+2]!=='--bridge-script-sha256') throw new Error('bridge override requires exact root + SHA pair');
|
|
91
|
+
explicitBridgeSha256=rawArgs[cursor+3]??null;cursor+=4;
|
|
92
|
+
}
|
|
93
|
+
let workerFlag=null,operationIdArg=null;
|
|
94
|
+
if(rawArgs[cursor]==='--worker'){workerFlag='--worker';operationIdArg=rawArgs[cursor+1]??null;cursor+=2;}
|
|
95
|
+
if(cursor!==rawArgs.length) throw new Error('deferred slot operation arguments invalid');
|
|
96
|
+
if((explicitBridgeRoot===null)!==(explicitBridgeSha256===null)) throw new Error('bridge override requires exact root + SHA pair');
|
|
97
|
+
if(mode==='rollback'&&(explicitBridgeRoot||explicitBridgeSha256)) throw new Error('rollback does not accept bridge override');
|
|
98
|
+
if(workerFlag==='--worker'){
|
|
99
|
+
if(!/^[0-9a-f]{32}$/.test(operationIdArg??'')) throw new Error('deferred worker operation id invalid');
|
|
100
|
+
const statePath=path.join(evidenceRoot,`${operationIdArg}.json`);
|
|
101
|
+
await new Promise(resolve=>setTimeout(resolve,4000));
|
|
102
|
+
await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'running',started_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
|
|
103
|
+
try{
|
|
104
|
+
const args=await normalizedArgs(mode,value,{explicitBridgeRoot,explicitBridgeSha256});
|
|
105
|
+
const result=await runSlotUpdateCli(args,{stateRoot});
|
|
106
|
+
await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'completed',
|
|
107
|
+
completed_at_utc:new Date().toISOString(),receipt_path:result.receipt_path,receipt_sha256:result.receipt_sha256,
|
|
108
|
+
active_release:result.pointer.release_id,generation_root:result.pointer.generation_root,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
|
|
109
|
+
}catch(error){
|
|
110
|
+
await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'failed',
|
|
111
|
+
completed_at_utc:new Date().toISOString(),error:String(error?.message??error),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
|
|
112
|
+
process.exitCode=1;
|
|
113
|
+
}
|
|
114
|
+
}else{
|
|
115
|
+
const operationId=randomBytes(16).toString('hex');
|
|
116
|
+
const statePath=path.join(evidenceRoot,`${operationId}.json`);
|
|
117
|
+
await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationId,mode,state:'scheduled',scheduled_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
|
|
118
|
+
const workerArgs=[fileURLToPath(import.meta.url),mode,value];
|
|
119
|
+
if(explicitBridgeRoot) workerArgs.push('--bridge-root',explicitBridgeRoot,'--bridge-script-sha256',explicitBridgeSha256);
|
|
120
|
+
workerArgs.push('--worker',operationId);
|
|
121
|
+
const child=spawn(process.execPath,workerArgs,{
|
|
122
|
+
cwd:packageRoot,detached:true,stdio:'ignore',windowsHide:true,env:{...process.env,DEADBYTE_STATE_ROOT:stateRoot}
|
|
123
|
+
});
|
|
124
|
+
child.unref();
|
|
125
|
+
console.log(JSON.stringify({status:'scheduled',operation_id:operationId,mode,state_path:statePath,execution_provider:'deadbyte_mcp',rdc_operation_count:0,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256}));
|
|
126
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
5
|
+
const must=(text,from,to,label)=>{
|
|
6
|
+
if(!text.includes(from)) throw new Error(`derive missing ${label}: ${from}`);
|
|
7
|
+
return text.split(from).join(to);
|
|
8
|
+
};
|
|
9
|
+
let s=await readFile(path.join(root,'scripts','verify-r44-parent.mjs'),'utf8');
|
|
10
|
+
s=s.split('R44').join('R45').split('r44').join('r45');
|
|
11
|
+
for(const [from,to,label] of [
|
|
12
|
+
['DEADBYTE-R43-FINAL-CLOSURE-V1','DEADBYTE-R44-FINAL-CLOSURE-V1','closure domain'],
|
|
13
|
+
['v0.14.1-0a5a833892593283','v0.15.0-c15fa41719be61b3','parent release'],
|
|
14
|
+
["'0.14.1'","'0.15.0'",'parent version'],
|
|
15
|
+
['0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9','c15fa41719be61b3186e49b2367a5f4c057365cfb465102dbefb7d7355f45483','parent manifest'],
|
|
16
|
+
['===1834','===1871','parent file count'],
|
|
17
|
+
['fcfcb5a47d55039b7bb5d42faa0739b57b13d8a420d4418ae09d96d2862967cb','6d7429c050b7fe893492e102f00282019116e0c9e54e4f25a5791defa1661d30','parent generation'],
|
|
18
|
+
['f24100212b55d2016ea9c4ff47df5f026c8edc0b9b8643933ed8bf26fde3803f','8aa9c31ab18dfde67275d7cd59295ba08099839d35d6c97ee277fb184c05cae0','parent closure file'],
|
|
19
|
+
['2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b','533b7e0ff9ded04086dd90ed34e3b87bc427acc3c55c25bb9f4ec66cb448e667','parent closure'],
|
|
20
|
+
['deadbyte.r43-final-closure.v1','deadbyte.r44-final-closure.v1','closure schema'],
|
|
21
|
+
['R43 AUTHORITY HARDENING PATCH','R44 REMOTE AGENT SKILL BASELINE','closure label'],
|
|
22
|
+
['deadbyte.r43-parity.v1','deadbyte.r44-parity.v1','parity schema']
|
|
23
|
+
]) s=must(s,from,to,label);
|
|
24
|
+
await writeFile(path.join(root,'scripts','verify-r45-parent.mjs'),s,'utf8');
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
5
|
+
const oldRelease='v0.14.1-0a5a833892593283';
|
|
6
|
+
const oldManifest='0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9';
|
|
7
|
+
const oldClosure='2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b';
|
|
8
|
+
const parentRelease='v0.15.0-c15fa41719be61b3';
|
|
9
|
+
const parentManifest='c15fa41719be61b3186e49b2367a5f4c057365cfb465102dbefb7d7355f45483';
|
|
10
|
+
const parentClosure='533b7e0ff9ded04086dd90ed34e3b87bc427acc3c55c25bb9f4ec66cb448e667';
|
|
11
|
+
async function derive(src,dst,mutate){
|
|
12
|
+
let s=await readFile(path.join(root,src),'utf8');
|
|
13
|
+
s=s.split('R44').join('R45').split('r44').join('r45').split('0.15.0').join('0.15.1');
|
|
14
|
+
s=mutate?s=mutate(s):s;
|
|
15
|
+
await writeFile(path.join(root,dst),s,'utf8');
|
|
16
|
+
}
|
|
17
|
+
await derive('src/remote-mcp-r44-parity-client.mjs','src/remote-mcp-r45-parity-client.mjs',s=>{
|
|
18
|
+
s=s.replace("'desktop_status','desktop_observe','desktop_target','desktop_action','skill_catalog'","'desktop_status','desktop_observe','desktop_target','desktop_action','skill_catalog','machine_hardware_query'");
|
|
19
|
+
s=s.replace('R45_EXPECTED_TOOLS.length !== 81','R45_EXPECTED_TOOLS.length !== 82');
|
|
20
|
+
s=s.replace("const testScript='scripts/release-parity-tests-r40.ps1';","const testScript='scripts/release-parity-tests-r45.ps1';");
|
|
21
|
+
const needle=" const system=gateway(await client.callTool({name:'machine_observe',arguments:{op:'system_status'}}),'system status');\n observationReceipts.push(system.receipt_id);await verifyObservationReceipt(policy,system.receipt_id);";
|
|
22
|
+
const add=needle+"\n const hardware=gateway(await client.callTool({name:'machine_observe',arguments:{op:'hardware_query',query:'cpu'}}),'hardware query');\n if(hardware.query!=='cpu'||!hardware.data||typeof hardware.data!=='object'||!/^[0-9a-f]{64}$/.test(String(hardware.observer_sha256??''))) throw new Error('R45 native hardware observation malformed');\n observationReceipts.push(hardware.receipt_id);await verifyObservationReceipt(policy,hardware.receipt_id);";
|
|
23
|
+
if(!s.includes(needle)) throw new Error('R45 compact parity hardware insertion point missing');
|
|
24
|
+
s=s.replace(needle,add);
|
|
25
|
+
s=s.replace("observation_search_result_count:page.results.length,process_session_id:processSession","observation_search_result_count:page.results.length,native_hardware_query_verified:true,hardware_observer_sha256:hardware.observer_sha256,process_session_id:processSession");
|
|
26
|
+
return s;
|
|
27
|
+
});
|
|
28
|
+
await derive('src/r44-full-surface-probe.mjs','src/r45-full-surface-probe.mjs');
|
|
29
|
+
await derive('src/r44-compact-disarmed-probe.mjs','src/r45-compact-disarmed-probe.mjs');
|
|
30
|
+
await derive('scripts/deferred-slot-operation-r44.mjs','scripts/deferred-slot-operation-r45.mjs');
|
|
31
|
+
await derive('scripts/full-regression-r44.mjs','scripts/full-regression-r45.mjs');
|
|
32
|
+
await derive('scripts/release-parity-r44.mjs','scripts/release-parity-r45.mjs',s=>{
|
|
33
|
+
s=s.split(oldRelease).join(parentRelease).split(oldManifest).join(parentManifest);
|
|
34
|
+
s=s.replace("import { probeR40CompactDisarmed } from '../src/r40-compact-disarmed-probe.mjs';","import { probeR44CompactDisarmed as probeR44PredecessorDisarmed } from '../src/r44-compact-disarmed-probe.mjs';");
|
|
35
|
+
s=s.replaceAll('publicR43PredecessorDisarmed','publicR44PredecessorDisarmed').replaceAll('probeR40CompactDisarmed(url)','probeR44PredecessorDisarmed(url)');
|
|
36
|
+
s=s.replaceAll('R43 predecessor','R44 predecessor').replaceAll('exact R43 predecessor','exact R44 predecessor').replaceAll('sealed R43 predecessor','sealed R44 predecessor');
|
|
37
|
+
s=s.replace('result.tool_count===42','result.tool_count===43');
|
|
38
|
+
return s;
|
|
39
|
+
});
|
|
40
|
+
await derive('scripts/windows-gate-evidence-r44.mjs','scripts/windows-gate-evidence-r45.mjs',s=>{
|
|
41
|
+
s=s.replaceAll('REMOTE AGENT SKILL','MACHINE FREEDOM');
|
|
42
|
+
s=s.replace("full_regression_required:true,codex_live_binary_required:false","full_regression_required:true,codex_live_binary_required:false,host_inline_native:true,native_hardware_observation:true,doctor_release_truth:true");
|
|
43
|
+
return s;
|
|
44
|
+
});
|
|
45
|
+
await derive('scripts/final-closure-r44.mjs','scripts/final-closure-r45.mjs',s=>{
|
|
46
|
+
s=s.replaceAll('REMOTE AGENT SKILL','MACHINE FREEDOM');
|
|
47
|
+
s=s.replaceAll("'0.14.1'","'0.15.0'");
|
|
48
|
+
s=s.split(oldRelease).join(parentRelease).split(oldManifest).join(parentManifest);
|
|
49
|
+
return s;
|
|
50
|
+
});
|
|
51
|
+
await derive('scripts/final-closure-verify-r44.mjs','scripts/final-closure-verify-r45.mjs',s=>{
|
|
52
|
+
s=s.split(oldRelease).join(parentRelease).split(oldManifest).join(parentManifest);
|
|
53
|
+
s=s.replaceAll('R45_FULL_TOOL_COUNT=81','R45_FULL_TOOL_COUNT=82');
|
|
54
|
+
s=s.replaceAll('isR43PredecessorIdentity','isR44PredecessorIdentity').replaceAll('R43 predecessor','R44 predecessor');
|
|
55
|
+
s=s.replaceAll("value?.version==='0.14.1'","value?.version==='0.15.0'");
|
|
56
|
+
s=s.replaceAll('REMOTE AGENT SKILL','MACHINE FREEDOM');
|
|
57
|
+
return s;
|
|
58
|
+
});
|
|
59
|
+
await derive('scripts/finalize-r44.mjs','scripts/finalize-r45.mjs',s=>{
|
|
60
|
+
s=s.split(oldRelease).join(parentRelease).split(oldManifest).join(parentManifest).split(oldClosure).join(parentClosure);
|
|
61
|
+
s=s.replaceAll('REMOTE AGENT SKILL','MACHINE FREEDOM').replaceAll('sealed R43 parent','sealed R44 parent');
|
|
62
|
+
return s;
|
|
63
|
+
});
|
|
64
|
+
await derive('scripts/gate-windows-r44.ps1','scripts/gate-windows-r45.ps1',s=>{
|
|
65
|
+
s=s.replaceAll('REMOTE AGENT SKILL','MACHINE FREEDOM');
|
|
66
|
+
const needle="Invoke-GateStep -Name 'desktop-policy-refresh' -NpmArgs @('run','desktop:policy:refresh')";
|
|
67
|
+
if(!s.includes(needle)) throw new Error('R45 gate hardware insertion point missing');
|
|
68
|
+
s=s.replace(needle,needle+"\nInvoke-GateStep -Name 'hardware-build' -NpmArgs @('run','hardware:build')");
|
|
69
|
+
s=s.replace("'r45-feature-focused'","'r45-machine-freedom-focused'");
|
|
70
|
+
return s;
|
|
71
|
+
});
|
|
72
|
+
console.log('R45 successor files derived');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
5
|
+
async function copy(src,dst,mutate){
|
|
6
|
+
let s=await readFile(path.join(root,src),'utf8');
|
|
7
|
+
s=s.split('R44').join('R45').split('r44').join('r45').split('0.15.0').join('0.15.1');
|
|
8
|
+
s=mutate?s=mutate(s):s;
|
|
9
|
+
await writeFile(path.join(root,dst),s,'utf8');
|
|
10
|
+
}
|
|
11
|
+
await copy('test/full-max-catalog-r44.test.mjs','test/full-max-catalog-r45.test.mjs',s=>{
|
|
12
|
+
s=s.replaceAll('exactly 81','exactly 82').replaceAll('catalog 81','catalog 82').replace('assert.equal(names.length,81','assert.equal(names.length,82');
|
|
13
|
+
s=s.replace("for(const name of ['desktop_status'","for(const name of ['machine_hardware_query','desktop_status'");
|
|
14
|
+
return s;
|
|
15
|
+
});
|
|
16
|
+
await copy('test/compact-max-catalog-r44.test.mjs','test/compact-max-catalog-r45.test.mjs',s=>{
|
|
17
|
+
s=s.replace("const skill=m.capabilities.find(item=>item.id==='skill.catalog');","const hardware=m.capabilities.find(item=>item.id==='observation.hardware_query');\n assert.ok(hardware);assert.equal(hardware.authority,'none');assert.equal(hardware.compact_tool,'machine_observe');assert.equal(hardware.compact_op,'hardware_query');\n const skill=m.capabilities.find(item=>item.id==='skill.catalog');");
|
|
18
|
+
s=s.replace("desktop:true,skill:true","desktop:true,hardware_query:true,skill:true");
|
|
19
|
+
return s;
|
|
20
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { createHash, createPrivateKey, createPublicKey, sign as cryptoSign } from 'node:crypto';
|
|
2
|
+
import { lstat, mkdir, open, readFile, rename, rm } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { probeR45FullSurface } from '../src/r45-full-surface-probe.mjs';
|
|
7
|
+
import { probeR45CompactDisarmed } from '../src/r45-compact-disarmed-probe.mjs';
|
|
8
|
+
import {
|
|
9
|
+
validateParityEvidence,
|
|
10
|
+
R45_PREDECESSOR_RELEASE_ID,
|
|
11
|
+
R45_PREDECESSOR_MANIFEST
|
|
12
|
+
} from './release-parity-r45.mjs';
|
|
13
|
+
|
|
14
|
+
const DOMAIN=Buffer.from('DEADBYTE-R45-FINAL-CLOSURE-V1\0','utf8');
|
|
15
|
+
const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
16
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
17
|
+
const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
|
|
18
|
+
?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
|
|
19
|
+
const canonicalJson=value=>JSON.stringify(canonical(value));
|
|
20
|
+
function insist(ok,msg){if(!ok) throw new Error(msg);}
|
|
21
|
+
function samePath(a,b){return path.resolve(String(a)).toLowerCase()===path.resolve(String(b)).toLowerCase();}
|
|
22
|
+
async function fileEvidence(file){const abs=path.resolve(file),bytes=await readFile(abs);return {path:abs,sha256:sha256(bytes)};}
|
|
23
|
+
async function publicUrl(){
|
|
24
|
+
const value=(await readFile(path.join(stateRoot,'bridge','mcp-url.txt'),'utf8')).trim();
|
|
25
|
+
const url=new URL(value);insist(url.protocol==='https:','final closure requires HTTPS public endpoint');return value;
|
|
26
|
+
}
|
|
27
|
+
async function grantAbsence(){
|
|
28
|
+
const out={};
|
|
29
|
+
for(const name of ['process-grant.json','coding-grant.json','autonomous-grant.json','desktop-grant.json','host-grant.json']){
|
|
30
|
+
let absent=false;try{await lstat(path.join(stateRoot,'runtime',name));}catch(error){if(error?.code==='ENOENT') absent=true;else throw error;}
|
|
31
|
+
insist(absent,`authority grant still present: ${name}`);out[name]=true;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
async function atomicCreate(file,bytes){
|
|
36
|
+
await mkdir(path.dirname(file),{recursive:true});
|
|
37
|
+
const temp=`${file}.tmp-${process.pid}-${Math.random().toString(16).slice(2)}`;
|
|
38
|
+
const handle=await open(temp,'wx');
|
|
39
|
+
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
40
|
+
try{await rename(temp,file);}catch(error){await rm(temp,{force:true}).catch(()=>{});throw error;}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function writeFinalClosure({parityPath,activationPath,windowsGatePath}){
|
|
44
|
+
const pointer=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
|
|
45
|
+
insist(pointer.version==='0.15.1','R45 final closure requires V0.15.1 active release');
|
|
46
|
+
insist(pointer.release_id===`v${pointer.version}-${pointer.manifest_sha256.slice(0,16)}`,'final closure release id/content address mismatch');
|
|
47
|
+
|
|
48
|
+
const parity=JSON.parse(await readFile(path.resolve(parityPath),'utf8'));
|
|
49
|
+
insist(parity.schema==='deadbyte.r45-parity.v1','R45 parity schema mismatch at final closure');
|
|
50
|
+
validateParityEvidence(parity);
|
|
51
|
+
insist(parity.candidate?.release_id===pointer.release_id&&parity.candidate?.manifest_sha256===pointer.manifest_sha256,'parity candidate/current release mismatch');
|
|
52
|
+
insist(parity.successor?.release_id===pointer.release_id&&parity.successor?.manifest_sha256===pointer.manifest_sha256,'parity successor/current release mismatch');
|
|
53
|
+
insist(parity.predecessor?.release_id===R45_PREDECESSOR_RELEASE_ID&&parity.predecessor?.manifest_sha256===R45_PREDECESSOR_MANIFEST,'parity predecessor identity mismatch');
|
|
54
|
+
insist(parity.rollback?.receipt_path&&parity.restore?.receipt_path,'parity rollback/restore receipt paths missing');
|
|
55
|
+
insist(parity.immutable_slot?.protected===true,'parity immutable-slot proof missing');
|
|
56
|
+
insist(samePath(parity.immutable_slot.release_root,pointer.release_root),'parity immutable release root mismatch');
|
|
57
|
+
insist(!samePath(parity.immutable_slot.development_root,pointer.release_root),'development_root must differ from immutable release_root');
|
|
58
|
+
|
|
59
|
+
const windowsGate=JSON.parse(await readFile(path.resolve(windowsGatePath),'utf8'));
|
|
60
|
+
insist(windowsGate.schema==='deadbyte.r45-windows-gate.v1'&&windowsGate.status==='passed'&&windowsGate.exit_code===0,'R45 Windows gate evidence invalid');
|
|
61
|
+
insist(windowsGate.version==='0.15.1'&&windowsGate.manifest_sha256===pointer.manifest_sha256,'R45 Windows gate/current release mismatch');
|
|
62
|
+
insist(windowsGate.marker==='DEADBYTE V0.15.1 / R45 MACHINE FREEDOM WINDOWS BATCH GATE: PASS','R45 Windows gate marker mismatch');
|
|
63
|
+
|
|
64
|
+
const localFull=await probeR45FullSurface({packageRoot:pointer.release_root,generationRoot:pointer.generation_root,stateRoot});
|
|
65
|
+
insist(localFull.status==='passed'&&localFull.tool_count===82&&localFull.strict_output_schemas===true,'final local full 82-tool proof failed');
|
|
66
|
+
const compact=await probeR45CompactDisarmed(await publicUrl());
|
|
67
|
+
insist(compact.status==='passed'&&compact.tool_count===43&&compact.capability_closure===true&&compact.skill_catalog_verified===true,'final public compact capability/skill closure failed');
|
|
68
|
+
insist(compact.coding_armed===false&&compact.autonomous_armed===false&&compact.desktop_armed===false,'final public compact authority is not DISARMED');
|
|
69
|
+
insist(compact.desktop_observation_receipt_verified===true&&compact.desktop_grounding_receipt_verified===true,'final public Desktop read-only proof missing');
|
|
70
|
+
insist(compact.release_id===pointer.release_id&&compact.release_manifest_sha256===pointer.manifest_sha256,'final public compact release binding mismatch');
|
|
71
|
+
insist(compact.machine_status?.release_id===pointer.release_id&&compact.machine_status?.release_manifest_sha256===pointer.manifest_sha256,'final machine status/current release mismatch');
|
|
72
|
+
insist(compact.machine_ping?.nonce===compact.nonce,'final machine ping nonce mismatch');
|
|
73
|
+
|
|
74
|
+
const windowsGateBytes=await readFile(path.resolve(windowsGatePath));
|
|
75
|
+
insist(parity.feature_gate_sha256===sha256(windowsGateBytes),'R45 parity feature gate hash/current Windows gate mismatch');
|
|
76
|
+
for(const key of ['skill_integrity','agent_backend_persistence','codex_protocol_contract','remote_device_identity','durable_job_supervisor','real_external_supervisor_smoke','full_regression_required','host_inline_native','native_hardware_observation','doctor_release_truth']) {
|
|
77
|
+
insist(windowsGate.features?.[key]===true,`R45 Windows gate feature missing ${key}`);
|
|
78
|
+
}
|
|
79
|
+
const evidence={
|
|
80
|
+
parity:await fileEvidence(parityPath),activation:await fileEvidence(activationPath),
|
|
81
|
+
rollback:await fileEvidence(parity.rollback.receipt_path),restore:await fileEvidence(parity.restore.receipt_path),
|
|
82
|
+
windows_gate:await fileEvidence(windowsGatePath)
|
|
83
|
+
};
|
|
84
|
+
const body={
|
|
85
|
+
schema:'deadbyte.r45-final-closure.v1',version:'0.15.1',release_label:'R45 MACHINE FREEDOM FINAL BASELINE',
|
|
86
|
+
completed_at_utc:new Date().toISOString(),active_pointer:pointer,
|
|
87
|
+
predecessor:{release_id:R45_PREDECESSOR_RELEASE_ID,version:'0.15.0',manifest_sha256:R45_PREDECESSOR_MANIFEST},
|
|
88
|
+
immutable_slot:{protected:true,release_root:path.resolve(pointer.release_root),development_root:path.resolve(parity.immutable_slot.development_root)},
|
|
89
|
+
surfaces:{
|
|
90
|
+
local_full:{status:localFull.status,profile:localFull.profile,tool_count:localFull.tool_count,catalog_sha256:localFull.catalog_sha256,strict_output_schemas:localFull.strict_output_schemas,protocol_revision:localFull.protocol_revision},
|
|
91
|
+
public_compact:{status:compact.status,profile:compact.profile,tool_count:compact.tool_count,catalog_sha256:compact.catalog_sha256,strict_output_schemas:compact.strict_output_schemas,ledger_sha256:compact.ledger_sha256,capability_count:compact.capability_count,production_non_host_capabilities:compact.production_non_host_capabilities,capability_closure:compact.capability_closure,coding_armed:compact.coding_armed,autonomous_armed:compact.autonomous_armed,desktop_armed:compact.desktop_armed,desktop_observation_receipt_verified:compact.desktop_observation_receipt_verified,desktop_grounding_receipt_verified:compact.desktop_grounding_receipt_verified,protocol_revision:compact.protocol_revision,skill_catalog_verified:compact.skill_catalog_verified,skill_count:compact.skill_count},
|
|
92
|
+
deterministic_memory:parity.deterministic_memory,
|
|
93
|
+
feature_contract:parity.feature_gate
|
|
94
|
+
},
|
|
95
|
+
evidence,
|
|
96
|
+
machine:{status:compact.machine_status,ping:compact.machine_ping,nonce:compact.nonce},
|
|
97
|
+
authority:{all_disarmed:true,grants_absent:await grantAbsence()}
|
|
98
|
+
};
|
|
99
|
+
const privateKey=createPrivateKey(await readFile(path.join(stateRoot,'trust','ed25519-private.pem')));
|
|
100
|
+
const publicKey=createPublicKey(privateKey);
|
|
101
|
+
insist(privateKey.asymmetricKeyType==='ed25519'&&publicKey.asymmetricKeyType==='ed25519','closure signing key must be Ed25519');
|
|
102
|
+
const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
|
|
103
|
+
const bodyBytes=Buffer.from(canonicalJson(body),'utf8');
|
|
104
|
+
const signature=cryptoSign(null,Buffer.concat([DOMAIN,bodyBytes]),privateKey);
|
|
105
|
+
const envelope={body,body_sha256:sha256(bodyBytes),attestation:{algorithm:'ed25519',domain:'DEADBYTE-R45-FINAL-CLOSURE-V1',key_id:keyId,signature_base64:signature.toString('base64')}};
|
|
106
|
+
envelope.closure_sha256=sha256(Buffer.from(canonicalJson(envelope),'utf8'));
|
|
107
|
+
const dir=path.join(stateRoot,'evidence','release');
|
|
108
|
+
const file=path.join(dir,`r45-final-${pointer.manifest_sha256.slice(0,16)}.json`);
|
|
109
|
+
const bytes=Buffer.from(`${JSON.stringify(envelope,null,2)}\n`,'utf8');
|
|
110
|
+
await atomicCreate(file,bytes);
|
|
111
|
+
return {status:'written',path:file,sha256:sha256(bytes),closure_sha256:envelope.closure_sha256,release_id:pointer.release_id};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
115
|
+
if(invoked){
|
|
116
|
+
const [parityPath,activationPath,windowsGatePath]=process.argv.slice(2);
|
|
117
|
+
if(!parityPath||!activationPath||!windowsGatePath) throw new Error('usage: node scripts/final-closure-r45.mjs <parity.json> <activation-receipt.json> <windows-gate.json>');
|
|
118
|
+
writeFinalClosure({parityPath,activationPath,windowsGatePath})
|
|
119
|
+
.then(result=>console.log(JSON.stringify(result,null,2)))
|
|
120
|
+
.catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
121
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createHash, createPrivateKey, createPublicKey, sign as cryptoSign } 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
|
+
|
|
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
|
+
async function fileEvidence(file){const bytes=await readFile(file);return {path:path.resolve(file),sha256:sha256(bytes)};}
|
|
17
|
+
|
|
18
|
+
export async function writeFinalClosure({root=packageRoot,runtimeStateRoot=stateRoot,clock=()=>new Date()}={}){
|
|
19
|
+
const candidate=path.resolve(root),state=path.resolve(runtimeStateRoot);
|
|
20
|
+
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
21
|
+
const manifestSha256=sha256(manifestBytes);
|
|
22
|
+
const pointer=JSON.parse(await readFile(path.join(state,'active-release.json'),'utf8'));
|
|
23
|
+
insist(pointer.version==='0.15.2'&&pointer.manifest_sha256===manifestSha256,'R46 final closure active candidate mismatch');
|
|
24
|
+
insist(pointer.release_id===`v0.15.2-${manifestSha256.slice(0,16)}`,'R46 final closure release id mismatch');
|
|
25
|
+
|
|
26
|
+
const gatePath=path.join(state,'evidence','release',`r46-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
27
|
+
const parityPath=path.join(state,'evidence','release',`r46-parity-${manifestSha256.slice(0,16)}.json`);
|
|
28
|
+
const gate=JSON.parse(await readFile(gatePath,'utf8'));
|
|
29
|
+
const parity=JSON.parse(await readFile(parityPath,'utf8'));
|
|
30
|
+
insist(gate.schema==='deadbyte.r46-windows-gate.v1'&&gate.status==='passed'&&gate.version==='0.15.2','R46 gate evidence invalid');
|
|
31
|
+
insist(gate.manifest_sha256===manifestSha256,'R46 gate evidence candidate mismatch');
|
|
32
|
+
insist(parity.schema==='deadbyte.r46-parity.v1'&&parity.status==='passed'&&parity.version==='0.15.2','R46 parity evidence invalid');
|
|
33
|
+
insist(parity.candidate?.manifest_sha256===manifestSha256&&parity.candidate?.generation_manifest_sha256===pointer.generation_manifest_sha256,'R46 parity active generation mismatch');
|
|
34
|
+
insist(parity.process_policy?.target_repin_verified===true,'R46 target-machine process repin proof missing');
|
|
35
|
+
insist(parity.fileless_powershell?.exit_code===0&&parity.fileless_powershell?.pscommandpath_empty===true&&parity.fileless_powershell?.invocation_path_empty===true&&parity.fileless_powershell?.new_temp_ps1_count===0,'R46 fileless PowerShell proof missing');
|
|
36
|
+
insist(parity.persistent_powershell_repl?.state_persisted===true&&parity.persistent_powershell_repl?.observed_value===42&&parity.persistent_powershell_repl?.wait_for_verified===true&&parity.persistent_powershell_repl?.tail_read_verified===true&&parity.persistent_powershell_repl?.raw_input_not_journaled===true,'R46 persistent PowerShell REPL proof missing');
|
|
37
|
+
insist(parity.retained_output_ring?.eviction_verified===true&&parity.retained_output_ring?.tail_marker_verified===true&&parity.retained_output_ring?.earliest_offset>0,'R46 retained-output ring proof missing');
|
|
38
|
+
|
|
39
|
+
const completed=clock();
|
|
40
|
+
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'R46 final closure clock invalid');
|
|
41
|
+
const body={
|
|
42
|
+
schema:'deadbyte.r46-final-closure.v1',
|
|
43
|
+
version:'0.15.2',
|
|
44
|
+
train:'R46',
|
|
45
|
+
release_label:'FILELESS POWERSHELL PRODUCT BASELINE',
|
|
46
|
+
completed_at_utc:completed.toISOString(),
|
|
47
|
+
active_pointer:pointer,
|
|
48
|
+
parent:gate.parent,
|
|
49
|
+
runtime_predecessor:gate.runtime_predecessor,
|
|
50
|
+
features:gate.features,
|
|
51
|
+
process_policy:parity.process_policy,
|
|
52
|
+
fileless_powershell:parity.fileless_powershell,
|
|
53
|
+
persistent_powershell_repl:parity.persistent_powershell_repl,
|
|
54
|
+
retained_output_ring:parity.retained_output_ring,
|
|
55
|
+
evidence:{
|
|
56
|
+
windows_gate:await fileEvidence(gatePath),
|
|
57
|
+
parity:await fileEvidence(parityPath)
|
|
58
|
+
},
|
|
59
|
+
execution_provider:'deadbyte_mcp',
|
|
60
|
+
rdc_operation_count:0
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const privateKey=createPrivateKey(await readFile(path.join(state,'trust','ed25519-private.pem')));
|
|
64
|
+
const publicKey=createPublicKey(privateKey);
|
|
65
|
+
insist(privateKey.asymmetricKeyType==='ed25519'&&publicKey.asymmetricKeyType==='ed25519','R46 closure signing key must be Ed25519');
|
|
66
|
+
const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
|
|
67
|
+
const bodyBytes=Buffer.from(canonicalJson(body),'utf8');
|
|
68
|
+
const signature=cryptoSign(null,Buffer.concat([DOMAIN,bodyBytes]),privateKey);
|
|
69
|
+
const envelope={
|
|
70
|
+
body,
|
|
71
|
+
body_sha256:sha256(bodyBytes),
|
|
72
|
+
attestation:{
|
|
73
|
+
algorithm:'ed25519',
|
|
74
|
+
domain:'DEADBYTE-R46-FINAL-CLOSURE-V1',
|
|
75
|
+
key_id:keyId,
|
|
76
|
+
signature_base64:signature.toString('base64')
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
envelope.closure_sha256=sha256(Buffer.from(canonicalJson(envelope),'utf8'));
|
|
80
|
+
const bytes=Buffer.from(`${JSON.stringify(envelope,null,2)}\n`,'utf8');
|
|
81
|
+
const dir=path.join(state,'evidence','release');
|
|
82
|
+
await mkdir(dir,{recursive:true});
|
|
83
|
+
const file=path.join(dir,`r46-final-${manifestSha256.slice(0,16)}.json`);
|
|
84
|
+
try{
|
|
85
|
+
const handle=await open(file,'wx',0o600);
|
|
86
|
+
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
87
|
+
return {status:'written',path:file,sha256:sha256(bytes),closure_sha256:envelope.closure_sha256,release_id:pointer.release_id};
|
|
88
|
+
}catch(error){
|
|
89
|
+
if(error?.code!=='EEXIST')throw error;
|
|
90
|
+
const existingBytes=await readFile(file);
|
|
91
|
+
const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
92
|
+
insist(existing.body?.version==='0.15.2'&&existing.body?.active_pointer?.manifest_sha256===manifestSha256,'existing R46 closure identity mismatch');
|
|
93
|
+
return {status:'existing',path:file,sha256:sha256(existingBytes),closure_sha256:existing.closure_sha256,release_id:pointer.release_id};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
98
|
+
if(invoked)writeFinalClosure().then(value=>console.log(JSON.stringify(value))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|