deadbyte-mcp 0.15.60 → 0.15.62
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 +90 -42
- package/PROVENANCE.json +33 -14
- package/README.txt +18 -18
- package/RELEASE.json +45 -16
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +24 -2
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +78 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R156-LOOP-AND-EPOCH-ROUTING.md +86 -0
- package/docs/R157-ARCHITECTURE-DEPENDENCIES.md +58 -0
- package/docs/R157-ARCHITECTURE-GRAPH.json +2874 -0
- package/docs/R157-ENGINEERING-HANDOFF.md +71 -0
- package/docs/R157-FILE-DELTA.json +80 -0
- package/docs/R157-FOCUSED-VERIFICATION.log +0 -0
- package/docs/R157-REFERENCE-CAPABILITY-MATRIX.md +207 -0
- package/docs/R157-REFERENCE-DECISIONS.md +46 -0
- package/docs/R157-REFERENCE-INVENTORY.json +2849 -0
- package/docs/R158-COMBINED-REGRESSION.log +0 -0
- package/docs/R158-DELTA.json +80 -0
- package/docs/R158-EPOCH-BOOTSTRAP-GREEN.log +0 -0
- package/docs/R158-EPOCH-BOOTSTRAP-RED.log +0 -0
- package/docs/R158-EPOCH-IDENTITY-RED.log +0 -0
- package/docs/R158-FOCUSED-GREEN.log +0 -0
- package/docs/R158-PROTECTED-EPOCH-VERIFIED.md +43 -0
- package/docs/R158-PROTECTED-EXACT-SOURCE-LIVE.log +0 -0
- package/docs/R158-UPDATER-REGRESSION.log +0 -0
- package/docs/R159-COMPLETED-HISTORY-BACKUP/deadbyte-cli.mjs.before +965 -0
- package/docs/R159-COMPLETED-HISTORY-BACKUP/legacy-marker-evidence-r159.mjs.before +102 -0
- package/docs/R159-COMPLETED-HISTORY-BACKUP/r159-legacy-marker-evidence.test.mjs.before +79 -0
- package/docs/R159-COMPLETED-HISTORY-PATCH.json +26 -0
- package/docs/R159-MARKER-LOCATOR-CHECKPOINT.md +46 -0
- package/docs/R160-ENGINEERING-HANDOFF.md +32 -0
- package/docs/R160-REFERENCE-CAPABILITY-MATRIX.json +165 -0
- package/package.json +2 -2
- package/scripts/bootstrap-uac-migration-r153.ps1 +17 -5
- package/scripts/deploy-r48.mjs +7 -6
- package/scripts/gate-windows-r160.ps1 +57 -0
- package/scripts/issue-uac-migration-r153.mjs +12 -5
- package/scripts/npm-release-r48.mjs +5 -0
- package/scripts/npm-release-readiness-r163.mjs +67 -0
- package/scripts/r153-prepublish-identity.mjs +3 -3
- package/scripts/request-uac-migration-r153.ps1 +17 -4
- package/scripts/verify-protected-stage-r153.mjs +1 -0
- package/src/autonomous-supervisor.mjs +21 -4
- package/src/clean-activation-recovery-r153.mjs +1 -1
- package/src/deadbyte-cli.mjs +83 -60
- package/src/host-command-pins-r154.mjs +34 -0
- package/src/legacy-marker-evidence-r159.mjs +128 -0
- package/src/package-identity-r160.mjs +61 -0
- package/src/release-generation.mjs +13 -0
- package/src/release-slot.mjs +2 -1
- package/src/remote-live-log.mjs +30 -2
- package/src/runtime-update.mjs +18 -6
- package/src/trusted-epoch-bootstrap-r158.mjs +42 -0
- package/src/uac-approval-contract-r153.mjs +6 -3
- package/src/version.mjs +1 -1
- package/src/windows-powershell-environment.mjs +5 -2
- package/test/r106-trusted-powershell-spawn.test.mjs +1 -0
- package/test/r130-release-security-contract.test.mjs +9 -9
- package/test/r132-release-identity.test.mjs +8 -10
- package/test/r153-clean-activation-recovery.test.mjs +2 -2
- package/test/r153-prepublish-identity.test.mjs +26 -5
- package/test/r153-r65-signed-precondition-recovery.test.mjs +2 -2
- package/test/r153-staging-leaf-acl.test.mjs +24 -10
- package/test/r153-uac-approval-contract.test.mjs +5 -3
- package/test/r153-uac-launch-parameter-contract.test.mjs +1 -1
- package/test/r154-multipin-recovery.test.mjs +45 -0
- package/test/r155-commander-live-log.test.mjs +44 -0
- package/test/r155-default-live-log.test.mjs +89 -0
- package/test/r156-epoch-route-smoke.ps1 +48 -0
- package/test/r156-supervisor-pacing.test.mjs +59 -0
- package/test/r157-architecture-map.mjs +61 -0
- package/test/r157-reference-survey.mjs +91 -0
- package/test/r157-supervisor-singleflight.test.mjs +32 -0
- package/test/r158-epoch-bootstrap.test.mjs +34 -0
- package/test/r159-legacy-marker-evidence.test.mjs +100 -0
- package/test/r159-legacy-marker-evidence.test.mjs.before-assertion-fix-20261025-120246.bak +100 -0
- package/test/r160-marker-proof.test.mjs +87 -0
- package/test/r160-package-decision-manifest.test.mjs +67 -0
- package/test/r160-release-contract.test.mjs +30 -0
- package/test/r160-stable-launcher.test.mjs +10 -0
- package/test/r163-isolated-slot-rollback-restore.test.mjs +58 -0
- package/test/r163-publish-fence.test.mjs +13 -0
- package/test/r48-release-contract.test.mjs +7 -1
- package/test/r58-launcher-shell.test.mjs +4 -1
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/release-generation.test.mjs +16 -0
- package/test/remote-live-log-r37.test.mjs +5 -3
- package/test/remote-session-cli.test.mjs +11 -11
- package/test/stabilization-state-root.test.mjs +2 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
[CmdletBinding()]
|
|
3
|
+
param([ValidateSet('preflight','focused','full','manifest','doctor','all')][string]$Stage='preflight')
|
|
4
|
+
Set-StrictMode -Version Latest
|
|
5
|
+
$ErrorActionPreference='Stop'
|
|
6
|
+
$repo=Split-Path -Parent $PSScriptRoot
|
|
7
|
+
$state=Join-Path $env:USERPROFILE '.deadbyte-mcp'
|
|
8
|
+
$parentId='v0.15.61-055d1ff0aa99e60b'
|
|
9
|
+
$parentSha='055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf'
|
|
10
|
+
$parentGen='f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4'
|
|
11
|
+
$nativeNode='C:\Program Files\nodejs\node.exe'
|
|
12
|
+
$node=if(Test-Path -LiteralPath $nativeNode -PathType Leaf){$nativeNode}else{(Get-Command node -ErrorAction Stop).Source}
|
|
13
|
+
function Sha([string]$file){
|
|
14
|
+
$sha=[Security.Cryptography.SHA256]::Create()
|
|
15
|
+
try{$stream=[IO.File]::OpenRead($file);try{return ([BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-','').ToLowerInvariant()}finally{$stream.Dispose()}}finally{$sha.Dispose()}
|
|
16
|
+
}
|
|
17
|
+
function Run-Node([string]$label,[string[]]$nodeArgs){
|
|
18
|
+
if($null -eq $nodeArgs -or $nodeArgs.Count -lt 1){throw "R160_${label}_NO_NODE_ARGUMENTS"}
|
|
19
|
+
Write-Output "R160_STAGE_START=$label"
|
|
20
|
+
Write-Output "R160_STAGE_ARGS=$($nodeArgs.Count)"
|
|
21
|
+
$global:LASTEXITCODE=0
|
|
22
|
+
& $node @nodeArgs
|
|
23
|
+
$exit=$global:LASTEXITCODE
|
|
24
|
+
if($exit -ne 0){throw "R160_${label}_FAILED exit=$exit"}
|
|
25
|
+
Write-Output "R160_STAGE_PASS=$label"
|
|
26
|
+
}
|
|
27
|
+
Push-Location $repo
|
|
28
|
+
try{
|
|
29
|
+
$pkg=Get-Content -LiteralPath 'package.json' -Raw | ConvertFrom-Json
|
|
30
|
+
$release=Get-Content -LiteralPath 'RELEASE.json' -Raw | ConvertFrom-Json
|
|
31
|
+
if($pkg.version -ne '0.15.62' -or $release.version -ne '0.15.62' -or $release.train -ne 'R160'){throw 'R160_CANDIDATE_VERSION_DRIFT'}
|
|
32
|
+
if($release.runtime_predecessor.release_id -ne $parentId -or $release.runtime_predecessor.manifest_sha256 -ne $parentSha -or $release.runtime_predecessor.generation_manifest_sha256 -ne $parentGen){throw 'R160_RUNTIME_PREDECESSOR_IDENTITY_DRIFT'}
|
|
33
|
+
$active=Get-Content -LiteralPath (Join-Path $state 'active-release.json') -Raw | ConvertFrom-Json
|
|
34
|
+
if($active.version -ne '0.15.61' -or $active.release_id -ne $parentId -or $active.manifest_sha256 -ne $parentSha -or $active.generation_manifest_sha256 -ne $parentGen){throw 'R160_ACTIVE_RUNTIME_DRIFT'}
|
|
35
|
+
if((Sha (Join-Path $active.release_root 'MANIFEST.SHA256')) -ne $parentSha){throw 'R160_ACTIVE_MANIFEST_MISMATCH'}
|
|
36
|
+
Write-Output 'R160_PREDECESSOR_PREFLIGHT=PASS'
|
|
37
|
+
if($Stage -eq 'preflight'){return}
|
|
38
|
+
if($Stage -in @('focused','all')){
|
|
39
|
+
Run-Node -label 'focused' -nodeArgs @('--test','--test-concurrency=1','test/r89-privileged-install-boundary.test.mjs','test/r92-acl-ace-applicability.test.mjs','test/r153-clean-activation-recovery.test.mjs','test/r155-commander-live-log.test.mjs','test/r155-default-live-log.test.mjs','test/r156-supervisor-pacing.test.mjs','test/r157-supervisor-singleflight.test.mjs','test/r158-epoch-bootstrap.test.mjs','test/r159-legacy-marker-evidence.test.mjs','test/r160-marker-proof.test.mjs','test/r160-package-decision-manifest.test.mjs','test/r160-stable-launcher.test.mjs','test/r160-release-contract.test.mjs','test/r59-tool-surface-compat.test.mjs')
|
|
40
|
+
if($Stage -eq 'focused'){return}
|
|
41
|
+
}
|
|
42
|
+
if($Stage -in @('full','all')){
|
|
43
|
+
Run-Node -label 'full' -nodeArgs @('--test','--test-concurrency=4','test/*.test.mjs')
|
|
44
|
+
if($Stage -eq 'full'){return}
|
|
45
|
+
}
|
|
46
|
+
if($Stage -in @('manifest','all')){
|
|
47
|
+
Run-Node -label 'manifest' -nodeArgs @('scripts/release-manifest.mjs','verify')
|
|
48
|
+
if($Stage -eq 'manifest'){return}
|
|
49
|
+
}
|
|
50
|
+
if($Stage -in @('doctor','all')){
|
|
51
|
+
$previous=$env:DEADBYTE_STATE_ROOT
|
|
52
|
+
$isolated=Join-Path $env:TEMP ('deadbyte-r160-doctor-'+[guid]::NewGuid().ToString('N'))
|
|
53
|
+
try{[IO.Directory]::CreateDirectory($isolated)|Out-Null;$env:DEADBYTE_STATE_ROOT=$isolated;Run-Node -label 'isolated_doctor' -nodeArgs @('src/deadbyte-cli.mjs','doctor')}
|
|
54
|
+
finally{$env:DEADBYTE_STATE_ROOT=$previous;Remove-Item -LiteralPath $isolated -Recurse -Force -ErrorAction SilentlyContinue}
|
|
55
|
+
}
|
|
56
|
+
Write-Output 'R160_WINDOWS_CANDIDATE_GATE=PASS_PREPUBLICATION'
|
|
57
|
+
}finally{Pop-Location}
|
|
@@ -9,6 +9,7 @@ import {parseActivePointer} from '../src/release-slot.mjs';
|
|
|
9
9
|
import {inspectTrustedInstallation,privilegedEpochInstallFiles} from '../src/privileged-install-trust-r89.mjs';
|
|
10
10
|
import {verifyMarkerReconciliationReceipt} from '../src/clean-activation-recovery-r153.mjs';
|
|
11
11
|
import {createUacApproval,uacPointerSha256,protectedUacReceiptPath} from '../src/uac-approval-contract-r153.mjs';
|
|
12
|
+
import {decodeHostCommandPins} from '../src/host-command-pins-r154.mjs';
|
|
12
13
|
|
|
13
14
|
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
14
15
|
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
@@ -17,11 +18,15 @@ const hash=async f=>sha(await read(f));
|
|
|
17
18
|
const fail=text=>{throw new Error('R153 UAC issuer rejected: '+text);};
|
|
18
19
|
function args(argv){
|
|
19
20
|
const expected=['--state-root','--marker-receipt','--marker-receipt-sha256','--preflight-subject-sha256'];
|
|
20
|
-
if(argv.length
|
|
21
|
+
if(![8,10].includes(argv.length)||expected.some((key,i)=>argv[2*i]!==key)||
|
|
22
|
+
(argv.length===10&&argv[8]!=='--host-command-pins-json'))fail('unexpected arguments');
|
|
21
23
|
const [state,receipt,receiptHash,preflight]=[argv[1],argv[3],argv[5],argv[7]];
|
|
22
24
|
if(!path.win32.isAbsolute(state)||!path.win32.isAbsolute(receipt)||
|
|
23
25
|
!/^[0-9a-f]{64}$/.test(receiptHash)||!/^[0-9a-f]{64}$/.test(preflight))fail('subject arguments invalid');
|
|
24
|
-
|
|
26
|
+
let hostCommandPins=[];
|
|
27
|
+
try{hostCommandPins=decodeHostCommandPins(argv.length===10?argv[9]:'[]');}
|
|
28
|
+
catch(error){fail(error.message);}
|
|
29
|
+
return {state:path.resolve(state),receipt:path.resolve(receipt),receiptHash,preflight,hostCommandPins};
|
|
25
30
|
}
|
|
26
31
|
async function regular(file,label){const s=await lstat(file);if(!s.isFile()||s.isSymbolicLink())fail(label+' must be regular');return s;}
|
|
27
32
|
async function absent(file,label){try{await lstat(file);fail(label+' present');}catch(e){if(e?.code!=='ENOENT')throw e;}}
|
|
@@ -33,7 +38,7 @@ async function main(){
|
|
|
33
38
|
{encoding:'utf8',shell:false,windowsHide:true,timeout:12000});
|
|
34
39
|
if(elevated.error||elevated.status!==0||String(elevated.stdout).trim().toLowerCase()!=='true')
|
|
35
40
|
fail('explicit Windows UAC elevation required');
|
|
36
|
-
const {state,receipt,receiptHash,preflight}=args(process.argv.slice(2));
|
|
41
|
+
const {state,receipt,receiptHash,preflight,hostCommandPins}=args(process.argv.slice(2));
|
|
37
42
|
if(path.dirname(receipt).toLowerCase()!==path.join(state,'evidence','legacy-migration').toLowerCase())
|
|
38
43
|
fail('marker receipt path not in state evidence root');
|
|
39
44
|
const issueFile=fileURLToPath(import.meta.url);
|
|
@@ -41,11 +46,12 @@ async function main(){
|
|
|
41
46
|
const helperFile=path.join(root,'scripts','request-uac-migration-r153.ps1');
|
|
42
47
|
const trust=await inspectTrustedInstallation([...privilegedEpochInstallFiles(root,process.execPath),
|
|
43
48
|
issueFile,deployFile,helperFile,path.join(root,'package.json'),path.join(root,'MANIFEST.SHA256'),path.join(root,'RELEASE.json'),path.join(root,'src','uac-approval-contract-r153.mjs'),
|
|
44
|
-
path.join(root,'src','clean-activation-recovery-r153.mjs'),path.join(root,'src','legacy-offline-policy-proof-r146.mjs')
|
|
49
|
+
path.join(root,'src','clean-activation-recovery-r153.mjs'),path.join(root,'src','legacy-offline-policy-proof-r146.mjs'),
|
|
50
|
+
path.join(root,'src','host-command-pins-r154.mjs')]);
|
|
45
51
|
if(trust.trusted!==true)fail('candidate not R89 protected');
|
|
46
52
|
const pkg=JSON.parse((await read(path.join(root,'package.json'))).toString('utf8'));
|
|
47
53
|
const rel=JSON.parse((await read(path.join(root,'RELEASE.json'))).toString('utf8'));
|
|
48
|
-
if(pkg.version!=='0.15.
|
|
54
|
+
if(pkg.version!=='0.15.61'||rel.version!==pkg.version)fail('candidate release identity mismatch');
|
|
49
55
|
const pointer=parseActivePointer((await read(path.join(state,'active-release.json'))).toString('utf8'));
|
|
50
56
|
if(pointer.version!=='0.15.45'||rel.parent?.release_id!==pointer.release_id||
|
|
51
57
|
rel.parent?.manifest_sha256!==pointer.manifest_sha256||
|
|
@@ -85,6 +91,7 @@ async function main(){
|
|
|
85
91
|
predecessorPointerSha256:uacPointerSha256(pointer),
|
|
86
92
|
predecessorPolicySha256:policies,preflightSubjectSha256:preflight,
|
|
87
93
|
nodeSha256:await hash(process.execPath),deployScriptSha256:await hash(deployFile),
|
|
94
|
+
hostCommandPins,
|
|
88
95
|
nonce,issuedAt,expiresAt});
|
|
89
96
|
// The strict installation manifest disallows unmanifested files. A receipt
|
|
90
97
|
// under root would turn an otherwise valid candidate into an invalid tree.
|
|
@@ -7,6 +7,7 @@ import {assertR67NpmPublishReady} from './npm-release-readiness-r67.mjs';
|
|
|
7
7
|
import {assertR71NpmPublishReady} from './npm-release-readiness-r71.mjs';
|
|
8
8
|
import {assertR72NpmPublishReady} from './npm-release-readiness-r72.mjs';
|
|
9
9
|
import {assertR74NpmPublishReady} from './npm-release-readiness-r74.mjs';
|
|
10
|
+
import {assertR163NpmPublishReady} from './npm-release-readiness-r163.mjs';
|
|
10
11
|
import { existsSync } from 'node:fs';
|
|
11
12
|
import { resolveStateRoot } from '../src/state-root.mjs';
|
|
12
13
|
import path from 'node:path';
|
|
@@ -95,6 +96,10 @@ async function main() {
|
|
|
95
96
|
if (!isVerifyOnly && version==='0.15.45') assertR71NpmPublishReady(release);
|
|
96
97
|
if (!isVerifyOnly && version==='0.15.46') await assertR72NpmPublishReady(release,{root});
|
|
97
98
|
if (!isVerifyOnly && version==='0.15.47') await assertR74NpmPublishReady(release,{root});
|
|
99
|
+
if (!isVerifyOnly && version==='0.15.62') {
|
|
100
|
+
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R163 0.15.62 requires --publish-only; production activation is a separate authority boundary');
|
|
101
|
+
await assertR163NpmPublishReady(release,{root});
|
|
102
|
+
}
|
|
98
103
|
if (release.parent?.release_id !== provenance.parent_release_id ||
|
|
99
104
|
release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
|
|
100
105
|
release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** R163 0.15.62 publication fence. No evidence generation or authority mutation. */
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
import {readFile,lstat} from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
7
|
+
const parent='v0.15.61-055d1ff0aa99e60b';
|
|
8
|
+
const parentManifest='055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf';
|
|
9
|
+
const parentGen='f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4';
|
|
10
|
+
const reject=(m)=>{throw new Error('PUBLISH_BLOCKED R163 '+m);};
|
|
11
|
+
const hex=x=>typeof x==='string'&&/^[0-9a-f]{64}$/.test(x);
|
|
12
|
+
const readJson=async f=>JSON.parse(await readFile(f,'utf8'));
|
|
13
|
+
async function checkedEvidenceFile(file,digest,{allowEmpty=false}={}){
|
|
14
|
+
if(!hex(digest))reject('missing exact evidence digest');
|
|
15
|
+
const info=await lstat(file).catch(()=>reject('evidence file missing '+file));
|
|
16
|
+
if(!info.isFile()||info.isSymbolicLink()||(!allowEmpty&&info.size<1)||info.size>16*1024*1024)reject('invalid evidence file');
|
|
17
|
+
const bytes=await readFile(file);
|
|
18
|
+
if(sha(bytes)!==digest)reject('evidence SHA-256 mismatch '+file);
|
|
19
|
+
return bytes;
|
|
20
|
+
}
|
|
21
|
+
function boundedEvidence(root,relative){
|
|
22
|
+
if(typeof relative!=='string'||!relative||relative.includes('\\'))reject('invalid evidence relative path');
|
|
23
|
+
const p=path.resolve(root,relative),r=path.relative(root,p);
|
|
24
|
+
if(!r||r.startsWith('..')||path.isAbsolute(r))reject('evidence path escape');
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
export async function assertR163NpmPublishReady(release,{root,evidenceRoot=process.env.DEADBYTE_R163_CLOSURE_ROOT}={}){
|
|
28
|
+
if(release?.name!=='deadbyte-mcp'||release?.version!=='0.15.62'||release?.train!=='R160'||release?.r163?.publication_mode!=='PUBLISH_ONLY')reject('release metadata not R163-closed');
|
|
29
|
+
if(release?.parent?.release_id!==parent||release?.parent?.manifest_sha256!==parentManifest||release?.parent?.generation_manifest_sha256!==parentGen||release?.runtime_predecessor?.release_id!==parent)reject('active predecessor lineage mismatch');
|
|
30
|
+
if(!root||!path.isAbsolute(root))reject('candidate root missing');
|
|
31
|
+
if(!evidenceRoot||!path.isAbsolute(evidenceRoot))reject('closure evidence path missing');
|
|
32
|
+
const testRoot=path.resolve(root,'..','..','testing','r163-release-closure');
|
|
33
|
+
const evidence=path.resolve(evidenceRoot);
|
|
34
|
+
const relative=path.relative(testRoot,evidence);
|
|
35
|
+
if(!relative||relative.startsWith('..')||path.isAbsolute(relative))reject('evidence outside bounded R163 testing root');
|
|
36
|
+
for(const p of [testRoot,evidence]){const st=await lstat(p).catch(()=>reject('evidence directory absent'));if(!st.isDirectory()||st.isSymbolicLink())reject('evidence directory is reparse/symlink');}
|
|
37
|
+
const closurePath=path.join(evidence,'closure.json');
|
|
38
|
+
const closureInfo=await lstat(closurePath).catch(()=>reject('closure missing'));
|
|
39
|
+
if(!closureInfo.isFile()||closureInfo.isSymbolicLink()||closureInfo.size<1||closureInfo.size>1024*1024)reject('closure file not regular/bounded');
|
|
40
|
+
const closure=await readJson(closurePath).catch(()=>reject('closure missing/invalid'));
|
|
41
|
+
if(closure?.schema!=='deadbyte.r163-release-closure.v1'||closure?.version!=='0.15.62'||closure?.status!=='PASS'||closure?.production_release_id!==parent)reject('closure subject/status mismatch');
|
|
42
|
+
const manifestSha=sha(await readFile(path.join(root,'MANIFEST.SHA256')));
|
|
43
|
+
if(closure.source_manifest_sha256!==manifestSha)reject('final manifest differs from closure');
|
|
44
|
+
const files=closure?.files;
|
|
45
|
+
if(!files||!['protected_receipt','protected_stdout','protected_stderr','verify_receipt','verify_stdout','verify_stderr'].every(k=>files[k]&&typeof files[k].path==='string'&&hex(files[k].sha256)))reject('required receipts missing');
|
|
46
|
+
const data={};
|
|
47
|
+
for(const [key,info] of Object.entries(files)) data[key]=await checkedEvidenceFile(boundedEvidence(testRoot,info.path),info.sha256,{allowEmpty:key.endsWith('_stderr')});
|
|
48
|
+
let protectedReceipt,verifyReceipt;
|
|
49
|
+
try{protectedReceipt=JSON.parse(data.protected_receipt);verifyReceipt=JSON.parse(data.verify_receipt);}
|
|
50
|
+
catch{reject('gate receipts invalid JSON');}
|
|
51
|
+
if(protectedReceipt?.schema!=='deadbyte.r163-protected-windows-gate.v1'||protectedReceipt?.stage!=='full'||protectedReceipt?.exit_code!==0||protectedReceipt?.source_manifest_sha256!==manifestSha||protectedReceipt?.active_release_id!==parent)reject('protected gate missing or unbound');
|
|
52
|
+
if(protectedReceipt.stdout_sha256!==sha(data.protected_stdout)||protectedReceipt.stderr_sha256!==sha(data.protected_stderr))reject('protected log mismatch');
|
|
53
|
+
const stdout=data.protected_stdout.toString('utf8');
|
|
54
|
+
const counts=Object.fromEntries(['tests','pass','fail','skipped'].map(k=>[k,Number(new RegExp('^# '+k+' (\\d+)\\s*$','m').exec(stdout)?.[1]??NaN)]));
|
|
55
|
+
if(counts.tests<1951||counts.pass<1902||counts.fail!==0||counts.skipped!==49||counts.pass+counts.skipped!==counts.tests||/^not ok\s+\d+/m.test(stdout))reject('full regression totals mismatch');
|
|
56
|
+
if(!/^ok\s+\d+\s+-\s+R163 isolated immutable slot activates, rolls back, and restores 0\.15\.62/m.test(stdout))reject('R163 live rollback proof missing');
|
|
57
|
+
const skips=stdout.split(/\r?\n/).filter(x=>/^ok\s+\d+\s+-.*# SKIP/.test(x));
|
|
58
|
+
if(skips.length!==49||skips.some(x=>!/historical|R35 external semantic backend|POSIX|R100 POSIX/i.test(x)))reject('unexpected unclassified skipped test');
|
|
59
|
+
if(verifyReceipt?.schema!=='deadbyte.r163-release-verify.v1'||verifyReceipt?.status!=='PASS'||verifyReceipt?.version!=='0.15.62'||verifyReceipt?.source_manifest_sha256!==manifestSha||verifyReceipt?.production_release_id!==parent||verifyReceipt?.exit_code!==0)reject('verify-only receipt subject/status mismatch');
|
|
60
|
+
if(verifyReceipt.stdout_sha256!==sha(data.verify_stdout)||verifyReceipt.stderr_sha256!==sha(data.verify_stderr))reject('verify-only transcript hash mismatch');
|
|
61
|
+
const vout=data.verify_stdout.toString('utf8');
|
|
62
|
+
if(!vout.includes('VERIFY-ONLY PIPELINE PASS')||!vout.includes('Artifact isolation gate PASS')||!vout.includes('VERIFIED_TARBALL '))reject('npm verify-only output missing');
|
|
63
|
+
const tarLine=vout.split(/\r?\n/).find(x=>x.startsWith('VERIFIED_TARBALL '));
|
|
64
|
+
try{const p=JSON.parse(tarLine.slice('VERIFIED_TARBALL '.length));if(p.filename!=='deadbyte-mcp-0.15.62.tgz'||!hex(p.sha256)||p.bytes<1)reject('npm tarball identity invalid');}
|
|
65
|
+
catch{reject('npm tarball evidence invalid');}
|
|
66
|
+
return Object.freeze({status:'R163_RELEASE_READY_EVIDENCE_BOUND',version:'0.15.62',manifest_sha256:manifestSha,checks:6});
|
|
67
|
+
}
|
|
@@ -6,9 +6,9 @@ import {fileURLToPath} from 'node:url';
|
|
|
6
6
|
const defaultRoot=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
7
7
|
const hex64=/^[0-9a-f]{64}$/;
|
|
8
8
|
const EXPECTED=Object.freeze({
|
|
9
|
-
candidateVersion:'0.15.
|
|
10
|
-
sourceVersion:'0.15.
|
|
11
|
-
sourceSha256:'
|
|
9
|
+
candidateVersion:'0.15.61', train:'R154',
|
|
10
|
+
sourceVersion:'0.15.60',
|
|
11
|
+
sourceSha256:'b85f735f4c8be56f97ea5c78f0cc48583e8d5708a704c903596f5720e36ace83',
|
|
12
12
|
runtimeVersion:'0.15.45',
|
|
13
13
|
runtimeReleaseId:'v0.15.45-34aa8d1241cfb8bf',
|
|
14
14
|
runtimeManifest:'34aa8d1241cfb8bf0b5ba303bf3c06e0e9e1bf01f64457bca659d6dd4d634fdc',
|
|
@@ -7,7 +7,7 @@ param(
|
|
|
7
7
|
[Parameter(Mandatory=$true)][string]$MarkerReceiptPath,
|
|
8
8
|
[Parameter(Mandatory=$true)][ValidatePattern('^[0-9a-f]{64}$')][string]$MarkerReceiptSha256,
|
|
9
9
|
[ValidatePattern('^[0-9a-f]{64}$')][string]$PreflightSubjectSha256,
|
|
10
|
-
[
|
|
10
|
+
[string]$HostCommandPinsJson = '[]',
|
|
11
11
|
[switch]$Elevated
|
|
12
12
|
)
|
|
13
13
|
$ErrorActionPreference = 'Stop'
|
|
@@ -21,6 +21,19 @@ function Require-AbsoluteFile([string]$Value,[string]$Label) {
|
|
|
21
21
|
return $item.FullName
|
|
22
22
|
}
|
|
23
23
|
function Full([string]$Value) { [IO.Path]::GetFullPath($Value).TrimEnd('\') }
|
|
24
|
+
function Validate-PinsJson([string]$Value) {
|
|
25
|
+
try { $pins = @($Value | ConvertFrom-Json) } catch { throw 'R154 host command pins JSON invalid' }
|
|
26
|
+
if ($pins.Count -gt 16) { throw 'R154 host command pin limit exceeded' }
|
|
27
|
+
$seen = @{}
|
|
28
|
+
foreach ($pin in $pins) {
|
|
29
|
+
if ([string]$pin -cnotmatch '^[A-Za-z0-9._-]{1,64}=[0-9a-f]{64}$') { throw 'R154 host command pin contract invalid' }
|
|
30
|
+
$id = ([string]$pin).Split('=')[0]
|
|
31
|
+
if ($seen.ContainsKey($id)) { throw 'R154 duplicate host command pin' }
|
|
32
|
+
$seen[$id] = $true
|
|
33
|
+
}
|
|
34
|
+
return $pins
|
|
35
|
+
}
|
|
36
|
+
$HostCommandPins = @(Validate-PinsJson $HostCommandPinsJson)
|
|
24
37
|
$NodePath = Require-AbsoluteFile $NodePath 'Node executable'
|
|
25
38
|
$DeployScript = Require-AbsoluteFile $DeployScript 'Deploy script'
|
|
26
39
|
$MarkerReceiptPath = Require-AbsoluteFile $MarkerReceiptPath 'Marker reconciliation receipt'
|
|
@@ -100,7 +113,7 @@ if (-not $Elevated) {
|
|
|
100
113
|
# -Verb RunAs is the UseShellExecute parameter set. PowerShell 5.1 rejects
|
|
101
114
|
# -RedirectStandardOutput/-RedirectStandardError in that same Start-Process.
|
|
102
115
|
# The elevated child writes bounded, no-clobber evidence instead.
|
|
103
|
-
if ($
|
|
116
|
+
if ($HostCommandPinsJson -cne '[]') { $arguments += @('-HostCommandPinsJson',('"' + $HostCommandPinsJson.Replace('"','\"') + '"')) }
|
|
104
117
|
$child = Start-Process -FilePath $powershell -ArgumentList $arguments -Verb RunAs -Wait -PassThru -WindowStyle Hidden
|
|
105
118
|
if (Test-Path -LiteralPath $StdoutPath) { [Console]::Out.Write([IO.File]::ReadAllText($StdoutPath)) }
|
|
106
119
|
if (Test-Path -LiteralPath $StderrPath) { [Console]::Error.Write([IO.File]::ReadAllText($StderrPath)) }
|
|
@@ -123,7 +136,7 @@ try {
|
|
|
123
136
|
try {
|
|
124
137
|
$issuerOutput = @(& $NodePath $issuerScript '--state-root' $env:DEADBYTE_STATE_ROOT `
|
|
125
138
|
'--marker-receipt' $MarkerReceiptPath '--marker-receipt-sha256' $MarkerReceiptSha256 `
|
|
126
|
-
'--preflight-subject-sha256' $PreflightSubjectSha256 2>&1)
|
|
139
|
+
'--preflight-subject-sha256' $PreflightSubjectSha256 '--host-command-pins-json' $HostCommandPinsJson 2>&1)
|
|
127
140
|
$issuerExit = $LASTEXITCODE
|
|
128
141
|
} finally { $ErrorActionPreference = $priorErrorAction }
|
|
129
142
|
$issuerText = (@($issuerOutput) | ForEach-Object { [string]$_ }) -join "`n"
|
|
@@ -145,7 +158,7 @@ try {
|
|
|
145
158
|
'--migration-expires-at',$issued.expires_at_utc,
|
|
146
159
|
'--uac-approval-receipt',$issued.receipt_path,
|
|
147
160
|
'--uac-approval-receipt-sha256',$issued.receipt_sha256)
|
|
148
|
-
|
|
161
|
+
foreach ($pin in $HostCommandPins) { $deployArgs += @('--host-command-pin',[string]$pin) }
|
|
149
162
|
$deployOutput = @(& $NodePath $DeployScript @deployArgs 2>&1)
|
|
150
163
|
$deployExit = $LASTEXITCODE
|
|
151
164
|
} finally { $ErrorActionPreference = $priorErrorAction }
|
|
@@ -14,6 +14,7 @@ const files=[...privilegedEpochInstallFiles(root,process.execPath),
|
|
|
14
14
|
path.join(root,'package.json'),path.join(root,'MANIFEST.SHA256'),path.join(root,'RELEASE.json'),
|
|
15
15
|
path.join(root,'src','uac-approval-contract-r153.mjs'),
|
|
16
16
|
path.join(root,'src','clean-activation-recovery-r153.mjs'),
|
|
17
|
+
path.join(root,'src','host-command-pins-r154.mjs'),
|
|
17
18
|
path.join(root,'src','legacy-offline-policy-proof-r146.mjs')];
|
|
18
19
|
const verdict=await inspectTrustedInstallation(files);
|
|
19
20
|
if(verdict.trusted!==true)throw new Error('R153 protected stage trust rejected');
|
|
@@ -24,7 +24,7 @@ async function listGoalIds(policy) {
|
|
|
24
24
|
export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
|
|
25
25
|
idleDelayMs = 750, maxCycles = 32, logger = console, continuous = true } = {}) {
|
|
26
26
|
if (!runtime || !policy) throw new Error('autonomous supervisor requires runtime + policy');
|
|
27
|
-
const providerBacked = ['openai_compatible','openai_responses'].includes(policy.planner.backend);
|
|
27
|
+
const providerBacked = ['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend);
|
|
28
28
|
if (!Number.isInteger(idleDelayMs) || idleDelayMs < 25 || idleDelayMs > 60_000) {
|
|
29
29
|
throw new Error('autonomous supervisor idleDelayMs out of range');
|
|
30
30
|
}
|
|
@@ -41,6 +41,10 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
|
|
|
41
41
|
let runnable = 0;
|
|
42
42
|
for (const goalId of await listGoalIds(policy)) {
|
|
43
43
|
if (abort.signal.aborted) break;
|
|
44
|
+
// A known retry deadline is authoritative until elapsed. Avoid
|
|
45
|
+
// polling goal state again just to rediscover the same backoff.
|
|
46
|
+
const pendingRetry=failures.get(goalId);
|
|
47
|
+
if (pendingRetry && Date.now() < pendingRetry.retry_at) continue;
|
|
44
48
|
let status;
|
|
45
49
|
try { status = await runtime.status({ goalId }); }
|
|
46
50
|
catch (error) { logger.warn?.(`DEADBYTE supervisor status ${goalId}: ${String(error)}`); continue; }
|
|
@@ -61,9 +65,10 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
|
|
|
61
65
|
failures.delete(goalId); continue;
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
|
-
runnable += 1;
|
|
65
68
|
const failure = failures.get(goalId);
|
|
66
69
|
if (failure && Date.now() < failure.retry_at) continue;
|
|
70
|
+
// Only an eligible dispatch is runnable. Backoff is not useful work.
|
|
71
|
+
runnable += 1;
|
|
67
72
|
try {
|
|
68
73
|
const result = await runtime.run({ goalId, maxCycles });
|
|
69
74
|
if (result.status === 'paused' && result.reason === 'provider_circuit_open') {
|
|
@@ -89,10 +94,22 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
|
|
|
89
94
|
return runnable;
|
|
90
95
|
}
|
|
91
96
|
|
|
97
|
+
// One supervisor, one in-flight scan. A manual scan and the polling
|
|
98
|
+
// loop must never race to dispatch the same durable goal.
|
|
99
|
+
let inFlightPass=null;
|
|
100
|
+
function scanOnce(){
|
|
101
|
+
if(inFlightPass)return inFlightPass;
|
|
102
|
+
const task=pass();
|
|
103
|
+
inFlightPass=task;
|
|
104
|
+
const clear=()=>{if(inFlightPass===task)inFlightPass=null;};
|
|
105
|
+
task.then(clear,clear);
|
|
106
|
+
return task;
|
|
107
|
+
}
|
|
108
|
+
|
|
92
109
|
const done = continuous ? (async () => {
|
|
93
110
|
while (!abort.signal.aborted) {
|
|
94
111
|
let runnable = 0;
|
|
95
|
-
try { runnable = await
|
|
112
|
+
try { runnable = await scanOnce(); }
|
|
96
113
|
catch (error) { logger.error?.(`DEADBYTE supervisor scan failed: ${String(error)}`); }
|
|
97
114
|
if (abort.signal.aborted) break;
|
|
98
115
|
await delay(runnable > 0 ? 25 : idleDelayMs, abort.signal);
|
|
@@ -103,7 +120,7 @@ export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
|
|
|
103
120
|
get running() { return !abort.signal.aborted; },
|
|
104
121
|
get passes() { return passes; },
|
|
105
122
|
failures,
|
|
106
|
-
async scanNow() { return
|
|
123
|
+
async scanNow() { return scanOnce(); },
|
|
107
124
|
async stop() { abort.abort(); await done; }
|
|
108
125
|
});
|
|
109
126
|
}
|
|
@@ -32,7 +32,7 @@ export function classifyLegacyMigration(input){
|
|
|
32
32
|
if(!input.pointer||input.pointer.version!=='0.15.45'||
|
|
33
33
|
!HEX64.test(String(input.pointer.manifest_sha256??''))||!HEX64.test(String(input.pointer.generation_manifest_sha256??'')))
|
|
34
34
|
return reject('predecessor identity invalid',subject);
|
|
35
|
-
if(!input.candidate||input.candidate.version!=='0.15.
|
|
35
|
+
if(!input.candidate||input.candidate.version!=='0.15.61'||
|
|
36
36
|
!HEX64.test(String(input.candidate.manifest_sha256??''))||!HEX64.test(String(input.candidate.tarball_sha256??'')))
|
|
37
37
|
return reject('candidate identity invalid',subject);
|
|
38
38
|
if(PLANES.some(plane=>!HEX64.test(String(input.policySha256?.[plane]??''))))
|