deadbyte-mcp 0.15.64 → 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 +25 -20
- package/PROVENANCE.json +20 -7
- package/README.txt +18 -18
- package/RELEASE.json +22 -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-r167.ps1 +75 -0
- package/scripts/npm-release-r48.mjs +10 -0
- package/scripts/npm-release-readiness-r167.mjs +70 -0
- package/src/activation-path-r167.mjs +55 -0
- 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/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
- package/node_modules/which/CHANGELOG.md +0 -166
|
@@ -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}
|
|
@@ -10,6 +10,7 @@ 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
12
|
import {assertR166NpmPublishReady} from './npm-release-readiness-r166.mjs';
|
|
13
|
+
import {assertR167NpmPublishReady,assertR167PackedIdentity} from './npm-release-readiness-r167.mjs';
|
|
13
14
|
import { existsSync } from 'node:fs';
|
|
14
15
|
import { resolveStateRoot } from '../src/state-root.mjs';
|
|
15
16
|
import path from 'node:path';
|
|
@@ -110,6 +111,11 @@ async function main() {
|
|
|
110
111
|
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R166 requires --publish-only; activation is separate');
|
|
111
112
|
await assertR166NpmPublishReady(release,{root});
|
|
112
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
|
+
}
|
|
113
119
|
if (release.parent?.release_id !== provenance.parent_release_id ||
|
|
114
120
|
release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
|
|
115
121
|
release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
|
|
@@ -232,6 +238,10 @@ async function main() {
|
|
|
232
238
|
const localBytes = await readFile(publishTarball);
|
|
233
239
|
const localIntegrity=`sha512-${createHash('sha512').update(localBytes).digest('base64')}`;
|
|
234
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
|
+
});
|
|
235
245
|
|
|
236
246
|
console.log('[6/7] Publishing artifact to npm registry...');
|
|
237
247
|
publishAttempted = true;
|
|
@@ -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
|
+
}
|
|
@@ -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
|
+
}
|
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.64');
|
|
17
|
-
assert.equal(release.train,'R166');
|
|
18
|
-
assert.equal(matrix.train,'R166');
|
|
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,124 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import {mkdtemp,mkdir,readFile,readdir,rm,writeFile} from 'node:fs/promises';
|
|
5
|
+
import {spawnSync} from 'node:child_process';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import {fileURLToPath} from 'node:url';
|
|
9
|
+
import {
|
|
10
|
+
parseActivationPathFlags,
|
|
11
|
+
assertTrustedActivationEntrypoint,
|
|
12
|
+
appendActivationPathArgs
|
|
13
|
+
} from '../src/activation-path-r167.mjs';
|
|
14
|
+
|
|
15
|
+
const protectedRoot='C:\\Program Files\\DEADBYTE-R167';
|
|
16
|
+
const developmentRoot='D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.65-r167-activation-path';
|
|
17
|
+
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
18
|
+
const H=value=>createHash('sha256').update(value).digest('hex');
|
|
19
|
+
|
|
20
|
+
test('R167 parses one exact protected epoch root and one separate development root',()=>{
|
|
21
|
+
const parsed=parseActivationPathFlags([
|
|
22
|
+
'--preflight','--authority-epoch-root',protectedRoot,'--development-root',developmentRoot
|
|
23
|
+
]);
|
|
24
|
+
assert.equal(parsed.authorityEpochRoot,protectedRoot);
|
|
25
|
+
assert.equal(parsed.developmentRoot,developmentRoot);
|
|
26
|
+
assert.deepEqual(parsed.remainingArgs,['--preflight']);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('R167 rejects missing duplicate relative UNC drive-relative and noncanonical roots',()=>{
|
|
30
|
+
const invalid=[
|
|
31
|
+
['--authority-epoch-root'],
|
|
32
|
+
['--development-root'],
|
|
33
|
+
['--authority-epoch-root','relative'],
|
|
34
|
+
['--authority-epoch-root','\\\\server\\share'],
|
|
35
|
+
['--authority-epoch-root','C:relative'],
|
|
36
|
+
['--authority-epoch-root','C:\\Program Files\\..\\Writable'],
|
|
37
|
+
['--authority-epoch-root',protectedRoot,'--authority-epoch-root',protectedRoot],
|
|
38
|
+
['--development-root',developmentRoot,'--development-root',developmentRoot]
|
|
39
|
+
];
|
|
40
|
+
for(const argv of invalid)assert.throws(()=>parseActivationPathFlags(argv));
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('R167 EPOCH_NATIVE activation requires the executing package root to be the trusted protected root',()=>{
|
|
44
|
+
assert.throws(()=>assertTrustedActivationEntrypoint({
|
|
45
|
+
continuity:'EPOCH_NATIVE',packageRoot:developmentRoot,
|
|
46
|
+
authorityEpochRoot:protectedRoot,developmentRoot,trusted:true
|
|
47
|
+
}),/protected entrypoint/i);
|
|
48
|
+
assert.throws(()=>assertTrustedActivationEntrypoint({
|
|
49
|
+
continuity:'EPOCH_NATIVE',packageRoot:protectedRoot,
|
|
50
|
+
authorityEpochRoot:protectedRoot,developmentRoot,trusted:false
|
|
51
|
+
}),/ACL-trusted/i);
|
|
52
|
+
assert.deepEqual(assertTrustedActivationEntrypoint({
|
|
53
|
+
continuity:'EPOCH_NATIVE',packageRoot:protectedRoot,
|
|
54
|
+
authorityEpochRoot:protectedRoot,developmentRoot,trusted:true
|
|
55
|
+
}),{authorityEpochRoot:protectedRoot,developmentRoot});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('R167 forwards exact protected stage epoch and development roots to updater without fallback',()=>{
|
|
59
|
+
const args=appendActivationPathArgs(['--expected-version','0.15.65'],{
|
|
60
|
+
stageRoot:protectedRoot,authorityEpochRoot:protectedRoot,developmentRoot
|
|
61
|
+
});
|
|
62
|
+
assert.deepEqual(args,[
|
|
63
|
+
'--expected-version','0.15.65','--stage',protectedRoot,
|
|
64
|
+
'--development-root',developmentRoot,'--authority-epoch-root',protectedRoot
|
|
65
|
+
]);
|
|
66
|
+
assert.throws(()=>appendActivationPathArgs([],{
|
|
67
|
+
stageRoot:developmentRoot,authorityEpochRoot:protectedRoot,developmentRoot
|
|
68
|
+
}),/stage.*protected/i);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('R167 writable EPOCH_NATIVE entrypoint rejects before creating an activation claim',
|
|
72
|
+
{skip:process.platform!=='win32'},async()=>{
|
|
73
|
+
const isolated=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r167-preclaim-'));
|
|
74
|
+
try{
|
|
75
|
+
const state=path.join(isolated,'state'),runtime=path.join(state,'runtime'),bin=path.join(state,'bin');
|
|
76
|
+
const generation=path.join(state,'generations','fixture'),policies=path.join(state,'policies');
|
|
77
|
+
await Promise.all([mkdir(runtime,{recursive:true}),mkdir(bin,{recursive:true}),mkdir(generation,{recursive:true}),mkdir(policies,{recursive:true})]);
|
|
78
|
+
const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
|
|
79
|
+
const fields={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
|
|
80
|
+
const policyPaths={},config=[];
|
|
81
|
+
const configFields={process:'ProcessPolicyFile',coding:'CodingPolicyFile',autonomous:'AutonomousPolicyFile',desktop:'DesktopPolicyFile',host:'HostPolicyFile'};
|
|
82
|
+
for(const [plane,field] of Object.entries(fields)){
|
|
83
|
+
const grant=path.join(runtime,`${plane}-grant.json`),policy=path.join(policies,`${plane}.json`);
|
|
84
|
+
const body={schema:plane==='host'?'deadbyte.host-policy.v2':`deadbyte.${plane}-policy.v1`,enabled:true,[field]:grant};
|
|
85
|
+
await writeFile(policy,JSON.stringify(body));
|
|
86
|
+
policyPaths[plane]=policy;
|
|
87
|
+
config.push(`${configFields[plane]} = '${policy.replaceAll("'","''")}'`);
|
|
88
|
+
if(plane==='coding')await writeFile(grant,JSON.stringify({schema:'fixture',nonce:H('coding-grant')}));
|
|
89
|
+
}
|
|
90
|
+
const pointer={schema:'deadbyte.active-release.v1',...release.parent,
|
|
91
|
+
release_root:path.join(state,'releases',release.parent.release_id),generation_root:generation,
|
|
92
|
+
launcher_sha256:H('launcher'),config_path:path.join(generation,'controller-config.psd1')};
|
|
93
|
+
await writeFile(pointer.config_path,`@{ ${config.join('; ')} }\n`);
|
|
94
|
+
const pointerBytes=Buffer.from(JSON.stringify(pointer));
|
|
95
|
+
await writeFile(path.join(state,'active-release.json'),pointerBytes);
|
|
96
|
+
const disarmed=plane=>({configured:true,armed:false,reason:plane==='autonomous'?'coding-disarmed':'disarmed'});
|
|
97
|
+
const observation={schema:'deadbyte.controller-observation.v1',state:'ONLINE',local_ready:true,
|
|
98
|
+
bridge:{alive:true,reason:'verified',pid:101},core:{alive:true,reason:'verified',pid:102},
|
|
99
|
+
cloud:{alive:true,reason:'verified',pid:103},supervisor:{running:true},
|
|
100
|
+
authority:{process:disarmed('process'),coding:{configured:true,armed:true,reason:'standing-grant',epoch_seq:7,epoch_sha256:H('coding-epoch')},
|
|
101
|
+
autonomous:disarmed('autonomous'),desktop:disarmed('desktop'),host:disarmed('host')}};
|
|
102
|
+
const observationPath=path.join(state,'observation.json');
|
|
103
|
+
await writeFile(observationPath,JSON.stringify(observation));
|
|
104
|
+
await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),`param([string]$Command,[switch]$Json)\nif($Command -ne 'status' -or -not $Json){throw 'mutation attempted'}\nGet-Content -Raw -LiteralPath '${observationPath.replaceAll("'","''")}'\n`);
|
|
105
|
+
const before=H(pointerBytes);
|
|
106
|
+
const preflightRun=spawnSync(process.execPath,[path.join(root,'scripts','deploy-r48.mjs'),'--preflight',
|
|
107
|
+
'--authority-epoch-root',protectedRoot,'--development-root',developmentRoot],{
|
|
108
|
+
env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:root,encoding:'utf8',timeout:30000,windowsHide:true});
|
|
109
|
+
assert.equal(preflightRun.status,0,preflightRun.stderr);
|
|
110
|
+
const preflight=JSON.parse(preflightRun.stdout.trim());
|
|
111
|
+
assert.equal(preflight.authority_continuity,'EPOCH_NATIVE');
|
|
112
|
+
assert.equal(preflight.activation_entrypoint_state,'REJECTED');
|
|
113
|
+
assert.equal(preflight.protected_activation_entrypoint,false);
|
|
114
|
+
assert.match(preflight.activation_entrypoint_reason,/protected|trusted|UNTRUSTED_WRITE_ACE/i);
|
|
115
|
+
const run=spawnSync(process.execPath,[path.join(root,'scripts','deploy-r48.mjs'),
|
|
116
|
+
'--authority-epoch-root',protectedRoot,'--development-root',developmentRoot],{
|
|
117
|
+
env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:root,encoding:'utf8',timeout:30000,windowsHide:true});
|
|
118
|
+
assert.notEqual(run.status,0,run.stdout);
|
|
119
|
+
assert.match(run.stderr,/trusted|protected|UNTRUSTED_WRITE_ACE/i);
|
|
120
|
+
assert.equal(H(await readFile(path.join(state,'active-release.json'))),before);
|
|
121
|
+
const updates=path.join(state,'evidence','updates');
|
|
122
|
+
await assert.rejects(readdir(updates),error=>error?.code==='ENOENT');
|
|
123
|
+
}finally{await rm(isolated,{recursive:true,force:true});}
|
|
124
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {DEADBYTE_VERSION} from '../src/version.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
9
|
+
const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
|
|
10
|
+
const readOptional=async rel=>{try{return await read(rel);}catch(error){if(error?.code==='ENOENT')return null;throw error;}};
|
|
11
|
+
const VERSION='0.15.65';
|
|
12
|
+
const R166_MANIFEST='ad3c091fbbe2bac6d234548724008b67305fd483ad6542f92d5aeb1aa84f5849';
|
|
13
|
+
const R166_TARBALL='3d22412c3cebabd66bfa92ca4dbaaf3ef49acba7f92436a16485d7e4cb18c653';
|
|
14
|
+
|
|
15
|
+
test('R167 package identity binds published R166 source separately from active R153 runtime',async()=>{
|
|
16
|
+
const [pkg,lock,bridge,release,provenance,matrix,bom]=await Promise.all([
|
|
17
|
+
read('package.json'),readOptional('package-lock.json'),read('bridge/package.json'),read('RELEASE.json'),
|
|
18
|
+
read('PROVENANCE.json'),read('TEST-MATRIX.json'),read('SBOM.cdx.json')]);
|
|
19
|
+
const versions=[pkg.version,bridge.version,release.version,
|
|
20
|
+
provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION];
|
|
21
|
+
if(lock)versions.push(lock.version,lock.packages[''].version);
|
|
22
|
+
for(const version of versions)assert.equal(version,VERSION);
|
|
23
|
+
assert.equal(release.train,'R167');
|
|
24
|
+
assert.equal(matrix.train,'R167');
|
|
25
|
+
assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r167:0.15.65');
|
|
26
|
+
assert.deepEqual(release.runtime_predecessor,{
|
|
27
|
+
version:'0.15.61',release_id:'v0.15.61-055d1ff0aa99e60b',
|
|
28
|
+
manifest_sha256:'055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf',
|
|
29
|
+
generation_manifest_sha256:'f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4'
|
|
30
|
+
});
|
|
31
|
+
assert.equal(release.source_predecessor.version,'0.15.64');
|
|
32
|
+
assert.equal(release.source_predecessor.train,'R166');
|
|
33
|
+
assert.equal(release.source_predecessor.tarball_sha256,R166_TARBALL);
|
|
34
|
+
assert.equal(release.r167.source_predecessor_manifest_sha256,R166_MANIFEST);
|
|
35
|
+
assert.equal(provenance.source_predecessor_manifest_file_sha256,R166_MANIFEST);
|
|
36
|
+
assert.equal(provenance.source_predecessor_tarball_sha256,R166_TARBALL);
|
|
37
|
+
assert.equal(release.r167.public_tool_delta,0);
|
|
38
|
+
assert.equal(release.r167.authority_scope_delta,0);
|
|
39
|
+
assert.equal(release.r167.production_activation,'NOT_RUN');
|
|
40
|
+
assert.equal(release.r167.npm_publish,'NOT_RUN');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('R167 protected continuity remains pending until exact Windows fixture evidence exists',async()=>{
|
|
44
|
+
const [release,provenance,matrix]=await Promise.all([
|
|
45
|
+
read('RELEASE.json'),read('PROVENANCE.json'),read('TEST-MATRIX.json')]);
|
|
46
|
+
assert.equal(release.r167.protected_entrypoint_continuity,'PENDING_PROTECTED_WINDOWS_FIXTURE');
|
|
47
|
+
assert.equal(provenance.r167.final_manifest_evidence,'PENDING_PROTECTED_WINDOWS_FIXTURE');
|
|
48
|
+
assert.equal(matrix.r167.protected_epoch_continuity,'PENDING_PROTECTED_WINDOWS_FIXTURE');
|
|
49
|
+
assert.equal(matrix.r167.new_public_tools,0);
|
|
50
|
+
assert.equal(matrix.r167.new_authority_scopes,0);
|
|
51
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
import {readFile} from 'node:fs/promises';
|
|
6
|
+
import {assertR167NpmPublishReady,assertR167PackedIdentity} from '../scripts/npm-release-readiness-r167.mjs';
|
|
7
|
+
|
|
8
|
+
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
9
|
+
|
|
10
|
+
test('R167 publication refuses absent external exact-byte closure',async()=>{
|
|
11
|
+
const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
|
|
12
|
+
const prior=process.env.DEADBYTE_R167_CLOSURE_ROOT;
|
|
13
|
+
try{
|
|
14
|
+
delete process.env.DEADBYTE_R167_CLOSURE_ROOT;
|
|
15
|
+
await assert.rejects(assertR167NpmPublishReady(release,{root}),/PUBLISH_BLOCKED R167/);
|
|
16
|
+
}finally{
|
|
17
|
+
if(prior===undefined)delete process.env.DEADBYTE_R167_CLOSURE_ROOT;
|
|
18
|
+
else process.env.DEADBYTE_R167_CLOSURE_ROOT=prior;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('R167 publication rejects a repacked artifact that differs from verified closure bytes',()=>{
|
|
23
|
+
const expected={tarball_sha256:'a'.repeat(64),tarball_integrity:'sha512-expected',tarball_shasum:'b'.repeat(40)};
|
|
24
|
+
assert.throws(()=>assertR167PackedIdentity({
|
|
25
|
+
...expected,observedSha256:'c'.repeat(64),observedIntegrity:'sha512-other',observedShasum:'d'.repeat(40)
|
|
26
|
+
}),/PUBLISH_BLOCKED R167.*tarball/i);
|
|
27
|
+
});
|