deadbyte-mcp 0.15.68 → 0.15.70
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 +85 -38
- package/PROVENANCE.json +52 -24
- package/README.txt +44 -31
- package/RELEASE.json +47 -17
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +44 -2
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +65 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R184-package-lock.json +97 -0
- package/docs/R186-OWNER-CONSENT-HANDOFF.txt +87 -0
- package/package.json +1 -1
- package/scripts/install-r186-owner-trust.ps1 +59 -0
- package/scripts/r175-focused-runner.mjs +38 -0
- package/scripts/r176-log-preview.mjs +18 -0
- package/scripts/r177-owner-trust-inventory.ps1 +36 -0
- package/scripts/r178-full-regression.mjs +21 -0
- package/scripts/r178-npm-ci.mjs +10 -0
- package/scripts/r178-npm-preflight.mjs +16 -0
- package/scripts/r178-release-gates-readonly.mjs +9 -0
- package/scripts/r178-shard-regression.mjs +25 -0
- package/scripts/r179-predecessor-registry.mjs +24 -0
- package/scripts/r179-protected-inventory.ps1 +21 -0
- package/scripts/r186-focused-runner.mjs +22 -0
- package/scripts/r186-owner-anchor-inspect.mjs +6 -0
- package/scripts/r186-owner-consent-check.mjs +86 -0
- package/scripts/r186-owner-grant-cli.mjs +45 -0
- package/scripts/r186-owner-key-local.mjs +22 -0
- package/scripts/r186-owner-review-export.mjs +34 -0
- package/src/deadbyte-cli.mjs +130 -56
- package/src/foreground-owner-recovery-r190.mjs +117 -0
- package/src/r174-owner-webauthn.mjs +176 -0
- package/src/r175-foreground-boundary.mjs +28 -0
- package/src/r186-owner-anchor.mjs +12 -0
- package/src/r186-owner-consent-preflight.mjs +63 -0
- package/src/r186-owner-grant-broker.mjs +96 -0
- package/src/r186-owner-local-signing.mjs +25 -0
- package/src/r186-owner-request.mjs +40 -0
- package/src/r186-owner-review-export.mjs +49 -0
- package/src/remote-live-log.mjs +81 -5
- package/src/remote-session-guardian.mjs +23 -0
- package/src/version.mjs +1 -1
- package/test/helpers/r175-active-pointer.mjs +28 -0
- package/test/helpers/release-lock.mjs +12 -0
- package/test/r129-sdk-security-baseline.test.mjs +2 -1
- package/test/r130-release-security-contract.test.mjs +11 -10
- package/test/r132-release-identity.test.mjs +12 -11
- package/test/r153-prepublish-identity.test.mjs +1 -1
- package/test/r155-default-live-log.test.mjs +17 -16
- package/test/r160-package-decision-manifest.test.mjs +1 -1
- package/test/r160-release-contract.test.mjs +4 -5
- package/test/r163-isolated-slot-rollback-restore.test.mjs +8 -8
- package/test/r165-live-cli-skew.test.mjs +6 -6
- package/test/r167-release-contract.test.mjs +15 -13
- package/test/r168-protected-entrypoint.test.mjs +5 -2
- package/test/r168-release-contract.test.mjs +4 -3
- package/test/r168-remote-one-shot-coherence.test.mjs +2 -1
- package/test/r172-release-contract.test.mjs +7 -7
- package/test/r173-release-contract.test.mjs +18 -17
- package/test/r174-owner-webauthn.test.mjs +144 -0
- package/test/r175-cli-flags.test.mjs +23 -0
- package/test/r175-foreground-boundary.test.mjs +87 -0
- package/test/r175-guardian-owner-boundary.test.mjs +56 -0
- package/test/r176-pretty-live-log.test.mjs +54 -0
- package/test/r177-windows-absolute-live-path.test.mjs +37 -0
- package/test/r179-absolute-path-live-log.test.mjs +40 -0
- package/test/r179-release-contract.test.mjs +62 -0
- package/test/r186-controller-owner-grant.test.mjs +20 -0
- package/test/r186-owner-consent-preflight.test.mjs +98 -0
- package/test/r186-owner-enrollment.test.mjs +20 -0
- package/test/r186-owner-grant-broker.test.mjs +85 -0
- package/test/r186-owner-local-signing.test.mjs +30 -0
- package/test/r186-owner-request.test.mjs +28 -0
- package/test/r186-owner-review-export.test.mjs +52 -0
- package/test/r190-foreground-cli.test.mjs +41 -0
- package/test/r190-foreground-owner-recovery.test.mjs +61 -0
- package/test/r190-release-contract.test.mjs +33 -0
- package/test/r48-release-contract.test.mjs +2 -1
- package/test/r51-runtime-coherence.test.mjs +4 -2
- package/test/r58-cleanup-retention.test.mjs +5 -12
- package/test/r58-concurrent-recovery.test.mjs +5 -1
- package/test/r58-stale-owner.test.mjs +9 -3
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/remote-live-log-r37.test.mjs +2 -2
- package/test/remote-live-log-recovery-r36.test.mjs +1 -1
- package/test/remote-session-cli.test.mjs +92 -126
- package/node_modules/which/CHANGELOG.md +0 -166
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {readdirSync,mkdirSync,writeFileSync,readFileSync} from 'node:fs';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const root=path.resolve(import.meta.dirname,'..');
|
|
6
|
+
const testRoot=path.join(root,'test');
|
|
7
|
+
const files=readdirSync(testRoot).filter(n=>n.endsWith('.test.mjs')).sort().map(n=>path.join('test',n));
|
|
8
|
+
const outDir=path.resolve(root,'..','..','testing','r178-01569-candidate');
|
|
9
|
+
mkdirSync(outDir,{recursive:true});
|
|
10
|
+
const args=['--test','--test-concurrency=4',...files];
|
|
11
|
+
console.log('R178_TOTAL_TEST_FILES='+files.length);
|
|
12
|
+
const result=spawnSync(process.execPath,args,{cwd:root,encoding:'utf8',windowsHide:true,timeout:300000,maxBuffer:40*1024*1024,
|
|
13
|
+
env:{...process.env,DEADBYTE_RELEASE_TEST:'1'}});
|
|
14
|
+
const log=String(result.stdout||'')+'\n=== STDERR ===\n'+String(result.stderr||'');
|
|
15
|
+
const fp=path.join(outDir,'R178-FULL-REGRESSION.txt');
|
|
16
|
+
writeFileSync(fp,log);
|
|
17
|
+
console.log('R178_FULL_EXIT='+result.status+' signal='+result.signal+' error='+String(result.error?.code??'none'));
|
|
18
|
+
for(const l of log.split(/\r?\n/).filter(s=>/^(ℹ (tests|pass|fail|skipped|duration_ms)|# (tests|pass|fail|skipped|duration_ms)|✖|not ok)/.test(s)).slice(-30))console.log(l.slice(0,300));
|
|
19
|
+
console.log('R178_EVIDENCE='+fp);
|
|
20
|
+
console.log('R178_EVIDENCE_SHA256='+createHash('sha256').update(readFileSync(fp)).digest('hex'));
|
|
21
|
+
if(result.status!==0)process.exitCode=1;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const root=path.resolve(import.meta.dirname,'..');
|
|
4
|
+
const npm=process.env.npm_execpath||path.join(path.dirname(process.execPath),'node_modules','npm','bin','npm-cli.js');
|
|
5
|
+
const r=spawnSync(process.execPath,[npm,'ci','--ignore-scripts','--no-audit','--no-fund','--prefer-offline'],{cwd:root,encoding:'utf8',timeout:180000,windowsHide:true,maxBuffer:1024*1024});
|
|
6
|
+
console.log('NPM_CI_EXIT='+r.status);
|
|
7
|
+
if(r.error)console.log('NPM_CI_ERROR='+String(r.error.code));
|
|
8
|
+
console.log('NPM_CI_STDOUT='+String(r.stdout||'').slice(-1500));
|
|
9
|
+
console.log('NPM_CI_STDERR='+String(r.stderr||'').slice(-1500));
|
|
10
|
+
if(r.status!==0)process.exitCode=1;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {existsSync} from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const cwd=path.resolve(import.meta.dirname,'..');
|
|
5
|
+
const npm=process.env.npm_execpath||path.join(path.dirname(process.execPath),'node_modules','npm','bin','npm-cli.js');
|
|
6
|
+
function exec(args,ms=30000){
|
|
7
|
+
const r=spawnSync(process.execPath,[npm,...args],{cwd,encoding:'utf8',windowsHide:true,timeout:ms,env:{...process.env,npm_config_update_notifier:'false'}});
|
|
8
|
+
const s=String(r.stdout||'').trim(),e=String(r.stderr||'').trim();
|
|
9
|
+
return {ok:r.status===0,exit:r.status,error:r.error?.code??null,
|
|
10
|
+
output:args[0]==='whoami'?(r.status===0?s:'[NOT_AUTHENTICATED]'):String((s||e).slice(0,500)).replace(/https?:\/\/[^\s]+/g,'[url-redacted]')};
|
|
11
|
+
}
|
|
12
|
+
console.log('NODE='+process.version+' npm_cli_available='+existsSync(npm));
|
|
13
|
+
console.log('node_modules_present='+existsSync(path.join(cwd,'node_modules')));
|
|
14
|
+
console.log('NPM_VERSION='+JSON.stringify(exec(['--version'])));
|
|
15
|
+
console.log('NPM_WHOAMI='+JSON.stringify(exec(['whoami'])));
|
|
16
|
+
console.log('NPM_01569_REGISTRY='+JSON.stringify(exec(['view','deadbyte-mcp@0.15.69','version','--json'])));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const root=path.resolve(import.meta.dirname,'..');
|
|
4
|
+
for(const args of [['scripts/release-manifest.mjs','verify'],['scripts/npm-release-r48.mjs','--verify-only']]){
|
|
5
|
+
const r=spawnSync(process.execPath,args,{cwd:root,encoding:'utf8',timeout:30000,windowsHide:true,maxBuffer:2*1024*1024});
|
|
6
|
+
console.log('R178_CHECK='+args.join(' ')+' EXIT='+r.status);
|
|
7
|
+
const out=String(r.stdout||'')+'\n'+String(r.stderr||'');
|
|
8
|
+
for(const line of out.split(/\r?\n/).filter(x=>/MANIFEST_|FAIL|release identity|version mismatch|not published|PROVENANCE|PUBLISH|READY|error:/i.test(x)).slice(0,12))console.log(line.slice(0,500));
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {readdirSync,mkdirSync,writeFileSync,readFileSync} from 'node:fs';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const root=path.resolve(import.meta.dirname,'..');
|
|
6
|
+
const testRoot=path.join(root,'test');
|
|
7
|
+
const files=readdirSync(testRoot).filter(n=>n.endsWith('.test.mjs')).sort();
|
|
8
|
+
const size=Number(process.argv[3]??16),index=Number(process.argv[2]);
|
|
9
|
+
if(!Number.isInteger(index)||index<0||!Number.isInteger(size)||size<1||size>32)throw Error('invalid shard');
|
|
10
|
+
const selection=files.slice(index*size,(index+1)*size);
|
|
11
|
+
if(!selection.length)throw Error('empty shard');
|
|
12
|
+
const outDir=path.resolve(root,'..','..','testing','r178-01569-candidate');
|
|
13
|
+
mkdirSync(outDir,{recursive:true});
|
|
14
|
+
const testArgs=['--test','--test-concurrency=3',...selection.map(n=>path.join('test',n))];
|
|
15
|
+
const result=spawnSync(process.execPath,testArgs,{cwd:root,encoding:'utf8',windowsHide:true,
|
|
16
|
+
timeout:26000,maxBuffer:12*1024*1024});
|
|
17
|
+
const log=String(result.stdout||'')+'\n=== STDERR ===\n'+String(result.stderr||'');
|
|
18
|
+
const fp=path.join(outDir,'shard-'+String(index).padStart(2,'0')+'.log');
|
|
19
|
+
writeFileSync(fp,log);
|
|
20
|
+
const sha=createHash('sha256').update(readFileSync(fp)).digest('hex');
|
|
21
|
+
const stat=log.split(/\r?\n/).filter(x=>/^(ℹ (tests|pass|fail|skipped|duration_ms)|# (tests|pass|fail|skipped|duration_ms)|✖|not ok)/.test(x));
|
|
22
|
+
console.log('R178_SHARD='+index+' FILES='+selection.length+' EXIT='+result.status+' TIMEOUT='+Boolean(result.error?.code==='ETIMEDOUT'));
|
|
23
|
+
console.log(stat.slice(-8).map(x=>x.slice(0,300)).join('\n'));
|
|
24
|
+
console.log('EVIDENCE='+fp+' SHA256='+sha);
|
|
25
|
+
if(result.status!==0)process.exitCode=1;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {mkdtempSync,readdirSync,readFileSync,rmSync} from 'node:fs';
|
|
3
|
+
import {tmpdir} from 'node:os';
|
|
4
|
+
import {createHash} from 'node:crypto';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
const npm=process.env.npm_execpath||path.join(path.dirname(process.execPath),'node_modules','npm','bin','npm-cli.js');
|
|
7
|
+
function run(args,timeout=80000){const p=spawnSync(process.execPath,[npm,...args],{encoding:'utf8',shell:false,windowsHide:true,timeout,maxBuffer:3*1024*1024});if(p.error||p.status!==0)throw Error('npm read-only '+args[0]+' failed '+(p.stderr||p.error));return p.stdout.trim();}
|
|
8
|
+
const dir=mkdtempSync(path.join(tmpdir(),'deadbyte-r179-source-'));
|
|
9
|
+
try {
|
|
10
|
+
const metadata=JSON.parse(run(['view','deadbyte-mcp@0.15.68','dist','--json']));
|
|
11
|
+
console.log('PREDECESSOR_DIST_TARBALL='+JSON.stringify(metadata.tarball));
|
|
12
|
+
console.log('PREDECESSOR_DIST_SHASUM='+metadata.shasum);
|
|
13
|
+
const info=JSON.parse(run(['pack','deadbyte-mcp@0.15.68','--pack-destination',dir,'--ignore-scripts','--json']));
|
|
14
|
+
if(!Array.isArray(info)||info.length!==1)throw Error('parent npm pack response shape invalid');
|
|
15
|
+
const file=path.join(dir,info[0].filename);
|
|
16
|
+
const bytes=readFileSync(file);
|
|
17
|
+
const sha256=createHash('sha256').update(bytes).digest('hex');
|
|
18
|
+
const sha1=createHash('sha1').update(bytes).digest('hex');
|
|
19
|
+
if(sha1!==metadata.shasum)throw Error('parent npm registry SHA-1 identity mismatch');
|
|
20
|
+
console.log('PREDECESSOR_VERSION=0.15.68');
|
|
21
|
+
console.log('PREDECESSOR_TARBALL_SHA256='+sha256);
|
|
22
|
+
console.log('PREDECESSOR_PACKED_BYTES='+bytes.length);
|
|
23
|
+
console.log('PREDECESSOR_REGISTRY_MATCH=PASS');
|
|
24
|
+
}finally{rmSync(dir,{recursive:true,force:true});}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
$ErrorActionPreference='Stop'
|
|
2
|
+
$root='C:\Program Files'
|
|
3
|
+
$paths=@(
|
|
4
|
+
'C:\Program Files\DEADBYTE-R153-Protected-01560-Test',
|
|
5
|
+
'C:\Program Files\DEADBYTE-R168-Protected-Test',
|
|
6
|
+
'C:\Program Files\DEADBYTE-R174-Test'
|
|
7
|
+
)
|
|
8
|
+
if(Test-Path -LiteralPath $root){
|
|
9
|
+
Get-ChildItem -LiteralPath $root -Directory -ErrorAction SilentlyContinue |
|
|
10
|
+
Where-Object {$_.Name -match 'DEADBYTE|R174|R175|R178'} |
|
|
11
|
+
Select-Object -First 25 | ForEach-Object {
|
|
12
|
+
$package=Join-Path $_.FullName 'package.json'
|
|
13
|
+
$ver='missing';if(Test-Path -LiteralPath $package){try{$ver=(Get-Content -Raw -LiteralPath $package|ConvertFrom-Json).version}catch{$ver='invalid'}}
|
|
14
|
+
$owner=(Get-Acl -LiteralPath $_.FullName).Owner
|
|
15
|
+
Write-Output ('PROTECTED_CANDIDATE='+$_.FullName+' version='+$ver+' owner='+$owner)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
$state=Join-Path $HOME '.deadbyte-mcp'
|
|
19
|
+
$a=Get-Content (Join-Path $state 'active-release.json') -Raw|ConvertFrom-Json
|
|
20
|
+
Write-Output ('ACTIVE='+$a.release_id+' version='+$a.version)
|
|
21
|
+
Write-Output ('R179_READONLY_COMPLETE=TRUE')
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {spawnSync} from 'node:child_process';
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
import {readFileSync,writeFileSync,existsSync} from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const root=path.resolve(import.meta.dirname,'..');
|
|
6
|
+
const dir=path.resolve(root,'..','..','testing','r186-owner-consent');
|
|
7
|
+
const tests=['test/r186-owner-consent-preflight.test.mjs','test/r186-owner-request.test.mjs',
|
|
8
|
+
'test/r70-owner-approval.test.mjs',
|
|
9
|
+
'test/r70-controller-owner-issue-boundary.test.mjs',
|
|
10
|
+
'test/r70-autonomous-grant-expiry.test.mjs',
|
|
11
|
+
'test/r174-owner-webauthn.test.mjs'];
|
|
12
|
+
const result=spawnSync(process.execPath,['--test','--test-concurrency=2',...tests],{
|
|
13
|
+
cwd:root,encoding:'utf8',windowsHide:true,timeout:60000,maxBuffer:2*1024*1024});
|
|
14
|
+
const s=String(result.stdout??'')+'\n'+String(result.stderr??'');
|
|
15
|
+
const sha=createHash('sha256').update(s).digest('hex');
|
|
16
|
+
const output=path.join(dir,'R186-OWNER-FOCUSED-V2-20261028.log');
|
|
17
|
+
if(existsSync(output))throw Error('R186_FOCUSED_EVIDENCE_ALREADY_EXISTS');
|
|
18
|
+
writeFileSync(output,s,{flag:'wx'});
|
|
19
|
+
for(const line of s.split(/\r?\n/).filter(x=>/^(✔|✖|ℹ (tests|pass|fail|skipped|cancelled))/.test(x)).slice(-45))
|
|
20
|
+
console.log(line);
|
|
21
|
+
console.log('R186_FOCUSED_EXIT='+result.status+' LOG_SHA256='+sha);
|
|
22
|
+
if(result.status!==0)process.exitCode=1;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import {readFile} from 'node:fs/promises';
|
|
2
|
+
import {createR186OwnerAnchor} from '../src/r186-owner-anchor.mjs';
|
|
3
|
+
const [file]=process.argv.slice(2);
|
|
4
|
+
if(process.argv.slice(2).length!==1)throw new Error('usage: r186-owner-anchor-inspect.mjs <owner-public.pem>');
|
|
5
|
+
const out=createR186OwnerAnchor(await readFile(file,'utf8'));
|
|
6
|
+
process.stdout.write(JSON.stringify(out));
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// R186 read-only inspection of independently enrolled owner authorization.
|
|
2
|
+
// No key enrollment, challenge consumption, grant or policy mutation occurs here.
|
|
3
|
+
// This CLI MUST run from an R89-protected exact release. Any agent-writable
|
|
4
|
+
// source tree or owner public key path is rejected by the native OS ACL audit.
|
|
5
|
+
import {createHash} from 'node:crypto';
|
|
6
|
+
import {readFile,lstat} from 'node:fs/promises';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import {fileURLToPath} from 'node:url';
|
|
9
|
+
import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
|
|
10
|
+
import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
|
|
11
|
+
import {verifyR186OwnerConsent,verifyR186PolicyRootBinding} from '../src/r186-owner-consent-preflight.mjs';
|
|
12
|
+
|
|
13
|
+
const THIS=fileURLToPath(import.meta.url);
|
|
14
|
+
const ROOT=path.resolve(path.dirname(THIS),'..');
|
|
15
|
+
const OWNER_DIR='C:\\Program Files\\DEADBYTE-OwnerTrust';
|
|
16
|
+
const KEY=path.win32.join(OWNER_DIR,'owner-public.pem');
|
|
17
|
+
const ANCHOR=path.win32.join(OWNER_DIR,'owner-anchor.json');
|
|
18
|
+
const SHA=/^[0-9a-f]{64}$/;
|
|
19
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
20
|
+
const reject=m=>{throw Error('R186_OWNER_PREFLIGHT_BLOCKED: '+m)};
|
|
21
|
+
async function bounded(file,limit){
|
|
22
|
+
const st=await lstat(file);
|
|
23
|
+
if(!st.isFile()||st.isSymbolicLink()||st.size<1||st.size>limit)reject('unsafe input file');
|
|
24
|
+
return readFile(file);
|
|
25
|
+
}
|
|
26
|
+
async function main(){
|
|
27
|
+
if(process.platform!=='win32'||process.arch!=='x64')reject('requires Windows x64');
|
|
28
|
+
// No dynamic owner key paths. Owner trust must have been installed by the
|
|
29
|
+
// physical owner through an independently approved protected workflow.
|
|
30
|
+
const args=process.argv.slice(2);
|
|
31
|
+
if(args.length!==5)reject('usage: <approval-json> <root-id> <project-root> <coding-policy-json> <autonomous-policy-json>');
|
|
32
|
+
const [approvalPath,rootId,projectRoot,codingPolicyPath,autonomousPolicyPath]=args;
|
|
33
|
+
if(![approvalPath,projectRoot,codingPolicyPath,autonomousPolicyPath].every(p=>path.win32.isAbsolute(p)))
|
|
34
|
+
reject('absolute paths required');
|
|
35
|
+
if(!/^[A-Za-z0-9._-]{1,64}$/.test(rootId))reject('root identity invalid');
|
|
36
|
+
// Do not trust agent-provided signature keys. R89 rejects writable ancestor,
|
|
37
|
+
// unsafe owner and any writable ACE on the pin or enrolled public key.
|
|
38
|
+
const trustedFiles=[
|
|
39
|
+
process.execPath,THIS,ANCHOR,KEY,
|
|
40
|
+
path.join(ROOT,'MANIFEST.SHA256'),
|
|
41
|
+
path.join(ROOT,'src','r186-owner-consent-preflight.mjs'),
|
|
42
|
+
path.join(ROOT,'src','r70-owner-approval.mjs'),
|
|
43
|
+
path.join(ROOT,'src','canonical-json.mjs'),
|
|
44
|
+
path.join(ROOT,'src','release-slot.mjs'),
|
|
45
|
+
path.join(ROOT,'src','privileged-install-trust-r89.mjs')
|
|
46
|
+
];
|
|
47
|
+
const os=await inspectTrustedInstallation(trustedFiles);
|
|
48
|
+
if(!os.trusted)reject('owner trust ACL untrusted');
|
|
49
|
+
const manifestBytes=await bounded(path.join(ROOT,'MANIFEST.SHA256'),512*1024);
|
|
50
|
+
const manifest=parseManifest(manifestBytes.toString('utf8'));
|
|
51
|
+
await verifyManifestTreeExact(ROOT,manifest);
|
|
52
|
+
const codingBytes=await bounded(codingPolicyPath,1024*1024);
|
|
53
|
+
const autonomousBytes=await bounded(autonomousPolicyPath,1024*1024);
|
|
54
|
+
const binding=verifyR186PolicyRootBinding({
|
|
55
|
+
codingPolicy:JSON.parse(codingBytes.toString('utf8')),
|
|
56
|
+
autonomousPolicy:JSON.parse(autonomousBytes.toString('utf8')),
|
|
57
|
+
rootId,projectRoot,codingPolicySha256:sha(codingBytes)
|
|
58
|
+
});
|
|
59
|
+
const [approvalBuf,trustBuf,keyBuf]=await Promise.all([
|
|
60
|
+
bounded(approvalPath,64*1024),bounded(ANCHOR,4*1024),bounded(KEY,8*1024)
|
|
61
|
+
]);
|
|
62
|
+
const decision=await verifyR186OwnerConsent({
|
|
63
|
+
ownerTrust:JSON.parse(trustBuf.toString('utf8')),
|
|
64
|
+
ownerPublicKeyPem:keyBuf.toString('utf8'),
|
|
65
|
+
approval:JSON.parse(approvalBuf.toString('utf8')),
|
|
66
|
+
expected:{
|
|
67
|
+
rootId:binding.root_id,projectRoot:binding.project_root,
|
|
68
|
+
codingPolicySha256:sha(codingBytes),
|
|
69
|
+
autonomousPolicySha256:sha(autonomousBytes),
|
|
70
|
+
reviewedArtifactSha256:sha(manifestBytes)
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
console.log(JSON.stringify({
|
|
74
|
+
schema:'deadbyte.r186-owner-preflight.v1',
|
|
75
|
+
status:decision.status,
|
|
76
|
+
authority_granted:false,
|
|
77
|
+
owner_key_id:decision.owner_key_id,
|
|
78
|
+
subject_sha256:decision.subject_sha256,
|
|
79
|
+
release_manifest_sha256:sha(manifestBytes),
|
|
80
|
+
os_acl_trusted:true,
|
|
81
|
+
project_root:decision.project_root,
|
|
82
|
+
expires_at_utc:decision.expires_at_utc,
|
|
83
|
+
next_gate:'OWNER_APPROVAL_SINGLE_USE_CONSUMPTION_AND_SIGNED_EPOCH_ISSUANCE'
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
main().catch(e=>{console.error('R186_OWNER_PREFLIGHT_BLOCKED '+String(e?.message??e).slice(0,300));process.exitCode=2;});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Protected, fixed-scope R186 grant broker entrypoint. The controller chooses
|
|
2
|
+
// neither a trust key nor an approval path; both are fixed by the contract.
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import {lstat,readFile} from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import {fileURLToPath} from 'node:url';
|
|
7
|
+
import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
|
|
8
|
+
import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
|
|
9
|
+
import {issueR186AutonomousGrant} from '../src/r186-owner-grant-broker.mjs';
|
|
10
|
+
|
|
11
|
+
const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
|
|
12
|
+
const OWNER_DIR='C:\\Program Files\\DEADBYTE-OwnerTrust';
|
|
13
|
+
const KEY=path.win32.join(OWNER_DIR,'owner-public.pem');
|
|
14
|
+
const ANCHOR=path.win32.join(OWNER_DIR,'owner-anchor.json');
|
|
15
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
16
|
+
const block=m=>{throw new Error(`R186_OWNER_GRANT_BLOCKED: ${m}`);};
|
|
17
|
+
async function bounded(file,limit){const st=await lstat(file);if(!st.isFile()||st.isSymbolicLink()||st.size<1||st.size>limit)block('unsafe input file');return readFile(file);}
|
|
18
|
+
async function main(){
|
|
19
|
+
if(process.platform!=='win32'||process.arch!=='x64')block('requires Windows x64');
|
|
20
|
+
const [runtimeDir,codingPolicyPath,autonomousPolicyPath]=process.argv.slice(2);
|
|
21
|
+
if(process.argv.slice(2).length!==3||![runtimeDir,codingPolicyPath,autonomousPolicyPath].every(p=>path.win32.isAbsolute(p)))
|
|
22
|
+
block('usage: <runtime-dir> <coding-policy-json> <autonomous-policy-json>');
|
|
23
|
+
const approvalPath=path.join(runtimeDir,'owner-consent','autonomous-approval.json');
|
|
24
|
+
const protectedFiles=[process.execPath,THIS,ANCHOR,KEY,path.join(ROOT,'MANIFEST.SHA256'),
|
|
25
|
+
path.join(ROOT,'src','r186-owner-grant-broker.mjs'),path.join(ROOT,'src','r186-owner-consent-preflight.mjs'),
|
|
26
|
+
path.join(ROOT,'src','r70-owner-approval.mjs'),path.join(ROOT,'src','authority-continuity-r65.mjs'),
|
|
27
|
+
path.join(ROOT,'src','epoch-lock-r85.mjs'),path.join(ROOT,'bin','deadbyte-epoch-lock-r85.node')];
|
|
28
|
+
const trust=await inspectTrustedInstallation(protectedFiles);
|
|
29
|
+
if(!trust.trusted)block('protected package or owner trust ACL untrusted');
|
|
30
|
+
const manifestBytes=await bounded(path.join(ROOT,'MANIFEST.SHA256'),512*1024);
|
|
31
|
+
await verifyManifestTreeExact(ROOT,parseManifest(manifestBytes.toString('utf8')));
|
|
32
|
+
const [codingBytes,autonomousBytes,approvalBytes,anchorBytes,keyBytes]=await Promise.all([
|
|
33
|
+
bounded(codingPolicyPath,1024*1024),bounded(autonomousPolicyPath,1024*1024),bounded(approvalPath,64*1024),
|
|
34
|
+
bounded(ANCHOR,4096),bounded(KEY,8192)]);
|
|
35
|
+
const autonomous=JSON.parse(autonomousBytes.toString('utf8'));
|
|
36
|
+
const result=await issueR186AutonomousGrant({runtimeDir,grantFile:autonomous.lease_file,
|
|
37
|
+
codingPolicy:JSON.parse(codingBytes.toString('utf8')),codingPolicyBytes:codingBytes,
|
|
38
|
+
autonomousPolicy:autonomous,autonomousPolicyBytes:autonomousBytes,releaseManifestBytes:manifestBytes,
|
|
39
|
+
ownerTrust:JSON.parse(anchorBytes.toString('utf8')),ownerPublicKeyPem:keyBytes.toString('utf8'),
|
|
40
|
+
approval:JSON.parse(approvalBytes.toString('utf8'))});
|
|
41
|
+
if(sha(await readFile(codingPolicyPath))!==sha(codingBytes)||sha(await readFile(autonomousPolicyPath))!==sha(autonomousBytes))
|
|
42
|
+
block('policy changed during grant transaction; outcome requires reconciliation');
|
|
43
|
+
process.stdout.write(JSON.stringify(result));
|
|
44
|
+
}
|
|
45
|
+
main().catch(error=>{console.error(String(error?.message??error).slice(0,500));process.exitCode=2;});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Owner-operated only. Do not invoke from an agent workflow.
|
|
2
|
+
import {generateKeyPairSync} from 'node:crypto';
|
|
3
|
+
import {mkdir,open,readFile} from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {createR186OwnerAnchor} from '../src/r186-owner-anchor.mjs';
|
|
6
|
+
import {createR186OwnerApproval} from '../src/r186-owner-local-signing.mjs';
|
|
7
|
+
|
|
8
|
+
function args(values){const out={};for(let i=0;i<values.length;i+=2){if(!values[i]?.startsWith('--')||!values[i+1])throw new Error('invalid arguments');out[values[i].slice(2)]=path.resolve(values[i+1]);}return out;}
|
|
9
|
+
async function exclusive(file,data,mode=0o600){await mkdir(path.dirname(file),{recursive:true});const h=await open(file,'wx',mode);try{await h.writeFile(data);await h.sync();}finally{await h.close();}}
|
|
10
|
+
const [command,...rest]=process.argv.slice(2),opt=args(rest);
|
|
11
|
+
if(command==='keygen'){
|
|
12
|
+
if(!opt['private-out']||!opt['public-out'])throw new Error('usage: keygen --private-out PATH --public-out PATH');
|
|
13
|
+
const pair=generateKeyPairSync('ed25519'),privatePem=pair.privateKey.export({type:'pkcs8',format:'pem'}).toString();
|
|
14
|
+
const material=createR186OwnerAnchor(pair.publicKey.export({type:'spki',format:'pem'}).toString());
|
|
15
|
+
await exclusive(opt['private-out'],privatePem,0o600);await exclusive(opt['public-out'],material.public_key_pem,0o644);
|
|
16
|
+
console.log(`R186_OWNER_KEY_CREATED public=${opt['public-out']} owner_key_id=${material.anchor.owner_key_id}`);
|
|
17
|
+
}else if(command==='sign'){
|
|
18
|
+
if(!opt.request||!opt['private-key']||!opt['approval-out'])throw new Error('usage: sign --request PATH --private-key PATH --approval-out PATH');
|
|
19
|
+
const approval=createR186OwnerApproval({request:JSON.parse(await readFile(opt.request,'utf8')),privateKeyPem:await readFile(opt['private-key'],'utf8')});
|
|
20
|
+
await exclusive(opt['approval-out'],Buffer.from(JSON.stringify(approval,null,2)+'\n'),0o600);
|
|
21
|
+
console.log(`R186_OWNER_APPROVAL_CREATED approval=${opt['approval-out']} subject_sha256=${approval.subject_sha256} owner_key_id=${approval.owner_key_id}`);
|
|
22
|
+
}else throw new Error('usage: r186-owner-key-local.mjs <keygen|sign> ...');
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Protected exact-byte review-request export. No owner key or grant is used.
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
|
|
5
|
+
import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
|
|
6
|
+
import {writeR186OwnerReviewRequest} from '../src/r186-owner-review-export.mjs';
|
|
7
|
+
import {readFile} from 'node:fs/promises';
|
|
8
|
+
|
|
9
|
+
const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
|
|
10
|
+
const fail=message=>{throw new Error(`R186_OWNER_REVIEW_EXPORT_BLOCKED: ${message}`);};
|
|
11
|
+
async function main(){
|
|
12
|
+
if(process.platform!=='win32'||process.arch!=='x64')fail('requires Windows x64');
|
|
13
|
+
const [rootId,projectRoot,codingPolicyPath,autonomousPolicyPath,outputPath]=process.argv.slice(2);
|
|
14
|
+
if(process.argv.slice(2).length!==5||
|
|
15
|
+
![projectRoot,codingPolicyPath,autonomousPolicyPath,outputPath].every(value=>path.win32.isAbsolute(value)))
|
|
16
|
+
fail('usage: <root-id> <project-root> <coding-policy-json> <autonomous-policy-json> <output-json>');
|
|
17
|
+
const manifestPath=path.join(ROOT,'MANIFEST.SHA256');
|
|
18
|
+
const protectedFiles=[process.execPath,THIS,manifestPath,
|
|
19
|
+
path.join(ROOT,'src','r186-owner-review-export.mjs'),
|
|
20
|
+
path.join(ROOT,'src','r186-owner-request.mjs'),
|
|
21
|
+
path.join(ROOT,'src','r186-owner-consent-preflight.mjs'),
|
|
22
|
+
path.join(ROOT,'src','canonical-json.mjs'),
|
|
23
|
+
path.join(ROOT,'src','privileged-install-trust-r89.mjs'),
|
|
24
|
+
path.join(ROOT,'src','release-slot.mjs')];
|
|
25
|
+
const trust=await inspectTrustedInstallation(protectedFiles);
|
|
26
|
+
if(!trust.trusted)fail('protected package ACL untrusted');
|
|
27
|
+
const manifestBytes=await readFile(manifestPath);
|
|
28
|
+
await verifyManifestTreeExact(ROOT,parseManifest(manifestBytes.toString('utf8')));
|
|
29
|
+
const request=await writeR186OwnerReviewRequest({rootId,projectRoot,codingPolicyPath,
|
|
30
|
+
autonomousPolicyPath,manifestPath,outputPath});
|
|
31
|
+
process.stdout.write(JSON.stringify({status:'REVIEW_REQUEST_EXPORTED',authority_granted:false,
|
|
32
|
+
owner_signature_present:false,subject_sha256:request.subject_sha256,output_path:outputPath}));
|
|
33
|
+
}
|
|
34
|
+
main().catch(error=>{console.error(String(error?.message??error).slice(0,500));process.exitCode=2;});
|