deadbyte-mcp 0.15.74 → 0.15.75
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 +102 -42
- package/PROVENANCE.json +19 -21
- package/README.txt +23 -18
- package/RELEASE.json +51 -18
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +22 -2
- package/bin/deadbyte-desktop-uia-r199-fixed.exe +0 -0
- package/bin/deadbyte-desktop-uia-r199-fixed.obj +0 -0
- package/bin/deadbyte-desktop-uia-r199.exe +0 -0
- package/bin/deadbyte-desktop-uia-r199.obj +0 -0
- package/bin/deadbyte-fs-read-r197-fixed.exe +0 -0
- package/bin/deadbyte-fs-read-r198.exe +0 -0
- package/bin/deadbyte-fs-read-r198.obj +0 -0
- package/bin/deadbyte-root-relative-probe-r197.exe +0 -0
- package/bridge/package.json +1 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R184-package-lock.json +2 -8
- package/native/deadbyte-desktop-uia-r199.cpp +345 -0
- package/native/deadbyte-fs-read-r197.cpp +174 -0
- package/native/deadbyte-fs-read-r198.cpp +181 -0
- package/native/deadbyte-root-relative-probe-r197.cpp +97 -0
- package/package.json +4 -2
- package/scripts/build-native-desktop-uia-r199-fixed.ps1 +28 -0
- package/scripts/build-native-desktop-uia-r199.ps1 +28 -0
- package/scripts/build-native-fs-read-r197-fixed.ps1 +28 -0
- package/scripts/build-native-fs-read-r197.ps1 +28 -0
- package/scripts/build-native-fs-read-r198.ps1 +28 -0
- package/scripts/build-native-root-probe-r197.ps1 +28 -0
- package/scripts/gate-windows-r195.ps1 +114 -0
- package/scripts/gate-windows-r206.ps1 +116 -0
- package/scripts/init-desktop-policy-r199.ps1 +85 -0
- package/scripts/npm-release-r48.mjs +17 -0
- package/scripts/npm-release-readiness-r195.mjs +72 -0
- package/scripts/npm-release-readiness-r206.mjs +76 -0
- package/scripts/r193-owner-request-live.mjs +5 -6
- package/scripts/r193-owner-uac-broker.mjs +3 -3
- package/scripts/r205-candidate-selection.mjs +22 -0
- package/src/candidate-selection-evidence-r206.mjs +71 -0
- package/src/candidate-selection-r205.mjs +96 -0
- package/src/desktop-postcondition-r196.mjs +30 -0
- package/src/desktop-runtime-r40.mjs +44 -7
- package/src/desktop-uia-identity-r199.mjs +51 -0
- package/src/desktop-uia-r40.mjs +9 -1
- package/src/machine-fs-handle-read-r196.mjs +43 -0
- package/src/machine-fs-native-read-r197.mjs +73 -0
- package/src/machine-fs-native-read-r198.mjs +76 -0
- package/src/machine-fs-read-worker.mjs +5 -25
- package/src/machine-fs.mjs +31 -16
- package/src/r195-canonical-owner-observation.mjs +15 -0
- package/src/remote-destination-journal-r202.mjs +120 -0
- package/src/remote-device-r44.mjs +89 -14
- package/src/remote-payload-boundary-r201.mjs +71 -0
- package/src/remote-terminal-evidence-r200.mjs +60 -0
- package/src/version.mjs +1 -1
- package/test/desktop-runtime-r40.test.mjs +111 -0
- package/test/desktop-uia-r40.test.mjs +15 -0
- package/test/fixtures/r197-junction-swap-worker.mjs +21 -0
- package/test/fixtures/r203-journal-writer.mjs +6 -0
- package/test/process-policy-refresh.test.mjs +4 -4
- package/test/r130-release-security-contract.test.mjs +8 -8
- package/test/r132-release-identity.test.mjs +7 -7
- package/test/r153-prepublish-identity.test.mjs +1 -1
- package/test/r160-release-contract.test.mjs +3 -3
- package/test/r165-live-cli-skew.test.mjs +1 -1
- package/test/r167-release-contract.test.mjs +11 -11
- package/test/r168-release-contract.test.mjs +4 -4
- package/test/r172-release-contract.test.mjs +6 -6
- package/test/r173-release-contract.test.mjs +16 -16
- package/test/r179-release-contract.test.mjs +12 -12
- package/test/r190-release-contract.test.mjs +10 -10
- package/test/r191-release-contract.test.mjs +12 -12
- package/test/r192-release-identity.test.mjs +9 -9
- package/test/r193-release-identity.test.mjs +24 -22
- package/test/r193-release-readiness.test.mjs +2 -2
- package/test/r193-windows-gate.test.mjs +8 -8
- package/test/r194-release-identity.test.mjs +19 -15
- package/test/r194-release-readiness.test.mjs +2 -2
- package/test/r194-windows-gate.test.mjs +7 -6
- package/test/r195-canonical-owner-observation.test.mjs +32 -0
- package/test/r195-release-readiness.test.mjs +22 -0
- package/test/r196-desktop-postcondition.test.mjs +53 -0
- package/test/r196-handle-bound-read.test.mjs +99 -0
- package/test/r196-remote-outcome.test.mjs +94 -0
- package/test/r197-namespace-race.test.mjs +41 -0
- package/test/r197-native-dispatch-race.test.mjs +49 -0
- package/test/r197-native-file-read.test.mjs +60 -0
- package/test/r197-native-root-open.test.mjs +61 -0
- package/test/r198-root-identity.test.mjs +88 -0
- package/test/r199-native-uia-worker.test.mjs +28 -0
- package/test/r199-uia-identity.test.mjs +43 -0
- package/test/r200-remote-reconcile.test.mjs +106 -0
- package/test/r201-payload-boundary.test.mjs +78 -0
- package/test/r201-payload-fuzz.test.mjs +37 -0
- package/test/r201-tool-boundary-fuzz.test.mjs +120 -0
- package/test/r202-destination-journal.test.mjs +92 -0
- package/test/r203-atomic-journal.test.mjs +86 -0
- package/test/r205-candidate-selection-cli.test.mjs +31 -0
- package/test/r205-candidate-selection.test.mjs +83 -0
- package/test/r206-candidate-evidence.test.mjs +64 -0
- package/test/r206-release-contract.test.mjs +42 -0
- package/test/r206-release-readiness.test.mjs +23 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r64-machine-fs-large-read.test.mjs +26 -12
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
[CmdletBinding()]
|
|
3
|
+
param([Parameter(Mandatory=$true)][ValidatePattern('^[0-9a-f]{64}$')][string]$SourceSha256)
|
|
4
|
+
Set-StrictMode -Version Latest
|
|
5
|
+
$ErrorActionPreference='Stop'
|
|
6
|
+
$repo=Split-Path -Parent $PSScriptRoot
|
|
7
|
+
$src=Join-Path $repo 'native\deadbyte-root-relative-probe-r197.cpp'
|
|
8
|
+
$actual=(Get-FileHash -LiteralPath $src -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
9
|
+
if($actual -cne $SourceSha256){throw 'R197_NATIVE_SOURCE_HASH_DRIFT'}
|
|
10
|
+
$vswhere='C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe'
|
|
11
|
+
if(!(Test-Path -LiteralPath $vswhere)){throw 'R197_MSVC_UNAVAILABLE'}
|
|
12
|
+
$install=(& $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath | Select-Object -First 1)
|
|
13
|
+
if(!$install){throw 'R197_MSVC_TOOLCHAIN_MISSING'}
|
|
14
|
+
$dev=Join-Path $install 'Common7\Tools\VsDevCmd.bat'
|
|
15
|
+
$bin=Join-Path $repo 'bin'
|
|
16
|
+
$exe=Join-Path $bin 'deadbyte-root-relative-probe-r197.exe'
|
|
17
|
+
$obj=Join-Path $bin 'deadbyte-root-relative-probe-r197.obj'
|
|
18
|
+
if(Test-Path -LiteralPath $exe){throw 'R197_NATIVE_OUTPUT_EXISTS'}
|
|
19
|
+
if(Test-Path -LiteralPath $obj){throw 'R197_NATIVE_OBJECT_EXISTS'}
|
|
20
|
+
$common='/nologo /std:c++17 /permissive- /W4 /WX /O2 /MT /EHsc /guard:cf /diagnostics:caret /utf-8 /Brepro /DUNICODE /D_UNICODE /D_WIN32_WINNT=0x0A00'
|
|
21
|
+
$compile='cl {0} "{1}" /Fo:"{2}" /Fe:"{3}" /link /Brepro /INCREMENTAL:NO' -f $common,$src,$obj,$exe
|
|
22
|
+
$cmd=Join-Path $env:SystemRoot 'System32\cmd.exe'
|
|
23
|
+
$line='call "{0}" -no_logo -arch=x64 -host_arch=x64 && {1}' -f $dev,$compile
|
|
24
|
+
& $cmd /d /s /c $line
|
|
25
|
+
if($LASTEXITCODE -ne 0){throw ('R197_NATIVE_COMPILATION_FAIL exit='+$LASTEXITCODE)}
|
|
26
|
+
if(!(Test-Path -LiteralPath $exe -PathType Leaf)){throw 'R197_NATIVE_OUTPUT_MISSING'}
|
|
27
|
+
$hash=(Get-FileHash -LiteralPath $exe -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
28
|
+
Write-Output ('R197_NATIVE_BUILD_PASS exe_sha256='+$hash)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
[CmdletBinding()]
|
|
3
|
+
param(
|
|
4
|
+
[ValidateSet('preflight','focused','full','manifest','doctor','all')][string]$Stage='preflight'
|
|
5
|
+
)
|
|
6
|
+
Set-StrictMode -Version Latest
|
|
7
|
+
$ErrorActionPreference='Stop'
|
|
8
|
+
$repo=Split-Path -Parent $PSScriptRoot
|
|
9
|
+
$productionState=Join-Path $env:USERPROFILE '.deadbyte-mcp'
|
|
10
|
+
$parentId='v0.15.74-e84bf4eed16e9443'
|
|
11
|
+
$parentSha='e84bf4eed16e9443fbd0bf9f0f562e26b01db778647aefcc8b12fd7f48636b47'
|
|
12
|
+
$parentGen='598f896be9ce65e6b0c618e8c8f6eaa2a9d91617a76a146bf3deb385a56d19e7'
|
|
13
|
+
$parentTarball='5da436a3f8068107e74caf6da58ff1e211d4a62f94266853136b601762f36f0c'
|
|
14
|
+
$nativeNode='C:\Program Files\nodejs\node.exe'
|
|
15
|
+
$node=if(Test-Path -LiteralPath $nativeNode -PathType Leaf){$nativeNode}else{(Get-Command node -ErrorAction Stop).Source}
|
|
16
|
+
function Sha([string]$file){
|
|
17
|
+
$sha=[Security.Cryptography.SHA256]::Create()
|
|
18
|
+
try{$stream=[IO.File]::OpenRead($file);try{return ([BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-','').ToLowerInvariant()}finally{$stream.Dispose()}}finally{$sha.Dispose()}
|
|
19
|
+
}
|
|
20
|
+
function Need([bool]$condition,[string]$message){if(-not $condition){throw $message}}
|
|
21
|
+
function Run-Node([string]$label,[string[]]$nodeArgs){
|
|
22
|
+
Need ($null -ne $nodeArgs -and $nodeArgs.Count -gt 0) "R195_${label}_NO_NODE_ARGUMENTS"
|
|
23
|
+
Write-Output "R195_STAGE_START=$label"
|
|
24
|
+
$global:LASTEXITCODE=0
|
|
25
|
+
& $node @nodeArgs
|
|
26
|
+
$exit=$global:LASTEXITCODE
|
|
27
|
+
if($exit -ne 0){throw "R195_${label}_FAILED exit=$exit"}
|
|
28
|
+
Write-Output "R195_STAGE_PASS=$label"
|
|
29
|
+
}
|
|
30
|
+
Push-Location $repo
|
|
31
|
+
$previousExpectedDevelopmentRoot=$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT
|
|
32
|
+
try{
|
|
33
|
+
$pkg=Get-Content -LiteralPath 'package.json' -Raw | ConvertFrom-Json
|
|
34
|
+
$release=Get-Content -LiteralPath 'RELEASE.json' -Raw | ConvertFrom-Json
|
|
35
|
+
Need (-not [string]::IsNullOrWhiteSpace([string]$release.r195.development_policy_root)) 'R195_DEVELOPMENT_PROVENANCE_ROOT_MISSING'
|
|
36
|
+
$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT=[IO.Path]::GetFullPath([string]$release.r195.development_policy_root)
|
|
37
|
+
Need ($pkg.version -eq '0.15.75' -and $release.version -eq '0.15.75' -and $release.train -eq 'R195') 'R195_CANDIDATE_VERSION_DRIFT'
|
|
38
|
+
Need ($release.source_predecessor.version -eq '0.15.74' -and $release.source_predecessor.train -eq 'R194') 'R195_SOURCE_PREDECESSOR_VERSION_DRIFT'
|
|
39
|
+
Need ($release.source_predecessor.manifest_sha256 -eq $parentSha -and $release.source_predecessor.tarball_sha256 -eq $parentTarball) 'R195_SOURCE_PREDECESSOR_IDENTITY_DRIFT'
|
|
40
|
+
Need ($release.runtime_predecessor.release_id -eq $parentId -and $release.runtime_predecessor.manifest_sha256 -eq $parentSha -and $release.runtime_predecessor.generation_manifest_sha256 -eq $parentGen) 'R195_RUNTIME_PREDECESSOR_IDENTITY_DRIFT'
|
|
41
|
+
$active=Get-Content -LiteralPath (Join-Path $productionState 'active-release.json') -Raw | ConvertFrom-Json
|
|
42
|
+
Need ($active.version -eq '0.15.74' -and $active.release_id -eq $parentId -and $active.manifest_sha256 -eq $parentSha -and $active.generation_manifest_sha256 -eq $parentGen) 'R195_ACTIVE_RUNTIME_DRIFT'
|
|
43
|
+
Need ((Sha (Join-Path $active.release_root 'MANIFEST.SHA256')) -eq $parentSha) 'R195_ACTIVE_MANIFEST_MISMATCH'
|
|
44
|
+
Write-Output 'R195_PREDECESSOR_PREFLIGHT=PASS'
|
|
45
|
+
if($Stage -eq 'preflight'){return}
|
|
46
|
+
if($Stage -in @('focused','all')){
|
|
47
|
+
$focused=@(
|
|
48
|
+
'test/r70-owner-approval.test.mjs',
|
|
49
|
+
'test/r89-privileged-install-boundary.test.mjs',
|
|
50
|
+
'test/r186-controller-owner-grant.test.mjs',
|
|
51
|
+
'test/r186-owner-consent-preflight.test.mjs',
|
|
52
|
+
'test/r186-owner-enrollment.test.mjs',
|
|
53
|
+
'test/r186-owner-grant-broker.test.mjs',
|
|
54
|
+
'test/r186-owner-local-signing.test.mjs',
|
|
55
|
+
'test/r186-owner-request.test.mjs',
|
|
56
|
+
'test/r186-owner-review-export.test.mjs',
|
|
57
|
+
'test/r188-owner-uac.test.mjs',
|
|
58
|
+
'test/r188-uac-boundary.test.mjs',
|
|
59
|
+
'test/r193-limited-migration-contract.test.mjs',
|
|
60
|
+
'test/r193-live-owner-subject.test.mjs',
|
|
61
|
+
'test/r193-native-process-observer.test.mjs',
|
|
62
|
+
'test/r193-native-token.test.mjs',
|
|
63
|
+
'test/r193-owner-enrollment-entrypoint.test.mjs',
|
|
64
|
+
'test/r193-owner-secret-acl.test.mjs',
|
|
65
|
+
'test/r193-owner-uac-broker.test.mjs',
|
|
66
|
+
'test/r193-owner-uac-entrypoint.test.mjs',
|
|
67
|
+
'test/r193-release-readiness.test.mjs',
|
|
68
|
+
'test/r193-release-identity.test.mjs',
|
|
69
|
+
'test/r194-release-identity.test.mjs',
|
|
70
|
+
'test/r194-release-readiness.test.mjs',
|
|
71
|
+
'test/r193-uac-r70-bridge.test.mjs',
|
|
72
|
+
'test/r194-windows-gate.test.mjs',
|
|
73
|
+
'test/r194-npm-auth-recovery.test.mjs',
|
|
74
|
+
'test/r194-npm-preauth.test.mjs'
|
|
75
|
+
'test/r195-canonical-owner-observation.test.mjs'
|
|
76
|
+
'test/r195-release-readiness.test.mjs'
|
|
77
|
+
)
|
|
78
|
+
Run-Node -label 'focused' -nodeArgs (@('--test','--test-reporter=tap','--test-concurrency=1')+$focused)
|
|
79
|
+
if($Stage -eq 'focused'){return}
|
|
80
|
+
}
|
|
81
|
+
if($Stage -in @('full','all')){
|
|
82
|
+
$previousCrossVolume=$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT
|
|
83
|
+
$tempDrive=[IO.Path]::GetPathRoot([IO.Path]::GetFullPath($env:TEMP))
|
|
84
|
+
$scratchDrive=if($tempDrive -ieq 'D:\'){'C:\'}else{'D:\'}
|
|
85
|
+
Need (Test-Path -LiteralPath $scratchDrive -PathType Container) 'R195_CROSS_VOLUME_DRIVE_UNAVAILABLE'
|
|
86
|
+
$crossVolume=Join-Path $scratchDrive 'DEADBYTE-R195-CrossVolume'
|
|
87
|
+
try{
|
|
88
|
+
[IO.Directory]::CreateDirectory($crossVolume)|Out-Null
|
|
89
|
+
$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT=$crossVolume
|
|
90
|
+
Run-Node -label 'full' -nodeArgs @('--test','--test-reporter=tap','--test-concurrency=4','test/*.test.mjs')
|
|
91
|
+
}finally{$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT=$previousCrossVolume}
|
|
92
|
+
if($Stage -eq 'full'){return}
|
|
93
|
+
}
|
|
94
|
+
if($Stage -in @('manifest','all')){
|
|
95
|
+
Run-Node -label 'manifest' -nodeArgs @('scripts/release-manifest.mjs','verify')
|
|
96
|
+
if($Stage -eq 'manifest'){return}
|
|
97
|
+
}
|
|
98
|
+
if($Stage -in @('doctor','all')){
|
|
99
|
+
$previousStateRoot=$env:DEADBYTE_STATE_ROOT
|
|
100
|
+
$isolated=Join-Path $env:TEMP ('deadbyte-r195-doctor-'+[guid]::NewGuid().ToString('N'))
|
|
101
|
+
try{
|
|
102
|
+
[IO.Directory]::CreateDirectory($isolated)|Out-Null
|
|
103
|
+
$env:DEADBYTE_STATE_ROOT=$isolated
|
|
104
|
+
Run-Node -label 'isolated_doctor' -nodeArgs @('src/deadbyte-cli.mjs','doctor')
|
|
105
|
+
}finally{
|
|
106
|
+
$env:DEADBYTE_STATE_ROOT=$previousStateRoot
|
|
107
|
+
Remove-Item -LiteralPath $isolated -Recurse -Force -ErrorAction SilentlyContinue
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
Write-Output 'R195_WINDOWS_CANDIDATE_GATE=PASS_PREPUBLICATION'
|
|
111
|
+
}finally{
|
|
112
|
+
$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT=$previousExpectedDevelopmentRoot
|
|
113
|
+
Pop-Location
|
|
114
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
[CmdletBinding()]
|
|
3
|
+
param(
|
|
4
|
+
[ValidateSet('preflight','focused','full','manifest','doctor','all')][string]$Stage='preflight'
|
|
5
|
+
)
|
|
6
|
+
Set-StrictMode -Version Latest
|
|
7
|
+
$ErrorActionPreference='Stop'
|
|
8
|
+
$repo=Split-Path -Parent $PSScriptRoot
|
|
9
|
+
$productionState=Join-Path $env:USERPROFILE '.deadbyte-mcp'
|
|
10
|
+
$parentId='v0.15.74-e84bf4eed16e9443'
|
|
11
|
+
$parentSha='e84bf4eed16e9443fbd0bf9f0f562e26b01db778647aefcc8b12fd7f48636b47'
|
|
12
|
+
$parentGen='598f896be9ce65e6b0c618e8c8f6eaa2a9d91617a76a146bf3deb385a56d19e7'
|
|
13
|
+
$parentTarball='5da436a3f8068107e74caf6da58ff1e211d4a62f94266853136b601762f36f0c'
|
|
14
|
+
$nativeNode='C:\Program Files\nodejs\node.exe'
|
|
15
|
+
$node=if(Test-Path -LiteralPath $nativeNode -PathType Leaf){$nativeNode}else{(Get-Command node -ErrorAction Stop).Source}
|
|
16
|
+
function Sha([string]$file){
|
|
17
|
+
$sha=[Security.Cryptography.SHA256]::Create()
|
|
18
|
+
try{$stream=[IO.File]::OpenRead($file);try{return ([BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-','').ToLowerInvariant()}finally{$stream.Dispose()}}finally{$sha.Dispose()}
|
|
19
|
+
}
|
|
20
|
+
function Need([bool]$condition,[string]$message){if(-not $condition){throw $message}}
|
|
21
|
+
function Run-Node([string]$label,[string[]]$nodeArgs){
|
|
22
|
+
Need ($null -ne $nodeArgs -and $nodeArgs.Count -gt 0) "R206_${label}_NO_NODE_ARGUMENTS"
|
|
23
|
+
Write-Output "R206_STAGE_START=$label"
|
|
24
|
+
$global:LASTEXITCODE=0
|
|
25
|
+
& $node @nodeArgs
|
|
26
|
+
$exit=$global:LASTEXITCODE
|
|
27
|
+
if($exit -ne 0){throw "R206_${label}_FAILED exit=$exit"}
|
|
28
|
+
Write-Output "R206_STAGE_PASS=$label"
|
|
29
|
+
}
|
|
30
|
+
Push-Location $repo
|
|
31
|
+
$previousExpectedDevelopmentRoot=$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT
|
|
32
|
+
try{
|
|
33
|
+
$pkg=Get-Content -LiteralPath 'package.json' -Raw | ConvertFrom-Json
|
|
34
|
+
$release=Get-Content -LiteralPath 'RELEASE.json' -Raw | ConvertFrom-Json
|
|
35
|
+
Need (-not [string]::IsNullOrWhiteSpace([string]$release.r206.development_policy_root)) 'R206_DEVELOPMENT_PROVENANCE_ROOT_MISSING'
|
|
36
|
+
$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT=[IO.Path]::GetFullPath([string]$release.r206.development_policy_root)
|
|
37
|
+
Need ($pkg.version -eq '0.15.75' -and $release.version -eq '0.15.75' -and $release.train -eq 'R206') 'R206_CANDIDATE_VERSION_DRIFT'
|
|
38
|
+
Need ($release.source_predecessor.version -eq '0.15.75' -and $release.source_predecessor.train -eq 'R205') 'R206_SOURCE_PREDECESSOR_VERSION_DRIFT'
|
|
39
|
+
Need ($release.source_predecessor.manifest_sha256 -eq '166eebde18d53a9ec46f738383c289733f9cd37918b3572b7515d1ab9b122c92' -and $null -eq $release.source_predecessor.tarball_sha256) 'R206_SOURCE_PREDECESSOR_IDENTITY_DRIFT'
|
|
40
|
+
Need ($release.runtime_predecessor.release_id -eq $parentId -and $release.runtime_predecessor.manifest_sha256 -eq $parentSha -and $release.runtime_predecessor.generation_manifest_sha256 -eq $parentGen) 'R206_RUNTIME_PREDECESSOR_IDENTITY_DRIFT'
|
|
41
|
+
$active=Get-Content -LiteralPath (Join-Path $productionState 'active-release.json') -Raw | ConvertFrom-Json
|
|
42
|
+
Need ($active.version -eq '0.15.74' -and $active.release_id -eq $parentId -and $active.manifest_sha256 -eq $parentSha -and $active.generation_manifest_sha256 -eq $parentGen) 'R206_ACTIVE_RUNTIME_DRIFT'
|
|
43
|
+
Need ((Sha (Join-Path $active.release_root 'MANIFEST.SHA256')) -eq $parentSha) 'R206_ACTIVE_MANIFEST_MISMATCH'
|
|
44
|
+
Write-Output 'R206_PREDECESSOR_PREFLIGHT=PASS'
|
|
45
|
+
if($Stage -eq 'preflight'){return}
|
|
46
|
+
if($Stage -in @('focused','all')){
|
|
47
|
+
$focused=@(
|
|
48
|
+
'test/r70-owner-approval.test.mjs',
|
|
49
|
+
'test/r89-privileged-install-boundary.test.mjs',
|
|
50
|
+
'test/r186-controller-owner-grant.test.mjs',
|
|
51
|
+
'test/r186-owner-consent-preflight.test.mjs',
|
|
52
|
+
'test/r186-owner-enrollment.test.mjs',
|
|
53
|
+
'test/r186-owner-grant-broker.test.mjs',
|
|
54
|
+
'test/r186-owner-local-signing.test.mjs',
|
|
55
|
+
'test/r186-owner-request.test.mjs',
|
|
56
|
+
'test/r186-owner-review-export.test.mjs',
|
|
57
|
+
'test/r188-owner-uac.test.mjs',
|
|
58
|
+
'test/r188-uac-boundary.test.mjs',
|
|
59
|
+
'test/r193-limited-migration-contract.test.mjs',
|
|
60
|
+
'test/r193-live-owner-subject.test.mjs',
|
|
61
|
+
'test/r193-native-process-observer.test.mjs',
|
|
62
|
+
'test/r193-native-token.test.mjs',
|
|
63
|
+
'test/r193-owner-enrollment-entrypoint.test.mjs',
|
|
64
|
+
'test/r193-owner-secret-acl.test.mjs',
|
|
65
|
+
'test/r193-owner-uac-broker.test.mjs',
|
|
66
|
+
'test/r193-owner-uac-entrypoint.test.mjs',
|
|
67
|
+
'test/r193-release-readiness.test.mjs',
|
|
68
|
+
'test/r193-release-identity.test.mjs',
|
|
69
|
+
'test/r194-release-identity.test.mjs',
|
|
70
|
+
'test/r194-release-readiness.test.mjs',
|
|
71
|
+
'test/r193-uac-r70-bridge.test.mjs',
|
|
72
|
+
'test/r194-windows-gate.test.mjs',
|
|
73
|
+
'test/r194-npm-auth-recovery.test.mjs',
|
|
74
|
+
'test/r194-npm-preauth.test.mjs'
|
|
75
|
+
'test/r195-canonical-owner-observation.test.mjs'
|
|
76
|
+
'test/r206-candidate-evidence.test.mjs'
|
|
77
|
+
'test/r206-release-contract.test.mjs'
|
|
78
|
+
'test/r206-release-readiness.test.mjs'
|
|
79
|
+
)
|
|
80
|
+
Run-Node -label 'focused' -nodeArgs (@('--test','--test-reporter=tap','--test-concurrency=1')+$focused)
|
|
81
|
+
if($Stage -eq 'focused'){return}
|
|
82
|
+
}
|
|
83
|
+
if($Stage -in @('full','all')){
|
|
84
|
+
$previousCrossVolume=$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT
|
|
85
|
+
$tempDrive=[IO.Path]::GetPathRoot([IO.Path]::GetFullPath($env:TEMP))
|
|
86
|
+
$scratchDrive=if($tempDrive -ieq 'D:\'){'C:\'}else{'D:\'}
|
|
87
|
+
Need (Test-Path -LiteralPath $scratchDrive -PathType Container) 'R206_CROSS_VOLUME_DRIVE_UNAVAILABLE'
|
|
88
|
+
$crossVolume=Join-Path $scratchDrive 'DEADBYTE-R206-CrossVolume'
|
|
89
|
+
try{
|
|
90
|
+
[IO.Directory]::CreateDirectory($crossVolume)|Out-Null
|
|
91
|
+
$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT=$crossVolume
|
|
92
|
+
Run-Node -label 'full' -nodeArgs @('--test','--test-reporter=tap','--test-concurrency=4','test/*.test.mjs')
|
|
93
|
+
}finally{$env:DEADBYTE_TEST_CROSS_VOLUME_ROOT=$previousCrossVolume}
|
|
94
|
+
if($Stage -eq 'full'){return}
|
|
95
|
+
}
|
|
96
|
+
if($Stage -in @('manifest','all')){
|
|
97
|
+
Run-Node -label 'manifest' -nodeArgs @('scripts/release-manifest.mjs','verify')
|
|
98
|
+
if($Stage -eq 'manifest'){return}
|
|
99
|
+
}
|
|
100
|
+
if($Stage -in @('doctor','all')){
|
|
101
|
+
$previousStateRoot=$env:DEADBYTE_STATE_ROOT
|
|
102
|
+
$isolated=Join-Path $env:TEMP ('deadbyte-r206-doctor-'+[guid]::NewGuid().ToString('N'))
|
|
103
|
+
try{
|
|
104
|
+
[IO.Directory]::CreateDirectory($isolated)|Out-Null
|
|
105
|
+
$env:DEADBYTE_STATE_ROOT=$isolated
|
|
106
|
+
Run-Node -label 'isolated_doctor' -nodeArgs @('src/deadbyte-cli.mjs','doctor')
|
|
107
|
+
}finally{
|
|
108
|
+
$env:DEADBYTE_STATE_ROOT=$previousStateRoot
|
|
109
|
+
Remove-Item -LiteralPath $isolated -Recurse -Force -ErrorAction SilentlyContinue
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
Write-Output 'R206_WINDOWS_CANDIDATE_GATE=PASS_PREPUBLICATION'
|
|
113
|
+
}finally{
|
|
114
|
+
$env:DEADBYTE_EXPECTED_DEVELOPMENT_ROOT=$previousExpectedDevelopmentRoot
|
|
115
|
+
Pop-Location
|
|
116
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
[CmdletBinding()]
|
|
2
|
+
param(
|
|
3
|
+
[string]$RuntimeRoot = '',
|
|
4
|
+
[string]$OutputPath = '',
|
|
5
|
+
[string[]]$AllowedActions = @('pointer_move','click_primary','click_secondary','double_click_primary','scroll','key_chord','text_input')
|
|
6
|
+
)
|
|
7
|
+
$ErrorActionPreference='Stop'
|
|
8
|
+
Set-StrictMode -Version Latest
|
|
9
|
+
function Get-Sha256Hex {
|
|
10
|
+
param([Parameter(Mandatory=$true)][string]$Path)
|
|
11
|
+
$Stream=[System.IO.File]::OpenRead([System.IO.Path]::GetFullPath($Path))
|
|
12
|
+
try{$Hasher=[System.Security.Cryptography.SHA256]::Create();try{return ([System.BitConverter]::ToString($Hasher.ComputeHash($Stream))).Replace('-','').ToLowerInvariant()}finally{$Hasher.Dispose()}}
|
|
13
|
+
finally{$Stream.Dispose()}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
$Root=Split-Path -Parent $PSScriptRoot
|
|
17
|
+
$Controller=Join-Path $Root 'controller'
|
|
18
|
+
if([string]::IsNullOrWhiteSpace($RuntimeRoot)){ $RuntimeRoot=Join-Path $Controller 'runtime' }
|
|
19
|
+
if([string]::IsNullOrWhiteSpace($OutputPath)){ $OutputPath=Join-Path $Controller 'deadbyte-desktop-policy.json' }
|
|
20
|
+
$RuntimeRoot=[System.IO.Path]::GetFullPath($RuntimeRoot)
|
|
21
|
+
$OutputPath=[System.IO.Path]::GetFullPath($OutputPath)
|
|
22
|
+
$Observer=[System.IO.Path]::GetFullPath((Join-Path $Root 'bin\deadbyte-desktop-observer-r40.exe'))
|
|
23
|
+
$Input=[System.IO.Path]::GetFullPath((Join-Path $Root 'bin\deadbyte-desktop-input-r40.exe'))
|
|
24
|
+
$Grounder=[System.IO.Path]::GetFullPath((Join-Path $Root 'bin\deadbyte-desktop-uia-r199-fixed.exe'))
|
|
25
|
+
if(-not (Test-Path -LiteralPath $Observer -PathType Leaf)){throw "observer binary missing: $Observer"}
|
|
26
|
+
if(-not (Test-Path -LiteralPath $Input -PathType Leaf)){throw "input binary missing: $Input"}
|
|
27
|
+
if(-not (Test-Path -LiteralPath $Grounder -PathType Leaf)){throw "UIA grounder binary missing: $Grounder"}
|
|
28
|
+
$Known=@('pointer_move','click_primary','click_secondary','double_click_primary','scroll','key_chord','text_input')
|
|
29
|
+
if($AllowedActions.Count -lt 1){throw 'AllowedActions cannot be empty'}
|
|
30
|
+
$Unique=@($AllowedActions | Sort-Object -Unique)
|
|
31
|
+
if($Unique.Count -ne $AllowedActions.Count -or @($AllowedActions | Where-Object { $_ -notin $Known }).Count -gt 0){throw 'AllowedActions invalid'}
|
|
32
|
+
New-Item -ItemType Directory -Force -Path $RuntimeRoot | Out-Null
|
|
33
|
+
$Evidence=Join-Path $RuntimeRoot 'desktop-evidence'
|
|
34
|
+
New-Item -ItemType Directory -Force -Path $Evidence | Out-Null
|
|
35
|
+
$Grant=Join-Path $RuntimeRoot 'desktop-grant.json'
|
|
36
|
+
Remove-Item -LiteralPath $Grant -Force -ErrorAction SilentlyContinue
|
|
37
|
+
$Policy=[ordered]@{
|
|
38
|
+
schema='deadbyte.desktop-policy.v1'
|
|
39
|
+
enabled=$true
|
|
40
|
+
grant_file=$Grant
|
|
41
|
+
evidence_dir=$Evidence
|
|
42
|
+
observer=[ordered]@{
|
|
43
|
+
executable=$Observer
|
|
44
|
+
sha256=Get-Sha256Hex -Path $Observer
|
|
45
|
+
backend='gdi-bitblt-fallback'
|
|
46
|
+
}
|
|
47
|
+
input=[ordered]@{
|
|
48
|
+
executable=$Input
|
|
49
|
+
sha256=Get-Sha256Hex -Path $Input
|
|
50
|
+
}
|
|
51
|
+
grounder=[ordered]@{
|
|
52
|
+
executable=$Grounder
|
|
53
|
+
sha256=Get-Sha256Hex -Path $Grounder
|
|
54
|
+
}
|
|
55
|
+
allowed_input_desktops=@('Default')
|
|
56
|
+
allowed_actions=@($AllowedActions)
|
|
57
|
+
limits=[ordered]@{
|
|
58
|
+
max_frame_age_ms=2000
|
|
59
|
+
max_frame_bytes=134217728
|
|
60
|
+
capture_timeout_ms=10000
|
|
61
|
+
input_timeout_ms=5000
|
|
62
|
+
ground_timeout_ms=5000
|
|
63
|
+
post_observe_timeout_ms=10000
|
|
64
|
+
max_preview_bytes=1048576
|
|
65
|
+
max_text_bytes=4096
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
$Parent=Split-Path -Parent $OutputPath
|
|
69
|
+
New-Item -ItemType Directory -Force -Path $Parent | Out-Null
|
|
70
|
+
$Json=$Policy | ConvertTo-Json -Depth 8
|
|
71
|
+
$Utf8=New-Object System.Text.UTF8Encoding($false)
|
|
72
|
+
$Tmp=$OutputPath+'.tmp'
|
|
73
|
+
[System.IO.File]::WriteAllText($Tmp,$Json,$Utf8)
|
|
74
|
+
Move-Item -LiteralPath $Tmp -Destination $OutputPath -Force
|
|
75
|
+
[pscustomobject]@{
|
|
76
|
+
status='created'
|
|
77
|
+
policy_path=$OutputPath
|
|
78
|
+
policy_sha256=Get-Sha256Hex -Path $OutputPath
|
|
79
|
+
observer_sha256=$Policy.observer.sha256
|
|
80
|
+
input_sha256=$Policy.input.sha256
|
|
81
|
+
grounder_sha256=$Policy.grounder.sha256
|
|
82
|
+
grant_file=$Grant
|
|
83
|
+
grant_state='DISARMED'
|
|
84
|
+
action_kinds=@($AllowedActions)
|
|
85
|
+
}|ConvertTo-Json -Depth 6
|
|
@@ -15,6 +15,8 @@ import {assertR167NpmPublishReady,assertR167PackedIdentity} from './npm-release-
|
|
|
15
15
|
import {assertR168NpmPublishReady,assertR168PackedIdentity} from './npm-release-readiness-r168.mjs';
|
|
16
16
|
import {assertR193NpmPublishReady,assertR193PackedIdentity} from './npm-release-readiness-r193.mjs';
|
|
17
17
|
import {assertR194NpmPublishReady,assertR194PackedIdentity} from './npm-release-readiness-r194.mjs';
|
|
18
|
+
import {assertR195NpmPublishReady,assertR195PackedIdentity} from './npm-release-readiness-r195.mjs';
|
|
19
|
+
import {assertR206NpmPublishReady,assertR206PackedIdentity} from './npm-release-readiness-r206.mjs';
|
|
18
20
|
import {resumePackRecord} from '../src/npm-publication-resume-r168.mjs';
|
|
19
21
|
import { existsSync,mkdtempSync,readdirSync,readFileSync,rmSync } from 'node:fs';
|
|
20
22
|
import { resolveStateRoot } from '../src/state-root.mjs';
|
|
@@ -157,6 +159,13 @@ async function main() {
|
|
|
157
159
|
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R194 requires --publish-only; activation remains separately authorized');
|
|
158
160
|
r194Readiness=await assertR194NpmPublishReady(release,{root});
|
|
159
161
|
}
|
|
162
|
+
let r195Readiness=null;
|
|
163
|
+
let r206Readiness=null;
|
|
164
|
+
if (!isVerifyOnly && version==='0.15.75') {
|
|
165
|
+
if (!publishOnly) throw new Error('PUBLISH_BLOCKED R206 requires --publish-only; owner enrollment and activation remain separate');
|
|
166
|
+
if(release.train==='R206')r206Readiness=await assertR206NpmPublishReady(release,{root});
|
|
167
|
+
else r195Readiness=await assertR195NpmPublishReady(release,{root});
|
|
168
|
+
}
|
|
160
169
|
if (release.parent?.release_id !== provenance.parent_release_id ||
|
|
161
170
|
release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
|
|
162
171
|
release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
|
|
@@ -304,6 +313,14 @@ async function main() {
|
|
|
304
313
|
...r194Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
|
|
305
314
|
observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
|
|
306
315
|
});
|
|
316
|
+
if(r195Readiness)assertR195PackedIdentity({
|
|
317
|
+
...r195Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
|
|
318
|
+
observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
|
|
319
|
+
});
|
|
320
|
+
if(r206Readiness)assertR206PackedIdentity({
|
|
321
|
+
...r206Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
|
|
322
|
+
observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
|
|
323
|
+
});
|
|
307
324
|
|
|
308
325
|
console.log('[6/7] Publishing artifact to npm registry...');
|
|
309
326
|
publishAttempted = true;
|
|
@@ -0,0 +1,72 @@
|
|
|
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 hex64=value=>typeof value==='string'&&/^[0-9a-f]{64}$/.test(value);
|
|
7
|
+
const fail=message=>{throw new Error(`PUBLISH_BLOCKED R195 ${message}`);};
|
|
8
|
+
const required=(value,message)=>{if(!value)fail(message);};
|
|
9
|
+
|
|
10
|
+
async function checkedFile(file,expected,{maxBytes=64*1024*1024}={}){
|
|
11
|
+
required(hex64(expected),'evidence digest missing');
|
|
12
|
+
let info;try{info=await lstat(file);}catch{fail('evidence file absent');}
|
|
13
|
+
required(info.isFile()&&!info.isSymbolicLink()&&info.size>0&&info.size<=maxBytes,'evidence file invalid');
|
|
14
|
+
const bytes=await readFile(file);
|
|
15
|
+
required(sha256(bytes)===expected,'evidence digest differs');
|
|
16
|
+
return bytes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function tapSummary(text,label){
|
|
20
|
+
const summaries=[...text.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)];
|
|
21
|
+
required(summaries.length>0,`${label} TAP summary absent`);
|
|
22
|
+
const last=summaries.at(-1);
|
|
23
|
+
return {tests:Number(last[1]),passes:Number(last[3]),fails:Number(last[4]),cancelled:Number(last[5]),skips:Number(last[6])};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function assertR195PackedIdentity({tarball_sha256,tarball_integrity,tarball_shasum,observedSha256,observedIntegrity,observedShasum}={}){
|
|
27
|
+
required(hex64(tarball_sha256)&&typeof tarball_integrity==='string'&&tarball_integrity.startsWith('sha512-')&&
|
|
28
|
+
typeof tarball_shasum==='string'&&/^[0-9a-f]{40}$/.test(tarball_shasum),'verified tarball identity invalid');
|
|
29
|
+
required(observedSha256===tarball_sha256&&observedIntegrity===tarball_integrity&&observedShasum===tarball_shasum,
|
|
30
|
+
'repacked tarball differs from verified closure bytes');
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function assertR195NpmPublishReady(release,{root,closureRoot=process.env.DEADBYTE_R195_CLOSURE_ROOT}={}){
|
|
35
|
+
required(release?.version==='0.15.75'&&release?.train==='R195'&&
|
|
36
|
+
release?.r195?.scope==='CANONICAL_PROTECTED_OWNER_OBSERVATION','candidate metadata invalid');
|
|
37
|
+
required(release?.r195?.public_tool_delta===0&&release?.r195?.authority_scope_delta===0,'public authority surface widened');
|
|
38
|
+
required(release?.parent?.version==='0.15.74'&&release?.parent?.release_id==='v0.15.74-e84bf4eed16e9443'&&
|
|
39
|
+
release?.parent?.manifest_sha256==='e84bf4eed16e9443fbd0bf9f0f562e26b01db778647aefcc8b12fd7f48636b47'&&
|
|
40
|
+
release?.parent?.generation_manifest_sha256==='598f896be9ce65e6b0c618e8c8f6eaa2a9d91617a76a146bf3deb385a56d19e7','lineage mismatch');
|
|
41
|
+
required(root&&path.isAbsolute(root)&&closureRoot&&path.isAbsolute(closureRoot),'closure root absent');
|
|
42
|
+
const expected=path.resolve(root,'..','..','testing','r195-final-closure');
|
|
43
|
+
required(path.resolve(closureRoot).toLowerCase()===expected.toLowerCase(),'closure root outside scoped testing folder');
|
|
44
|
+
let closure;try{closure=JSON.parse(await readFile(path.join(closureRoot,'closure.json'),'utf8'));}catch{fail('closure unreadable');}
|
|
45
|
+
required(closure?.schema==='deadbyte.r195-release-closure.v1'&&closure.status==='RELEASE_READY'&&
|
|
46
|
+
closure.version==='0.15.75'&&closure.train==='R195','closure status mismatch');
|
|
47
|
+
required(closure.production_release_id===release.parent.release_id&&closure.production_manifest_sha256===release.parent.manifest_sha256&&
|
|
48
|
+
closure.production_generation_manifest_sha256===release.parent.generation_manifest_sha256,'production predecessor mismatch');
|
|
49
|
+
required(hex64(closure.manifest_sha256)&&closure.manifest_sha256===sha256(await readFile(path.join(root,'MANIFEST.SHA256'))),'final manifest drift');
|
|
50
|
+
required(closure.compact_tools===43&&closure.full_tools===117,'catalog count mismatch');
|
|
51
|
+
required(closure.owner_enrollment==='NOT_RUN'&&closure.production_activation==='NOT_RUN','prepublication closure crossed authority boundary');
|
|
52
|
+
const receipt=JSON.parse((await checkedFile(path.join(closureRoot,'protected-install-receipt.json'),closure.protected_receipt_sha256)).toString('utf8'));
|
|
53
|
+
required(receipt?.status==='PASS'&&receipt.package_version==='0.15.75'&&receipt.source_manifest_sha256===closure.manifest_sha256&&
|
|
54
|
+
receipt.protected_manifest_sha256===closure.manifest_sha256,'protected exact-byte receipt mismatch');
|
|
55
|
+
const focused=(await checkedFile(path.join(closureRoot,'windows-focused.stdout.log'),closure.focused_stdout_sha256)).toString('utf8');
|
|
56
|
+
const full=(await checkedFile(path.join(closureRoot,'windows-full.stdout.log'),closure.full_stdout_sha256)).toString('utf8');
|
|
57
|
+
const verify=(await checkedFile(path.join(closureRoot,'npm-verify.stdout.log'),closure.verify_stdout_sha256)).toString('utf8');
|
|
58
|
+
required(focused.includes('R195_STAGE_PASS=focused'),'focused protected gate incomplete');
|
|
59
|
+
const focusedSummary=tapSummary(focused,'focused');
|
|
60
|
+
required(focusedSummary.fails===0&&focusedSummary.cancelled===0&&focusedSummary.passes>=70&&focusedSummary.skips<=3,'focused regression count mismatch');
|
|
61
|
+
required(full.includes('R195_STAGE_PASS=full'),'full protected gate incomplete');
|
|
62
|
+
const summary=tapSummary(full,'full');
|
|
63
|
+
required(summary.tests>=2200&&summary.passes>=2100&&summary.fails===0&&summary.cancelled===0&&summary.skips<=70&&summary.passes+summary.skips===summary.tests,'full regression count mismatch');
|
|
64
|
+
required(verify.includes('VERIFY-ONLY PIPELINE PASS')&&verify.includes('Artifact isolation gate PASS')&&verify.includes('VERIFIED_TARBALL '),'npm exact-artifact verification incomplete');
|
|
65
|
+
const line=verify.split(/\r?\n/).find(value=>value.startsWith('VERIFIED_TARBALL '));
|
|
66
|
+
let artifact;try{artifact=JSON.parse(line.slice('VERIFIED_TARBALL '.length));}catch{fail('tarball evidence malformed');}
|
|
67
|
+
required(artifact.filename==='deadbyte-mcp-0.15.75.tgz'&&artifact.bytes>0&&artifact.sha256===closure.tarball_sha256&&
|
|
68
|
+
artifact.integrity===closure.tarball_integrity&&artifact.shasum===closure.tarball_shasum,'tarball identity mismatch');
|
|
69
|
+
return Object.freeze({status:'R195_RELEASE_READY_EVIDENCE_BOUND',manifest_sha256:closure.manifest_sha256,
|
|
70
|
+
tarball_sha256:artifact.sha256,tarball_integrity:artifact.integrity,tarball_shasum:artifact.shasum,
|
|
71
|
+
tests:summary.tests,passes:summary.passes,skips:summary.skips});
|
|
72
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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 hex64=value=>typeof value==='string'&&/^[0-9a-f]{64}$/.test(value);
|
|
7
|
+
const fail=message=>{throw new Error(`PUBLISH_BLOCKED R206 ${message}`);};
|
|
8
|
+
const required=(value,message)=>{if(!value)fail(message);};
|
|
9
|
+
|
|
10
|
+
async function checkedFile(file,expected,{maxBytes=64*1024*1024}={}){
|
|
11
|
+
required(hex64(expected),'evidence digest missing');
|
|
12
|
+
let info;try{info=await lstat(file);}catch{fail('evidence file absent');}
|
|
13
|
+
required(info.isFile()&&!info.isSymbolicLink()&&info.size>0&&info.size<=maxBytes,'evidence file invalid');
|
|
14
|
+
const bytes=await readFile(file);
|
|
15
|
+
required(sha256(bytes)===expected,'evidence digest differs');
|
|
16
|
+
return bytes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function tapSummary(text,label){
|
|
20
|
+
const summaries=[...text.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)];
|
|
21
|
+
required(summaries.length>0,`${label} TAP summary absent`);
|
|
22
|
+
const last=summaries.at(-1);
|
|
23
|
+
return {tests:Number(last[1]),passes:Number(last[3]),fails:Number(last[4]),cancelled:Number(last[5]),skips:Number(last[6])};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function assertR206PackedIdentity({tarball_sha256,tarball_integrity,tarball_shasum,observedSha256,observedIntegrity,observedShasum}={}){
|
|
27
|
+
required(hex64(tarball_sha256)&&typeof tarball_integrity==='string'&&tarball_integrity.startsWith('sha512-')&&
|
|
28
|
+
typeof tarball_shasum==='string'&&/^[0-9a-f]{40}$/.test(tarball_shasum),'verified tarball identity invalid');
|
|
29
|
+
required(observedSha256===tarball_sha256&&observedIntegrity===tarball_integrity&&observedShasum===tarball_shasum,
|
|
30
|
+
'repacked tarball differs from verified closure bytes');
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function assertR206NpmPublishReady(release,{root,closureRoot=process.env.DEADBYTE_R206_CLOSURE_ROOT}={}){
|
|
35
|
+
required(release?.version==='0.15.75'&&release?.train==='R206'&&
|
|
36
|
+
release?.r206?.scope==='EVIDENCE_BOUND_CANDIDATE_SELECTION_RELEASE_CLOSURE','candidate metadata invalid');
|
|
37
|
+
required(release?.r206?.public_tool_delta===0&&release?.r206?.authority_scope_delta===0&&
|
|
38
|
+
release?.r206?.selector_release_authority===false,'public authority surface widened');
|
|
39
|
+
required(release?.source_predecessor?.train==='R205'&&
|
|
40
|
+
release?.source_predecessor?.manifest_sha256==='166eebde18d53a9ec46f738383c289733f9cd37918b3572b7515d1ab9b122c92',
|
|
41
|
+
'source predecessor mismatch');
|
|
42
|
+
required(release?.parent?.version==='0.15.74'&&release?.parent?.release_id==='v0.15.74-e84bf4eed16e9443'&&
|
|
43
|
+
release?.parent?.manifest_sha256==='e84bf4eed16e9443fbd0bf9f0f562e26b01db778647aefcc8b12fd7f48636b47'&&
|
|
44
|
+
release?.parent?.generation_manifest_sha256==='598f896be9ce65e6b0c618e8c8f6eaa2a9d91617a76a146bf3deb385a56d19e7','lineage mismatch');
|
|
45
|
+
required(root&&path.isAbsolute(root)&&closureRoot&&path.isAbsolute(closureRoot),'closure root absent');
|
|
46
|
+
const expected=path.resolve(root,'..','..','testing','r206-final-closure');
|
|
47
|
+
required(path.resolve(closureRoot).toLowerCase()===expected.toLowerCase(),'closure root outside scoped testing folder');
|
|
48
|
+
let closure;try{closure=JSON.parse(await readFile(path.join(closureRoot,'closure.json'),'utf8'));}catch{fail('closure unreadable');}
|
|
49
|
+
required(closure?.schema==='deadbyte.r206-release-closure.v1'&&closure.status==='RELEASE_READY'&&
|
|
50
|
+
closure.version==='0.15.75'&&closure.train==='R206','closure status mismatch');
|
|
51
|
+
required(closure.production_release_id===release.parent.release_id&&closure.production_manifest_sha256===release.parent.manifest_sha256&&
|
|
52
|
+
closure.production_generation_manifest_sha256===release.parent.generation_manifest_sha256,'production predecessor mismatch');
|
|
53
|
+
required(hex64(closure.manifest_sha256)&&closure.manifest_sha256===sha256(await readFile(path.join(root,'MANIFEST.SHA256'))),'final manifest drift');
|
|
54
|
+
required(closure.compact_tools===43&&closure.full_tools===117,'catalog count mismatch');
|
|
55
|
+
required(closure.owner_enrollment==='NOT_RUN'&&closure.production_activation==='NOT_RUN','prepublication closure crossed authority boundary');
|
|
56
|
+
const receipt=JSON.parse((await checkedFile(path.join(closureRoot,'protected-install-receipt.json'),closure.protected_receipt_sha256)).toString('utf8'));
|
|
57
|
+
required(receipt?.status==='PASS'&&receipt.package_version==='0.15.75'&&receipt.source_manifest_sha256===closure.manifest_sha256&&
|
|
58
|
+
receipt.protected_manifest_sha256===closure.manifest_sha256,'protected exact-byte receipt mismatch');
|
|
59
|
+
const focused=(await checkedFile(path.join(closureRoot,'windows-focused.stdout.log'),closure.focused_stdout_sha256)).toString('utf8');
|
|
60
|
+
const full=(await checkedFile(path.join(closureRoot,'windows-full.stdout.log'),closure.full_stdout_sha256)).toString('utf8');
|
|
61
|
+
const verify=(await checkedFile(path.join(closureRoot,'npm-verify.stdout.log'),closure.verify_stdout_sha256)).toString('utf8');
|
|
62
|
+
required(focused.includes('R206_STAGE_PASS=focused'),'focused protected gate incomplete');
|
|
63
|
+
const focusedSummary=tapSummary(focused,'focused');
|
|
64
|
+
required(focusedSummary.fails===0&&focusedSummary.cancelled===0&&focusedSummary.passes>=70&&focusedSummary.skips<=3,'focused regression count mismatch');
|
|
65
|
+
required(full.includes('R206_STAGE_PASS=full'),'full protected gate incomplete');
|
|
66
|
+
const summary=tapSummary(full,'full');
|
|
67
|
+
required(summary.tests>=2200&&summary.passes>=2100&&summary.fails===0&&summary.cancelled===0&&summary.skips<=70&&summary.passes+summary.skips===summary.tests,'full regression count mismatch');
|
|
68
|
+
required(verify.includes('VERIFY-ONLY PIPELINE PASS')&&verify.includes('Artifact isolation gate PASS')&&verify.includes('VERIFIED_TARBALL '),'npm exact-artifact verification incomplete');
|
|
69
|
+
const line=verify.split(/\r?\n/).find(value=>value.startsWith('VERIFIED_TARBALL '));
|
|
70
|
+
let artifact;try{artifact=JSON.parse(line.slice('VERIFIED_TARBALL '.length));}catch{fail('tarball evidence malformed');}
|
|
71
|
+
required(artifact.filename==='deadbyte-mcp-0.15.75.tgz'&&artifact.bytes>0&&artifact.sha256===closure.tarball_sha256&&
|
|
72
|
+
artifact.integrity===closure.tarball_integrity&&artifact.shasum===closure.tarball_shasum,'tarball identity mismatch');
|
|
73
|
+
return Object.freeze({status:'R206_RELEASE_READY_EVIDENCE_BOUND',manifest_sha256:closure.manifest_sha256,
|
|
74
|
+
tarball_sha256:artifact.sha256,tarball_integrity:artifact.integrity,tarball_shasum:artifact.shasum,
|
|
75
|
+
tests:summary.tests,passes:summary.passes,skips:summary.skips});
|
|
76
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// Protected, fixed-scope request generation after Limited migration.
|
|
2
2
|
import {createHash} from 'node:crypto';
|
|
3
|
-
import {execFile} from 'node:child_process';
|
|
4
|
-
import {promisify} from 'node:util';
|
|
5
3
|
import {lstat,open,readFile} from 'node:fs/promises';
|
|
6
4
|
import path from 'node:path';
|
|
7
5
|
import {fileURLToPath} from 'node:url';
|
|
@@ -10,6 +8,9 @@ import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mj
|
|
|
10
8
|
import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
|
|
11
9
|
import {createR188OwnerUacRequest} from '../src/r188-owner-uac.mjs';
|
|
12
10
|
import {createR193LiveMachineEpoch} from '../src/r193-live-owner-subject.mjs';
|
|
11
|
+
import {observeCanonicalController} from '../src/r195-canonical-owner-observation.mjs';
|
|
12
|
+
import {execFile} from 'node:child_process';
|
|
13
|
+
import {promisify} from 'node:util';
|
|
13
14
|
const execFileAsync=promisify(execFile);
|
|
14
15
|
const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
|
|
15
16
|
const STATE='C:\\Users\\DEADBYTE\\.deadbyte-mcp',RUNTIME=path.win32.join(STATE,'runtime');
|
|
@@ -21,6 +22,7 @@ async function main(){
|
|
|
21
22
|
const manifestPath=path.join(ROOT,'MANIFEST.SHA256');
|
|
22
23
|
await inspectTrustedInstallation(['C:\\Program Files\\nodejs\\node.exe',THIS,manifestPath,
|
|
23
24
|
path.join(ROOT,'src','r188-owner-uac.mjs'),path.join(ROOT,'src','r193-live-owner-subject.mjs'),
|
|
25
|
+
path.join(ROOT,'src','r195-canonical-owner-observation.mjs'),
|
|
24
26
|
path.join(ROOT,'src','privileged-install-trust-r89.mjs')]);
|
|
25
27
|
const manifestBytes=await bounded(manifestPath,1024*1024);
|
|
26
28
|
await verifyManifestTreeExact(ROOT,parseManifest(manifestBytes.toString('utf8')));
|
|
@@ -32,10 +34,7 @@ async function main(){
|
|
|
32
34
|
if(!coding.roots?.core?.path||!Array.isArray(autonomous.root_ids)||autonomous.root_ids.length!==1||autonomous.root_ids[0]!=='core')
|
|
33
35
|
throw Error('R193 request policy root is not the bounded core project');
|
|
34
36
|
const env={...process.env,DEADBYTE_CONTROLLER_CONFIG:pointer.config_path,DEADBYTE_CONTROLLER_RUNTIME_ROOT:RUNTIME};
|
|
35
|
-
const
|
|
36
|
-
const {stdout}=await execFileAsync(PS,['-NoLogo','-NoProfile','-NonInteractive','-ExecutionPolicy','Bypass','-File',controller,'status','-Json'],
|
|
37
|
-
{env,windowsHide:true,timeout:20000,maxBuffer:1024*1024,encoding:'utf8'});
|
|
38
|
-
const observation=JSON.parse(stdout);
|
|
37
|
+
const observation=await observeCanonicalController({stateRoot:STATE,powershell:PS,env,execFileAsync});
|
|
39
38
|
if(observation.state!=='ONLINE'||!observation.supervisor?.running)throw Error('R193 request requires ONLINE Limited runtime');
|
|
40
39
|
const machineEpoch=createR193LiveMachineEpoch({activePointer:pointer,controllerObservation:observation});
|
|
41
40
|
const request=createR188OwnerUacRequest({machineEpoch,releaseManifestSha256:sha(manifestBytes),
|
|
@@ -15,6 +15,7 @@ import {buildR193LiveOwnerBoundary} from '../src/r193-live-owner-subject.mjs';
|
|
|
15
15
|
import {approveR193OwnerRequest} from '../src/r193-owner-uac-broker.mjs';
|
|
16
16
|
import {createR186OwnerAnchor} from '../src/r186-owner-anchor.mjs';
|
|
17
17
|
import {inspectR193OwnerSecretAcl} from '../src/r193-owner-secret-acl.mjs';
|
|
18
|
+
import {observeCanonicalController} from '../src/r195-canonical-owner-observation.mjs';
|
|
18
19
|
|
|
19
20
|
const execFileAsync=promisify(execFile);
|
|
20
21
|
const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
|
|
@@ -61,6 +62,7 @@ async function live(request){
|
|
|
61
62
|
const protectedFiles=[NODE,THIS,manifestPath,NATIVE,
|
|
62
63
|
path.join(ROOT,'src','r193-live-owner-subject.mjs'),
|
|
63
64
|
path.join(ROOT,'src','r193-owner-uac-broker.mjs'),
|
|
65
|
+
path.join(ROOT,'src','r195-canonical-owner-observation.mjs'),
|
|
64
66
|
path.join(ROOT,'src','r193-uac-r70-bridge.mjs'),
|
|
65
67
|
path.join(ROOT,'src','r193-owner-secret-acl.mjs'),
|
|
66
68
|
path.join(ROOT,'src','r188-owner-uac.mjs'),
|
|
@@ -77,11 +79,9 @@ async function live(request){
|
|
|
77
79
|
const codingPath=path.win32.join(generation,'coding-policy.json');
|
|
78
80
|
const autonomousPath=path.win32.join(generation,'autonomous-policy.json');
|
|
79
81
|
const configPath=pointer.config_path;
|
|
80
|
-
const controller=path.join(ROOT,'controller','deadbyte-controller.ps1');
|
|
81
82
|
const env={...process.env,DEADBYTE_CONTROLLER_CONFIG:configPath,
|
|
82
83
|
DEADBYTE_CONTROLLER_RUNTIME_ROOT:RUNTIME};
|
|
83
|
-
const observation=await
|
|
84
|
-
'-ExecutionPolicy','Bypass','-File',controller,'status','-Json'],{env});
|
|
84
|
+
const observation=await observeCanonicalController({stateRoot:STATE,powershell:PS,env,execFileAsync});
|
|
85
85
|
const supervisor=JSON.parse((await bounded(path.win32.join(RUNTIME,'supervisor.instance.json'),64*1024)).toString('utf8'));
|
|
86
86
|
const sources={bridge:observation.bridge,core:observation.core,cloud:observation.cloud,supervisor};
|
|
87
87
|
const processReports={};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Read-only bounded stdin candidate comparison. Does not promote, publish, or grant authority.
|
|
2
|
+
import { evaluateCandidateSelectionR205 } from '../src/candidate-selection-r205.mjs';
|
|
3
|
+
|
|
4
|
+
const MAX_BYTES=64*1024;
|
|
5
|
+
let length=0;
|
|
6
|
+
const parts=[];
|
|
7
|
+
try{
|
|
8
|
+
for await (const chunk of process.stdin){
|
|
9
|
+
length+=chunk.length;
|
|
10
|
+
if(length>MAX_BYTES)throw Error('R205_INPUT_LIMIT_EXCEEDED');
|
|
11
|
+
parts.push(chunk);
|
|
12
|
+
}
|
|
13
|
+
if(length<1)throw Error('R205_INPUT_EMPTY');
|
|
14
|
+
const raw=Buffer.concat(parts).toString('utf8');
|
|
15
|
+
const parsed=JSON.parse(raw);
|
|
16
|
+
const result=evaluateCandidateSelectionR205(parsed);
|
|
17
|
+
process.stdout.write(JSON.stringify(result)+'\n');
|
|
18
|
+
if(result.state!=='PROVISIONAL_CANDIDATE')process.exitCode=2;
|
|
19
|
+
}catch(error){
|
|
20
|
+
process.stderr.write('R205_SELECTION_REFUSED '+String(error?.message??error)+'\n');
|
|
21
|
+
process.exitCode=3;
|
|
22
|
+
}
|