deadbyte-mcp 0.13.0 → 0.15.0
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/.gitattributes +7 -0
- package/AGENTS.md +18 -0
- package/CONTEXT.md +3 -3
- package/MANIFEST.SHA256 +152 -75
- package/R42-PARENT.json +19 -0
- package/R43-PARENT.json +20 -0
- package/R44-DONORS.json +99 -0
- package/R44-PARENT.json +18 -0
- package/README.txt +7 -2
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/controller/README.TXT +4 -5
- package/controller/deadbyte-controller.ps1 +1 -1
- package/controller/deadbyte-desktop-policy.json +5 -5
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/ARCHITECTURE.md +8 -1
- package/docs/R44-ARCHITECTURE.md +37 -0
- package/harness/r42-agent-evals.json +48 -0
- package/harness/task-contract.schema.json +33 -0
- package/package.json +15 -8
- package/proof/CONTAINMENT-BUILD.txt +6 -6
- package/scripts/agent-eval-r42.mjs +46 -0
- package/scripts/deferred-slot-operation-r42.mjs +126 -0
- package/scripts/deferred-slot-operation-r43.mjs +126 -0
- package/scripts/deferred-slot-operation-r44.mjs +126 -0
- package/scripts/final-closure-r42.mjs +116 -0
- package/scripts/final-closure-r43.mjs +115 -0
- package/scripts/final-closure-r44.mjs +121 -0
- package/scripts/final-closure-verify-r42.mjs +223 -0
- package/scripts/final-closure-verify-r43.mjs +213 -0
- package/scripts/final-closure-verify-r44.mjs +220 -0
- package/scripts/finalize-r43.mjs +217 -0
- package/scripts/finalize-r44.mjs +217 -0
- package/scripts/full-regression-r43.mjs +20 -0
- package/scripts/full-regression-r44.mjs +20 -0
- package/scripts/gate-windows-r42.ps1 +54 -0
- package/scripts/gate-windows-r43.ps1 +36 -0
- package/scripts/gate-windows-r44.ps1 +36 -0
- package/scripts/release-parity-r42.mjs +235 -0
- package/scripts/release-parity-r43.mjs +218 -0
- package/scripts/release-parity-r44.mjs +242 -0
- package/scripts/release-parity-tests-r42.ps1 +6 -0
- package/scripts/release-parity-tests-r43.ps1 +8 -0
- package/scripts/release-parity-tests-r44.ps1 +8 -0
- package/scripts/verify-r42-parent.mjs +101 -0
- package/scripts/verify-r43-parent.mjs +126 -0
- package/scripts/verify-r44-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r42.mjs +64 -0
- package/scripts/windows-gate-evidence-r43.mjs +55 -0
- package/scripts/windows-gate-evidence-r44.mjs +55 -0
- package/src/agent-backend-r44.mjs +254 -0
- package/src/agent-eval-r42.mjs +73 -0
- package/src/agent-eval-runner-r42.mjs +138 -0
- package/src/agent-governance-r42.mjs +142 -0
- package/src/autonomous-context-engine.mjs +2 -0
- package/src/autonomous-loop-state.mjs +10 -0
- package/src/autonomous-mcp-tools.mjs +21 -6
- package/src/autonomous-output-contracts.mjs +18 -2
- package/src/autonomous-planner-contracts.mjs +3 -0
- package/src/autonomous-planner.mjs +46 -6
- package/src/autonomous-policy.mjs +50 -5
- package/src/autonomous-runtime.mjs +138 -25
- package/src/autonomous-supervisor-host.mjs +12 -2
- package/src/autonomous-supervisor.mjs +1 -1
- package/src/capability-ledger.mjs +2 -1
- package/src/codex-app-server-r44.mjs +154 -0
- package/src/coding-plane.mjs +66 -19
- package/src/durable-job-r44.mjs +145 -0
- package/src/evidence-publisher-r42.mjs +76 -0
- package/src/external-job-provider-r44.mjs +126 -0
- package/src/host-plane.mjs +27 -6
- package/src/job-supervisor-host-r44.mjs +112 -0
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +21 -10
- package/src/mcp-host-smoke-client.mjs +1 -1
- package/src/mcp-server.mjs +20 -3
- package/src/mcp-smoke-client.mjs +1 -1
- package/src/native-diff-v2.mjs +3 -3
- package/src/native-diff.mjs +3 -2
- package/src/observation-smoke-client.mjs +1 -1
- package/src/operator-surface.mjs +2 -2
- package/src/process-policy.mjs +19 -0
- package/src/process-runtime.mjs +5 -2
- package/src/process-smoke-client.mjs +2 -2
- package/src/provider-circuit.mjs +10 -4
- package/src/r44-compact-disarmed-probe.mjs +74 -0
- package/src/r44-full-surface-probe.mjs +34 -0
- package/src/remote-device-r44.mjs +205 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +4 -4
- package/src/remote-mcp-r44-parity-client.mjs +203 -0
- package/src/remote-mcp-smoke-client.mjs +7 -4
- package/src/runtime-update.mjs +64 -31
- package/src/skill-mcp-tools-r44.mjs +37 -0
- package/src/skill-plane-r44.mjs +203 -0
- package/src/tunnel-stdio-compat-smoke.mjs +1 -1
- package/src/version.mjs +1 -1
- package/test/agent-backend-r44.test.mjs +115 -0
- package/test/agent-eval-r42.test.mjs +39 -0
- package/test/agent-eval-runner-r42.test.mjs +61 -0
- package/test/agent-governance-r42.test.mjs +77 -0
- package/test/agent-runtime.test.mjs +3 -3
- package/test/autonomous-loop.test.mjs +97 -11
- package/test/autonomous-r34-e2e.test.mjs +2 -1
- package/test/autonomous-runtime.test.mjs +2 -2
- package/test/capability-ledger-r36.test.mjs +3 -3
- package/test/cli-entrypoint.test.mjs +1 -1
- package/test/codex-app-server-r44.test.mjs +115 -0
- package/test/codex-autonomous-r44.test.mjs +87 -0
- package/test/coding-plane.test.mjs +2 -2
- package/test/coding-runtime.test.mjs +36 -1
- package/test/compact-catalog-r36.test.mjs +3 -3
- package/test/compact-max-catalog-r40.test.mjs +4 -2
- package/test/compact-max-catalog-r44.test.mjs +97 -0
- package/test/core.test.mjs +1 -1
- package/test/durable-job-r44.test.mjs +75 -0
- package/test/evidence-publisher-r42.test.mjs +53 -0
- package/test/external-job-provider-r44.test.mjs +46 -0
- package/test/full-max-catalog-r40.test.mjs +5 -3
- package/test/full-max-catalog-r44.test.mjs +91 -0
- package/test/host-plane.test.mjs +15 -1
- package/test/human-clarification-r42.test.mjs +53 -0
- package/test/native-diff.test.mjs +28 -0
- package/test/output-schema.test.mjs +2 -2
- package/test/process-policy.test.mjs +22 -1
- package/test/prompts-resources.test.mjs +1 -1
- package/test/provider-responses-r42.test.mjs +90 -0
- package/test/r33-closeout-regression.test.mjs +14 -16
- package/test/r33-finalization.test.mjs +7 -7
- package/test/r42-finalization.test.mjs +38 -0
- package/test/r43-finalization.test.mjs +31 -0
- package/test/r43-finalizer.test.mjs +34 -0
- package/test/r43-parent.test.mjs +29 -0
- package/test/r44-finalization.test.mjs +58 -0
- package/test/r44-finalizer.test.mjs +48 -0
- package/test/r44-parent.test.mjs +25 -0
- package/test/release-version.test.mjs +53 -19
- package/test/remote-device-r44.test.mjs +104 -0
- package/test/runtime-self-update.test.mjs +42 -0
- package/test/skill-mcp-r44.test.mjs +38 -0
- package/test/skill-plane-r44.test.mjs +93 -0
- package/test/standing-grants.test.mjs +5 -1
- package/test/task-contract-r42.test.mjs +41 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
|
2
|
+
import { lstat, readFile, readdir } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
import { canonicalJson } from '../src/canonical-json.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
9
|
+
const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
10
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const insist=(ok,message)=>{if(!ok)throw new Error(message);};
|
|
12
|
+
const UPDATE_DOMAIN=Buffer.from('DEADBYTE-R27-SLOT-UPDATE-V1\0','utf8');
|
|
13
|
+
const HEX64=/^[0-9a-f]{64}$/;
|
|
14
|
+
|
|
15
|
+
function inputPath(value){
|
|
16
|
+
if(value instanceof URL) return fileURLToPath(value);
|
|
17
|
+
return path.resolve(String(value));
|
|
18
|
+
}
|
|
19
|
+
function parseManifest(bytes,label){
|
|
20
|
+
const entries=new Map();
|
|
21
|
+
for(const [index,line] of bytes.toString('utf8').split(/\r?\n/).entries()){
|
|
22
|
+
if(!line)continue;
|
|
23
|
+
const match=/^([0-9a-f]{64}) ([^\0]+)$/.exec(line);
|
|
24
|
+
insist(match,`${label} line ${index+1} malformed`);
|
|
25
|
+
const rel=match[2].replaceAll('\\','/');
|
|
26
|
+
insist(!path.posix.isAbsolute(rel)&&!rel.split('/').includes('..')&&!entries.has(rel),`unsafe/duplicate ${label} path ${rel}`);
|
|
27
|
+
entries.set(rel,match[1]);
|
|
28
|
+
}
|
|
29
|
+
insist(entries.size>0,`${label} has no entries`);
|
|
30
|
+
return entries;
|
|
31
|
+
}
|
|
32
|
+
async function walk(rootDir,manifestName,rel=''){
|
|
33
|
+
const dir=rel?path.join(rootDir,...rel.split('/')):rootDir;
|
|
34
|
+
const out=[];
|
|
35
|
+
for(const name of (await readdir(dir)).sort((a,b)=>a.localeCompare(b,'en'))){
|
|
36
|
+
const child=rel?`${rel}/${name}`:name;
|
|
37
|
+
if(child===manifestName)continue;
|
|
38
|
+
const full=path.join(rootDir,...child.split('/'));
|
|
39
|
+
const st=await lstat(full);
|
|
40
|
+
insist(!st.isSymbolicLink(),`parent tree symlink forbidden: ${child}`);
|
|
41
|
+
if(st.isDirectory())out.push(...await walk(rootDir,manifestName,child));
|
|
42
|
+
else{insist(st.isFile(),`parent tree non-file forbidden: ${child}`);out.push(child);}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
async function verifyTree(dir,manifestName,expectedManifest,expectedCount){
|
|
47
|
+
const base=path.resolve(dir);
|
|
48
|
+
const rootStat=await lstat(base);
|
|
49
|
+
insist(rootStat.isDirectory()&&!rootStat.isSymbolicLink(),`${manifestName} root must be a real directory`);
|
|
50
|
+
const bytes=await readFile(path.join(base,manifestName));
|
|
51
|
+
insist(sha256(bytes)===expectedManifest,`${manifestName} digest mismatch`);
|
|
52
|
+
const entries=parseManifest(bytes,manifestName);
|
|
53
|
+
insist(entries.size===expectedCount,`${manifestName} entry count mismatch`);
|
|
54
|
+
const actual=(await walk(base,manifestName)).sort((a,b)=>a.localeCompare(b,'en'));
|
|
55
|
+
const expected=[...entries.keys()].sort((a,b)=>a.localeCompare(b,'en'));
|
|
56
|
+
insist(actual.length===expected.length&&actual.every((rel,index)=>rel===expected[index]),`${manifestName} exact tree mismatch`);
|
|
57
|
+
for(const [rel,digest] of entries){
|
|
58
|
+
insist(sha256(await readFile(path.join(base,...rel.split('/'))))===digest,`${manifestName} file hash mismatch: ${rel}`);
|
|
59
|
+
}
|
|
60
|
+
return entries.size;
|
|
61
|
+
}
|
|
62
|
+
function publicKeyInfo(publicPem){
|
|
63
|
+
const key=createPublicKey(publicPem);
|
|
64
|
+
insist(key.asymmetricKeyType==='ed25519','R43 parent trust key must be Ed25519');
|
|
65
|
+
const der=Buffer.from(key.export({type:'spki',format:'der'}));
|
|
66
|
+
return {key,key_id:sha256(der)};
|
|
67
|
+
}
|
|
68
|
+
function verifyActivationEnvelope(env,keyInfo,record){
|
|
69
|
+
insist(env?.body&&env?.attestation,'R42 activation envelope malformed');
|
|
70
|
+
const bodyBytes=Buffer.from(canonicalJson(env.body),'utf8');
|
|
71
|
+
insist(sha256(bodyBytes)===env.body_sha256,'R42 activation body hash mismatch');
|
|
72
|
+
const {receipt_sha256:claimed,...unsigned}=env;
|
|
73
|
+
insist(claimed===record.parent_activation_receipt_sha256,'R42 activation signed receipt identity mismatch');
|
|
74
|
+
insist(sha256(Buffer.from(canonicalJson(unsigned),'utf8'))===claimed,'R42 activation receipt hash mismatch');
|
|
75
|
+
insist(env.attestation.algorithm==='ed25519'&&env.attestation.domain==='DEADBYTE-R27-SLOT-UPDATE-V1','R42 activation attestation contract mismatch');
|
|
76
|
+
insist(env.attestation.key_id===record.parent_activation_signer_key_id&&env.attestation.key_id===keyInfo.key_id,'R42 activation signer mismatch');
|
|
77
|
+
insist(cryptoVerify(null,Buffer.concat([UPDATE_DOMAIN,bodyBytes]),keyInfo.key,Buffer.from(env.attestation.signature_base64,'base64')),'R42 activation signature invalid');
|
|
78
|
+
const body=env.body;
|
|
79
|
+
insist(body.schema==='deadbyte.r27-slot-update-receipt.v1'&&body.rollback_performed===false,'R42 activation receipt state invalid');
|
|
80
|
+
insist(body.release_version===record.parent_version&&body.candidate_manifest_sha256===record.parent_manifest_sha256,'R42 activation candidate mismatch');
|
|
81
|
+
const active=body.active_pointer;
|
|
82
|
+
insist(active?.release_id===record.parent_release_id&&active?.version===record.parent_version&&active?.manifest_sha256===record.parent_manifest_sha256,'R42 activation active release mismatch');
|
|
83
|
+
insist(active?.generation_manifest_sha256===record.parent_generation_manifest_sha256,'R42 activation generation mismatch');
|
|
84
|
+
insist(path.resolve(active.release_root)===path.resolve(record.parent_release_root),'R42 activation release root mismatch');
|
|
85
|
+
insist(path.resolve(active.generation_root)===path.resolve(record.parent_generation_root),'R42 activation generation root mismatch');
|
|
86
|
+
const prior=body.prior_pointer;
|
|
87
|
+
insist(prior?.release_id===record.parent_predecessor_release_id&&prior?.manifest_sha256===record.parent_predecessor_manifest_sha256,'R42 activation predecessor mismatch');
|
|
88
|
+
insist(body.authority?.final?.coding_armed===false&&body.authority?.final?.autonomous_armed===false&&body.authority?.final?.desktop_armed===false&&body.authority?.final?.host_armed===false,'R42 activation final authority was not disarmed');
|
|
89
|
+
return body;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function verifyR43Parent(file=path.join(root,'R43-PARENT.json')){
|
|
93
|
+
const record=JSON.parse(await readFile(inputPath(file),'utf8'));
|
|
94
|
+
insist(record.schema==='deadbyte.r43-parent.v1','R43 parent schema mismatch');
|
|
95
|
+
insist(record.parent_release_id==='v0.14.0-08cd8f3b98c90e0e'&&record.parent_version==='0.14.0','R43 parent release identity mismatch');
|
|
96
|
+
insist(record.parent_manifest_sha256==='08cd8f3b98c90e0e250cf506ff396515065ff5457909f850b75b0b6e8ecc2dd1','R43 parent manifest mismatch');
|
|
97
|
+
insist(record.parent_generation_manifest_sha256==='df8ca9894a3e2ca9a9f145cfa3e4e23fd71f42c1988266a1591fc16261ab18a5','R43 parent generation mismatch');
|
|
98
|
+
insist(record.parent_manifest_file_count===1820&&record.parent_generation_file_count===7,'R43 parent file count mismatch');
|
|
99
|
+
insist(record.parent_final_closure_present===false&&!Object.prototype.hasOwnProperty.call(record,'parent_final_closure_path'),'R43 parent must not invent unavailable R42 final closure');
|
|
100
|
+
insist(record.parent_proof==='immutable-slot+generation+signed-activation','R43 parent proof class mismatch');
|
|
101
|
+
for(const key of ['parent_activation_receipt_file_sha256','parent_activation_receipt_sha256','parent_activation_signer_key_id']) insist(HEX64.test(record[key]??''),`R43 parent ${key} malformed`);
|
|
102
|
+
|
|
103
|
+
const [releaseFiles,generationFiles]=await Promise.all([
|
|
104
|
+
verifyTree(record.parent_release_root,'MANIFEST.SHA256',record.parent_manifest_sha256,record.parent_manifest_file_count),
|
|
105
|
+
verifyTree(record.parent_generation_root,'GENERATION.SHA256',record.parent_generation_manifest_sha256,record.parent_generation_file_count)
|
|
106
|
+
]);
|
|
107
|
+
const activationBytes=await readFile(path.resolve(record.parent_activation_receipt_path));
|
|
108
|
+
insist(sha256(activationBytes)===record.parent_activation_receipt_file_sha256,'R42 activation raw file hash mismatch');
|
|
109
|
+
const activation=JSON.parse(activationBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
110
|
+
const keyInfo=publicKeyInfo(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
|
|
111
|
+
verifyActivationEnvelope(activation,keyInfo,record);
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
status:'passed',parent_release_id:record.parent_release_id,parent_manifest_sha256:record.parent_manifest_sha256,
|
|
115
|
+
parent_generation_manifest_sha256:record.parent_generation_manifest_sha256,release_files:releaseFiles,generation_files:generationFiles,
|
|
116
|
+
parent_activation_receipt_file_sha256:record.parent_activation_receipt_file_sha256,
|
|
117
|
+
parent_activation_receipt_sha256:record.parent_activation_receipt_sha256,parent_activation_signer_key_id:keyInfo.key_id,
|
|
118
|
+
parent_final_closure_present:false
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){
|
|
123
|
+
const file=process.argv[2]??path.join(root,'R43-PARENT.json');
|
|
124
|
+
verifyR43Parent(file).then(value=>console.log(JSON.stringify(value,null,2)))
|
|
125
|
+
.catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
126
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
|
2
|
+
import { lstat, readFile, readdir } 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 CLOSURE_DOMAIN=Buffer.from('DEADBYTE-R43-FINAL-CLOSURE-V1\0','utf8');
|
|
8
|
+
const HEX64=/^[0-9a-f]{64}$/;
|
|
9
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
10
|
+
const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
|
|
11
|
+
?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
|
|
12
|
+
const canonicalJson=value=>JSON.stringify(canonical(value));
|
|
13
|
+
const same=(a,b)=>canonicalJson(a)===canonicalJson(b);
|
|
14
|
+
const samePath=(a,b)=>path.resolve(String(a)).toLowerCase()===path.resolve(String(b)).toLowerCase();
|
|
15
|
+
function insist(ok,message){if(!ok) throw new Error(message);}
|
|
16
|
+
|
|
17
|
+
function parseManifest(text){
|
|
18
|
+
const out=new Map();
|
|
19
|
+
for(const [i,line] of text.split(/\r?\n/).entries()){
|
|
20
|
+
if(!line) continue;
|
|
21
|
+
const m=/^([0-9a-f]{64}) ([^\0]+)$/.exec(line);
|
|
22
|
+
insist(m,`manifest line ${i+1} malformed`);
|
|
23
|
+
const rel=m[2];
|
|
24
|
+
insist(!path.posix.isAbsolute(rel)&&!rel.split('/').includes('..')&&!out.has(rel),`unsafe/duplicate manifest path ${rel}`);
|
|
25
|
+
out.set(rel,m[1]);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
async function walk(root,rel=''){
|
|
30
|
+
const dir=path.join(root,...(rel?rel.split('/'):[]));
|
|
31
|
+
const names=(await readdir(dir)).sort((a,b)=>a.localeCompare(b,'en'));
|
|
32
|
+
const files=[];
|
|
33
|
+
for(const name of names){
|
|
34
|
+
const childRel=rel?`${rel}/${name}`:name;
|
|
35
|
+
const full=path.join(root,...childRel.split('/'));
|
|
36
|
+
const st=await lstat(full);
|
|
37
|
+
insist(!st.isSymbolicLink(),`symlink forbidden: ${childRel}`);
|
|
38
|
+
if(st.isDirectory()) files.push(...await walk(root,childRel));
|
|
39
|
+
else { insist(st.isFile(),`non-file forbidden: ${childRel}`); files.push(childRel); }
|
|
40
|
+
}
|
|
41
|
+
return files;
|
|
42
|
+
}
|
|
43
|
+
async function verifyTree(root,manifestName,expectedDigest,expectedCount){
|
|
44
|
+
const manifestBytes=await readFile(path.join(root,manifestName));
|
|
45
|
+
insist(sha256(manifestBytes)===expectedDigest,`${manifestName} digest mismatch`);
|
|
46
|
+
const entries=parseManifest(manifestBytes.toString('utf8'));
|
|
47
|
+
insist(entries.size===expectedCount,`${manifestName} file count mismatch`);
|
|
48
|
+
const actual=(await walk(root)).filter(rel=>rel!==manifestName).sort((a,b)=>a.localeCompare(b,'en'));
|
|
49
|
+
const expected=[...entries.keys()].sort((a,b)=>a.localeCompare(b,'en'));
|
|
50
|
+
insist(same(actual,expected),`${manifestName} exact tree mismatch`);
|
|
51
|
+
for(const [rel,digest] of entries){
|
|
52
|
+
insist(sha256(await readFile(path.join(root,...rel.split('/'))))===digest,`${manifestName} file hash mismatch: ${rel}`);
|
|
53
|
+
}
|
|
54
|
+
return entries.size;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function verifyR44Parent(parentFile,{stateRoot=path.join(os.homedir(),'.deadbyte-mcp')}={}){
|
|
58
|
+
const parentPath=path.resolve(parentFile);
|
|
59
|
+
const parent=JSON.parse(await readFile(parentPath,'utf8'));
|
|
60
|
+
insist(parent?.schema==='deadbyte.r44-parent.v1','R44 parent schema mismatch');
|
|
61
|
+
insist(parent.parent_release_id==='v0.14.1-0a5a833892593283','R44 parent release id mismatch');
|
|
62
|
+
insist(parent.parent_version==='0.14.1','R44 parent version mismatch');
|
|
63
|
+
insist(parent.parent_manifest_sha256==='0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9','R44 parent manifest mismatch');
|
|
64
|
+
insist(parent.parent_manifest_file_count===1834,'R44 parent file count mismatch');
|
|
65
|
+
insist(parent.parent_generation_manifest_sha256==='fcfcb5a47d55039b7bb5d42faa0739b57b13d8a420d4418ae09d96d2862967cb','R44 parent generation mismatch');
|
|
66
|
+
insist(parent.parent_generation_file_count===7,'R44 parent generation file count mismatch');
|
|
67
|
+
insist(parent.parent_final_closure_file_sha256==='f24100212b55d2016ea9c4ff47df5f026c8edc0b9b8643933ed8bf26fde3803f','R44 parent closure file hash mismatch');
|
|
68
|
+
insist(parent.parent_final_closure_sha256==='2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b','R44 parent closure hash mismatch');
|
|
69
|
+
insist(parent.parent_final_closure_signer_key_id==='c0727a7911e29a0f1edd3cd910e47f89f43edb484743988c89cd82bfd5e37936','R44 parent closure signer mismatch');
|
|
70
|
+
insist(parent.parent_proof==='immutable-slot+generation+signed-final-closure','R44 parent proof class mismatch');
|
|
71
|
+
|
|
72
|
+
const closureBytes=await readFile(path.resolve(parent.parent_final_closure_path));
|
|
73
|
+
insist(sha256(closureBytes)===parent.parent_final_closure_file_sha256,'R44 parent closure file bytes mismatch');
|
|
74
|
+
const envelope=JSON.parse(closureBytes.toString('utf8'));
|
|
75
|
+
insist(envelope?.body?.schema==='deadbyte.r43-final-closure.v1','R44 parent closure schema mismatch');
|
|
76
|
+
insist(envelope.body.version===parent.parent_version,'R44 parent closure version mismatch');
|
|
77
|
+
insist(envelope.body.release_label==='R43 AUTHORITY HARDENING PATCH','R44 parent closure label mismatch');
|
|
78
|
+
|
|
79
|
+
const publicKey=createPublicKey(await readFile(path.join(path.resolve(stateRoot),'trust','ed25519-public.pem')));
|
|
80
|
+
insist(publicKey.asymmetricKeyType==='ed25519','R44 parent trust key must be Ed25519');
|
|
81
|
+
const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
|
|
82
|
+
insist(keyId===parent.parent_final_closure_signer_key_id,'R44 parent trust key id mismatch');
|
|
83
|
+
const bodyBytes=Buffer.from(canonicalJson(envelope.body),'utf8');
|
|
84
|
+
insist(sha256(bodyBytes)===envelope.body_sha256,'R44 parent closure body hash mismatch');
|
|
85
|
+
const {closure_sha256,...unsigned}=envelope;
|
|
86
|
+
insist(sha256(Buffer.from(canonicalJson(unsigned),'utf8'))===closure_sha256,'R44 parent closure envelope hash mismatch');
|
|
87
|
+
insist(closure_sha256===parent.parent_final_closure_sha256,'R44 parent closure content address mismatch');
|
|
88
|
+
insist(envelope.attestation?.algorithm==='ed25519'&&envelope.attestation?.domain==='DEADBYTE-R43-FINAL-CLOSURE-V1','R44 parent closure attestation contract mismatch');
|
|
89
|
+
insist(envelope.attestation.key_id===keyId,'R44 parent closure attestation signer mismatch');
|
|
90
|
+
insist(cryptoVerify(null,Buffer.concat([CLOSURE_DOMAIN,bodyBytes]),publicKey,Buffer.from(envelope.attestation.signature_base64,'base64')),'R44 parent closure signature invalid');
|
|
91
|
+
|
|
92
|
+
const pointer=envelope.body.active_pointer;
|
|
93
|
+
insist(pointer?.release_id===parent.parent_release_id&&pointer?.version===parent.parent_version&&pointer?.manifest_sha256===parent.parent_manifest_sha256,'R44 parent closure release binding mismatch');
|
|
94
|
+
insist(pointer.generation_manifest_sha256===parent.parent_generation_manifest_sha256,'R44 parent closure generation binding mismatch');
|
|
95
|
+
insist(pointer.launcher_sha256===parent.parent_launcher_sha256,'R44 parent launcher binding mismatch');
|
|
96
|
+
insist(samePath(pointer.release_root,parent.parent_release_root),'R44 parent release root mismatch');
|
|
97
|
+
insist(samePath(pointer.generation_root,parent.parent_generation_root),'R44 parent generation root mismatch');
|
|
98
|
+
insist(envelope.body.immutable_slot?.protected===true,'R44 parent immutable slot proof missing');
|
|
99
|
+
insist(samePath(envelope.body.immutable_slot.release_root,parent.parent_release_root),'R44 parent immutable release root mismatch');
|
|
100
|
+
insist(!samePath(envelope.body.immutable_slot.development_root,parent.parent_release_root),'R44 parent development root aliases release slot');
|
|
101
|
+
insist(samePath(envelope.body.immutable_slot.development_root,parent.development_root),'R44 parent development root mismatch');
|
|
102
|
+
insist(envelope.body.authority?.all_disarmed===true,'R44 parent closure did not record all-disarmed state');
|
|
103
|
+
for(const name of ['process-grant.json','coding-grant.json','autonomous-grant.json','desktop-grant.json','host-grant.json']){
|
|
104
|
+
insist(envelope.body.authority.grants_absent?.[name]===true,`R44 parent closure grant absence missing: ${name}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const evidence=envelope.body.evidence;
|
|
108
|
+
insist(evidence&&evidence.parity&&evidence.activation&&evidence.rollback&&evidence.restore&&evidence.windows_gate,'R44 parent closure evidence set incomplete');
|
|
109
|
+
for(const [name,item] of Object.entries(evidence)){
|
|
110
|
+
insist(typeof item?.path==='string'&&HEX64.test(item?.sha256??''),`R44 parent ${name} evidence identity malformed`);
|
|
111
|
+
insist(sha256(await readFile(item.path))===item.sha256,`R44 parent ${name} evidence hash mismatch`);
|
|
112
|
+
}
|
|
113
|
+
const parity=JSON.parse(await readFile(evidence.parity.path,'utf8'));
|
|
114
|
+
insist(parity?.schema==='deadbyte.r43-parity.v1'&&parity.status==='passed','R44 parent parity status mismatch');
|
|
115
|
+
insist(parity.candidate?.release_id===parent.parent_release_id&&parity.candidate?.manifest_sha256===parent.parent_manifest_sha256,'R44 parent parity candidate mismatch');
|
|
116
|
+
insist(parity.successor?.release_id===parent.parent_release_id&&parity.successor?.manifest_sha256===parent.parent_manifest_sha256,'R44 parent parity successor mismatch');
|
|
117
|
+
insist(parity.successor_disarmed?.status==='passed','R44 parent successor-disarmed proof missing');
|
|
118
|
+
|
|
119
|
+
const releaseFiles=await verifyTree(parent.parent_release_root,'MANIFEST.SHA256',parent.parent_manifest_sha256,parent.parent_manifest_file_count);
|
|
120
|
+
const generationFiles=await verifyTree(parent.parent_generation_root,'GENERATION.SHA256',parent.parent_generation_manifest_sha256,parent.parent_generation_file_count);
|
|
121
|
+
return {
|
|
122
|
+
ok:true,
|
|
123
|
+
status:'passed',
|
|
124
|
+
proof_class:parent.parent_proof,
|
|
125
|
+
release_id:parent.parent_release_id,
|
|
126
|
+
manifest_sha256:parent.parent_manifest_sha256,
|
|
127
|
+
generation_manifest_sha256:parent.parent_generation_manifest_sha256,
|
|
128
|
+
release_files:releaseFiles,
|
|
129
|
+
generation_files:generationFiles,
|
|
130
|
+
closure_sha256:parent.parent_final_closure_sha256,
|
|
131
|
+
closure_file_sha256:parent.parent_final_closure_file_sha256,
|
|
132
|
+
signer_key_id:keyId,
|
|
133
|
+
recorded_all_disarmed:true
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
138
|
+
if(invoked){
|
|
139
|
+
const file=process.argv[2]??path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..','R44-PARENT.json');
|
|
140
|
+
verifyR44Parent(file).then(result=>console.log(JSON.stringify(result,null,2)))
|
|
141
|
+
.catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
142
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
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 { canonicalJson } from '../src/canonical-json.mjs';
|
|
7
|
+
import { readAndVerifyR42EvalEvidence } from '../src/agent-eval-runner-r42.mjs';
|
|
8
|
+
|
|
9
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const root=path.resolve(here,'..');
|
|
11
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
12
|
+
const marker='DEADBYTE V0.14.0 / R42 WINDOWS BATCH GATE: PASS';
|
|
13
|
+
function insist(ok,message){if(!ok) throw new Error(message);}
|
|
14
|
+
|
|
15
|
+
export async function writeWindowsGateEvidence({
|
|
16
|
+
candidateRoot=root,
|
|
17
|
+
stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
|
|
18
|
+
clock=()=>new Date()
|
|
19
|
+
}={}){
|
|
20
|
+
const candidate=path.resolve(candidateRoot);
|
|
21
|
+
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
22
|
+
const manifestSha256=sha256(manifestBytes);
|
|
23
|
+
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
24
|
+
insist(pkg.version==='0.14.0',`Windows gate evidence requires V0.14.0, found ${pkg.version}`);
|
|
25
|
+
|
|
26
|
+
const suite=JSON.parse(await readFile(path.join(candidate,'harness','r42-agent-evals.json'),'utf8'));
|
|
27
|
+
const suiteSha256=sha256(Buffer.from(canonicalJson(suite),'utf8'));
|
|
28
|
+
const evalId=`r42-${manifestSha256.slice(0,16)}-${suiteSha256.slice(0,16)}`;
|
|
29
|
+
const evalPath=path.join(path.resolve(stateRoot),'evidence','release','r42-agent-evals','agent_eval',`${evalId}.json`);
|
|
30
|
+
const evalVerified=await readAndVerifyR42EvalEvidence(evalPath,{subjectManifestSha256:manifestSha256,suiteSha256});
|
|
31
|
+
|
|
32
|
+
const completed=clock();
|
|
33
|
+
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
|
|
34
|
+
const evidence={
|
|
35
|
+
schema:'deadbyte.r42-windows-gate.v1',status:'passed',exit_code:0,version:'0.14.0',
|
|
36
|
+
marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256,
|
|
37
|
+
model_eval:{path:evalPath,evidence_sha256:evalVerified.evidence_sha256,payload_sha256:evalVerified.payload_sha256,
|
|
38
|
+
suite_sha256:suiteSha256,case_count:evalVerified.payload.case_count}
|
|
39
|
+
};
|
|
40
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
|
|
41
|
+
const dir=path.join(path.resolve(stateRoot),'evidence','release');
|
|
42
|
+
await mkdir(dir,{recursive:true});
|
|
43
|
+
const file=path.join(dir,`r42-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
44
|
+
try{
|
|
45
|
+
const handle=await open(file,'wx',0o600);
|
|
46
|
+
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
47
|
+
return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256,model_eval:evidence.model_eval};
|
|
48
|
+
}catch(error){
|
|
49
|
+
if(error?.code!=='EEXIST') throw error;
|
|
50
|
+
const existingBytes=await readFile(file);
|
|
51
|
+
const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
52
|
+
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing R42 Windows gate evidence invalid');
|
|
53
|
+
insist(existing.version==='0.14.0'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing R42 Windows gate identity mismatch');
|
|
54
|
+
insist(existing.model_eval?.evidence_sha256===evidence.model_eval.evidence_sha256&&existing.model_eval?.suite_sha256===suiteSha256,'existing R42 Windows gate model-eval mismatch');
|
|
55
|
+
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256,model_eval:existing.model_eval};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
60
|
+
if(invoked){
|
|
61
|
+
writeWindowsGateEvidence()
|
|
62
|
+
.then(result=>console.log(JSON.stringify(result)))
|
|
63
|
+
.catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
64
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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 { verifyR43Parent } from './verify-r43-parent.mjs';
|
|
7
|
+
|
|
8
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const root=path.resolve(here,'..');
|
|
10
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const marker='DEADBYTE V0.14.1 / R43 AUTHORITY HARDENING WINDOWS BATCH GATE: PASS';
|
|
12
|
+
function insist(ok,message){if(!ok)throw new Error(message);}
|
|
13
|
+
|
|
14
|
+
export async function writeWindowsGateEvidence({
|
|
15
|
+
candidateRoot=root,
|
|
16
|
+
stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
|
|
17
|
+
clock=()=>new Date()
|
|
18
|
+
}={}){
|
|
19
|
+
const candidate=path.resolve(candidateRoot);
|
|
20
|
+
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
21
|
+
const manifestSha256=sha256(manifestBytes);
|
|
22
|
+
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
23
|
+
insist(pkg.version==='0.14.1',`Windows gate evidence requires V0.14.1, found ${pkg.version}`);
|
|
24
|
+
const parent=await verifyR43Parent(path.join(candidate,'R43-PARENT.json'));
|
|
25
|
+
const completed=clock();
|
|
26
|
+
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
|
|
27
|
+
const evidence={
|
|
28
|
+
schema:'deadbyte.r43-windows-gate.v1',status:'passed',exit_code:0,version:'0.14.1',
|
|
29
|
+
marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256,
|
|
30
|
+
parent:{release_id:parent.parent_release_id,manifest_sha256:parent.parent_manifest_sha256,
|
|
31
|
+
generation_manifest_sha256:parent.parent_generation_manifest_sha256,
|
|
32
|
+
activation_receipt_sha256:parent.parent_activation_receipt_sha256},
|
|
33
|
+
hardening:{authority_toctou:true,absolute_execution_deadline:true,pre_spawn_authority_recheck:true,
|
|
34
|
+
full_regression_required:true,model_path_changed:false}
|
|
35
|
+
};
|
|
36
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
|
|
37
|
+
const dir=path.join(path.resolve(stateRoot),'evidence','release');
|
|
38
|
+
await mkdir(dir,{recursive:true});
|
|
39
|
+
const file=path.join(dir,`r43-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
40
|
+
try{
|
|
41
|
+
const handle=await open(file,'wx',0o600);
|
|
42
|
+
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
43
|
+
return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256,parent:evidence.parent};
|
|
44
|
+
}catch(error){
|
|
45
|
+
if(error?.code!=='EEXIST')throw error;
|
|
46
|
+
const existingBytes=await readFile(file);
|
|
47
|
+
const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
48
|
+
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing R43 Windows gate evidence invalid');
|
|
49
|
+
insist(existing.version==='0.14.1'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing R43 Windows gate identity mismatch');
|
|
50
|
+
insist(existing.parent?.release_id===parent.parent_release_id&&existing.parent?.activation_receipt_sha256===parent.parent_activation_receipt_sha256,'existing R43 parent evidence mismatch');
|
|
51
|
+
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256,parent:existing.parent};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
55
|
+
if(invoked)writeWindowsGateEvidence().then(value=>console.log(JSON.stringify(value))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
@@ -0,0 +1,55 @@
|
|
|
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 { verifyR44Parent } from './verify-r44-parent.mjs';
|
|
7
|
+
|
|
8
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const root=path.resolve(here,'..');
|
|
10
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const marker='DEADBYTE V0.15.0 / R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS';
|
|
12
|
+
function insist(ok,message){if(!ok)throw new Error(message);}
|
|
13
|
+
|
|
14
|
+
export async function writeWindowsGateEvidence({
|
|
15
|
+
candidateRoot=root,
|
|
16
|
+
stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
|
|
17
|
+
clock=()=>new Date()
|
|
18
|
+
}={}){
|
|
19
|
+
const candidate=path.resolve(candidateRoot);
|
|
20
|
+
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
21
|
+
const manifestSha256=sha256(manifestBytes);
|
|
22
|
+
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
23
|
+
insist(pkg.version==='0.15.0',`Windows gate evidence requires V0.15.0, found ${pkg.version}`);
|
|
24
|
+
const parent=await verifyR44Parent(path.join(candidate,'R44-PARENT.json'));
|
|
25
|
+
const completed=clock();
|
|
26
|
+
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
|
|
27
|
+
const evidence={
|
|
28
|
+
schema:'deadbyte.r44-windows-gate.v1',status:'passed',exit_code:0,version:'0.15.0',
|
|
29
|
+
marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256,
|
|
30
|
+
parent:{release_id:parent.release_id,manifest_sha256:parent.manifest_sha256,
|
|
31
|
+
generation_manifest_sha256:parent.generation_manifest_sha256,
|
|
32
|
+
final_closure_sha256:parent.closure_sha256,final_closure_file_sha256:parent.closure_file_sha256,
|
|
33
|
+
signer_key_id:parent.signer_key_id},
|
|
34
|
+
features:{skill_integrity:true,agent_backend_persistence:true,codex_protocol_contract:true,
|
|
35
|
+
remote_device_identity:true,durable_job_supervisor:true,real_external_supervisor_smoke:true,
|
|
36
|
+
full_regression_required:true,codex_live_binary_required:false}
|
|
37
|
+
};
|
|
38
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
|
|
39
|
+
const dir=path.join(path.resolve(stateRoot),'evidence','release');await mkdir(dir,{recursive:true});
|
|
40
|
+
const file=path.join(dir,`r44-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
41
|
+
try{
|
|
42
|
+
const handle=await open(file,'wx',0o600);try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
43
|
+
return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256,parent:evidence.parent};
|
|
44
|
+
}catch(error){
|
|
45
|
+
if(error?.code!=='EEXIST')throw error;
|
|
46
|
+
const existingBytes=await readFile(file);
|
|
47
|
+
const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
48
|
+
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing R44 Windows gate evidence invalid');
|
|
49
|
+
insist(existing.version==='0.15.0'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing R44 Windows gate identity mismatch');
|
|
50
|
+
insist(existing.parent?.release_id===parent.release_id&&existing.parent?.final_closure_sha256===parent.closure_sha256,'existing R44 parent evidence mismatch');
|
|
51
|
+
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256,parent:existing.parent};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
55
|
+
if(invoked)writeWindowsGateEvidence().then(value=>console.log(JSON.stringify(value))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|