deadbyte-mcp 0.15.63 → 0.15.65
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 +31 -21
- package/PROVENANCE.json +20 -7
- package/README.txt +18 -18
- package/RELEASE.json +30 -7
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +18 -2
- package/bridge/package.json +1 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/package.json +4 -3
- package/scripts/deploy-r48.mjs +37 -4
- package/scripts/gate-windows-r166.ps1 +57 -0
- package/scripts/gate-windows-r167.ps1 +75 -0
- package/scripts/npm-release-r48.mjs +15 -0
- package/scripts/npm-release-readiness-r166.mjs +37 -0
- package/scripts/npm-release-readiness-r167.mjs +70 -0
- package/src/activation-lock-r65.mjs +1 -1
- package/src/activation-path-r167.mjs +55 -0
- package/src/release-generation.mjs +1 -1
- package/src/version.mjs +1 -1
- package/test/process-policy-refresh.test.mjs +8 -5
- package/test/r130-release-security-contract.test.mjs +7 -7
- package/test/r132-release-identity.test.mjs +7 -7
- package/test/r153-prepublish-identity.test.mjs +2 -2
- package/test/r160-release-contract.test.mjs +4 -12
- package/test/r163-isolated-slot-rollback-restore.test.mjs +2 -2
- package/test/r165-live-cli-skew.test.mjs +2 -2
- package/test/r166-hotfix-contract.test.mjs +27 -0
- package/test/r166-release-readiness.test.mjs +10 -0
- package/test/r167-activation-path.test.mjs +124 -0
- package/test/r167-release-contract.test.mjs +51 -0
- package/test/r167-release-readiness.test.mjs +27 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -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 "R166_${label}_NO_NODE_ARGUMENTS"}
|
|
19
|
+
Write-Output "R166_STAGE_START=$label"
|
|
20
|
+
Write-Output "R166_STAGE_ARGS=$($nodeArgs.Count)"
|
|
21
|
+
$global:LASTEXITCODE=0
|
|
22
|
+
& $node @nodeArgs
|
|
23
|
+
$exit=$global:LASTEXITCODE
|
|
24
|
+
if($exit -ne 0){throw "R166_${label}_FAILED exit=$exit"}
|
|
25
|
+
Write-Output "R166_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.64' -or $release.version -ne '0.15.64' -or $release.train -ne 'R166'){throw 'R166_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 'R166_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 'R166_ACTIVE_RUNTIME_DRIFT'}
|
|
35
|
+
if((Sha (Join-Path $active.release_root 'MANIFEST.SHA256')) -ne $parentSha){throw 'R166_ACTIVE_MANIFEST_MISMATCH'}
|
|
36
|
+
Write-Output 'R166_PREDECESSOR_PREFLIGHT=PASS'
|
|
37
|
+
if($Stage -eq 'preflight'){return}
|
|
38
|
+
if($Stage -in @('focused','all')){
|
|
39
|
+
Run-Node -label 'focused' -nodeArgs @('--test','--test-reporter=tap','--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-reporter=tap','--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 'R166_WINDOWS_CANDIDATE_GATE=PASS_PREPUBLICATION'
|
|
57
|
+
}finally{Pop-Location}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
[CmdletBinding()]
|
|
3
|
+
param(
|
|
4
|
+
[ValidateSet('preflight','focused','full','manifest','doctor','all')][string]$Stage='preflight',
|
|
5
|
+
[string]$ExpectedDevelopmentRoot
|
|
6
|
+
)
|
|
7
|
+
Set-StrictMode -Version Latest
|
|
8
|
+
$ErrorActionPreference='Stop'
|
|
9
|
+
$repo=Split-Path -Parent $PSScriptRoot
|
|
10
|
+
if([string]::IsNullOrWhiteSpace($ExpectedDevelopmentRoot)){$ExpectedDevelopmentRoot=$repo}
|
|
11
|
+
$ExpectedDevelopmentRoot=[IO.Path]::GetFullPath($ExpectedDevelopmentRoot)
|
|
12
|
+
$state=Join-Path $env:USERPROFILE '.deadbyte-mcp'
|
|
13
|
+
$parentId='v0.15.61-055d1ff0aa99e60b'
|
|
14
|
+
$parentSha='055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf'
|
|
15
|
+
$parentGen='f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4'
|
|
16
|
+
$sourceManifest='ad3c091fbbe2bac6d234548724008b67305fd483ad6542f92d5aeb1aa84f5849'
|
|
17
|
+
$nativeNode='C:\Program Files\nodejs\node.exe'
|
|
18
|
+
$node=if(Test-Path -LiteralPath $nativeNode -PathType Leaf){$nativeNode}else{(Get-Command node -ErrorAction Stop).Source}
|
|
19
|
+
function Sha([string]$file){
|
|
20
|
+
$sha=[Security.Cryptography.SHA256]::Create()
|
|
21
|
+
try{$stream=[IO.File]::OpenRead($file);try{return ([BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-','').ToLowerInvariant()}finally{$stream.Dispose()}}finally{$sha.Dispose()}
|
|
22
|
+
}
|
|
23
|
+
function Run-Node([string]$label,[string[]]$nodeArgs){
|
|
24
|
+
if($null -eq $nodeArgs -or $nodeArgs.Count -lt 1){throw "R167_${label}_NO_NODE_ARGUMENTS"}
|
|
25
|
+
Write-Output "R167_STAGE_START=$label"
|
|
26
|
+
Write-Output "R167_STAGE_ARGS=$($nodeArgs.Count)"
|
|
27
|
+
$global:LASTEXITCODE=0
|
|
28
|
+
& $node @nodeArgs
|
|
29
|
+
$exit=$global:LASTEXITCODE
|
|
30
|
+
if($exit -ne 0){throw "R167_${label}_FAILED exit=$exit"}
|
|
31
|
+
Write-Output "R167_STAGE_PASS=$label"
|
|
32
|
+
}
|
|
33
|
+
Push-Location $repo
|
|
34
|
+
$previousExpectedDevelopmentRoot=$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT
|
|
35
|
+
try{
|
|
36
|
+
$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT=$ExpectedDevelopmentRoot
|
|
37
|
+
$pkg=Get-Content -LiteralPath 'package.json' -Raw | ConvertFrom-Json
|
|
38
|
+
$release=Get-Content -LiteralPath 'RELEASE.json' -Raw | ConvertFrom-Json
|
|
39
|
+
if($pkg.version -ne '0.15.65' -or $release.version -ne '0.15.65' -or $release.train -ne 'R167'){throw 'R167_CANDIDATE_VERSION_DRIFT'}
|
|
40
|
+
if($release.source_predecessor.version -ne '0.15.64' -or $release.source_predecessor.train -ne 'R166' -or $release.r167.source_predecessor_manifest_sha256 -ne $sourceManifest){throw 'R167_SOURCE_PREDECESSOR_IDENTITY_DRIFT'}
|
|
41
|
+
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 'R167_RUNTIME_PREDECESSOR_IDENTITY_DRIFT'}
|
|
42
|
+
$active=Get-Content -LiteralPath (Join-Path $state 'active-release.json') -Raw | ConvertFrom-Json
|
|
43
|
+
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 'R167_ACTIVE_RUNTIME_DRIFT'}
|
|
44
|
+
if((Sha (Join-Path $active.release_root 'MANIFEST.SHA256')) -ne $parentSha){throw 'R167_ACTIVE_MANIFEST_MISMATCH'}
|
|
45
|
+
Write-Output 'R167_PREDECESSOR_PREFLIGHT=PASS'
|
|
46
|
+
if($Stage -eq 'preflight'){return}
|
|
47
|
+
if($Stage -in @('focused','all')){
|
|
48
|
+
Run-Node -label 'focused' -nodeArgs @('--test','--test-reporter=tap','--test-concurrency=1','test/r167-activation-path.test.mjs','test/r167-release-contract.test.mjs','test/r160-release-contract.test.mjs','test/r158-epoch-bootstrap.test.mjs','test/r65-activation-orchestration.test.mjs','test/r89-privileged-install-boundary.test.mjs','test/r119-recovery-crash-after-commit.test.mjs','test/r59-tool-surface-compat.test.mjs')
|
|
49
|
+
if($Stage -eq 'focused'){return}
|
|
50
|
+
}
|
|
51
|
+
if($Stage -in @('full','all')){
|
|
52
|
+
$previousCrossVolume=$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT
|
|
53
|
+
$tempDrive=[IO.Path]::GetPathRoot([IO.Path]::GetFullPath($env:TEMP))
|
|
54
|
+
$scratchDrive=if($tempDrive -ieq 'D:\'){'C:\'}else{'D:\'}
|
|
55
|
+
if(-not (Test-Path -LiteralPath $scratchDrive -PathType Container)){throw 'R167_CROSS_VOLUME_DRIVE_UNAVAILABLE'}
|
|
56
|
+
$crossVolume=Join-Path $scratchDrive 'DEADBYTE-R167-CrossVolume'
|
|
57
|
+
try{
|
|
58
|
+
[IO.Directory]::CreateDirectory($crossVolume)|Out-Null
|
|
59
|
+
$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT=$crossVolume
|
|
60
|
+
Run-Node -label 'full' -nodeArgs @('--test','--test-reporter=tap','--test-concurrency=4','test/*.test.mjs')
|
|
61
|
+
}finally{$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT=$previousCrossVolume}
|
|
62
|
+
if($Stage -eq 'full'){return}
|
|
63
|
+
}
|
|
64
|
+
if($Stage -in @('manifest','all')){
|
|
65
|
+
Run-Node -label 'manifest' -nodeArgs @('scripts/release-manifest.mjs','verify')
|
|
66
|
+
if($Stage -eq 'manifest'){return}
|
|
67
|
+
}
|
|
68
|
+
if($Stage -in @('doctor','all')){
|
|
69
|
+
$previous=$env:DEADBYTE_STATE_ROOT
|
|
70
|
+
$isolated=Join-Path $env:TEMP ('deadbyte-r167-doctor-'+[guid]::NewGuid().ToString('N'))
|
|
71
|
+
try{[IO.Directory]::CreateDirectory($isolated)|Out-Null;$env:DEADBYTE_STATE_ROOT=$isolated;Run-Node -label 'isolated_doctor' -nodeArgs @('src/deadbyte-cli.mjs','doctor')}
|
|
72
|
+
finally{$env:DEADBYTE_STATE_ROOT=$previous;Remove-Item -LiteralPath $isolated -Recurse -Force -ErrorAction SilentlyContinue}
|
|
73
|
+
}
|
|
74
|
+
Write-Output 'R167_WINDOWS_CANDIDATE_GATE=PASS_PREPUBLICATION'
|
|
75
|
+
}finally{$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT=$previousExpectedDevelopmentRoot;Pop-Location}
|
|
@@ -9,6 +9,8 @@ import {assertR72NpmPublishReady} from './npm-release-readiness-r72.mjs';
|
|
|
9
9
|
import {assertR74NpmPublishReady} from './npm-release-readiness-r74.mjs';
|
|
10
10
|
import {assertR163NpmPublishReady} from './npm-release-readiness-r163.mjs';
|
|
11
11
|
import {assertR165NpmPublishReady} from './npm-release-readiness-r165.mjs';
|
|
12
|
+
import {assertR166NpmPublishReady} from './npm-release-readiness-r166.mjs';
|
|
13
|
+
import {assertR167NpmPublishReady,assertR167PackedIdentity} from './npm-release-readiness-r167.mjs';
|
|
12
14
|
import { existsSync } from 'node:fs';
|
|
13
15
|
import { resolveStateRoot } from '../src/state-root.mjs';
|
|
14
16
|
import path from 'node:path';
|
|
@@ -105,6 +107,15 @@ async function main() {
|
|
|
105
107
|
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R165 0.15.63 requires --publish-only; production activation is a separate authority boundary');
|
|
106
108
|
await assertR165NpmPublishReady(release,{root});
|
|
107
109
|
}
|
|
110
|
+
if (!isVerifyOnly && version==='0.15.64') {
|
|
111
|
+
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R166 requires --publish-only; activation is separate');
|
|
112
|
+
await assertR166NpmPublishReady(release,{root});
|
|
113
|
+
}
|
|
114
|
+
let r167Readiness=null;
|
|
115
|
+
if (!isVerifyOnly && version==='0.15.65') {
|
|
116
|
+
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R167 requires --publish-only; activation is separate');
|
|
117
|
+
r167Readiness=await assertR167NpmPublishReady(release,{root});
|
|
118
|
+
}
|
|
108
119
|
if (release.parent?.release_id !== provenance.parent_release_id ||
|
|
109
120
|
release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
|
|
110
121
|
release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
|
|
@@ -227,6 +238,10 @@ async function main() {
|
|
|
227
238
|
const localBytes = await readFile(publishTarball);
|
|
228
239
|
const localIntegrity=`sha512-${createHash('sha512').update(localBytes).digest('base64')}`;
|
|
229
240
|
if(packRecord.integrity&&packRecord.integrity!==localIntegrity)throw new Error('npm packed artifact integrity changed before publication');
|
|
241
|
+
if(r167Readiness)assertR167PackedIdentity({
|
|
242
|
+
...r167Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
|
|
243
|
+
observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
|
|
244
|
+
});
|
|
230
245
|
|
|
231
246
|
console.log('[6/7] Publishing artifact to npm registry...');
|
|
232
247
|
publishAttempted = true;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {readFile,lstat} from 'node:fs/promises';
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
5
|
+
const required=(v,m)=>{if(!v)throw new Error('PUBLISH_BLOCKED R166 '+m)};
|
|
6
|
+
const hex=s=>typeof s==='string'&&/^[a-f0-9]{64}$/.test(s);
|
|
7
|
+
async function checkedFile(f,expected){
|
|
8
|
+
required(hex(expected),'missing log hash');
|
|
9
|
+
const s=await lstat(f);
|
|
10
|
+
required(s.isFile()&&!s.isSymbolicLink()&&s.size>0&&s.size<32*1024*1024,'invalid log');
|
|
11
|
+
const b=await readFile(f);required(sha(b)===expected,'log digest differs');return b.toString('utf8');
|
|
12
|
+
}
|
|
13
|
+
export async function assertR166NpmPublishReady(release,{root}={}){
|
|
14
|
+
required(release?.version==='0.15.64'&&release?.train==='R166'&&release?.r166?.scope==='WINDOWS_GATE_AND_SIGNED_PRECONDITION_RECOVERY_HOTFIX','candidate metadata invalid');
|
|
15
|
+
required(release?.parent?.release_id==='v0.15.61-055d1ff0aa99e60b'&&release?.source_predecessor?.version==='0.15.63','lineage mismatch');
|
|
16
|
+
const evidence=process.env.DEADBYTE_R166_CLOSURE_ROOT;
|
|
17
|
+
required(root&&path.isAbsolute(root)&&evidence&&path.isAbsolute(evidence),'closure root absent');
|
|
18
|
+
const allowed=path.resolve(root,'..','..','testing','r166-final-gate');
|
|
19
|
+
required(path.resolve(evidence).toLowerCase()===allowed.toLowerCase(),'closure root not in scoped testing folder');
|
|
20
|
+
const data=JSON.parse(await readFile(path.join(evidence,'closure.json'),'utf8'));
|
|
21
|
+
required(data?.schema==='deadbyte.r166-release-closure.v1'&&data.status==='PASS'&&data.version==='0.15.64','closure status mismatch');
|
|
22
|
+
required(data?.production_release_id===release.parent.release_id&&hex(data.manifest_sha256),'predecessor or manifest invalid');
|
|
23
|
+
required(data.manifest_sha256===sha(await readFile(path.join(root,'MANIFEST.SHA256'))),'final manifest drift');
|
|
24
|
+
const gate=await checkedFile(path.join(evidence,'windows-gate.protected.stdout.log'),data.gate_stdout_sha256);
|
|
25
|
+
const verify=await checkedFile(path.join(evidence,'npm-verify.stdout.log'),data.verify_stdout_sha256);
|
|
26
|
+
required(gate.includes('R166_WINDOWS_CANDIDATE_GATE=PASS_PREPUBLICATION')&&gate.includes('MANIFEST_VERIFY_OK')&&gate.includes('R166_STAGE_PASS=full'),'Windows full gate transcript incomplete');
|
|
27
|
+
const matches=[...gate.matchAll(/^# tests (\d+)\s*\r?\n# suites (\d+)\s*\r?\n# pass (\d+)\s*\r?\n# fail (\d+)\s*\r?\n# cancelled (\d+)\s*\r?\n# skipped (\d+)/gm)];
|
|
28
|
+
required(matches.length>0,'full TAP summary absent');
|
|
29
|
+
const full=matches.at(-1);
|
|
30
|
+
const tests=Number(full[1]),passes=Number(full[3]),fails=Number(full[4]),skips=Number(full[6]);
|
|
31
|
+
required(tests>=1960&&passes>=1908&&fails===0&&skips<=55&&passes+skips===tests,'full regression count mismatch');
|
|
32
|
+
required(verify.includes('VERIFY-ONLY PIPELINE PASS')&&verify.includes('Artifact isolation gate PASS')&&verify.includes('VERIFIED_TARBALL '),'exact npm tarball gate missing');
|
|
33
|
+
const tar=verify.split(/\r?\n/).find(x=>x.startsWith('VERIFIED_TARBALL '));
|
|
34
|
+
let identity;try{identity=JSON.parse(tar.slice('VERIFIED_TARBALL '.length));}catch{required(false,'tarball evidence malformed');}
|
|
35
|
+
required(identity.filename==='deadbyte-mcp-0.15.64.tgz'&&hex(identity.sha256)&&identity.bytes>0,'tarball subject invalid');
|
|
36
|
+
return Object.freeze({status:'R166_RELEASE_READY_EVIDENCE_BOUND',manifest_sha256:data.manifest_sha256,tests,passes,skips});
|
|
37
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {createHash} from 'node:crypto';
|
|
2
|
+
import {lstat,readFile} from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
6
|
+
const hex=value=>typeof value==='string'&&/^[0-9a-f]{64}$/.test(value);
|
|
7
|
+
const required=(value,message)=>{if(!value)throw new Error(`PUBLISH_BLOCKED R167 ${message}`);};
|
|
8
|
+
|
|
9
|
+
async function checkedFile(file,expected,{maxBytes=32*1024*1024}={}){
|
|
10
|
+
required(hex(expected),'evidence digest missing');
|
|
11
|
+
const info=await lstat(file);
|
|
12
|
+
required(info.isFile()&&!info.isSymbolicLink()&&info.size>0&&info.size<maxBytes,'evidence file invalid');
|
|
13
|
+
const bytes=await readFile(file);
|
|
14
|
+
required(sha256(bytes)===expected,'evidence digest differs');
|
|
15
|
+
return bytes;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function assertR167PackedIdentity({
|
|
19
|
+
tarball_sha256,tarball_integrity,tarball_shasum,
|
|
20
|
+
observedSha256,observedIntegrity,observedShasum
|
|
21
|
+
}={}){
|
|
22
|
+
required(hex(tarball_sha256)&&typeof tarball_integrity==='string'&&tarball_integrity.startsWith('sha512-')&&
|
|
23
|
+
typeof tarball_shasum==='string'&&/^[0-9a-f]{40}$/.test(tarball_shasum),'verified tarball identity invalid');
|
|
24
|
+
required(observedSha256===tarball_sha256&&observedIntegrity===tarball_integrity&&observedShasum===tarball_shasum,
|
|
25
|
+
'repacked tarball differs from verified closure bytes');
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function assertR167NpmPublishReady(release,{root}={}){
|
|
30
|
+
required(release?.version==='0.15.65'&&release?.train==='R167'&&
|
|
31
|
+
release?.r167?.scope==='TRUSTED_EPOCH_ACTIVATION_ENTRYPOINT_AND_EXPLICIT_ROOT_FORWARDING',
|
|
32
|
+
'candidate metadata invalid');
|
|
33
|
+
required(release?.parent?.release_id==='v0.15.61-055d1ff0aa99e60b'&&
|
|
34
|
+
release?.source_predecessor?.version==='0.15.64'&&release?.source_predecessor?.train==='R166',
|
|
35
|
+
'lineage mismatch');
|
|
36
|
+
const evidence=process.env.DEADBYTE_R167_CLOSURE_ROOT;
|
|
37
|
+
required(root&&path.isAbsolute(root)&&evidence&&path.isAbsolute(evidence),'closure root absent');
|
|
38
|
+
const allowed=path.resolve(root,'..','..','testing','r167-final-gate-final');
|
|
39
|
+
required(path.resolve(evidence).toLowerCase()===allowed.toLowerCase(),'closure root not in scoped testing folder');
|
|
40
|
+
const closure=JSON.parse(await readFile(path.join(evidence,'closure.json'),'utf8'));
|
|
41
|
+
required(closure?.schema==='deadbyte.r167-release-closure.v1'&&closure.status==='PASS'&&closure.version==='0.15.65',
|
|
42
|
+
'closure status mismatch');
|
|
43
|
+
required(closure.production_release_id===release.parent.release_id&&hex(closure.manifest_sha256),'predecessor or manifest invalid');
|
|
44
|
+
required(closure.manifest_sha256===sha256(await readFile(path.join(root,'MANIFEST.SHA256'))),'final manifest drift');
|
|
45
|
+
|
|
46
|
+
const receiptBytes=await checkedFile(path.join(evidence,'protected-install-receipt.json'),closure.protected_receipt_sha256);
|
|
47
|
+
const receipt=JSON.parse(receiptBytes.toString('utf8'));
|
|
48
|
+
required(receipt?.status==='PASS'&&receipt.package_version==='0.15.65'&&
|
|
49
|
+
receipt.source_manifest_sha256===closure.manifest_sha256&&receipt.protected_manifest_sha256===closure.manifest_sha256,
|
|
50
|
+
'protected exact-byte receipt mismatch');
|
|
51
|
+
|
|
52
|
+
const focused=(await checkedFile(path.join(evidence,'windows-focused.stdout.log'),closure.focused_stdout_sha256)).toString('utf8');
|
|
53
|
+
const full=(await checkedFile(path.join(evidence,'windows-full.stdout.log'),closure.full_stdout_sha256)).toString('utf8');
|
|
54
|
+
const verify=(await checkedFile(path.join(evidence,'npm-verify.stdout.log'),closure.verify_stdout_sha256)).toString('utf8');
|
|
55
|
+
required(focused.includes('R167_STAGE_PASS=focused')&&focused.includes('# fail 0'),'focused protected gate incomplete');
|
|
56
|
+
required(full.includes('R167_STAGE_PASS=full')&&full.includes('# fail 0'),'full protected gate incomplete');
|
|
57
|
+
const summaries=[...full.matchAll(/^# tests (\d+)\s*\r?\n# suites (\d+)\s*\r?\n# pass (\d+)\s*\r?\n# fail (\d+)\s*\r?\n# cancelled (\d+)\s*\r?\n# skipped (\d+)/gm)];
|
|
58
|
+
required(summaries.length>0,'full TAP summary absent');
|
|
59
|
+
const final=summaries.at(-1),tests=Number(final[1]),passes=Number(final[3]),fails=Number(final[4]),skips=Number(final[6]);
|
|
60
|
+
required(tests>=1971&&passes>=1921&&fails===0&&skips<=50&&passes+skips===tests,'full regression count mismatch');
|
|
61
|
+
required(verify.includes('VERIFY-ONLY PIPELINE PASS')&&verify.includes('Artifact isolation gate PASS')&&verify.includes('VERIFIED_TARBALL '),
|
|
62
|
+
'npm exact-artifact verification incomplete');
|
|
63
|
+
const line=verify.split(/\r?\n/).find(value=>value.startsWith('VERIFIED_TARBALL '));
|
|
64
|
+
let artifact;try{artifact=JSON.parse(line.slice('VERIFIED_TARBALL '.length));}catch{required(false,'tarball evidence malformed');}
|
|
65
|
+
required(artifact.filename==='deadbyte-mcp-0.15.65.tgz'&&artifact.sha256===closure.tarball_sha256&&
|
|
66
|
+
artifact.integrity===closure.tarball_integrity&&artifact.shasum===closure.tarball_shasum&&artifact.bytes>0,
|
|
67
|
+
'tarball identity mismatch');
|
|
68
|
+
return Object.freeze({status:'R167_RELEASE_READY_EVIDENCE_BOUND',manifest_sha256:closure.manifest_sha256,
|
|
69
|
+
tarball_sha256:artifact.sha256,tarball_integrity:artifact.integrity,tarball_shasum:artifact.shasum,tests,passes,skips});
|
|
70
|
+
}
|
|
@@ -114,7 +114,7 @@ async function isSafeSignedPreconditionReject(outcome,lock,stateRoot){
|
|
|
114
114
|
body.result!=='PRECONDITION_REJECTED'||body.phase!=='initial'||
|
|
115
115
|
body.attempted_pointer!==null||body.rollback?.attempted!==false||
|
|
116
116
|
!Array.isArray(body.rollback?.errors)||body.rollback.errors.length!==0||
|
|
117
|
-
|
|
117
|
+
!(/^(?:host command 'powershell_script' executable pin drift detected;|windows release gate package script invalid$)/.test(String(body.error?.message??'')))||
|
|
118
118
|
!Number.isFinite(failedTime)||failedTime<lockTime||failedTime>observedTime||
|
|
119
119
|
!samePointerIdentity(body.prior_pointer,current))return false;
|
|
120
120
|
return true;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
function canonicalWindowsRoot(value,label){
|
|
4
|
+
if(typeof value!=='string'||value.length===0)throw new Error(`${label} requires a path`);
|
|
5
|
+
if(value.includes('\0')||value.startsWith('\\\\')||value.startsWith('\\\\?\\')||value.includes('/'))
|
|
6
|
+
throw new Error(`${label} must be a canonical local Windows path`);
|
|
7
|
+
if(!/^[A-Za-z]:\\/.test(value)||!path.win32.isAbsolute(value))
|
|
8
|
+
throw new Error(`${label} must be an absolute local Windows path`);
|
|
9
|
+
const normalized=path.win32.normalize(value);
|
|
10
|
+
if(normalized!==value||/(?:^|\\)\.\.?($|\\)/.test(value))
|
|
11
|
+
throw new Error(`${label} must be canonical`);
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const samePath=(left,right)=>path.win32.normalize(left).toLowerCase()===path.win32.normalize(right).toLowerCase();
|
|
16
|
+
|
|
17
|
+
export function parseActivationPathFlags(argv){
|
|
18
|
+
if(!Array.isArray(argv))throw new TypeError('deploy argv must be an array');
|
|
19
|
+
let authorityEpochRoot=null,developmentRoot=null;
|
|
20
|
+
const remainingArgs=[];
|
|
21
|
+
for(let index=0;index<argv.length;index++){
|
|
22
|
+
const arg=argv[index];
|
|
23
|
+
if(arg!=='--authority-epoch-root'&&arg!=='--development-root'){
|
|
24
|
+
remainingArgs.push(arg);continue;
|
|
25
|
+
}
|
|
26
|
+
const value=argv[++index];
|
|
27
|
+
if(arg==='--authority-epoch-root'){
|
|
28
|
+
if(authorityEpochRoot!==null)throw new Error('duplicate --authority-epoch-root');
|
|
29
|
+
authorityEpochRoot=canonicalWindowsRoot(value,'--authority-epoch-root');
|
|
30
|
+
}else{
|
|
31
|
+
if(developmentRoot!==null)throw new Error('duplicate --development-root');
|
|
32
|
+
developmentRoot=canonicalWindowsRoot(value,'--development-root');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return Object.freeze({authorityEpochRoot,developmentRoot,remainingArgs:Object.freeze(remainingArgs)});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function assertTrustedActivationEntrypoint({continuity,packageRoot,authorityEpochRoot,developmentRoot,trusted}){
|
|
39
|
+
if(continuity!=='EPOCH_NATIVE')return Object.freeze({authorityEpochRoot,developmentRoot});
|
|
40
|
+
const epoch=canonicalWindowsRoot(authorityEpochRoot,'--authority-epoch-root');
|
|
41
|
+
const development=canonicalWindowsRoot(developmentRoot,'--development-root');
|
|
42
|
+
const activeRoot=canonicalWindowsRoot(packageRoot,'deploy package root');
|
|
43
|
+
if(!samePath(activeRoot,epoch))throw new Error('EPOCH_NATIVE activation requires the protected entrypoint package root');
|
|
44
|
+
if(trusted!==true)throw new Error('EPOCH_NATIVE activation package root is not ACL-trusted');
|
|
45
|
+
return Object.freeze({authorityEpochRoot:epoch,developmentRoot:development});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function appendActivationPathArgs(args,{stageRoot,authorityEpochRoot,developmentRoot}){
|
|
49
|
+
if(!Array.isArray(args))throw new TypeError('updater args must be an array');
|
|
50
|
+
const stage=canonicalWindowsRoot(stageRoot,'stage root');
|
|
51
|
+
const epoch=canonicalWindowsRoot(authorityEpochRoot,'--authority-epoch-root');
|
|
52
|
+
const development=canonicalWindowsRoot(developmentRoot,'--development-root');
|
|
53
|
+
if(!samePath(stage,epoch))throw new Error('updater stage must equal the protected authority epoch root');
|
|
54
|
+
return [...args,'--stage',stage,'--development-root',development,'--authority-epoch-root',epoch];
|
|
55
|
+
}
|
|
@@ -87,7 +87,7 @@ async function currentWindowsGateScript(rootPath){
|
|
|
87
87
|
try{ pkg=JSON.parse(await readFile(packagePath,'utf8')); }
|
|
88
88
|
catch{ throw new Error('windows release gate package.json malformed'); }
|
|
89
89
|
const command=String(pkg?.scripts?.['gate:windows']??'').trim();
|
|
90
|
-
const match=/^powershell(?:\.exe)?\s+-NoProfile\s+-ExecutionPolicy\s+Bypass\s+-File\s+(scripts\/[A-Za-z0-9._\/-]+\.ps1)
|
|
90
|
+
const match=/^powershell(?:\.exe)?\s+-NoProfile\s+-ExecutionPolicy\s+Bypass\s+-File\s+(scripts\/[A-Za-z0-9._\/-]+\.ps1)(?:\s+-Stage\s+all)?$/i.exec(command);
|
|
91
91
|
if(!match) throw new Error('windows release gate package script invalid');
|
|
92
92
|
return safeRel(match[1]);
|
|
93
93
|
}
|
package/src/version.mjs
CHANGED
|
@@ -65,14 +65,17 @@ async function fixture() {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
test('
|
|
68
|
+
test('R167 process policy binds coherently to the explicit development root', async () => {
|
|
69
69
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
70
|
+
const expectedRoot = path.resolve(process.env.DEADBYTE_EXPECTED_DEVELOPMENT_ROOT || repoRoot);
|
|
70
71
|
const policyPath = path.join(repoRoot, 'controller', 'deadbyte-process-policy.json');
|
|
71
72
|
const policy = JSON.parse(await readFile(policyPath, 'utf8'));
|
|
72
|
-
assert.equal(policy.
|
|
73
|
-
assert.
|
|
74
|
-
assert.equal(policy.
|
|
75
|
-
assert.equal(policy.
|
|
73
|
+
assert.equal(path.resolve(policy.roots.core.path), expectedRoot);
|
|
74
|
+
assert.notEqual(expectedRoot, path.parse(expectedRoot).root, 'development root must not be a broad filesystem root');
|
|
75
|
+
assert.equal(policy.grant_file, path.join(expectedRoot, 'controller', 'runtime', 'process-grant.json'));
|
|
76
|
+
assert.equal(policy.state_dir, path.join(expectedRoot, 'controller', 'runtime', 'process-state'));
|
|
77
|
+
assert.equal(policy.native_host.path, path.join(expectedRoot, 'bin', 'deadbyte-process-host.exe'));
|
|
78
|
+
assert.equal(policy.native_host.sha256, sha256(await readFile(policy.native_host.path)));
|
|
76
79
|
assert.ok(policy.profiles.ping_hold);
|
|
77
80
|
assert.ok(policy.profiles.powershell);
|
|
78
81
|
assert.ok(policy.profiles.powershell_repl);
|
|
@@ -7,18 +7,18 @@ import {DEADBYTE_VERSION} from '../src/version.mjs';
|
|
|
7
7
|
|
|
8
8
|
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
9
9
|
const read=async file=>JSON.parse(await readFile(path.join(root,file),'utf8'));
|
|
10
|
-
test('
|
|
10
|
+
test('current successor retains the R130 security baseline with truthful R167 identity',async()=>{
|
|
11
11
|
const [pkg,release,provenance,bom,lock,matrix]=await Promise.all([
|
|
12
12
|
read('package.json'),read('RELEASE.json'),read('PROVENANCE.json'),
|
|
13
13
|
read('SBOM.cdx.json'),read('package-lock.json'),read('TEST-MATRIX.json')]);
|
|
14
14
|
assert.equal(pkg.name,'deadbyte-mcp');
|
|
15
15
|
for(const actual of [pkg.version,release.version,provenance.version,matrix.version,bom.metadata.component.version,lock.version,lock.packages[''].version,DEADBYTE_VERSION])
|
|
16
|
-
assert.equal(actual,'0.15.
|
|
17
|
-
assert.equal(release.train,'
|
|
18
|
-
assert.equal(matrix.train,'
|
|
19
|
-
assert.equal(release.source_predecessor.version,'0.15.
|
|
20
|
-
assert.equal(release.source_predecessor.train,'
|
|
21
|
-
assert.match(release.source_predecessor.source_path,/0\.15\.
|
|
16
|
+
assert.equal(actual,'0.15.65');
|
|
17
|
+
assert.equal(release.train,'R167');
|
|
18
|
+
assert.equal(matrix.train,'R167');
|
|
19
|
+
assert.equal(release.source_predecessor.version,'0.15.64');
|
|
20
|
+
assert.equal(release.source_predecessor.train,'R166');
|
|
21
|
+
assert.match(release.source_predecessor.source_path,/0\.15\.64-r166-final/i);
|
|
22
22
|
assert.equal(release.source_predecessor.manifest_status,'VERIFIED_FINAL_BYTES');
|
|
23
23
|
assert.equal(release.runtime_predecessor.version,'0.15.61');
|
|
24
24
|
assert.equal(provenance.r160.source_predecessor_manifest_status,'STALE_REJECTED');
|
|
@@ -8,22 +8,22 @@ import {DEADBYTE_VERSION} from '../src/version.mjs';
|
|
|
8
8
|
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
9
9
|
const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
|
|
10
10
|
|
|
11
|
-
test('
|
|
11
|
+
test('R167 package identity preserves R132 evidence and published R166 source predecessor',async()=>{
|
|
12
12
|
const [pkg,lock,release,prov,bom,matrix]=await Promise.all([
|
|
13
13
|
read('package.json'),read('package-lock.json'),read('RELEASE.json'),
|
|
14
14
|
read('PROVENANCE.json'),read('SBOM.cdx.json'),read('TEST-MATRIX.json')]);
|
|
15
15
|
for(const value of [pkg.version,lock.version,lock.packages[''].version,release.version,prov.version,bom.metadata.component.version,matrix.version,DEADBYTE_VERSION]){
|
|
16
16
|
assert.equal(value,pkg.version);
|
|
17
17
|
}
|
|
18
|
-
assert.equal(release.train,'
|
|
19
|
-
assert.equal(matrix.train,'
|
|
20
|
-
assert.equal(release.source_predecessor.version,'0.15.
|
|
21
|
-
assert.equal(release.source_predecessor.train,'
|
|
22
|
-
assert.match(release.source_predecessor.source_path,/0\.15\.
|
|
18
|
+
assert.equal(release.train,'R167');
|
|
19
|
+
assert.equal(matrix.train,'R167');
|
|
20
|
+
assert.equal(release.source_predecessor.version,'0.15.64');
|
|
21
|
+
assert.equal(release.source_predecessor.train,'R166');
|
|
22
|
+
assert.match(release.source_predecessor.source_path,/0\.15\.64-r166-final/i);
|
|
23
23
|
assert.equal(prov.r160.source_predecessor_manifest_status,'STALE_REJECTED');
|
|
24
24
|
assert.equal(release.r165.published_source_manifest_sha256,'4adf7d94682fbb71c4a91eb3147ecc48076bbc5d79cb67fcb875cde6a1bb4805');
|
|
25
25
|
assert.equal(release.r165.published_source_tarball_sha256,'812e97609b7c51353ed25f2202129737e43bb4fbe0778c3adec43ec065352641');
|
|
26
|
-
assert.equal(release.source_predecessor.tarball_sha256,
|
|
26
|
+
assert.equal(release.source_predecessor.tarball_sha256,'3d22412c3cebabd66bfa92ca4dbaaf3ef49acba7f92436a16485d7e4cb18c653');
|
|
27
27
|
assert.equal(prov.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
|
|
28
28
|
assert.equal(release.runtime_predecessor.version,'0.15.61');
|
|
29
29
|
assert.equal(prov.runtime_predecessor.release_id,release.runtime_predecessor.release_id);
|
|
@@ -22,11 +22,11 @@ const historical=()=>{
|
|
|
22
22
|
runtime_predecessor:runtime,parent:{...runtime}}};
|
|
23
23
|
};
|
|
24
24
|
const copy=()=>historical();
|
|
25
|
-
test('R153 historical verifier refuses current
|
|
25
|
+
test('R153 historical verifier refuses current successor package identity',async()=>{
|
|
26
26
|
const state={pkg:JSON.parse(await readFile(path.join(root,'package.json'),'utf8')),
|
|
27
27
|
release:JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8')),
|
|
28
28
|
bridge:JSON.parse(await readFile(path.join(root,'bridge/package.json'),'utf8'))};
|
|
29
|
-
assert.equal(state.pkg.version,'0.15.
|
|
29
|
+
assert.equal(state.pkg.version,'0.15.65');
|
|
30
30
|
assert.throws(()=>verifyR153Lineage(state),/package version/);
|
|
31
31
|
await assert.rejects(verifyR153IdentityTree(root),/package version/);
|
|
32
32
|
});
|
|
@@ -3,25 +3,17 @@ import assert from 'node:assert/strict';
|
|
|
3
3
|
import {readFile} from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
|
-
import {DEADBYTE_VERSION} from '../src/version.mjs';
|
|
7
|
-
|
|
8
6
|
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
9
7
|
const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
|
|
10
8
|
|
|
11
|
-
test('R160
|
|
12
|
-
const [
|
|
13
|
-
read('package.json'),read('package-lock.json'),read('bridge/package.json'),read('RELEASE.json'),
|
|
14
|
-
read('PROVENANCE.json'),read('TEST-MATRIX.json'),read('SBOM.cdx.json')]);
|
|
15
|
-
for(const version of [pkg.version,lock.version,lock.packages[''].version,bridge.version,release.version,
|
|
16
|
-
provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION]) assert.equal(version,'0.15.63');
|
|
17
|
-
assert.equal(release.train,'R165');
|
|
18
|
-
assert.equal(matrix.train,'R165');
|
|
9
|
+
test('R160 historical contract remains distinct from the current package identity',async()=>{
|
|
10
|
+
const [release,provenance]=await Promise.all([read('RELEASE.json'),read('PROVENANCE.json')]);
|
|
19
11
|
assert.equal(release.runtime_predecessor.version,'0.15.61');
|
|
20
12
|
assert.equal(release.runtime_predecessor.release_id,'v0.15.61-055d1ff0aa99e60b');
|
|
21
13
|
assert.equal(release.runtime_predecessor.manifest_sha256,'055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf');
|
|
22
14
|
assert.equal(release.runtime_predecessor.generation_manifest_sha256,'f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4');
|
|
23
|
-
assert.equal(release.
|
|
24
|
-
assert.
|
|
15
|
+
assert.equal(release.r160.source_predecessor_train,'R159');
|
|
16
|
+
assert.equal(release.r160.runtime_predecessor_version,'0.15.61');
|
|
25
17
|
assert.equal(release.r160.public_tool_delta,0);
|
|
26
18
|
assert.equal(release.r160.authority_scope_delta,0);
|
|
27
19
|
assert.equal(release.r160.production_activation,'NOT_RUN');
|
|
@@ -8,7 +8,7 @@ import {fileURLToPath} from 'node:url';
|
|
|
8
8
|
import {atomicWriteActivePointer,materializeReleaseSlot,parseActivePointer,parseManifest,renderStableLauncherPs1,verifyManifestTreeExact} from '../src/release-slot.mjs';
|
|
9
9
|
|
|
10
10
|
const candidate=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
11
|
-
const version='0.15.
|
|
11
|
+
const version='0.15.65';
|
|
12
12
|
const parent=path.join(os.homedir(),'.deadbyte-mcp','releases','v0.15.61-055d1ff0aa99e60b');
|
|
13
13
|
const parentDigest='055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf';
|
|
14
14
|
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
@@ -21,7 +21,7 @@ async function generation(state,label){
|
|
|
21
21
|
await writeFile(path.join(root,'GENERATION.SHA256'),manifest,{flag:'wx'});
|
|
22
22
|
return {root,manifest_sha256:sha(manifest),config_path:path.join(root,'controller-config.psd1')};
|
|
23
23
|
}
|
|
24
|
-
test('
|
|
24
|
+
test('R167 isolated immutable slot activates, rolls back, and restores 0.15.65 without authority or production mutation',async()=>{
|
|
25
25
|
const stateBase=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r163-isolated-'));
|
|
26
26
|
const state=path.join(stateBase,'state');
|
|
27
27
|
try{
|
|
@@ -17,7 +17,7 @@ const hashMarker=c=>c.repeat(64);
|
|
|
17
17
|
async function fixture(t,kind){
|
|
18
18
|
assert.equal(typeof envRoot,'string'); assert.ok(path.isAbsolute(envRoot));
|
|
19
19
|
assert.match(sha(await readFile(path.join(envRoot,'MANIFEST.SHA256'))),/^[0-9a-f]{64}$/);
|
|
20
|
-
assert.equal(JSON.parse(await readFile(path.join(envRoot,'package.json'),'utf8')).version,'0.15.
|
|
20
|
+
assert.equal(JSON.parse(await readFile(path.join(envRoot,'package.json'),'utf8')).version,'0.15.65');
|
|
21
21
|
const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r164-skew-e2e-'));
|
|
22
22
|
t.after(async()=>{await rm(dir,{recursive:true,force:true,maxRetries:10,retryDelay:150});});
|
|
23
23
|
const state=path.join(dir,'state'),bin=path.join(state,'bin');
|
|
@@ -65,7 +65,7 @@ async function run(fx){
|
|
|
65
65
|
assert.doesNotMatch(trace,/\b(?:start|restart|armprocess|armcoding|armautonomous|deploy)\b/i,'unexpected runtime operation');
|
|
66
66
|
return {output:(result.stderr||'')+'\n'+(result.stdout||''),trace};
|
|
67
67
|
}
|
|
68
|
-
gate('
|
|
68
|
+
gate('R167 executable CLI passes completed R159 history, reaches 0.15.61 -> 0.15.65 synchronization safely',async t=>{
|
|
69
69
|
const fx=await fixture(t,'completed');
|
|
70
70
|
const r=await run(fx);
|
|
71
71
|
assert.match(r.output,/runtime coherence 'disarmhost' failed exit=93/i,r.output);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
const release = await readFile(new URL('../src/release-generation.mjs',import.meta.url),'utf8');
|
|
5
|
+
const gate = await readFile(new URL('../scripts/gate-windows-r166.ps1',import.meta.url),'utf8');
|
|
6
|
+
const pkg = JSON.parse(await readFile(new URL('../package.json',import.meta.url),'utf8'));
|
|
7
|
+
const lock = await readFile(new URL('../src/activation-lock-r65.mjs',import.meta.url),'utf8');
|
|
8
|
+
test('exact Windows gate grammar supports only optional Stage all',()=>{
|
|
9
|
+
const line = release.split('\n').find(x=>x.includes('const match=/^powershell'));
|
|
10
|
+
assert.ok(line);
|
|
11
|
+
const regexSource=line.slice(line.indexOf('const match=')+12,line.lastIndexOf('.exec(command)'));
|
|
12
|
+
const regex=Function(`return ${regexSource}`)();
|
|
13
|
+
assert.ok(regex.test(pkg.scripts['gate:windows']));
|
|
14
|
+
assert.equal(regex.test(pkg.scripts['gate:windows']+'; echo injected'),false);
|
|
15
|
+
assert.equal(regex.test(pkg.scripts['gate:windows'].replace('all','focused')),false);
|
|
16
|
+
});
|
|
17
|
+
test('corrected gate matches candidate identity',()=>{
|
|
18
|
+
assert.match(gate,/R166_CANDIDATE_VERSION_DRIFT/);
|
|
19
|
+
assert.match(gate,/\$pkg.version -ne '0.15.64'/);
|
|
20
|
+
assert.match(gate,/\$release.train -ne 'R166'/);
|
|
21
|
+
});
|
|
22
|
+
test('recovery is restricted to exact recognized signed preconditions',()=>{
|
|
23
|
+
assert.match(lock,/windows release gate package script invalid\$/);
|
|
24
|
+
assert.match(lock,/verifySlotUpdateEnvelope\(signed,publicKey\)/);
|
|
25
|
+
assert.match(lock,/body.phase!=='initial'/);
|
|
26
|
+
assert.match(lock,/body.attempted_pointer!==null/);
|
|
27
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import {assertR166NpmPublishReady} from '../scripts/npm-release-readiness-r166.mjs';
|
|
5
|
+
test('R166 publication refuses absent external closure',async()=>{
|
|
6
|
+
const release=JSON.parse(await readFile(new URL('../RELEASE.json',import.meta.url)));
|
|
7
|
+
const old=process.env.DEADBYTE_R166_CLOSURE_ROOT;
|
|
8
|
+
try{delete process.env.DEADBYTE_R166_CLOSURE_ROOT;await assert.rejects(assertR166NpmPublishReady(release,{root:new URL('..',import.meta.url).pathname}),/PUBLISH_BLOCKED R166/);}
|
|
9
|
+
finally{if(old===undefined)delete process.env.DEADBYTE_R166_CLOSURE_ROOT;else process.env.DEADBYTE_R166_CLOSURE_ROOT=old;}
|
|
10
|
+
});
|