deadbyte-mcp 0.15.43 → 0.15.44
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 +128 -67
- package/PROVENANCE.json +23 -12
- package/README.txt +18 -18
- package/RELEASE.json +28 -14
- package/SBOM.cdx.json +14 -2
- package/TEST-MATRIX.json +41 -10
- 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-desktop-input-r40.obj +0 -0
- package/bin/deadbyte-desktop-observer-r40.obj +0 -0
- package/bin/deadbyte-desktop-uia-r40.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/bin/deadbyte-native-inspect-r67.exe +0 -0
- package/bin/deadbyte-native-inspect-r67.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/bridge/package.json +1 -1
- package/controller/deadbyte-desktop-policy.json +5 -5
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R67-ALPHA-REFERENCE-DIFFERENTIAL.md +42 -0
- package/docs/R67-ALPHA-STATIC-COMPARISON.json +205 -0
- package/docs/R67-CANDIDATE-PARENT.json +10 -0
- package/docs/R67-EVIDENCE-RECONCILE-CLOSEOUT-20261011.md +64 -0
- package/docs/R67-FULL-REGRESSION-UNKNOWN.json +27 -0
- package/docs/R67-NATIVE-INSPECT-BINARY.json +11 -0
- package/docs/R67-NPM-EXDEV-PRESERVATION-20261011.md +39 -0
- package/docs/R67-OBSERVATION-TRUTH.md +82 -0
- package/docs/R67-REFERENCE-GAP-MATRIX.json +57 -0
- package/docs/R67-REGRESSION-CLOSURE-20261011.md +24 -0
- package/native/deadbyte-native-inspect-r67.cpp +252 -0
- package/package.json +6 -3
- package/proof/CONTAINMENT-BUILD.txt +6 -6
- package/scripts/build-native-inspector-r67.ps1 +28 -0
- package/scripts/gate-windows-r67.ps1 +56 -0
- package/scripts/npm-preserve-artifact-r67.mjs +99 -0
- package/scripts/npm-release-r48.mjs +10 -2
- package/scripts/npm-release-readiness-r67.mjs +26 -0
- package/scripts/r67-acquire-alpha-reference.mjs +95 -0
- package/scripts/r67-audit-nonpass-source.mjs +39 -0
- package/scripts/r67-compare-desktop-alpha.mjs +48 -0
- package/scripts/r67-diagnose-failed-shard.mjs +23 -0
- package/scripts/r67-durable-batch.mjs +42 -0
- package/scripts/r67-focused-gate.mjs +58 -0
- package/scripts/r67-full-regression.mjs +28 -0
- package/scripts/r67-independent-observation-verify.mjs +36 -0
- package/scripts/r67-independent-runtime-observation-verify.mjs +63 -0
- package/scripts/r67-nonpass-adjudicate.mjs +20 -0
- package/scripts/r67-publish-boundary-audit.mjs +32 -0
- package/scripts/r67-regression-reconcile.mjs +10 -0
- package/scripts/r67-regression-shard-run.mjs +70 -0
- package/scripts/r67-run-shard-batch.mjs +18 -0
- package/scripts/r67-stage-candidate.mjs +30 -0
- package/scripts/r67-verify-parent-ping.mjs +22 -0
- package/scripts/release-manifest.mjs +1 -0
- package/src/activation-continuity-engine-r65.mjs +2 -1
- package/src/autonomous-runtime.mjs +1 -1
- package/src/deadbyte-cli.mjs +33 -1
- package/src/machine-fs-smoke-client.mjs +13 -5
- package/src/machine-identity.mjs +59 -2
- package/src/machine-mcp-tools.mjs +8 -0
- package/src/mcp-server.mjs +11 -2
- package/src/native-inspector-r67.mjs +66 -0
- package/src/r67-diagnostic-export.mjs +118 -0
- package/src/r67-diagnostics-verify.mjs +82 -0
- package/src/r67-evidence-reconcile.mjs +128 -0
- package/src/r67-native-observation-authority.mjs +45 -0
- package/src/r67-observation-receipt.mjs +43 -0
- package/src/r67-regression-shards.mjs +176 -0
- package/src/remote-live-log.mjs +14 -10
- package/src/tool-audit.mjs +1 -1
- package/src/version.mjs +1 -1
- package/test/agent-runtime.test.mjs +1 -1
- package/test/autonomous-loop.test.mjs +11 -6
- package/test/autonomous-runtime.test.mjs +1 -1
- package/test/coding-plane.test.mjs +1 -1
- package/test/full-max-catalog-r46.test.mjs +1 -1
- package/test/output-schema.test.mjs +1 -1
- package/test/r51-live-log-polling.test.mjs +12 -0
- package/test/r53-release-contract.test.mjs +1 -1
- package/test/r54-release-contract.test.mjs +1 -1
- package/test/r55-release-contract.test.mjs +1 -1
- package/test/r56-release-contract.test.mjs +1 -1
- package/test/r57-release-contract.test.mjs +1 -1
- package/test/r58-bundled-bridge.test.mjs +1 -1
- package/test/r58-release-contract.test.mjs +2 -2
- package/test/r58-windows-gate.test.mjs +1 -1
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r60-release-contract.test.mjs +3 -3
- package/test/r61-release-contract.test.mjs +1 -1
- package/test/r62-release-contract.test.mjs +1 -1
- package/test/r63-release-contract.test.mjs +1 -1
- package/test/r64-release-contract.test.mjs +1 -1
- package/test/r65-epoch-native-activation-integration.test.mjs +4 -4
- package/test/r65-release-contract.test.mjs +1 -1
- package/test/r66-release-contract.test.mjs +2 -1
- package/test/r67-cli-integration.test.mjs +41 -0
- package/test/r67-diagnostics-cli.test.mjs +60 -0
- package/test/r67-diagnostics-verify.test.mjs +49 -0
- package/test/r67-diagnostics-zip-oracle.test.mjs +38 -0
- package/test/r67-diagnostics.test.mjs +60 -0
- package/test/r67-evidence-reconcile.test.mjs +186 -0
- package/test/r67-isolated-slot-rollback-restore.test.mjs +62 -0
- package/test/r67-live-log-secret-canary.test.mjs +44 -0
- package/test/r67-machine-fs-smoke-epoch.test.mjs +22 -0
- package/test/r67-native-inspector.test.mjs +131 -0
- package/test/r67-native-observation-authority.test.mjs +49 -0
- package/test/r67-npm-cross-volume.test.mjs +74 -0
- package/test/r67-npm-publish-gate.test.mjs +38 -0
- package/test/r67-regression-shards.test.mjs +184 -0
- package/test/r67-release-contract.test.mjs +44 -0
- package/test/r67-runtime-observation-binding.test.mjs +86 -0
- package/test/r67-server-observation-wiring.test.mjs +12 -0
- package/test/r67-signed-receipt.test.mjs +66 -0
- package/test/r67-skip-rationale.test.mjs +31 -0
- package/test/r67-tool-annotations.test.mjs +21 -0
- package/test/r67-windows-gate-argv.test.mjs +13 -0
- package/test/release-version.test.mjs +1 -1
- package/test/remote-live-log-r36.test.mjs +10 -0
- package/test/remote-live-log-r37.test.mjs +29 -0
- package/test/semantic-multilang.test.mjs +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {readdir,mkdir,open,rename,lstat} from 'node:fs/promises';
|
|
2
|
+
import {spawnSync} from 'node:child_process';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
7
|
+
const operationId=process.argv[2];
|
|
8
|
+
if(!/^[a-z0-9][a-z0-9._-]{4,63}$/.test(operationId??''))throw new Error('unique operation ID required');
|
|
9
|
+
const evidence=path.resolve(root,'..','..','testing','0.15.44-r67','regression');
|
|
10
|
+
await mkdir(evidence,{recursive:true});
|
|
11
|
+
const finalFile=path.join(evidence,operationId+'.json');
|
|
12
|
+
try{await lstat(finalFile);throw new Error('operation already completed; reconcile receipt, never rerun');}
|
|
13
|
+
catch(e){if(e.code!=='ENOENT')throw e;}
|
|
14
|
+
const names=(await readdir(path.join(root,'test'))).filter(s=>s.endsWith('.test.mjs')).sort();
|
|
15
|
+
const args=['--test','--test-concurrency=4',...names.map(n=>'test/'+n)];
|
|
16
|
+
const started=Date.now();
|
|
17
|
+
const r=spawnSync(process.execPath,args,{cwd:root,shell:false,windowsHide:true,encoding:'utf8',maxBuffer:32*1024*1024,timeout:220000});
|
|
18
|
+
const out=String(r.stdout??''),err=String(r.stderr??'');
|
|
19
|
+
const parse=k=>{const m=[...out.matchAll(new RegExp('(?:^|\n)[#ℹ ]*'+k+'\\s+(\\d+(?:\\.\\d+)?)','g'))];return m.length?Number(m[m.length-1][1]):null};
|
|
20
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
21
|
+
const body={schema:'deadbyte.r67-full-source-regression.v1',status:r.status===0&&!r.error?'passed':'failed',tests_files:names.length,test_count:parse('tests'),passed:parse('pass'),failed:parse('fail'),skipped:parse('skipped'),exit_code:r.status,timed_out:r.error?.code==='ETIMEDOUT',elapsed_ms:Date.now()-started,stdout_sha256:sha(Buffer.from(out)),stderr_sha256:sha(Buffer.from(err))};
|
|
22
|
+
const receipt={...body,operation_id:operationId,started_at_utc:new Date(started).toISOString(),finished_at_utc:new Date().toISOString(),test_names_sha256:sha(Buffer.from(JSON.stringify(names)))};
|
|
23
|
+
const tmp=path.join(evidence,operationId+'.tmp-'+process.pid);
|
|
24
|
+
const handle=await open(tmp,'wx');
|
|
25
|
+
try{await handle.writeFile(JSON.stringify(receipt,null,2)+'\\n');await handle.sync();}finally{await handle.close();}
|
|
26
|
+
await rename(tmp,finalFile);
|
|
27
|
+
console.log(JSON.stringify({receipt,receipt_path:finalFile},null,2));
|
|
28
|
+
if(body.status!=='passed'){console.error('FULL_TEST_OUTPUT_TAIL\n'+out.slice(-18000));console.error('FULL_TEST_ERROR_TAIL\n'+err.slice(-4000));process.exitCode=1;}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {createHash,createPublicKey,verify as edVerify} from 'node:crypto';
|
|
2
|
+
const h=b=>createHash('sha256').update(b).digest('hex');
|
|
3
|
+
function stable(v){
|
|
4
|
+
if(v===null||typeof v!=='object')return JSON.stringify(v);
|
|
5
|
+
if(Array.isArray(v))return '['+v.map(stable).join(',')+']';
|
|
6
|
+
return '{'+Object.keys(v).sort().map(k=>JSON.stringify(k)+':'+stable(v[k])).join(',')+'}';
|
|
7
|
+
}
|
|
8
|
+
const hex=x=>typeof x==='string'&&/^[a-f0-9]{64}$/.test(x);
|
|
9
|
+
const canonicalHash=v=>h(Buffer.from(stable(v),'utf8'));
|
|
10
|
+
export function independentlyVerifyR67Receipt({receipt,result,trustedPublicSpkiBase64,requestArgs,expectedExecutableSha256}){
|
|
11
|
+
try{
|
|
12
|
+
if(!receipt||receipt.schema!=='deadbyte.native-observation-receipt.r67.v1')return {ok:false,reason:'invalid receipt schema'};
|
|
13
|
+
if(typeof trustedPublicSpkiBase64!=='string')return {ok:false,reason:'trusted public key required'};
|
|
14
|
+
const spki=Buffer.from(trustedPublicSpkiBase64,'base64');
|
|
15
|
+
if(spki.toString('base64')!==trustedPublicSpkiBase64)return {ok:false,reason:'bad base64 public key'};
|
|
16
|
+
const trust=h(spki);
|
|
17
|
+
if(receipt.signer_key_id!==trust||receipt.attestation?.key_id!==trust||receipt.attestation.algorithm!=='ed25519')return {ok:false,reason:'signer is not trusted'};
|
|
18
|
+
if(!hex(receipt.request_sha256)||!hex(receipt.executable_sha256)||!hex(receipt.result_sha256)||!hex(receipt.receipt_sha256))return {ok:false,reason:'binding malformed'};
|
|
19
|
+
if(!['process','identity','map','pe'].includes(receipt.operation))return {ok:false,reason:'invalid operation'};
|
|
20
|
+
if(!Array.isArray(requestArgs)||requestArgs.some(x=>typeof x!=='string')||receipt.request_sha256!==h(Buffer.from(JSON.stringify(requestArgs),'utf8')))return {ok:false,reason:'request args mismatch'};
|
|
21
|
+
if(!hex(expectedExecutableSha256)||receipt.executable_sha256!==expectedExecutableSha256)return {ok:false,reason:'trusted executable mismatch'};
|
|
22
|
+
if(!['ok','failed'].includes(receipt.result_status)||receipt.result_status!==result?.status)return {ok:false,reason:'result status mismatch'};
|
|
23
|
+
if(result.schema!=='deadbyte.native-inspect.r67.v1'||(result.status==='ok'&&(result.operation!==receipt.operation||result.data_sha256!==h(Buffer.from(JSON.stringify(result.data),'utf8')))))return {ok:false,reason:'result invalid'};
|
|
24
|
+
if(receipt.result_sha256!==canonicalHash(result))return {ok:false,reason:'result SHA mismatch'};
|
|
25
|
+
const {attestation,...signed}=receipt;
|
|
26
|
+
const {receipt_sha256,...body}=signed;
|
|
27
|
+
if(canonicalHash(body)!==receipt_sha256)return {ok:false,reason:'receipt SHA mismatch'};
|
|
28
|
+
const signature=Buffer.from(attestation.signature_base64,'base64');
|
|
29
|
+
if(signature.length!==64||signature.toString('base64')!==attestation.signature_base64)return {ok:false,reason:'signature encoding invalid'};
|
|
30
|
+
const pub=createPublicKey({key:spki,format:'der',type:'spki'});
|
|
31
|
+
if(pub.asymmetricKeyType!=='ed25519')return {ok:false,reason:'not Ed25519'};
|
|
32
|
+
const message=Buffer.concat([Buffer.from('DEADBYTE-R67-OBSERVATION-V1\0','utf8'),Buffer.from(stable(signed),'utf8')]);
|
|
33
|
+
if(!edVerify(null,message,pub,signature))return {ok:false,reason:'signature invalid'};
|
|
34
|
+
return {ok:true,signature_valid:true,receipt_sha256,result_sha256:receipt.result_sha256,signer_key_id:trust};
|
|
35
|
+
}catch(error){return {ok:false,reason:String(error?.message||error)};}
|
|
36
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {createHash,createPublicKey,verify as ed25519Verify} from 'node:crypto';
|
|
2
|
+
import {nativeInspectArgs} from '../src/native-inspector-r67.mjs';
|
|
3
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
4
|
+
const hex64=x=>typeof x==='string'&&/^[a-f0-9]{64}$/.test(x);
|
|
5
|
+
const domain=Buffer.from('DEADBYTE-R67-MACHINE-OBSERVATION-V1\0','utf8');
|
|
6
|
+
function serialize(v){
|
|
7
|
+
const canon=value=>Array.isArray(value)?value.map(canon):
|
|
8
|
+
value!==null&&typeof value==='object'?Object.fromEntries(Object.keys(value).sort().map(k=>[k,canon(value[k])])):value;
|
|
9
|
+
return JSON.stringify(canon(v));
|
|
10
|
+
}
|
|
11
|
+
export function independentlyVerifyR67RuntimeObservation({
|
|
12
|
+
receipt,result,requestArgs,machinePublicSpkiBase64,expectedMachineStatus,
|
|
13
|
+
expectedPolicySha256,expectedGrantId
|
|
14
|
+
}={}){
|
|
15
|
+
try{
|
|
16
|
+
if(!receipt||!result||!Array.isArray(requestArgs)||!expectedMachineStatus)return {ok:false,reason:'missing binding'};
|
|
17
|
+
if(receipt.schema!=='deadbyte.native-observation-runtime-r67.v1')return {ok:false,reason:'schema'};
|
|
18
|
+
if(!hex64(receipt.machine_id)||!hex64(receipt.request_sha256)||!hex64(receipt.result_sha256)||
|
|
19
|
+
!hex64(receipt.executable_sha256)||!hex64(receipt.generation_manifest_sha256)||
|
|
20
|
+
!hex64(receipt.release_manifest_sha256)||!hex64(receipt.online_epoch))return {ok:false,reason:'digest or generation'};
|
|
21
|
+
if(!Number.isInteger(receipt.identity_generation)||receipt.identity_generation<1||
|
|
22
|
+
!Number.isFinite(new Date(receipt.observed_at_utc).getTime())||
|
|
23
|
+
new Date(receipt.observed_at_utc).toISOString()!==receipt.observed_at_utc)return {ok:false,reason:'identity generation or timestamp'};
|
|
24
|
+
if(typeof machinePublicSpkiBase64!=='string'||Buffer.from(machinePublicSpkiBase64,'base64').toString('base64')!==machinePublicSpkiBase64)
|
|
25
|
+
return {ok:false,reason:'public key encoding'};
|
|
26
|
+
const der=Buffer.from(machinePublicSpkiBase64,'base64');
|
|
27
|
+
const key=createPublicKey({key:der,format:'der',type:'spki'});
|
|
28
|
+
if(key.asymmetricKeyType!=='ed25519'||sha(der)!==receipt.machine_id)return {ok:false,reason:'wrong machine key'};
|
|
29
|
+
for(const field of ['machine_id','identity_generation','online_epoch','release_id','release_manifest_sha256','generation_manifest_sha256'])
|
|
30
|
+
if(receipt[field]!==expectedMachineStatus[field])return {ok:false,reason:'runtime identity, release or generation changed'};
|
|
31
|
+
if(expectedMachineStatus.public_key_spki_base64!==machinePublicSpkiBase64)return {ok:false,reason:'status key changed'};
|
|
32
|
+
if(!hex64(expectedPolicySha256)||receipt.authority?.policy_sha256!==expectedPolicySha256||
|
|
33
|
+
receipt.authority?.grant_id!==expectedGrantId||
|
|
34
|
+
receipt.authority?.scope!=='native-observe-readonly'||
|
|
35
|
+
!Number.isSafeInteger(receipt.authority?.authority_generation)||
|
|
36
|
+
receipt.authority.authority_generation<1)return {ok:false,reason:'authority'};
|
|
37
|
+
if(Object.keys(receipt.authority).sort().join('|')!==['authority_generation','grant_id','policy_sha256','scope'].sort().join('|'))
|
|
38
|
+
return {ok:false,reason:'unexpected authority fields'};
|
|
39
|
+
const nativeArgs=nativeInspectArgs(requestArgs);
|
|
40
|
+
if(receipt.operation!==nativeArgs[0]||receipt.request_sha256!==sha(Buffer.from(JSON.stringify(nativeArgs),'utf8')))
|
|
41
|
+
return {ok:false,reason:'wrong native request'};
|
|
42
|
+
if(result.schema!=='deadbyte.native-inspect.r67.v1'||!['ok','failed'].includes(result.status)||
|
|
43
|
+
receipt.result_status!==result.status||receipt.result_sha256!==sha(Buffer.from(serialize(result),'utf8')))
|
|
44
|
+
return {ok:false,reason:'native result hash'};
|
|
45
|
+
if(result.status==='ok'&&(result.operation!==nativeArgs[0]||!result.data||
|
|
46
|
+
result.data_sha256!==sha(Buffer.from(JSON.stringify(result.data),'utf8'))))
|
|
47
|
+
return {ok:false,reason:'invalid native data digest'};
|
|
48
|
+
const att=receipt.attestation;
|
|
49
|
+
if(att?.algorithm!=='ed25519'||att.key_id!==receipt.machine_id||
|
|
50
|
+
typeof att.signature_base64!=='string')return {ok:false,reason:'attestation'};
|
|
51
|
+
const signature=Buffer.from(att.signature_base64,'base64');
|
|
52
|
+
if(signature.length!==64||signature.toString('base64')!==att.signature_base64)return {ok:false,reason:'signature encoding'};
|
|
53
|
+
const {attestation,...body}=receipt;
|
|
54
|
+
const keys=['schema','observed_at_utc','machine_id','identity_generation','online_epoch','release_id',
|
|
55
|
+
'release_manifest_sha256','generation_manifest_sha256','authority','operation','request_sha256',
|
|
56
|
+
'executable_sha256','result_status','result_sha256'];
|
|
57
|
+
if(Object.keys(body).sort().join('|')!==keys.sort().join('|'))return {ok:false,reason:'unexpected body fields'};
|
|
58
|
+
const valid=ed25519Verify(null,Buffer.concat([domain,Buffer.from(serialize(body),'utf8')]),key,signature);
|
|
59
|
+
if(!valid)return {ok:false,reason:'signature invalid'};
|
|
60
|
+
return {ok:true,signature_valid:true,signer_key_id:receipt.machine_id,
|
|
61
|
+
release_id:receipt.release_id,generation_manifest_sha256:receipt.generation_manifest_sha256};
|
|
62
|
+
}catch(e){return {ok:false,reason:'verification failed: '+String(e?.message||e)};}
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {readFile,writeFile,mkdir} from 'node:fs/promises';
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const base=process.cwd();
|
|
5
|
+
const source=path.resolve(base,'..','..','testing','0.15.44-r67','R67-NONPASS-SOURCE-AUDIT-20261011.json');
|
|
6
|
+
const output=path.resolve(base,'..','..','testing','0.15.44-r67','R67-NONPASS-ADJUDICATION-CANDIDATE.json');
|
|
7
|
+
const x=JSON.parse(await readFile(source,'utf8'));
|
|
8
|
+
if(x.schema!=='deadbyte.r67-nonpass-source-audit.v1'||x.count!==42||x.cases.length!==42)throw Error('Unexpected source audit');
|
|
9
|
+
const rows=x.cases.map((item,index)=>{
|
|
10
|
+
const candidates=(item.source_matches??[]).filter(m=>typeof m.context==='string');
|
|
11
|
+
const conditions=candidates.map(m=>({file:m.file,line:m.line,version_guard:/skip:\s*currentPackage\.version\s*!==\s*['"]([0-9.]+)['"]/.exec(m.context)?.[1]??null,explicit_skip:/\btest\.skip\s*\(/.test(m.context),historical_skip:/skipHistorical\s*\(/.test(m.context)}));
|
|
12
|
+
const reason=item.reason?{kind:'SOURCE_REPORTED',text:item.reason}:{kind:'UNCLASSIFIED',text:null};
|
|
13
|
+
return {index,shard:item.shard,name:item.name,source_reported_reason:reason,source_matches:conditions,
|
|
14
|
+
evidence_level:item.reason?'SOURCE_LOG_REASON_ONLY':'NO_PER_CASE_REASON',
|
|
15
|
+
release_gate:'BLOCKED_UNTIL_CASE_LEVEL_PROVENANCE'};
|
|
16
|
+
});
|
|
17
|
+
const counts={cases:rows.length,source_reported_reasons:rows.filter(r=>r.source_reported_reason.kind==='SOURCE_REPORTED').length,unclassified:rows.filter(r=>r.source_reported_reason.kind==='UNCLASSIFIED').length,version_guard_candidates:rows.filter(r=>r.source_matches.some(m=>m.version_guard)).length,explicit_skip_candidates:rows.filter(r=>r.source_matches.some(m=>m.explicit_skip)).length};
|
|
18
|
+
const data={schema:'deadbyte.r67-nonpass-adjudication.v1',status:'BLOCKED_NONPASS_CLASSIFICATION',source_audit_sha256:createHash('sha256').update(await readFile(source)).digest('hex'),counts,rows};
|
|
19
|
+
await writeFile(output,JSON.stringify(data,null,2)+'\n',{flag:'wx'});
|
|
20
|
+
console.log(JSON.stringify({status:data.status,counts,output}));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {createHash} from 'node:crypto';
|
|
2
|
+
import {readFile,lstat} from 'node:fs/promises';
|
|
3
|
+
import {resolveStateRoot} from '../src/state-root.mjs';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
|
|
7
|
+
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
8
|
+
const version=JSON.parse(await readFile(path.join(root,'package.json'),'utf8')).version;
|
|
9
|
+
const basename='deadbyte-mcp-'+version+'.tgz';
|
|
10
|
+
const pubDir=path.join(resolveStateRoot(),'evidence','npm-publication',version);
|
|
11
|
+
const paths={
|
|
12
|
+
source:path.join(root,basename),
|
|
13
|
+
preserved:path.join(pubDir,basename),
|
|
14
|
+
claim:path.join(pubDir,'claim.json')
|
|
15
|
+
};
|
|
16
|
+
const outputs={};
|
|
17
|
+
for(const [kind,p] of Object.entries(paths)){
|
|
18
|
+
try{
|
|
19
|
+
const s=await lstat(p);
|
|
20
|
+
if(!s.isFile()||s.isSymbolicLink()){outputs[kind]={state:'NON_REGULAR_OR_LINK'};continue;}
|
|
21
|
+
const bytes=await readFile(p);
|
|
22
|
+
outputs[kind]={state:'EXISTS',bytes:bytes.length,sha256:createHash('sha256').update(bytes).digest('hex')};
|
|
23
|
+
if(kind==='claim'){
|
|
24
|
+
try{const j=JSON.parse(bytes.toString('utf8'));outputs[kind].schema=j.schema;outputs[kind].version=j.version;outputs[kind].manifest_sha256=j.manifest_sha256;outputs[kind].tarball_sha256=j.tarball_sha256;}
|
|
25
|
+
catch{outputs[kind].parse_error=true;}
|
|
26
|
+
}
|
|
27
|
+
}catch(e){if(e?.code==='ENOENT')outputs[kind]={state:'ABSENT'};else throw e;}
|
|
28
|
+
}
|
|
29
|
+
console.log(JSON.stringify({schema:'deadbyte.r67-publication-boundary-audit.v1',
|
|
30
|
+
version,production_mutation:false,network_access:false,publication_dispatch:false,
|
|
31
|
+
artifacts:outputs,conclusion:outputs.claim.state==='EXISTS'?'CLAIM_EXISTS_RECONCILE_BEFORE_ANY_DISPATCH':
|
|
32
|
+
'NO_LOCAL_CLAIM_OBSERVED_DO_NOT_ASSUME_REGISTRY_STATE'},null,2));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import {fileURLToPath} from 'node:url';
|
|
3
|
+
import {reconcileR67Evidence} from '../src/r67-evidence-reconcile.mjs';
|
|
4
|
+
|
|
5
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
6
|
+
const operationId=process.argv[2];
|
|
7
|
+
const evidenceRoot=path.resolve(root,'..','..','testing','0.15.44-r67','regression-shards');
|
|
8
|
+
const result=await reconcileR67Evidence({root,evidenceRoot,operationId});
|
|
9
|
+
console.log(JSON.stringify(result,null,2));
|
|
10
|
+
if(result.status!=='PASS')process.exitCode=2;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {readdir,mkdir,open,readFile,rename} from 'node:fs/promises';
|
|
2
|
+
import {spawnSync} from 'node:child_process';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {createR67ShardPlan,r67ShardTimeoutMs,r67RegressionTreeHash,parseR67TapSummary,parseR67NonpassCases,parseR67FailedCases} from '../src/r67-regression-shards.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
9
|
+
const action=process.argv[2],operation=process.argv[3],number=process.argv[4];
|
|
10
|
+
if(!['run','status'].includes(action)||!/^[a-z0-9][a-z0-9._-]{5,63}$/.test(operation??'')||!/^(?:0|[1-9][0-9]?)$/.test(number??''))throw new Error('usage: run|status uniqueOperationId index');
|
|
11
|
+
const index=Number(number);
|
|
12
|
+
if(index>=32)throw new Error('R67 shard index must be 0..31');
|
|
13
|
+
const names=(await readdir(path.join(root,'test'))).filter(n=>n.endsWith('.test.mjs')).map(n=>'test/'+n).sort();
|
|
14
|
+
const plan=createR67ShardPlan(names,32),shard=plan.shards[index];
|
|
15
|
+
const hash=b=>createHash('sha256').update(b).digest('hex');
|
|
16
|
+
const evidenceRoot=path.resolve(root,'..','..','testing','0.15.44-r67','regression-shards');
|
|
17
|
+
const directory=path.join(evidenceRoot,operation+'-shard-'+String(index).padStart(2,'0'));
|
|
18
|
+
const intentPath=path.join(directory,'intent.json'),resultPath=path.join(directory,'result.json');
|
|
19
|
+
if(action==='status'){
|
|
20
|
+
let intent,result;
|
|
21
|
+
try{intent=JSON.parse(await readFile(intentPath,'utf8'));}catch(error){if(error.code==='ENOENT'){console.log(JSON.stringify({status:'NOT_STARTED',operation,shard_index:index}));process.exit(0);}throw error;}
|
|
22
|
+
try{result=JSON.parse(await readFile(resultPath,'utf8'));}catch(error){if(error.code==='ENOENT'){console.log(JSON.stringify({status:'RUNNING_OR_OUTCOME_UNKNOWN',operation,shard_index:index,intent}));process.exit(0);}throw error;}
|
|
23
|
+
const {receipt_sha256,...body}=result;
|
|
24
|
+
if(receipt_sha256!==hash(Buffer.from(JSON.stringify(body),'utf8')))throw new Error('durable result receipt hash mismatch');
|
|
25
|
+
console.log(JSON.stringify({status:'COMPLETED_RECORD',operation,shard_index:index,result},null,2));
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
await mkdir(evidenceRoot,{recursive:true});
|
|
29
|
+
await mkdir(directory,{recursive:false}); // EEXIST means NEVER rerun: reconcile existing intent/result
|
|
30
|
+
const startedAt=new Date().toISOString();
|
|
31
|
+
const fileHashes=[];
|
|
32
|
+
for(const name of names)fileHashes.push([name,hash(await readFile(path.join(root,name)))]);
|
|
33
|
+
const test_tree_sha256=hash(Buffer.from(JSON.stringify(fileHashes),'utf8'));
|
|
34
|
+
const sourceTree=await r67RegressionTreeHash(root);
|
|
35
|
+
const intent={schema:'deadbyte.r67-shard-intent.v1',operation,shard_index:index,plan_sha256:plan.plan_sha256,
|
|
36
|
+
files_sha256:shard.files_sha256,test_tree_sha256,source_tree_sha256:sourceTree.sha256,
|
|
37
|
+
source_file_count:sourceTree.file_count,started_at_utc:startedAt,files:shard.files};
|
|
38
|
+
const intentHandle=await open(intentPath,'wx',0o600);
|
|
39
|
+
try{await intentHandle.writeFile(JSON.stringify(intent,null,2)+'\n');await intentHandle.sync();}finally{await intentHandle.close();}
|
|
40
|
+
const began=Date.now();
|
|
41
|
+
const configuredTimeoutMs=r67ShardTimeoutMs(shard);
|
|
42
|
+
const child=spawnSync(process.execPath,['--test','--test-reporter=tap','--test-concurrency=2',...shard.files],{
|
|
43
|
+
cwd:root,encoding:'utf8',windowsHide:true,shell:false,timeout:configuredTimeoutMs,maxBuffer:16*1024*1024
|
|
44
|
+
});
|
|
45
|
+
const output=String(child.stdout||''),stderr=String(child.stderr||'');
|
|
46
|
+
const tap=parseR67TapSummary(output);
|
|
47
|
+
const nonpass=parseR67NonpassCases(output);
|
|
48
|
+
const failures=parseR67FailedCases(output);
|
|
49
|
+
const testCount=tap?.tests??null,passed=tap?.pass??null,failed=tap?.fail??null;
|
|
50
|
+
let status='OUTCOME_UNKNOWN';
|
|
51
|
+
if(!child.error&&Number.isInteger(child.status)&&tap!==null){
|
|
52
|
+
status=(child.status===0&&failed===0&&testCount>=shard.files.length)?'PASS':'FAILED';
|
|
53
|
+
}
|
|
54
|
+
const body={schema:'deadbyte.r67-shard-result.v2',operation_id:operation,shard_index:index,
|
|
55
|
+
plan_sha256:plan.plan_sha256,files_sha256:shard.files_sha256,test_tree_sha256,
|
|
56
|
+
source_tree_sha256:sourceTree.sha256,source_file_count:sourceTree.file_count,
|
|
57
|
+
status,exit_code:child.status,test_count:testCount,passed,failed,
|
|
58
|
+
skipped:tap?.skipped??null,cancelled:tap?.cancelled??null,todo:tap?.todo??null,
|
|
59
|
+
...(nonpass?{nonpass_cases:nonpass.cases,nonpass_fully_classified:nonpass.fully_classified}:{}),
|
|
60
|
+
failure_cases:failures.cases,failure_cases_complete:failures.complete,
|
|
61
|
+
timed_out:child.error?.code==='ETIMEDOUT',failure_reason:child.error?.code??null,
|
|
62
|
+
elapsed_ms:Date.now()-began,configured_timeout_ms:configuredTimeoutMs,finished_at_utc:new Date().toISOString(),
|
|
63
|
+
stdout_sha256:hash(Buffer.from(output,'utf8')),stderr_sha256:hash(Buffer.from(stderr,'utf8'))};
|
|
64
|
+
const receipt={...body,receipt_sha256:hash(Buffer.from(JSON.stringify(body),'utf8'))};
|
|
65
|
+
const temporary=path.join(directory,'result.tmp-'+process.pid);
|
|
66
|
+
const h=await open(temporary,'wx',0o600);
|
|
67
|
+
try{await h.writeFile(JSON.stringify(receipt,null,2)+'\n');await h.sync();}finally{await h.close();}
|
|
68
|
+
await rename(temporary,resultPath);
|
|
69
|
+
console.log(JSON.stringify({status,receipt_path:resultPath,receipt},null,2));
|
|
70
|
+
if(status!=='PASS')process.exitCode=1;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {readFile} from 'node:fs/promises';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
6
|
+
const op=process.argv[2],start=Number(process.argv[3]),end=Number(process.argv[4]);
|
|
7
|
+
if(!/^[a-z0-9][a-z0-9._-]{5,63}$/.test(op??'')||!Number.isInteger(start)||!Number.isInteger(end)||start<0||end>32||end<=start||end-start>8)throw Error('usage: operation id, start, end (max eight)');
|
|
8
|
+
const runner=path.join(root,'scripts','r67-regression-shard-run.mjs');
|
|
9
|
+
const results=[];
|
|
10
|
+
for(let i=start;i<end;i++){
|
|
11
|
+
const found=spawnSync(process.execPath,[runner,'run',op,String(i)],{cwd:root,encoding:'utf8',shell:false,windowsHide:true,timeout:220000,maxBuffer:256*1024});
|
|
12
|
+
const receiptPath=path.resolve(root,'..','..','testing','0.15.44-r67','regression-shards',op+'-shard-'+String(i).padStart(2,'0'),'result.json');
|
|
13
|
+
let body=null;try{body=JSON.parse(await readFile(receiptPath,'utf8'));}catch{}
|
|
14
|
+
results.push({shard_index:i,transport_exit:found.status,child_error:found.error?.code??null,recorded_status:body?.status??'MISSING',test_count:body?.test_count??null,passed:body?.passed??null,skipped:body?.skipped??null,nonpass_classified:body?.nonpass_fully_classified??null,source_tree_sha256:body?.source_tree_sha256??null,receipt_sha256:body?.receipt_sha256??null});
|
|
15
|
+
if(!body){break;}
|
|
16
|
+
}
|
|
17
|
+
console.log(JSON.stringify({schema:'deadbyte.r67-batch-progress.v1',operation_id:op,results},null,2));
|
|
18
|
+
if(results.length!==end-start||results.some(r=>r.recorded_status!=='PASS'))process.exitCode=2;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {readFile,writeFile,stat,lstat,mkdir,copyFile} from 'node:fs/promises';
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
const candidate=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
6
|
+
const parent=path.join(path.dirname(candidate),'deadbyte-mcp-0.15.43-r66');
|
|
7
|
+
const EXPECT='4c4a64a4c8e9f5a6e9eecce85fd0007ebcac99121b29c07f1a1fc81d1643cd33';
|
|
8
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
9
|
+
const manifest=await readFile(path.join(parent,'MANIFEST.SHA256'));
|
|
10
|
+
if(sha(manifest)!==EXPECT)throw new Error('R67 parent manifest SHA mismatch');
|
|
11
|
+
const rows=manifest.toString('utf8').trimEnd().split(/\r?\n/).map(line=>{const m=/^([a-f0-9]{64}) (.+)$/.exec(line);if(!m)throw new Error('bad manifest row');return {sha:m[1],rel:m[2]};});
|
|
12
|
+
const seen=new Set();
|
|
13
|
+
let copied=0,bytes=0;
|
|
14
|
+
for(const {sha:want,rel} of rows){
|
|
15
|
+
if(rel.startsWith('/')||rel.includes('\\')||rel.split('/').some(x=>!x||x==='.'||x==='..')||seen.has(rel))throw new Error('unsafe or duplicate parent path: '+rel);
|
|
16
|
+
seen.add(rel);
|
|
17
|
+
const src=path.join(parent,...rel.split('/'));const info=await lstat(src);
|
|
18
|
+
if(!info.isFile()||info.isSymbolicLink())throw new Error('non-file predecessor: '+rel);
|
|
19
|
+
const data=await readFile(src);if(sha(data)!==want)throw new Error('source drift: '+rel);
|
|
20
|
+
const dst=path.join(candidate,...rel.split('/'));
|
|
21
|
+
await mkdir(path.dirname(dst),{recursive:true});
|
|
22
|
+
try{const existing=await readFile(dst);if(sha(existing)!==want)throw new Error('destination differs: '+rel);}catch(e){if(e.code!=='ENOENT')throw e;await copyFile(src,dst);}
|
|
23
|
+
if(sha(await readFile(dst))!==want)throw new Error('copy differs: '+rel);
|
|
24
|
+
copied++;bytes+=data.length;
|
|
25
|
+
}
|
|
26
|
+
await writeFile(path.join(candidate,'MANIFEST.SHA256'),manifest,{flag:'wx'});
|
|
27
|
+
const proof={schema:'deadbyte.r67-candidate-parent.v1',parent_release_id:'v0.15.43-4c4a64a4c8e9f5a6',parent_manifest_sha256:EXPECT,source_directory:parent,candidate_directory:candidate,copied_files:copied,copied_bytes:bytes,mutation:false};
|
|
28
|
+
await mkdir(path.join(candidate,'docs'),{recursive:true});
|
|
29
|
+
await writeFile(path.join(candidate,'docs','R67-CANDIDATE-PARENT.json'),JSON.stringify(proof,null,2)+'\n',{flag:'wx'});
|
|
30
|
+
console.log(JSON.stringify({status:'STAGED',copied_files:copied,copied_bytes:bytes,parent_manifest_sha256:EXPECT,candidate},null,2));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {readFile} from 'node:fs/promises';
|
|
2
|
+
import {createHash,createPublicKey,verify as edVerify} from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
const root=path.resolve(fileURLToPath(new URL('../../..',import.meta.url)));
|
|
6
|
+
const receiptFile=path.join(root,'testing','0.15.44-r67','R67-PRODUCTION-BASELINE.json');
|
|
7
|
+
const receipt=JSON.parse(await readFile(receiptFile,'utf8'));
|
|
8
|
+
const ping=receipt.signed_ping;
|
|
9
|
+
const spki=Buffer.from(receipt.machine.public_key_spki_base64,'base64');
|
|
10
|
+
const keyId=createHash('sha256').update(spki).digest('hex');
|
|
11
|
+
const {attestation,...body}=ping;
|
|
12
|
+
const sorted=v=>Array.isArray(v)?v.map(sorted):v!==null&&typeof v==='object'?Object.fromEntries(Object.keys(v).sort().map(k=>[k,sorted(v[k])])):v;
|
|
13
|
+
const message=Buffer.concat([Buffer.from('DEADBYTE-MACHINE-PING-V1\0','utf8'),Buffer.from(JSON.stringify(sorted(body)),'utf8')]);
|
|
14
|
+
const digest=createHash('sha256').update(message).digest('hex');
|
|
15
|
+
const key=createPublicKey({key:spki,format:'der',type:'spki'});
|
|
16
|
+
const signature=Buffer.from(attestation.signature_base64,'base64');
|
|
17
|
+
const valid=key.asymmetricKeyType==='ed25519'&&signature.length===64&&attestation.key_id===keyId&&ping.machine_id===keyId&&receipt.machine.machine_id===keyId&&edVerify(null,message,key,signature);
|
|
18
|
+
const prior=receipt.independent_verification?.signed_message_sha256??null;
|
|
19
|
+
const ok=valid&&digest===prior;
|
|
20
|
+
const result={schema:'deadbyte.r67-independent-baseline-check.v1',status:ok?'PASS':'FAIL',ed25519_valid:valid,key_identity_matches:keyId===ping.machine_id,message_sha256:digest,claimed_message_sha256:prior,release_id:ping.release_id};
|
|
21
|
+
console.log(JSON.stringify(result,null,2));
|
|
22
|
+
if(!ok)process.exitCode=1;
|
|
@@ -59,6 +59,7 @@ function npmPackFiles() {
|
|
|
59
59
|
const raw = item?.path;
|
|
60
60
|
if (typeof raw !== 'string' || raw.length < 1) throw new Error('npm pack file path invalid');
|
|
61
61
|
const rel = raw.replaceAll('\\','/');
|
|
62
|
+
if (/\.tgz$/i.test(rel)) throw new Error(`npm archive self-inclusion forbidden: ${rel}; exclude existing tarballs from the npm package surface`);
|
|
62
63
|
if (rel === manifestName || excludedPackagePaths.has(rel) || excludedPackagePrefixes.some(prefix => rel.startsWith(prefix))) continue;
|
|
63
64
|
if (path.posix.isAbsolute(rel) || rel.split('/').includes('..') || rel.includes('\0')) {
|
|
64
65
|
throw new Error(`unsafe package path '${rel}'`);
|
|
@@ -2,6 +2,7 @@ import {createHash,randomBytes} from 'node:crypto';
|
|
|
2
2
|
import {open,readFile,rm} from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import {canonicalJson} from './canonical-json.mjs';
|
|
5
|
+
import {decodeUtf8Strict} from './text-policy.mjs';
|
|
5
6
|
import {
|
|
6
7
|
captureStandingGrant,compareSecurityEnvelopes,createAuthorityEpochStore,deriveSecurityEnvelope
|
|
7
8
|
} from './authority-continuity-r65.mjs';
|
|
@@ -17,7 +18,7 @@ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
|
17
18
|
const plain=value=>value&&typeof value==='object'&&!Array.isArray(value);
|
|
18
19
|
|
|
19
20
|
function parseJson(bytes,label){
|
|
20
|
-
try{return JSON.parse(bytes
|
|
21
|
+
try{return JSON.parse(decodeUtf8Strict(bytes));}
|
|
21
22
|
catch{throw new Error(`${label} JSON invalid`);}
|
|
22
23
|
}
|
|
23
24
|
function inside(root,target){
|
|
@@ -308,7 +308,7 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
|
|
|
308
308
|
const r34Paused=await pauseR34Ambiguous(checked.reason ?? error);
|
|
309
309
|
if (r34Paused) return r34Paused;
|
|
310
310
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{ reason:'profile_execution_without_receipt', profile_id:profileId,
|
|
311
|
-
action_key:actionKey, detail:truncated(error) });
|
|
311
|
+
action_key:actionKey, receipt_id:receiptId, request_sha256:requestSha256, detail:truncated(error,512) });
|
|
312
312
|
return { status:'paused', observation:null, existing:false };
|
|
313
313
|
}
|
|
314
314
|
result = null;
|
package/src/deadbyte-cli.mjs
CHANGED
|
@@ -11,6 +11,9 @@ import { defaultPublicKeyPath } from './trust.mjs';
|
|
|
11
11
|
import { verifyAuditChain } from './audit-verify.mjs';
|
|
12
12
|
import { openRemoteResultJournal, parseRemoteResultCursor } from './remote-result-journal.mjs';
|
|
13
13
|
import { DEADBYTE_VERSION } from './version.mjs';
|
|
14
|
+
import { runNativeInspect } from './native-inspector-r67.mjs';
|
|
15
|
+
import { exportOfflineDiagnostics } from './r67-diagnostic-export.mjs';
|
|
16
|
+
import { verifyOfflineDiagnosticsZip } from './r67-diagnostics-verify.mjs';
|
|
14
17
|
import { parseActivePointer } from './release-slot.mjs';
|
|
15
18
|
import { printDoctor } from './doctor-r45.mjs';
|
|
16
19
|
import { createLiveTimelineFilter, createLiveTimelineTracker, createLiveTimelineWriter, formatCompactAuditEvent, formatRemoteLifecycle, formatRemoteToolCall, formatRuntimeDiagnosticLine, selectLiveLogNames } from './remote-live-log.mjs';
|
|
@@ -60,7 +63,14 @@ function printHelp(){
|
|
|
60
63
|
` npx -y ${exact} supervisor status`,
|
|
61
64
|
` npx -y ${exact} supervisor recover`,
|
|
62
65
|
` npx -y ${exact} audit verify`,
|
|
63
|
-
` npx -y ${exact} audit status`,
|
|
66
|
+
` npx -y ${exact} audit status`,
|
|
67
|
+
` npx -y ${exact} diagnostics export --output <local.zip> # offline, never uploads`,
|
|
68
|
+
` npx -y ${exact} diagnostics verify --input <local.zip> # local structural/CRC verify`,
|
|
69
|
+
` npx -y ${exact} inspect process [limit] # local native process snapshot`,
|
|
70
|
+
` npx -y ${exact} inspect identity PID # native process creation token`,
|
|
71
|
+
` npx -y ${exact} inspect memory self [limit] # local VirtualQueryEx metadata only`,
|
|
72
|
+
` npx -y ${exact} inspect memory PID <creation_filetime> [limit] # PID-reuse guarded`,
|
|
73
|
+
` npx -y ${exact} inspect pe <file> # local native PE32/PE32+ inspection`,''
|
|
64
74
|
].join('\n'));
|
|
65
75
|
}
|
|
66
76
|
async function remoteContext(){
|
|
@@ -681,6 +691,28 @@ async function main(argv){
|
|
|
681
691
|
if(command==='remote'){await runRemote(rest);return;}
|
|
682
692
|
if(command==='supervisor'){await runSupervisor(rest);return;}
|
|
683
693
|
if(command==='audit'){await runAudit(rest);return;}
|
|
694
|
+
if(command==='diagnostics'){
|
|
695
|
+
if(rest.length!==3)throw new Error('diagnostics export --output or verify --input; no network upload supported');
|
|
696
|
+
if(rest[0]==='export'&&rest[1]==='--output'){
|
|
697
|
+
const report=await exportOfflineDiagnostics({stateRoot:stateRoot(),outputPath:rest[2]});
|
|
698
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
if(rest[0]==='verify'&&rest[1]==='--input'){
|
|
702
|
+
const file=path.resolve(rest[2]);
|
|
703
|
+
await requireRegular(file,'diagnostic ZIP');
|
|
704
|
+
const report=verifyOfflineDiagnosticsZip(await readFile(file));
|
|
705
|
+
process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
throw new Error('unsupported diagnostics mode; network upload is forbidden');
|
|
709
|
+
}
|
|
710
|
+
if(command==='inspect'){
|
|
711
|
+
const result=await runNativeInspect(rest);
|
|
712
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
713
|
+
if(result.status!=='ok')process.exitCode=2;
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
684
716
|
throw new Error(`unknown command '${command}'`);
|
|
685
717
|
}
|
|
686
718
|
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
import { Client } from '@modelcontextprotocol/client';
|
|
7
7
|
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
|
|
8
8
|
import { CODING_GRANT_SCHEMA, loadCodingPolicy } from './coding-plane.mjs';
|
|
9
|
+
import { createAuthorityEpochStore } from './authority-continuity-r65.mjs';
|
|
9
10
|
import { verifyMachineFsReceiptFile } from './machine-fs.mjs';
|
|
10
11
|
import { generateTrustKeypair } from './trust.mjs';
|
|
11
12
|
import { assertExactCatalog, expectedFullCatalogForEnv } from './runtime-catalog-expectation.mjs';
|
|
@@ -23,14 +24,16 @@ const structured = (result, label) => {
|
|
|
23
24
|
const scratch = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-machine-fs-smoke-'));
|
|
24
25
|
const coreRoot = path.join(scratch, 'core');
|
|
25
26
|
const trustRoot = path.join(scratch, 'trust');
|
|
27
|
+
const runtimeRoot = path.join(scratch, 'runtime');
|
|
26
28
|
await mkdir(coreRoot, { recursive: true });
|
|
27
29
|
await mkdir(trustRoot, { recursive: true });
|
|
30
|
+
await mkdir(runtimeRoot, { recursive: true });
|
|
28
31
|
const keys = await generateTrustKeypair({
|
|
29
|
-
privateKeyPath: path.join(trustRoot, 'private.pem'),
|
|
30
|
-
publicKeyPath: path.join(trustRoot, 'public.pem')
|
|
32
|
+
privateKeyPath: path.join(trustRoot, 'ed25519-private.pem'),
|
|
33
|
+
publicKeyPath: path.join(trustRoot, 'ed25519-public.pem')
|
|
31
34
|
});
|
|
32
35
|
const policyPath = path.join(scratch, 'coding-policy.json');
|
|
33
|
-
const grantPath = path.join(
|
|
36
|
+
const grantPath = path.join(runtimeRoot, 'coding-grant.json');
|
|
34
37
|
const evidenceDir = path.join(scratch, 'evidence');
|
|
35
38
|
const rawPolicy = {
|
|
36
39
|
schema: 'deadbyte.coding-policy.v1', enabled: true,
|
|
@@ -41,11 +44,16 @@ const rawPolicy = {
|
|
|
41
44
|
const policyBytes = Buffer.from(`${JSON.stringify(rawPolicy, null, 2)}\n`, 'utf8');
|
|
42
45
|
await writeFile(policyPath, policyBytes, { flag: 'wx' });
|
|
43
46
|
const policy = await loadCodingPolicy(policyPath);
|
|
44
|
-
|
|
47
|
+
const grantBytes = Buffer.from(`${JSON.stringify({
|
|
45
48
|
schema: CODING_GRANT_SCHEMA, policy_sha256: policy.policy_sha256,
|
|
46
49
|
instance_nonce: randomBytes(32).toString('hex'), root_ids: ['core'],
|
|
47
50
|
granted_at_utc: new Date().toISOString()
|
|
48
|
-
}, null, 2)}\n`,
|
|
51
|
+
}, null, 2)}\n`, 'utf8');
|
|
52
|
+
await writeFile(grantPath, grantBytes, { flag: 'wx' });
|
|
53
|
+
const grant = JSON.parse(grantBytes.toString('utf8'));
|
|
54
|
+
await createAuthorityEpochStore({ runtimeDir:runtimeRoot, policyBytes }).append({
|
|
55
|
+
plane:'coding', action:'grant', grantBytes, grantInstanceNonce:grant.instance_nonce, updateId:null
|
|
56
|
+
});
|
|
49
57
|
|
|
50
58
|
const client = new Client({ name: 'deadbyte-machine-fs-smoke', version: '0.8.0' },
|
|
51
59
|
{ versionNegotiation: { mode: { pin: '2026-07-28' } } });
|
package/src/machine-identity.mjs
CHANGED
|
@@ -11,11 +11,13 @@ import { lstat, mkdir, open, readFile, rename, rm, writeFile } from 'node:fs/pro
|
|
|
11
11
|
import os from 'node:os';
|
|
12
12
|
import path from 'node:path';
|
|
13
13
|
import { canonicalJson } from './canonical-json.mjs';
|
|
14
|
+
import {nativeInspectArgs,runNativeInspect} from './native-inspector-r67.mjs';
|
|
14
15
|
import { parseActivePointer } from './release-slot.mjs';
|
|
15
16
|
|
|
16
17
|
export const MACHINE_IDENTITY_SCHEMA = 'deadbyte.machine-identity.v1';
|
|
17
18
|
export const MACHINE_PING_SCHEMA = 'deadbyte.machine-ping.v1';
|
|
18
19
|
const MACHINE_PING_DOMAIN = Buffer.from('DEADBYTE-MACHINE-PING-V1\0', 'utf8');
|
|
20
|
+
export const R67_MACHINE_OBSERVATION_DOMAIN=Buffer.from('DEADBYTE-R67-MACHINE-OBSERVATION-V1\0','utf8');
|
|
19
21
|
const HEX64 = /^[0-9a-f]{64}$/;
|
|
20
22
|
|
|
21
23
|
const sha256 = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
@@ -182,7 +184,8 @@ function statusBody(identity, pointer, onlineEpoch) {
|
|
|
182
184
|
|
|
183
185
|
export async function createMachineRuntime({
|
|
184
186
|
stateRoot = path.join(os.homedir(), '.deadbyte-mcp'),
|
|
185
|
-
activePointerPath = path.join(stateRoot, 'active-release.json')
|
|
187
|
+
activePointerPath = path.join(stateRoot, 'active-release.json'),
|
|
188
|
+
assertObservationAuthority = null
|
|
186
189
|
} = {}) {
|
|
187
190
|
await initializeMachineIdentity({ stateRoot });
|
|
188
191
|
let identity = await loadIdentity(stateRoot);
|
|
@@ -238,7 +241,61 @@ export async function createMachineRuntime({
|
|
|
238
241
|
identity_generation: identity.state.identity_generation, online_epoch: onlineEpoch };
|
|
239
242
|
}
|
|
240
243
|
|
|
241
|
-
|
|
244
|
+
|
|
245
|
+
// A non-public server-owned signing path: observer + machine identity stay in one process.
|
|
246
|
+
// The MCP bridge must never expose this as a caller-supplied signing oracle.
|
|
247
|
+
async function observeNative({args}){
|
|
248
|
+
if(typeof assertObservationAuthority!=='function')throw new Error('R67 observation authority callback required');
|
|
249
|
+
if(!Array.isArray(args))throw new Error('R67 observation args required');
|
|
250
|
+
const nativeArgs=nativeInspectArgs(args);
|
|
251
|
+
const operation=nativeArgs[0];
|
|
252
|
+
const before=await status();
|
|
253
|
+
const checkGrant=grant=>{
|
|
254
|
+
if(!grant||!/^[-a-zA-Z0-9._:]{1,128}$/.test(grant.grant_id??'')||
|
|
255
|
+
!HEX64.test(grant.policy_sha256??'')||grant.scope!=='native-observe-readonly'||
|
|
256
|
+
!Number.isSafeInteger(grant.authority_generation)||grant.authority_generation<1)
|
|
257
|
+
throw new Error('R67 authority grant invalid');
|
|
258
|
+
return {grant_id:grant.grant_id,policy_sha256:grant.policy_sha256,
|
|
259
|
+
scope:grant.scope,authority_generation:grant.authority_generation};
|
|
260
|
+
};
|
|
261
|
+
const first=checkGrant(await assertObservationAuthority({phase:'pre',operation,args:nativeArgs,machine:before}));
|
|
262
|
+
const result=await runNativeInspect(args);
|
|
263
|
+
const after=await status();
|
|
264
|
+
const second=checkGrant(await assertObservationAuthority({phase:'post',operation,args:nativeArgs,machine:after}));
|
|
265
|
+
if(canonicalJson(first)!==canonicalJson(second))throw new Error('R67 authority lease changed during observation');
|
|
266
|
+
for(const field of ['machine_id','identity_generation','online_epoch','release_id','release_manifest_sha256','generation_manifest_sha256'])
|
|
267
|
+
if(before[field]!==after[field])throw new Error('R67 machine or release generation changed during observation');
|
|
268
|
+
const pinned=JSON.parse(await readFile(new URL('../docs/R67-NATIVE-INSPECT-BINARY.json',import.meta.url),'utf8'));
|
|
269
|
+
if(pinned.schema!=='deadbyte.r67-native-inspector-binary.v1'||!HEX64.test(pinned.sha256??''))
|
|
270
|
+
throw new Error('R67 observer executable pin invalid');
|
|
271
|
+
// Trusted signer is loaded from the machine identity store by this runtime, never provided by a client.
|
|
272
|
+
identity=await loadIdentity(stateRoot);
|
|
273
|
+
if(identity.machine_id!==before.machine_id||identity.state.identity_generation!==before.identity_generation)
|
|
274
|
+
throw new Error('R67 identity revoked before signing');
|
|
275
|
+
const receiptBody={
|
|
276
|
+
schema:'deadbyte.native-observation-runtime-r67.v1',
|
|
277
|
+
observed_at_utc:new Date().toISOString(),
|
|
278
|
+
machine_id:before.machine_id,
|
|
279
|
+
identity_generation:before.identity_generation,
|
|
280
|
+
online_epoch:before.online_epoch,
|
|
281
|
+
release_id:before.release_id,
|
|
282
|
+
release_manifest_sha256:before.release_manifest_sha256,
|
|
283
|
+
generation_manifest_sha256:before.generation_manifest_sha256,
|
|
284
|
+
authority:first,
|
|
285
|
+
operation,
|
|
286
|
+
request_sha256:sha256(Buffer.from(JSON.stringify(nativeArgs),'utf8')),
|
|
287
|
+
executable_sha256:pinned.sha256,
|
|
288
|
+
result_status:result.status,
|
|
289
|
+
result_sha256:sha256(Buffer.from(canonicalJson(result),'utf8'))
|
|
290
|
+
};
|
|
291
|
+
const signature=cryptoSign(null,Buffer.concat([R67_MACHINE_OBSERVATION_DOMAIN,
|
|
292
|
+
Buffer.from(canonicalJson(receiptBody),'utf8')]),identity.privateKey);
|
|
293
|
+
return {result,receipt:{...receiptBody,attestation:{
|
|
294
|
+
algorithm:'ed25519',key_id:identity.machine_id,signature_base64:signature.toString('base64')
|
|
295
|
+
}}};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return Object.freeze({ list, status, ping, revoke, observeNative });
|
|
242
299
|
}
|
|
243
300
|
|
|
244
301
|
export async function verifyMachinePingPublic({ ping, publicKeySpkiBase64 }) {
|
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
machineStructuredResult
|
|
8
8
|
} from './machine-output-contracts.mjs';
|
|
9
9
|
|
|
10
|
+
const READ_HINTS = Object.freeze({ readOnlyHint:true, destructiveHint:false, idempotentHint:true, openWorldHint:false });
|
|
11
|
+
const SIGNED_PING_HINTS = Object.freeze({ readOnlyHint:true, destructiveHint:false, idempotentHint:false, openWorldHint:false });
|
|
12
|
+
const REVOKE_HINTS = Object.freeze({ readOnlyHint:false, destructiveHint:true, idempotentHint:false, openWorldHint:false });
|
|
13
|
+
|
|
10
14
|
function ok(schema, value) { return machineStructuredResult(schema, value, false); }
|
|
11
15
|
function fail(schema, status, error) { return machineStructuredResult(schema, { status, error: String(error) }, true); }
|
|
12
16
|
|
|
@@ -16,21 +20,25 @@ export function registerMachineTools(server, { runtime, assertRevokeAuthority })
|
|
|
16
20
|
|
|
17
21
|
server.registerTool('machine_list', {
|
|
18
22
|
description: 'List DEADBYTE machine identities visible to this runtime. Identity is public-key based; hostname is informational.',
|
|
23
|
+
annotations: READ_HINTS,
|
|
19
24
|
inputSchema: z.strictObject({}), outputSchema: machineListOutputSchema
|
|
20
25
|
}, async () => { try { return ok(machineListOutputSchema, await runtime.list()); } catch (error) { return fail(machineListOutputSchema, 'failed', error); } });
|
|
21
26
|
|
|
22
27
|
server.registerTool('machine_status', {
|
|
23
28
|
description: 'Read this machine identity, online epoch, active release/generation binding, and capability set.',
|
|
29
|
+
annotations: READ_HINTS,
|
|
24
30
|
inputSchema: z.strictObject({}), outputSchema: machineStatusOutputSchema
|
|
25
31
|
}, async () => { try { return ok(machineStatusOutputSchema, await runtime.status()); } catch (error) { return fail(machineStatusOutputSchema, 'failed', error); } });
|
|
26
32
|
|
|
27
33
|
server.registerTool('machine_ping', {
|
|
28
34
|
description: 'Return an Ed25519-signed nonce echo bound to machine identity, online epoch, release, and generation.',
|
|
35
|
+
annotations: SIGNED_PING_HINTS,
|
|
29
36
|
inputSchema: z.strictObject({ nonce: z.string().min(1).max(256) }), outputSchema: machinePingOutputSchema
|
|
30
37
|
}, async ({ nonce }) => { try { return ok(machinePingOutputSchema, await runtime.ping({ nonce })); } catch (error) { return fail(machinePingOutputSchema, 'failed', error); } });
|
|
31
38
|
|
|
32
39
|
server.registerTool('machine_revoke', {
|
|
33
40
|
description: 'Invalidate the current machine online epoch/generation. Requires independently armed local host authority and never expands authority.',
|
|
41
|
+
annotations: REVOKE_HINTS,
|
|
34
42
|
inputSchema: z.strictObject({ reason: z.string().min(1).max(256) }), outputSchema: machineRevokeOutputSchema
|
|
35
43
|
}, async ({ reason }) => {
|
|
36
44
|
try {
|