deadbyte-mcp 0.15.41 → 0.15.43
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/DEADBYTE-MCP.cmd +8 -4
- package/MANIFEST.SHA256 +88 -43
- package/PROVENANCE.json +66 -15
- package/README.txt +27 -18
- package/RELEASE.json +55 -15
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +117 -14
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +132 -12
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R65-AUTHORITY-CONTINUITY-DESIGN.json +27 -0
- package/docs/R65-REFERENCE-GAP-MATRIX.json +22 -0
- package/package.json +6 -4
- package/scripts/deploy-r48.mjs +123 -7
- package/scripts/gate-windows-r65-prepublish.ps1 +65 -0
- package/scripts/gate-windows-r66-prepublish.ps1 +65 -0
- package/scripts/npm-publication-r65.mjs +139 -0
- package/scripts/npm-release-r48.mjs +56 -37
- package/scripts/r65-canonical-full.mjs +45 -0
- package/scripts/r65-focused.mjs +37 -0
- package/scripts/verify-r65-parent-source.mjs +75 -0
- package/src/activation-continuity-engine-r65.mjs +225 -0
- package/src/activation-lock-r65.mjs +155 -0
- package/src/activation-preflight-r65.mjs +197 -0
- package/src/authority-continuity-r65.mjs +541 -0
- package/src/authority-epoch-cli-r65.mjs +10 -0
- package/src/autonomous-policy.mjs +7 -3
- package/src/coding-plane.mjs +12 -3
- package/src/desktop-policy-r40.mjs +6 -3
- package/src/doctor-runtime-r58.mjs +3 -1
- package/src/doctor-transactions-r58.mjs +1 -1
- package/src/host-plane.mjs +9 -3
- package/src/process-policy.mjs +7 -4
- package/src/remote-authority.mjs +10 -1
- package/src/runtime-update.mjs +15 -5
- package/src/version.mjs +1 -1
- package/test/audit-context.test.mjs +15 -4
- package/test/autonomous-local-supervisor.test.mjs +7 -6
- package/test/autonomous-supervisor-integration.test.mjs +8 -7
- package/test/capability-resolver.test.mjs +11 -5
- package/test/codex-autonomous-r44.test.mjs +7 -6
- package/test/coding-observation.test.mjs +4 -3
- package/test/commander-real-parity-r47.test.mjs +5 -4
- package/test/commander-torture-r47.test.mjs +5 -4
- package/test/desktop-policy-r40.test.mjs +6 -4
- package/test/desktop-runtime-r40.test.mjs +8 -3
- package/test/host-inline-r45.test.mjs +4 -3
- package/test/machine-fs-runtime.test.mjs +4 -3
- package/test/process-longrun-r36.test.mjs +3 -2
- package/test/process-policy.test.mjs +10 -6
- package/test/process-runtime.test.mjs +9 -6
- package/test/r52-host-revocation.test.mjs +1 -0
- package/test/r58-doctor-runtime.test.mjs +18 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r64-release-contract.test.mjs +2 -1
- package/test/r65-activation-lock-recovery.test.mjs +72 -0
- package/test/r65-activation-lock.test.mjs +59 -0
- package/test/r65-activation-orchestration.test.mjs +179 -0
- package/test/r65-activation-preflight.test.mjs +35 -0
- package/test/r65-authority-continuity-decision.test.mjs +58 -0
- package/test/r65-authority-durable-policy-binding.test.mjs +34 -0
- package/test/r65-authority-epoch-cli.test.mjs +125 -0
- package/test/r65-authority-epoch-races.test.mjs +87 -0
- package/test/r65-authority-epoch-recovery.test.mjs +82 -0
- package/test/r65-authority-epoch-store.test.mjs +94 -0
- package/test/r65-authority-fixture.mjs +41 -0
- package/test/r65-authority-grant-capture.test.mjs +37 -0
- package/test/r65-authority-observation-epoch.test.mjs +25 -0
- package/test/r65-authority-policy-envelope.test.mjs +46 -0
- package/test/r65-authority-restored-safe.test.mjs +75 -0
- package/test/r65-authority-runtime-epoch.test.mjs +115 -0
- package/test/r65-authority-runtime-policy-binding.test.mjs +29 -0
- package/test/r65-authority-test-trust.mjs +20 -0
- package/test/r65-cli-invocation.test.mjs +38 -0
- package/test/r65-controller-authority-epoch-live.test.mjs +100 -0
- package/test/r65-controller-authority-epoch.test.mjs +37 -0
- package/test/r65-deploy-preflight.test.mjs +55 -0
- package/test/r65-epoch-native-activation-integration.test.mjs +141 -0
- package/test/r65-epoch-native-continuity-engine.test.mjs +112 -0
- package/test/r65-epoch-native-cross-plane.test.mjs +95 -0
- package/test/r65-legacy-authority-migration.test.mjs +63 -0
- package/test/r65-legacy-auto-restore-rejection.test.mjs +17 -0
- package/test/r65-npm-publication.test.mjs +114 -0
- package/test/r65-parent-source-verifier.test.mjs +63 -0
- package/test/r65-release-contract.test.mjs +75 -0
- package/test/r65-transaction-precondition.test.mjs +36 -0
- package/test/r66-release-contract.test.mjs +56 -0
- package/test/remote-session-cli.test.mjs +6 -6
- package/test/standing-grants.test.mjs +20 -4
|
@@ -937,6 +937,47 @@ function Assert-PolicyRootsAvailable($Policy, [string]$Plane) {
|
|
|
937
937
|
return $rootIds
|
|
938
938
|
}
|
|
939
939
|
|
|
940
|
+
function Get-AuthorityEpochStatus($Cfg, [string]$Plane, [string]$GrantFile, [string]$GrantNonce) {
|
|
941
|
+
if ([string]::IsNullOrWhiteSpace($GrantNonce) -or $GrantNonce -cnotmatch '^[0-9a-f]{64}$') {
|
|
942
|
+
return [pscustomobject]@{ Trusted=$false; Reason='epoch-grant-nonce-invalid'; Seq=$null; Action=$null; EventSha256=$null }
|
|
943
|
+
}
|
|
944
|
+
try {
|
|
945
|
+
$verified = Invoke-AuthorityEpochCommand $Cfg $Plane 'status' $GrantFile
|
|
946
|
+
if (-not $verified.trusted) {
|
|
947
|
+
return [pscustomobject]@{ Trusted=$false; Reason=[string]$verified.reason; Seq=$verified.seq; Action=$verified.action; EventSha256=$verified.event_sha256 }
|
|
948
|
+
}
|
|
949
|
+
return [pscustomobject]@{ Trusted=$true; Reason=[string]$verified.reason; Seq=$verified.seq; Action=$verified.action; EventSha256=$verified.event_sha256 }
|
|
950
|
+
} catch {
|
|
951
|
+
return [pscustomobject]@{ Trusted=$false; Reason='authority-epoch-verifier-unavailable'; Seq=$null; Action=$null; EventSha256=$null }
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
function Invoke-AuthorityEpochCommand($Cfg, [string]$Plane, [string]$Action, [string]$GrantFile, [string]$UpdateId = '', [string]$ExpectedHead = '') {
|
|
956
|
+
$cli = Join-Path ([string]$Cfg.CoreRoot) 'src\authority-epoch-cli-r65.mjs'
|
|
957
|
+
if (-not (Test-Path -LiteralPath $cli -PathType Leaf)) { Fail "authority epoch CLI missing: $cli" }
|
|
958
|
+
$node = [string]$Cfg.Bridge.FilePath
|
|
959
|
+
if ([string]::IsNullOrWhiteSpace($node) -or -not (Test-Path -LiteralPath $node -PathType Leaf)) { Fail 'authority epoch Node executable unavailable' }
|
|
960
|
+
$policyFile = switch ($Plane) {
|
|
961
|
+
'process' { [string]$Cfg.ProcessPolicyFile }
|
|
962
|
+
'coding' { [string]$Cfg.CodingPolicyFile }
|
|
963
|
+
'autonomous' { [string]$Cfg.AutonomousPolicyFile }
|
|
964
|
+
'desktop' { [string]$Cfg.DesktopPolicyFile }
|
|
965
|
+
'host' { [string]$Cfg.HostPolicyFile }
|
|
966
|
+
default { Fail "authority epoch plane invalid: $Plane" }
|
|
967
|
+
}
|
|
968
|
+
if ([string]::IsNullOrWhiteSpace($policyFile) -or -not (Test-Path -LiteralPath $policyFile -PathType Leaf)) { Fail "authority epoch policy unavailable for $Plane" }
|
|
969
|
+
$args = @($cli, $Action, '--plane', $Plane, '--grant-file', $GrantFile, '--policy-file', $policyFile)
|
|
970
|
+
if ($Action -in @('transaction-revoke','transaction-restore')) {
|
|
971
|
+
if ([string]::IsNullOrWhiteSpace($UpdateId) -or $ExpectedHead -cnotmatch '^[0-9a-f]{64}$') { Fail 'authority epoch transaction binding invalid' }
|
|
972
|
+
$args += @('--update-id', $UpdateId, '--expected-head', $ExpectedHead)
|
|
973
|
+
}
|
|
974
|
+
$output = @(& $node @args)
|
|
975
|
+
$exit = $LASTEXITCODE
|
|
976
|
+
if ($exit -ne 0) { Fail "authority epoch command '$Action' failed for $Plane (exit=$exit)" }
|
|
977
|
+
try { return (($output -join [Environment]::NewLine) | ConvertFrom-Json) }
|
|
978
|
+
catch { Fail "authority epoch command '$Action' returned invalid JSON for $Plane" }
|
|
979
|
+
}
|
|
980
|
+
|
|
940
981
|
function Get-HostPolicyMetadata($Cfg) {
|
|
941
982
|
if ([string]::IsNullOrWhiteSpace([string]$Cfg.HostPolicyFile)) { Fail 'privileged host plane is not configured' }
|
|
942
983
|
$policyPath = [string]$Cfg.HostPolicyFile
|
|
@@ -961,7 +1002,10 @@ function Get-HostArmStatus($Cfg) {
|
|
|
961
1002
|
try { $arm = Get-Content -LiteralPath $meta.ArmFile -Raw -Encoding UTF8 | ConvertFrom-Json } catch { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='invalid-grant' } }
|
|
962
1003
|
if ($arm.schema -ne 'deadbyte.host-grant.v2') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
|
|
963
1004
|
if ([string]$arm.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
|
|
964
|
-
return [pscustomobject]@{ Configured=$true; Armed=$
|
|
1005
|
+
if ([string]$arm.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
|
|
1006
|
+
$epoch = Get-AuthorityEpochStatus $Cfg 'host' $meta.ArmFile ([string]$arm.instance_nonce)
|
|
1007
|
+
if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
|
|
1008
|
+
return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
|
|
965
1009
|
}
|
|
966
1010
|
|
|
967
1011
|
function Arm-Host($Cfg) {
|
|
@@ -981,15 +1025,23 @@ function Arm-Host($Cfg) {
|
|
|
981
1025
|
$tmp = $meta.ArmFile + '.tmp'
|
|
982
1026
|
$body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
|
|
983
1027
|
Move-Item -LiteralPath $tmp -Destination $meta.ArmFile -Force
|
|
1028
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'host' 'grant' $meta.ArmFile | Out-Null }
|
|
1029
|
+
catch {
|
|
1030
|
+
Remove-Item -LiteralPath $meta.ArmFile -Force -ErrorAction SilentlyContinue
|
|
1031
|
+
throw
|
|
1032
|
+
}
|
|
984
1033
|
Write-Host 'PRIVILEGED HOST PLANE ENABLED UNTIL EXPLICIT REVOKE'
|
|
985
1034
|
}
|
|
986
1035
|
|
|
987
1036
|
function Disarm-Host($Cfg) {
|
|
988
1037
|
$meta = Get-HostPolicyMetadata $Cfg
|
|
1038
|
+
$epochError = $null
|
|
989
1039
|
if (Test-Path -LiteralPath $meta.ArmFile) {
|
|
990
|
-
|
|
1040
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'host' 'user-revoke' $meta.ArmFile | Out-Null } catch { $epochError = $_.Exception }
|
|
1041
|
+
Remove-Item -LiteralPath $meta.ArmFile -Force -ErrorAction SilentlyContinue
|
|
991
1042
|
}
|
|
992
1043
|
if (Test-Path -LiteralPath $meta.ArmFile) { throw 'Host authority revocation failed: grant remains present' }
|
|
1044
|
+
if ($null -ne $epochError) { throw $epochError }
|
|
993
1045
|
Write-Host 'PRIVILEGED HOST PLANE DISARMED'
|
|
994
1046
|
}
|
|
995
1047
|
|
|
@@ -1021,10 +1073,13 @@ function Get-ProcessGrantStatus($Cfg) {
|
|
|
1021
1073
|
try { $grant = Get-Content -LiteralPath $meta.GrantFile -Raw -Encoding UTF8 | ConvertFrom-Json } catch { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='invalid-grant' } }
|
|
1022
1074
|
if ($grant.schema -ne 'deadbyte.process-grant.v1') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
|
|
1023
1075
|
if ([string]$grant.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
|
|
1076
|
+
if ([string]$grant.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
|
|
1024
1077
|
$profiles = @($grant.profile_ids); $roots = @($grant.root_ids)
|
|
1025
1078
|
if ($profiles.Count -lt 1 -or @($profiles | Where-Object { $_ -notin $meta.ProfileIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='profiles-invalid' } }
|
|
1026
1079
|
if ($roots.Count -lt 1 -or @($roots | Where-Object { $_ -notin $meta.RootIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='roots-invalid' } }
|
|
1027
|
-
|
|
1080
|
+
$epoch = Get-AuthorityEpochStatus $Cfg 'process' $meta.GrantFile ([string]$grant.instance_nonce)
|
|
1081
|
+
if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
|
|
1082
|
+
return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
|
|
1028
1083
|
}
|
|
1029
1084
|
|
|
1030
1085
|
function Arm-Process($Cfg) {
|
|
@@ -1045,12 +1100,23 @@ function Arm-Process($Cfg) {
|
|
|
1045
1100
|
$tmp = $meta.GrantFile + '.tmp'
|
|
1046
1101
|
$body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
|
|
1047
1102
|
Move-Item -LiteralPath $tmp -Destination $meta.GrantFile -Force
|
|
1103
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'process' 'grant' $meta.GrantFile | Out-Null }
|
|
1104
|
+
catch {
|
|
1105
|
+
Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
|
|
1106
|
+
throw
|
|
1107
|
+
}
|
|
1048
1108
|
Write-Host 'PROCESS PLANE ENABLED UNTIL EXPLICIT REVOKE'
|
|
1049
1109
|
}
|
|
1050
1110
|
|
|
1051
1111
|
function Disarm-Process($Cfg) {
|
|
1052
1112
|
$meta = Get-ProcessPolicyMetadata $Cfg
|
|
1053
|
-
|
|
1113
|
+
$epochError = $null
|
|
1114
|
+
if (Test-Path -LiteralPath $meta.GrantFile -PathType Leaf) {
|
|
1115
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'process' 'user-revoke' $meta.GrantFile | Out-Null } catch { $epochError = $_.Exception }
|
|
1116
|
+
Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
|
|
1117
|
+
}
|
|
1118
|
+
if (Test-Path -LiteralPath $meta.GrantFile) { throw 'Process authority revocation failed: grant remains present' }
|
|
1119
|
+
if ($null -ne $epochError) { throw $epochError }
|
|
1054
1120
|
Write-Host 'PROCESS PLANE DISARMED'
|
|
1055
1121
|
}
|
|
1056
1122
|
|
|
@@ -1080,9 +1146,12 @@ function Get-CodingLeaseStatus($Cfg) {
|
|
|
1080
1146
|
try { $lease = Get-Content -LiteralPath $meta.LeaseFile -Raw -Encoding UTF8 | ConvertFrom-Json } catch { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='invalid-grant' } }
|
|
1081
1147
|
if ($lease.schema -ne 'deadbyte.coding-grant.v2') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
|
|
1082
1148
|
if ([string]$lease.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
|
|
1149
|
+
if ([string]$lease.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
|
|
1083
1150
|
$roots = @($lease.root_ids)
|
|
1084
1151
|
if ($roots.Count -lt 1 -or @($roots | Where-Object { $_ -notin $meta.RootIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='roots-invalid' } }
|
|
1085
|
-
|
|
1152
|
+
$epoch = Get-AuthorityEpochStatus $Cfg 'coding' $meta.LeaseFile ([string]$lease.instance_nonce)
|
|
1153
|
+
if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
|
|
1154
|
+
return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
|
|
1086
1155
|
}
|
|
1087
1156
|
|
|
1088
1157
|
function Arm-Coding($Cfg) {
|
|
@@ -1103,13 +1172,27 @@ function Arm-Coding($Cfg) {
|
|
|
1103
1172
|
$tmp = $meta.LeaseFile + '.tmp'
|
|
1104
1173
|
$body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
|
|
1105
1174
|
Move-Item -LiteralPath $tmp -Destination $meta.LeaseFile -Force
|
|
1175
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'coding' 'grant' $meta.LeaseFile | Out-Null }
|
|
1176
|
+
catch {
|
|
1177
|
+
Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
|
|
1178
|
+
throw
|
|
1179
|
+
}
|
|
1106
1180
|
Write-Host 'CODING PLANE ENABLED UNTIL EXPLICIT REVOKE'
|
|
1107
1181
|
}
|
|
1108
1182
|
|
|
1109
1183
|
function Disarm-Coding($Cfg) {
|
|
1110
1184
|
$meta = Get-CodingPolicyMetadata $Cfg
|
|
1111
|
-
|
|
1112
|
-
|
|
1185
|
+
$epochError = $null
|
|
1186
|
+
if (Test-Path -LiteralPath $meta.LeaseFile -PathType Leaf) {
|
|
1187
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'coding' 'user-revoke' $meta.LeaseFile | Out-Null } catch { $epochError = $_.Exception }
|
|
1188
|
+
Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
|
|
1189
|
+
}
|
|
1190
|
+
try { Disarm-Autonomous $Cfg -Quiet } catch {
|
|
1191
|
+
if ($null -eq $epochError) { $epochError = $_.Exception }
|
|
1192
|
+
else { Write-Warning "autonomous lease cleanup failed after coding revocation: $($_.Exception.Message)" }
|
|
1193
|
+
}
|
|
1194
|
+
if (Test-Path -LiteralPath $meta.LeaseFile) { throw 'Coding authority revocation failed: grant remains present' }
|
|
1195
|
+
if ($null -ne $epochError) { throw $epochError }
|
|
1113
1196
|
Write-Host 'CODING PLANE DISARMED; AUTONOMOUS AUTHORITY REVOKED'
|
|
1114
1197
|
}
|
|
1115
1198
|
|
|
@@ -1145,9 +1228,12 @@ function Get-AutonomousLeaseStatus($Cfg) {
|
|
|
1145
1228
|
if ($lease.schema -ne 'deadbyte.autonomous-grant.v2') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
|
|
1146
1229
|
if ([string]$lease.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
|
|
1147
1230
|
if ([string]$lease.coding_policy_sha256 -ne [string]$meta.CodingPolicySha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='coding-policy-digest' } }
|
|
1231
|
+
if ([string]$lease.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
|
|
1148
1232
|
$roots = @($lease.root_ids)
|
|
1149
1233
|
if ($roots.Count -lt 1 -or @($roots | Where-Object { $_ -notin $meta.RootIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='roots-invalid' } }
|
|
1150
|
-
|
|
1234
|
+
$epoch = Get-AuthorityEpochStatus $Cfg 'autonomous' $meta.LeaseFile ([string]$lease.instance_nonce)
|
|
1235
|
+
if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
|
|
1236
|
+
return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
|
|
1151
1237
|
}
|
|
1152
1238
|
|
|
1153
1239
|
function Arm-Autonomous($Cfg) {
|
|
@@ -1164,13 +1250,24 @@ function Arm-Autonomous($Cfg) {
|
|
|
1164
1250
|
$tmp = $meta.LeaseFile + '.tmp'
|
|
1165
1251
|
$body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
|
|
1166
1252
|
Move-Item -LiteralPath $tmp -Destination $meta.LeaseFile -Force
|
|
1253
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'autonomous' 'grant' $meta.LeaseFile | Out-Null }
|
|
1254
|
+
catch {
|
|
1255
|
+
Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
|
|
1256
|
+
throw
|
|
1257
|
+
}
|
|
1167
1258
|
Write-Host 'AUTONOMOUS PLANE ENABLED UNTIL EXPLICIT REVOKE'
|
|
1168
1259
|
}
|
|
1169
1260
|
|
|
1170
1261
|
function Disarm-Autonomous($Cfg, [switch]$Quiet) {
|
|
1171
1262
|
if ([string]::IsNullOrWhiteSpace([string]$Cfg.AutonomousPolicyFile)) { return }
|
|
1172
1263
|
$meta = Get-AutonomousPolicyMetadata $Cfg
|
|
1173
|
-
|
|
1264
|
+
$epochError = $null
|
|
1265
|
+
if (Test-Path -LiteralPath $meta.LeaseFile -PathType Leaf) {
|
|
1266
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'autonomous' 'user-revoke' $meta.LeaseFile | Out-Null } catch { $epochError = $_.Exception }
|
|
1267
|
+
Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
|
|
1268
|
+
}
|
|
1269
|
+
if (Test-Path -LiteralPath $meta.LeaseFile) { throw 'Autonomous authority revocation failed: grant remains present' }
|
|
1270
|
+
if ($null -ne $epochError) { throw $epochError }
|
|
1174
1271
|
if (-not $Quiet) { Write-Host 'AUTONOMOUS PLANE DISARMED' }
|
|
1175
1272
|
}
|
|
1176
1273
|
|
|
@@ -1244,7 +1341,9 @@ function Get-DesktopGrantStatus($Cfg) {
|
|
|
1244
1341
|
$unique = @($actions | Sort-Object -Unique)
|
|
1245
1342
|
if ($actions.Count -lt 1 -or $actions.Count -ne $unique.Count) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='actions-invalid'; ActionKinds=@() } }
|
|
1246
1343
|
if (@($actions | Where-Object { $_ -notin $meta.ActionKinds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='actions-outside-policy'; ActionKinds=@() } }
|
|
1247
|
-
|
|
1344
|
+
$epoch = Get-AuthorityEpochStatus $Cfg 'desktop' $meta.GrantFile ([string]$grant.instance_nonce)
|
|
1345
|
+
if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason; ActionKinds=$actions } }
|
|
1346
|
+
return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; ActionKinds=$actions; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
|
|
1248
1347
|
}
|
|
1249
1348
|
|
|
1250
1349
|
function Arm-Desktop($Cfg) {
|
|
@@ -1265,13 +1364,24 @@ function Arm-Desktop($Cfg) {
|
|
|
1265
1364
|
$tmp = $meta.GrantFile + '.tmp'
|
|
1266
1365
|
$body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
|
|
1267
1366
|
Move-Item -LiteralPath $tmp -Destination $meta.GrantFile -Force
|
|
1367
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'desktop' 'grant' $meta.GrantFile | Out-Null }
|
|
1368
|
+
catch {
|
|
1369
|
+
Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
|
|
1370
|
+
throw
|
|
1371
|
+
}
|
|
1268
1372
|
Write-Host ("DESKTOP PLANE ENABLED UNTIL EXPLICIT REVOKE [{0}]" -f ($meta.ActionKinds -join ','))
|
|
1269
1373
|
}
|
|
1270
1374
|
|
|
1271
1375
|
function Disarm-Desktop($Cfg, [switch]$Quiet) {
|
|
1272
1376
|
$grantFile = Get-DesktopGrantFileForRevoke $Cfg
|
|
1273
1377
|
if ([string]::IsNullOrWhiteSpace([string]$grantFile)) { return }
|
|
1274
|
-
|
|
1378
|
+
$epochError = $null
|
|
1379
|
+
if (Test-Path -LiteralPath $grantFile -PathType Leaf) {
|
|
1380
|
+
try { Invoke-AuthorityEpochCommand $Cfg 'desktop' 'user-revoke' $grantFile | Out-Null } catch { $epochError = $_.Exception }
|
|
1381
|
+
Remove-Item -LiteralPath $grantFile -Force -ErrorAction SilentlyContinue
|
|
1382
|
+
}
|
|
1383
|
+
if (Test-Path -LiteralPath $grantFile) { throw 'Desktop authority revocation failed: grant remains present' }
|
|
1384
|
+
if ($null -ne $epochError) { throw $epochError }
|
|
1275
1385
|
if (-not $Quiet) { Write-Host 'DESKTOP PLANE DISARMED' }
|
|
1276
1386
|
}
|
|
1277
1387
|
|
|
@@ -1346,7 +1456,17 @@ function Convert-OwnedObservation($Owned) {
|
|
|
1346
1456
|
}
|
|
1347
1457
|
|
|
1348
1458
|
function Convert-AuthorityObservation($Authority) {
|
|
1349
|
-
[ordered]@{ configured=[bool]$Authority.Configured; armed=[bool]$Authority.Armed; reason=(Get-BoundedObservationReason $Authority.Reason) }
|
|
1459
|
+
$out = [ordered]@{ configured=[bool]$Authority.Configured; armed=[bool]$Authority.Armed; reason=(Get-BoundedObservationReason $Authority.Reason) }
|
|
1460
|
+
$seqProp = $Authority.PSObject.Properties['EpochSeq']
|
|
1461
|
+
$shaProp = $Authority.PSObject.Properties['EpochSha256']
|
|
1462
|
+
if ($null -ne $seqProp -or $null -ne $shaProp) {
|
|
1463
|
+
if ($null -eq $seqProp -or $null -eq $shaProp -or [int64]$seqProp.Value -lt 1 -or [string]$shaProp.Value -cnotmatch '^[0-9a-f]{64}$') {
|
|
1464
|
+
Fail 'authority epoch observation incomplete or invalid'
|
|
1465
|
+
}
|
|
1466
|
+
$out['epoch_seq'] = [int64]$seqProp.Value
|
|
1467
|
+
$out['epoch_sha256'] = [string]$shaProp.Value
|
|
1468
|
+
}
|
|
1469
|
+
return $out
|
|
1350
1470
|
}
|
|
1351
1471
|
|
|
1352
1472
|
function Get-DownstreamCoreObservation($Cfg, $Bridge) {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "deadbyte.process-policy.v1",
|
|
3
3
|
"enabled": true,
|
|
4
|
-
"grant_file": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.
|
|
5
|
-
"state_dir": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.
|
|
4
|
+
"grant_file": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.43-r66\\controller\\runtime\\process-grant.json",
|
|
5
|
+
"state_dir": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.43-r66\\controller\\runtime\\process-state",
|
|
6
6
|
"native_host": {
|
|
7
|
-
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.
|
|
7
|
+
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.43-r66\\bin\\deadbyte-process-host.exe",
|
|
8
8
|
"sha256": "daf9cfb371bee88cafbf5597eaa507fec504dbe0b0ddd40d0c3c2e02817f49e4"
|
|
9
9
|
},
|
|
10
10
|
"roots": {
|
|
11
11
|
"core": {
|
|
12
|
-
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.
|
|
12
|
+
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.43-r66",
|
|
13
13
|
"deny_paths": [
|
|
14
14
|
"node_modules",
|
|
15
15
|
"controller/runtime",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "deadbyte.r65-authority-continuity-design.v1",
|
|
3
|
+
"status": "PARTIAL_IMPLEMENTATION",
|
|
4
|
+
"authority": "Current R65 candidate source and read-only R64 generation policies; production remains immutable.",
|
|
5
|
+
"observed_contracts": {
|
|
6
|
+
"controller": "controller/deadbyte-controller.ps1 Get-*GrantStatus checks schema and policy_sha256; Process/Coding/Autonomous/Desktop additionally carry scope and instance_nonce; Host carries nonce but no explicit scope.",
|
|
7
|
+
"process": "src/process-policy.mjs rechecks policy hash, nonce, profile_ids and root_ids; grant schema deadbyte.process-grant.v1.",
|
|
8
|
+
"coding": "src/coding-plane.mjs rechecks policy hash, nonce and root_ids; standing grant schema deadbyte.coding-grant.v2.",
|
|
9
|
+
"autonomous": "controller/deadbyte-controller.ps1 requires a Coding grant, coding_policy_sha256 and root_ids; grant schema deadbyte.autonomous-grant.v2.",
|
|
10
|
+
"desktop": "src/desktop-policy-r40.mjs and controller validate policy hash, nonce and action_kinds; grant schema deadbyte.desktop-grant.v1.",
|
|
11
|
+
"host": "controller/deadbyte-controller.ps1 validates policy hash; grant schema deadbyte.host-grant.v2 includes instance_nonce and granted_at_utc but no scoped IDs.",
|
|
12
|
+
"revocation": "R64 controller arm/disarm replace/delete grant files but expose no durable monotonic per-plane revocation epoch or transaction-owned temporary revoke. An absent grant after temporary revoke cannot prove no independent user revoke occurred."
|
|
13
|
+
},
|
|
14
|
+
"selected_method": {
|
|
15
|
+
"policy_envelope": "Derive canonical authority-bearing fields from each known policy schema; omit only operational grant/evidence storage paths and presentation descriptions. Unknown fields fail closed. Raw policy SHA remains evidence, not the sole ceiling comparator.",
|
|
16
|
+
"comparison": "EQUAL, NARROWER, WIDER, UNVERIFIED. Added capabilities, relaxed deny rules and larger ceilings are WIDER. Changed executable/native pins or disjoint roots are UNVERIFIED. Both deny automatic restoration.",
|
|
17
|
+
"r64_predecessor_continuity": "Because R64 has no durable revocation epoch, an armed predecessor cannot receive automatic cross-generation restoration. Outcome must be REAUTH_REQUIRED and disarmed unless a later explicit user grant is observed.",
|
|
18
|
+
"updater_boundary": "One restoration engine is required. The current inner updater's Process/Coding/Autonomous re-arm must be disabled or constrained by a verified continuity plan before any R65 activation with standing authority is permitted.",
|
|
19
|
+
"current_safety_guard": "scripts/deploy-r48.mjs --preflight returns AUTHORITY_POLICY_UNVERIFIED for armed vectors before opening an update transaction. This guard must not be removed until continuity integration is proven."
|
|
20
|
+
},
|
|
21
|
+
"acceptance_open": [
|
|
22
|
+
"Read-only capture of exact grant bytes and scope, bound to predecessor release/generation and candidate manifest.",
|
|
23
|
+
"Durable transaction-owned revocation epoch with crash-safe exclusion of external revocation/replacement.",
|
|
24
|
+
"Single restoration decision path across updater and deploy; separate runtime and authority outcomes.",
|
|
25
|
+
"Isolated end-to-end activation, interruption, rollback and independent receipt verification."
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "deadbyte.r65-reference-gap-matrix.v1",
|
|
3
|
+
"purpose": "Release/control-plane mechanisms only; donor source is read-only and no donor bytes are copied.",
|
|
4
|
+
"license_review": {
|
|
5
|
+
"better-remote-commander": "package.json declares MIT; no source bytes copied",
|
|
6
|
+
"cua": "pyproject.toml declares MIT; no source bytes copied",
|
|
7
|
+
"desktop-commander": "root LICENSE declares MIT; no source bytes copied",
|
|
8
|
+
"open-remote-mcp": "no root LICENSE or package declaration confirmed in this pass; architecture principle only, no source bytes copied",
|
|
9
|
+
"remcp": "package.json declares MIT; no source bytes copied",
|
|
10
|
+
"secure-host-mcp": "package.json declares MIT; no source bytes copied",
|
|
11
|
+
"winremote-mcp": "pyproject.toml declares MIT; no source bytes copied"
|
|
12
|
+
},
|
|
13
|
+
"decisions": [
|
|
14
|
+
{"reference":"better-remote-commander","evidence_path":"packages/agent/src/transport/ws-client.ts","mechanism":"bounded exponential reconnect and explicit unauthorized branch","deadbyte_comparison":"R64 has remote guardian and recovery, but npm visibility after accepted publish was not reconciled","decision":"ADAPT","r65_action":"bounded registry availability polling and terminal/unknown classification; no relay or multi-device import"},
|
|
15
|
+
{"reference":"cua","evidence_path":"rfcs/3007-cua-driver-lifecycle-sessions.md","mechanism":"idempotent lifecycle cleanup and host-held resume identity","deadbyte_comparison":"DEADBYTE has owned supervisor and signed transaction evidence; deterministic precondition failures still need terminality","decision":"ADAPT","r65_action":"preflight/transaction boundary tests and exact ownership preservation; no desktop redesign"},
|
|
16
|
+
{"reference":"desktop-commander","evidence_path":"dist/utils/toolHistory.js","mechanism":"bounded presentation history and trim target","deadbyte_comparison":"DEADBYTE evidence durability and bounded LIVELOG are stronger for authoritative release receipts","decision":"KEEP-OURS","r65_action":"do not batch or trim authoritative transaction journals"},
|
|
17
|
+
{"reference":"open-remote-mcp","evidence_path":"docs/ARCHITECTURE.md","mechanism":"relay policy may narrow but local device remains final enforcement","deadbyte_comparison":"DEADBYTE already enforces local authority planes; activation restore must preserve exact vector","decision":"KEEP-OURS","r65_action":"regress no-widening during activation orchestration"},
|
|
18
|
+
{"reference":"remcp","evidence_path":"packages/client/test/cli-update-runtime.test.mjs","mechanism":"separate client/runtime update and coherence checks","deadbyte_comparison":"DEADBYTE has immutable slots and version binding; exact-version npm invocation needs reproducible tests","decision":"ADAPT","r65_action":"CLI/package resolution matrix and isolated install test without runtime dependency"},
|
|
19
|
+
{"reference":"secure-host-mcp","evidence_path":"src/runtime.ts","mechanism":"explicit bounded runtime state vocabulary","deadbyte_comparison":"DEADBYTE has verified identities but activation preflight was not a separate read-only state classification","decision":"ADAPT","r65_action":"typed preflight classification; reject dirty/unknown state before mutation"},
|
|
20
|
+
{"reference":"winremote-mcp","evidence_path":"src/winremote/process_mgr.py","mechanism":"Windows process enumeration with stale-process handling","deadbyte_comparison":"DEADBYTE ledger binds PID to creation identity and hash, stronger than PID/name kill paths","decision":"SKIP","r65_action":"retain verified ownership; never adopt caller-selected PID/name termination"}
|
|
21
|
+
]
|
|
22
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deadbyte-mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.43",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Authenticated MCP agentic runtime with signed skills, persistent model backends, identity-bound remote devices, durable job supervision, immutable release slots, and separately revocable machine authority.",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"node": ">=22"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "node --test test/*.test.mjs",
|
|
11
|
+
"test": "node --test --test-concurrency=4 test/*.test.mjs",
|
|
12
12
|
"manifest:write": "node scripts/release-manifest.mjs write",
|
|
13
13
|
"manifest:verify": "node scripts/release-manifest.mjs verify",
|
|
14
14
|
"r41:parent:verify": "node scripts/verify-r41-parent.mjs",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
|
|
43
43
|
"contained:smoke": "node src/contained-smoke.mjs",
|
|
44
44
|
"mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
|
|
45
|
-
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-
|
|
45
|
+
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r66-prepublish.ps1",
|
|
46
46
|
"authority:smoke": "node src/authority-smoke.mjs",
|
|
47
47
|
"mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
|
|
48
48
|
"mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
|
|
@@ -89,7 +89,9 @@
|
|
|
89
89
|
"r61:focused:test": "node --test --test-concurrency=1 test/r61-release-contract.test.mjs test/r61-release-bridge-binding.test.mjs test/r61-control-lane.test.mjs test/r61-live-timeline-bounds.test.mjs test/r61-npm-artifact-identity.test.mjs test/remote-live-log-r37.test.mjs test/bridge-runtime-r59.test.mjs test/commander-schema-differential-r48.test.mjs test/package-boundary.test.mjs test/r60-bridge-dispatch.test.mjs test/r60-authority-enforcement.test.mjs",
|
|
90
90
|
"r62:focused:test": "node --test --test-concurrency=1 test/r62-release-contract.test.mjs test/r62-doctor-transactions-reconcile.test.mjs test/r62-doctor-receipt-semantics.test.mjs test/r62-rollback-failure-receipt.test.mjs test/r58-doctor-transactions.test.mjs test/r58-completed-update-receipt.test.mjs test/runtime-self-update.test.mjs test/r56-rollback-launcher-restore.test.mjs",
|
|
91
91
|
"r63:focused:test": "node --test --test-concurrency=1 test/r63-release-contract.test.mjs test/r63-one-shot-coherence.test.mjs test/r51-runtime-coherence.test.mjs test/remote-session-cli.test.mjs",
|
|
92
|
-
"r64:focused:test": "node --test --test-concurrency=1 test/r64-release-contract.test.mjs test/r64-machine-fs-large-read.test.mjs test/machine-fs-runtime.test.mjs test/compact-gateway-r36.test.mjs test/r61-control-lane.test.mjs test/r60-bridge-dispatch.test.mjs"
|
|
92
|
+
"r64:focused:test": "node --test --test-concurrency=1 test/r64-release-contract.test.mjs test/r64-machine-fs-large-read.test.mjs test/machine-fs-runtime.test.mjs test/compact-gateway-r36.test.mjs test/r61-control-lane.test.mjs test/r60-bridge-dispatch.test.mjs",
|
|
93
|
+
"r65:focused:test": "node scripts/r65-focused.mjs",
|
|
94
|
+
"r66:focused:test": "node --test --test-concurrency=1 test/r66-release-contract.test.mjs test/r58-doctor-runtime.test.mjs test/r58-doctor-foreground.test.mjs test/r58-doctor-installation.test.mjs test/r65-controller-authority-epoch.test.mjs test/r65-authority-observation-epoch.test.mjs"
|
|
93
95
|
},
|
|
94
96
|
"bundleDependencies": [
|
|
95
97
|
"@modelcontextprotocol/server",
|
package/scripts/deploy-r48.mjs
CHANGED
|
@@ -1,17 +1,91 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { readFile, access } from 'node:fs/promises';
|
|
1
|
+
import { createHash,randomBytes } from 'node:crypto';
|
|
2
|
+
import { readFile, access,open,mkdir,unlink,lstat } from 'node:fs/promises';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { runSlotUpdateCli } from '../src/runtime-update.mjs';
|
|
7
|
+
import { runSlotUpdateCli,windowsPowerShellEnvironment,loadPowerShellDataFile } from '../src/runtime-update.mjs';
|
|
8
8
|
import { parseActivePointer } from '../src/release-slot.mjs';
|
|
9
|
+
import {parseAuthorityObservation} from '../src/remote-authority.mjs';
|
|
10
|
+
import {classifyActivationPreflight,classifyAuthorityContinuity,orchestrateActivation} from '../src/activation-preflight-r65.mjs';
|
|
11
|
+
import {createEpochNativeContinuityEngine} from '../src/activation-continuity-engine-r65.mjs';
|
|
12
|
+
import {createActivationClaimManager} from '../src/activation-lock-r65.mjs';
|
|
9
13
|
|
|
10
14
|
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
11
15
|
const state=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
|
|
12
16
|
const sha=async f=>createHash('sha256').update(await readFile(f)).digest('hex');
|
|
13
17
|
const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
|
|
14
18
|
|
|
19
|
+
async function writeExclusive(file,value){
|
|
20
|
+
const handle=await open(file,'wx',0o600);
|
|
21
|
+
try{await handle.writeFile(JSON.stringify(value)+'\n');await handle.sync();}
|
|
22
|
+
finally{await handle.close();}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const activationClaimManager=createActivationClaimManager({stateRoot:state});
|
|
26
|
+
let activationClaimOperationId=null;
|
|
27
|
+
|
|
28
|
+
async function claimActivation(subjectSha256){
|
|
29
|
+
const claim=await activationClaimManager.claim(subjectSha256);
|
|
30
|
+
activationClaimOperationId=claim.operation_id;
|
|
31
|
+
return claim.release;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function activePolicyPaths(){
|
|
35
|
+
const active=parseActivePointer(await readFile(path.join(state,'active-release.json'),'utf8'));
|
|
36
|
+
const config=await loadPowerShellDataFile(active.config_path);
|
|
37
|
+
const fields={process:'ProcessPolicyFile',coding:'CodingPolicyFile',autonomous:'AutonomousPolicyFile',desktop:'DesktopPolicyFile',host:'HostPolicyFile'};
|
|
38
|
+
return Object.fromEntries(Object.entries(fields).map(([plane,key])=>{
|
|
39
|
+
const file=config[key];
|
|
40
|
+
return [plane,typeof file==='string'&&path.isAbsolute(file)?path.resolve(file):null];
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function observeController(){
|
|
45
|
+
const launcher=path.join(state,'bin','DEADBYTE-MCP.ps1');
|
|
46
|
+
const powershell=path.join(process.env.SystemRoot||'C:\\Windows','System32','WindowsPowerShell','v1.0','powershell.exe');
|
|
47
|
+
const run=spawnSync(powershell,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,'status','-Json'],{
|
|
48
|
+
cwd:root,env:windowsPowerShellEnvironment(),encoding:'utf8',timeout:20000,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
49
|
+
if(run.error||run.status!==0)throw new Error(`activation preflight controller observation failed exit=${run.status} code=${run.error?.code??'none'}`);
|
|
50
|
+
const observed=parseAuthorityObservation(run.stdout);
|
|
51
|
+
const active=parseActivePointer(await readFile(path.join(state,'active-release.json'),'utf8'));
|
|
52
|
+
const policyPaths=await activePolicyPaths(),policySha256={};
|
|
53
|
+
for(const [plane,file] of Object.entries(policyPaths)){
|
|
54
|
+
if(!observed.authority[plane].configured){policySha256[plane]=null;continue;}
|
|
55
|
+
if(typeof file!=='string'||!path.isAbsolute(file))throw new Error(`activation ${plane} policy path missing`);
|
|
56
|
+
const info=await lstat(file);
|
|
57
|
+
if(!info.isFile()||info.isSymbolicLink())throw new Error(`activation ${plane} policy must be a regular file`);
|
|
58
|
+
policySha256[plane]=await sha(file);
|
|
59
|
+
}
|
|
60
|
+
return {...observed,policy_sha256:policySha256,policy_paths:policyPaths,active_release_id:active.release_id,active_manifest_sha256:active.manifest_sha256,
|
|
61
|
+
active_generation_manifest_sha256:active.generation_manifest_sha256};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function controllerCommand(command){
|
|
65
|
+
if(!/^(?:arm|disarm)(?:process|coding|autonomous|desktop|host)$|^supervisorstop$|^stop$/.test(command))throw new Error('activation controller command not declared');
|
|
66
|
+
const launcher=path.join(state,'bin','DEADBYTE-MCP.ps1');
|
|
67
|
+
const powershell=path.join(process.env.SystemRoot||'C:\\Windows','System32','WindowsPowerShell','v1.0','powershell.exe');
|
|
68
|
+
const run=spawnSync(powershell,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,command],{
|
|
69
|
+
cwd:root,env:windowsPowerShellEnvironment(),encoding:'utf8',timeout:30000,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
70
|
+
if(run.error||run.status!==0)throw new Error(`activation controller ${command} failed exit=${run.status} code=${run.error?.code??'none'}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function activationPreflight(manifest,pkg,pointer){
|
|
74
|
+
const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
|
|
75
|
+
const observed=await observeController();
|
|
76
|
+
const result=classifyActivationPreflight({pointer,expectedParent:release.parent,
|
|
77
|
+
candidate:{version:pkg.version,manifest_sha256:manifest},
|
|
78
|
+
expectedCandidate:{version:release.version,manifest_sha256:manifest},observation:observed});
|
|
79
|
+
const continuity=classifyAuthorityContinuity(observed);
|
|
80
|
+
if(continuity.state==='UNVERIFIED')return {...result,state:'AUTHORITY_CONTINUITY_UNVERIFIED',safe_to_activate:false,
|
|
81
|
+
reason:continuity.reason??'authority continuity observation unverified',authority_continuity:'UNVERIFIED',reauth_planes:continuity.reauth_planes??[]};
|
|
82
|
+
if(continuity.state==='EPOCH_NATIVE')return {...result,authority_continuity:'EPOCH_NATIVE',
|
|
83
|
+
epoch_planes:continuity.epoch_planes??[],reauth_planes:[]};
|
|
84
|
+
if(continuity.state==='LEGACY_REAUTH_REQUIRED'||continuity.state==='MIXED_REAUTH_REQUIRED')
|
|
85
|
+
return {...result,authority_continuity:'REAUTH_REQUIRED',reauth_planes:continuity.reauth_planes??continuity.armed_planes??[]};
|
|
86
|
+
return {...result,authority_continuity:'NOT_APPLICABLE',reauth_planes:[]};
|
|
87
|
+
}
|
|
88
|
+
|
|
15
89
|
async function waitForActivation({handoffPath,expectedVersion,expectedManifest,timeoutMs=900000,pollMs=1000}){
|
|
16
90
|
const evidenceDir=path.dirname(path.resolve(handoffPath));
|
|
17
91
|
const statePath=path.join(evidenceDir,'state.json');
|
|
@@ -62,6 +136,15 @@ const bridgeRoot=path.join(root,'bridge');
|
|
|
62
136
|
const bridgeScript=path.join(bridgeRoot,'src','bridge.mjs');
|
|
63
137
|
const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
|
|
64
138
|
const expectedVersion=pkg.version;
|
|
139
|
+
const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
|
|
140
|
+
const preflight=await activationPreflight(manifest,pkg,pointer);
|
|
141
|
+
if(process.argv.includes('--preflight')){
|
|
142
|
+
console.log(JSON.stringify(preflight));
|
|
143
|
+
process.exit(0);
|
|
144
|
+
}
|
|
145
|
+
if(process.argv.length>2)throw new Error('deploy accepts only --preflight');
|
|
146
|
+
if(!['ONLINE_READY','ONLINE_HOST_ARMED','PARKED_DIRTY','OFFLINE_CLEAN'].includes(preflight.state))
|
|
147
|
+
throw new Error(`activation preflight rejected: ${preflight.state} subject=${preflight.subject_sha256??'<incomplete>'}`);
|
|
65
148
|
const args=[
|
|
66
149
|
'--stage',root,'--development-root',root,'--expected-version',expectedVersion,'--expected-manifest',manifest,
|
|
67
150
|
'--process-policy',path.join(root,'controller','deadbyte-process-policy.json'),'--process-policy-sha256',await sha(path.join(root,'controller','deadbyte-process-policy.json')),
|
|
@@ -70,9 +153,40 @@ const args=[
|
|
|
70
153
|
'--bridge-root',bridgeRoot,'--bridge-script-sha256',await sha(bridgeScript),
|
|
71
154
|
'--enable-machine-fs','--enable-observation','--enable-desktop','--enable-autonomous-supervisor','--recover-offline-predecessor'
|
|
72
155
|
];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
156
|
+
let result=null,verification=null,activationOutcomePath=null;
|
|
157
|
+
let continuityEngine=null,continuityUpdateId=null;
|
|
158
|
+
|
|
159
|
+
async function recordActivationOutcome(outcome){
|
|
160
|
+
if(typeof activationClaimOperationId!=='string')throw new Error('activation claim operation id unavailable');
|
|
161
|
+
const outcomeFile=path.join(state,'evidence','updates',`r65-activation-outcome-${Date.now()}-${randomBytes(8).toString('hex')}.json`);
|
|
162
|
+
await writeExclusive(outcomeFile,{schema:'deadbyte.r65-activation-outcome.v1',claim_operation_id:activationClaimOperationId,
|
|
163
|
+
candidate_version:expectedVersion,candidate_manifest_sha256:manifest,
|
|
164
|
+
predecessor_release_id:pointer.release_id,preflight_subject_sha256:preflight.subject_sha256,outcome,
|
|
165
|
+
update_id:result?.update_id??null,continuity_update_id:continuityUpdateId,
|
|
166
|
+
state_path:result?.state_path??null,observed_at_utc:new Date().toISOString()});
|
|
167
|
+
activationOutcomePath=outcomeFile;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if(preflight.authority_continuity==='EPOCH_NATIVE'){
|
|
171
|
+
const predecessorObservation=await observeController();
|
|
172
|
+
continuityUpdateId=`r65-${randomBytes(16).toString('hex')}`;
|
|
173
|
+
continuityEngine=createEpochNativeContinuityEngine({stateRoot:state,predecessorPolicyPaths:predecessorObservation.policy_paths,
|
|
174
|
+
successorPolicyPaths:async()=>activePolicyPaths(),updateId:continuityUpdateId});
|
|
175
|
+
}
|
|
176
|
+
const outcome=await orchestrateActivation({pointer,expectedParent:release.parent,
|
|
177
|
+
candidate:{version:expectedVersion,manifest_sha256:manifest},expectedCandidate:{version:release.version,manifest_sha256:manifest},
|
|
178
|
+
observe:async()=>observeController(),command:async command=>controllerCommand(command),claim:claimActivation,continuityEngine,
|
|
179
|
+
recordOutcome:recordActivationOutcome,
|
|
180
|
+
activate:async()=>{
|
|
181
|
+
result=await runSlotUpdateCli(args,{stateRoot:state});
|
|
182
|
+
if(!result.handed_off)throw new Error('release activation unexpectedly completed inline');
|
|
183
|
+
verification=await waitForActivation({handoffPath:result.handoff_path,expectedVersion,expectedManifest:manifest});
|
|
184
|
+
return {verified:true,release_id:verification.release_id};
|
|
185
|
+
}});
|
|
186
|
+
if(outcome.state!=='ACTIVATED'){
|
|
187
|
+
console.log(JSON.stringify({...outcome,update_id:result?.update_id??null,state_path:result?.state_path??null,outcome_path:activationOutcomePath}));
|
|
188
|
+
process.exitCode=2;
|
|
189
|
+
}else{
|
|
76
190
|
console.log(JSON.stringify({
|
|
77
191
|
status:'activated',
|
|
78
192
|
manifest_sha256:manifest,
|
|
@@ -81,5 +195,7 @@ console.log(JSON.stringify({
|
|
|
81
195
|
supervisor_pid:result.supervisor_pid,
|
|
82
196
|
release_id:verification.release_id,
|
|
83
197
|
receipt_path:verification.receiptPath,
|
|
84
|
-
state_path:verification.statePath
|
|
198
|
+
state_path:verification.statePath,
|
|
199
|
+
outcome_path:activationOutcomePath
|
|
85
200
|
},null,2));
|
|
201
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[ValidateSet('all','preflight','focused','full','manifest','doctor')]
|
|
3
|
+
[string]$Stage='all'
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
$ErrorActionPreference='Stop'
|
|
7
|
+
Set-StrictMode -Version 3.0
|
|
8
|
+
$root=Split-Path $PSScriptRoot -Parent
|
|
9
|
+
Set-Location -LiteralPath $root
|
|
10
|
+
|
|
11
|
+
function Invoke-Npm([string]$Name,[string[]]$NpmArgs){
|
|
12
|
+
Write-Host "==== $Name ===="
|
|
13
|
+
& npm.cmd @NpmArgs
|
|
14
|
+
if($LASTEXITCODE -ne 0){ throw "R65 prepublish gate failed at $Name exit=$LASTEXITCODE" }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function Get-FileSha256([string]$File){
|
|
18
|
+
$hasher=[Security.Cryptography.SHA256]::Create()
|
|
19
|
+
try{
|
|
20
|
+
$bytes=[IO.File]::ReadAllBytes($File)
|
|
21
|
+
return (($hasher.ComputeHash($bytes) | ForEach-Object { $_.ToString('x2') }) -join '')
|
|
22
|
+
}finally{ $hasher.Dispose() }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
$sourceRoot='D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.41-r64'
|
|
26
|
+
$sourceManifest='63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e'
|
|
27
|
+
if(-not (Test-Path -LiteralPath $sourceRoot -PathType Container)){ throw 'R65 source predecessor missing' }
|
|
28
|
+
$observedSourceManifest=Get-FileSha256 (Join-Path $sourceRoot 'MANIFEST.SHA256')
|
|
29
|
+
if($observedSourceManifest -ne $sourceManifest){ throw 'R65 source predecessor manifest identity mismatch' }
|
|
30
|
+
& node (Join-Path $root 'scripts\\verify-r65-parent-source.mjs') --root $sourceRoot --expected-manifest-sha256 $sourceManifest
|
|
31
|
+
if($LASTEXITCODE -ne 0){ throw 'R65 source predecessor declared-manifest verification failed' }
|
|
32
|
+
|
|
33
|
+
$stateRoot=Join-Path $env:USERPROFILE '.deadbyte-mcp'
|
|
34
|
+
$pointer=Join-Path $stateRoot 'active-release.json'
|
|
35
|
+
if(-not (Test-Path -LiteralPath $pointer -PathType Leaf)){ throw "R65 runtime predecessor pointer missing: $pointer" }
|
|
36
|
+
$active=Get-Content -LiteralPath $pointer -Raw | ConvertFrom-Json
|
|
37
|
+
if($active.release_id -ne 'v0.15.41-63a78ad159ad3003'){ throw "R65 runtime predecessor release mismatch: $($active.release_id)" }
|
|
38
|
+
if($active.manifest_sha256 -ne '63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e'){ throw 'R65 runtime predecessor manifest mismatch' }
|
|
39
|
+
if($active.generation_manifest_sha256 -ne '19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'){ throw 'R65 runtime predecessor generation mismatch' }
|
|
40
|
+
if($Stage -eq 'preflight'){Write-Host '==== R65 WINDOWS GATE: PASS preflight ====';return}
|
|
41
|
+
|
|
42
|
+
if($Stage -eq 'all' -or $Stage -eq 'focused'){
|
|
43
|
+
Invoke-Npm 'r65-focused' @('run','r65:focused:test')
|
|
44
|
+
if($Stage -eq 'focused'){Write-Host '==== R65 WINDOWS GATE: PASS focused ====';return}
|
|
45
|
+
}
|
|
46
|
+
if($Stage -eq 'all' -or $Stage -eq 'full'){
|
|
47
|
+
Invoke-Npm 'full-regression' @('test')
|
|
48
|
+
if($Stage -eq 'full'){Write-Host '==== R65 WINDOWS GATE: PASS full ====';return}
|
|
49
|
+
}
|
|
50
|
+
if($Stage -eq 'all' -or $Stage -eq 'manifest'){
|
|
51
|
+
Invoke-Npm 'manifest-write' @('run','manifest:write')
|
|
52
|
+
Invoke-Npm 'manifest-verify' @('run','manifest:verify')
|
|
53
|
+
if($Stage -eq 'manifest'){Write-Host '==== R65 WINDOWS GATE: PASS manifest ====';return}
|
|
54
|
+
}
|
|
55
|
+
if($Stage -eq 'all' -or $Stage -eq 'doctor'){
|
|
56
|
+
$doctorRoot='D:\Projects\deadbyte-mcp\testing\0.15.42-r65\doctor-isolated-empty'
|
|
57
|
+
if(Test-Path -LiteralPath (Join-Path $doctorRoot 'active-release.json')){ throw 'R65 isolated doctor root unexpectedly contains a release pointer' }
|
|
58
|
+
$priorStateRoot=$env:DEADBYTE_STATE_ROOT
|
|
59
|
+
try{
|
|
60
|
+
$env:DEADBYTE_STATE_ROOT=$doctorRoot
|
|
61
|
+
Invoke-Npm 'doctor-isolated-empty-state' @('run','doctor')
|
|
62
|
+
}finally{ $env:DEADBYTE_STATE_ROOT=$priorStateRoot }
|
|
63
|
+
if($Stage -eq 'doctor'){Write-Host '==== R65 WINDOWS GATE: PASS doctor ====';return}
|
|
64
|
+
}
|
|
65
|
+
Write-Host '==== R65 PREPUBLISH WINDOWS GATE: PASS ===='
|