deadbyte-mcp 0.15.72 → 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.
Files changed (144) hide show
  1. package/MANIFEST.SHA256 +143 -35
  2. package/PROVENANCE.json +47 -21
  3. package/README.txt +29 -18
  4. package/RELEASE.json +85 -18
  5. package/SBOM.cdx.json +14 -2
  6. package/TEST-MATRIX.json +50 -2
  7. package/bin/deadbyte-desktop-uia-r199-fixed.exe +0 -0
  8. package/bin/deadbyte-desktop-uia-r199-fixed.obj +0 -0
  9. package/bin/deadbyte-desktop-uia-r199.exe +0 -0
  10. package/bin/deadbyte-desktop-uia-r199.obj +0 -0
  11. package/bin/deadbyte-fs-read-r197-fixed.exe +0 -0
  12. package/bin/deadbyte-fs-read-r198.exe +0 -0
  13. package/bin/deadbyte-fs-read-r198.obj +0 -0
  14. package/bin/deadbyte-owner-token-r193.exe +0 -0
  15. package/bin/deadbyte-root-relative-probe-r197.exe +0 -0
  16. package/bridge/package.json +1 -1
  17. package/controller/deadbyte-process-policy.json +4 -4
  18. package/docs/R184-package-lock.json +2 -8
  19. package/native/deadbyte-desktop-uia-r199.cpp +345 -0
  20. package/native/deadbyte-fs-read-r197.cpp +174 -0
  21. package/native/deadbyte-fs-read-r198.cpp +181 -0
  22. package/native/deadbyte-owner-token-r193.cpp +156 -0
  23. package/native/deadbyte-root-relative-probe-r197.cpp +97 -0
  24. package/package.json +4 -2
  25. package/scripts/build-native-desktop-uia-r199-fixed.ps1 +28 -0
  26. package/scripts/build-native-desktop-uia-r199.ps1 +28 -0
  27. package/scripts/build-native-fs-read-r197-fixed.ps1 +28 -0
  28. package/scripts/build-native-fs-read-r197.ps1 +28 -0
  29. package/scripts/build-native-fs-read-r198.ps1 +28 -0
  30. package/scripts/build-native-root-probe-r197.ps1 +28 -0
  31. package/scripts/gate-windows-r193.ps1 +108 -0
  32. package/scripts/gate-windows-r194.ps1 +112 -0
  33. package/scripts/gate-windows-r195.ps1 +114 -0
  34. package/scripts/gate-windows-r206.ps1 +116 -0
  35. package/scripts/init-desktop-policy-r199.ps1 +85 -0
  36. package/scripts/npm-interactive-r194.mjs +13 -0
  37. package/scripts/npm-publication-r65.mjs +64 -4
  38. package/scripts/npm-release-r48.mjs +75 -11
  39. package/scripts/npm-release-readiness-r193.mjs +80 -0
  40. package/scripts/npm-release-readiness-r194.mjs +80 -0
  41. package/scripts/npm-release-readiness-r195.mjs +72 -0
  42. package/scripts/npm-release-readiness-r206.mjs +76 -0
  43. package/scripts/r188-owner-uac-review.ps1 +91 -0
  44. package/scripts/r188-uac-review-preview.mjs +65 -0
  45. package/scripts/r193-compile-token.ps1 +22 -0
  46. package/scripts/r193-evidence-relocate.ps1 +12 -0
  47. package/scripts/r193-focused-gate.mjs +20 -0
  48. package/scripts/r193-import-r188-scripts.ps1 +14 -0
  49. package/scripts/r193-limited-subject-probe.ps1 +25 -0
  50. package/scripts/r193-migrate-runtime-limited.ps1 +103 -0
  51. package/scripts/r193-owner-keygen.mjs +43 -0
  52. package/scripts/r193-owner-request-live.mjs +49 -0
  53. package/scripts/r193-owner-uac-approve.ps1 +42 -0
  54. package/scripts/r193-owner-uac-broker.mjs +139 -0
  55. package/scripts/r193-owner-uac-enroll-and-approve.ps1 +62 -0
  56. package/scripts/r193-test-limited-token.ps1 +49 -0
  57. package/scripts/r193-toolchain-inventory.ps1 +7 -0
  58. package/scripts/r193-uac-bridge-focused.mjs +21 -0
  59. package/scripts/r205-candidate-selection.mjs +22 -0
  60. package/src/candidate-selection-evidence-r206.mjs +71 -0
  61. package/src/candidate-selection-r205.mjs +96 -0
  62. package/src/desktop-postcondition-r196.mjs +30 -0
  63. package/src/desktop-runtime-r40.mjs +44 -7
  64. package/src/desktop-uia-identity-r199.mjs +51 -0
  65. package/src/desktop-uia-r40.mjs +9 -1
  66. package/src/machine-fs-handle-read-r196.mjs +43 -0
  67. package/src/machine-fs-native-read-r197.mjs +73 -0
  68. package/src/machine-fs-native-read-r198.mjs +76 -0
  69. package/src/machine-fs-read-worker.mjs +5 -25
  70. package/src/machine-fs.mjs +31 -16
  71. package/src/r188-owner-uac.mjs +105 -0
  72. package/src/r188-uac-boundary.mjs +21 -0
  73. package/src/r193-live-owner-subject.mjs +110 -0
  74. package/src/r193-owner-secret-acl.mjs +67 -0
  75. package/src/r193-owner-uac-broker.mjs +85 -0
  76. package/src/r193-uac-r70-bridge.mjs +54 -0
  77. package/src/r195-canonical-owner-observation.mjs +15 -0
  78. package/src/remote-destination-journal-r202.mjs +120 -0
  79. package/src/remote-device-r44.mjs +89 -14
  80. package/src/remote-payload-boundary-r201.mjs +71 -0
  81. package/src/remote-terminal-evidence-r200.mjs +60 -0
  82. package/src/version.mjs +1 -1
  83. package/test/desktop-runtime-r40.test.mjs +111 -0
  84. package/test/desktop-uia-r40.test.mjs +15 -0
  85. package/test/fixtures/r197-junction-swap-worker.mjs +21 -0
  86. package/test/fixtures/r203-journal-writer.mjs +6 -0
  87. package/test/process-policy-refresh.test.mjs +4 -4
  88. package/test/r130-release-security-contract.test.mjs +8 -8
  89. package/test/r132-release-identity.test.mjs +7 -7
  90. package/test/r153-prepublish-identity.test.mjs +1 -1
  91. package/test/r160-release-contract.test.mjs +3 -3
  92. package/test/r165-live-cli-skew.test.mjs +1 -1
  93. package/test/r167-release-contract.test.mjs +11 -11
  94. package/test/r168-release-contract.test.mjs +4 -4
  95. package/test/r172-release-contract.test.mjs +6 -6
  96. package/test/r173-release-contract.test.mjs +16 -16
  97. package/test/r179-release-contract.test.mjs +12 -12
  98. package/test/r188-owner-uac.test.mjs +48 -0
  99. package/test/r188-uac-boundary.test.mjs +42 -0
  100. package/test/r190-release-contract.test.mjs +10 -10
  101. package/test/r191-release-contract.test.mjs +12 -12
  102. package/test/r192-release-identity.test.mjs +10 -10
  103. package/test/r193-limited-migration-contract.test.mjs +26 -0
  104. package/test/r193-live-owner-subject.test.mjs +61 -0
  105. package/test/r193-native-process-observer.test.mjs +36 -0
  106. package/test/r193-native-token.test.mjs +43 -0
  107. package/test/r193-owner-enrollment-entrypoint.test.mjs +38 -0
  108. package/test/r193-owner-secret-acl.test.mjs +23 -0
  109. package/test/r193-owner-uac-broker.test.mjs +82 -0
  110. package/test/r193-owner-uac-entrypoint.test.mjs +36 -0
  111. package/test/r193-release-identity.test.mjs +58 -0
  112. package/test/r193-release-readiness.test.mjs +87 -0
  113. package/test/r193-uac-r70-bridge.test.mjs +88 -0
  114. package/test/r193-windows-gate.test.mjs +30 -0
  115. package/test/r194-npm-auth-recovery.test.mjs +77 -0
  116. package/test/r194-npm-preauth.test.mjs +57 -0
  117. package/test/r194-release-identity.test.mjs +47 -0
  118. package/test/r194-release-readiness.test.mjs +87 -0
  119. package/test/r194-windows-gate.test.mjs +22 -0
  120. package/test/r195-canonical-owner-observation.test.mjs +32 -0
  121. package/test/r195-release-readiness.test.mjs +22 -0
  122. package/test/r196-desktop-postcondition.test.mjs +53 -0
  123. package/test/r196-handle-bound-read.test.mjs +99 -0
  124. package/test/r196-remote-outcome.test.mjs +94 -0
  125. package/test/r197-namespace-race.test.mjs +41 -0
  126. package/test/r197-native-dispatch-race.test.mjs +49 -0
  127. package/test/r197-native-file-read.test.mjs +60 -0
  128. package/test/r197-native-root-open.test.mjs +61 -0
  129. package/test/r198-root-identity.test.mjs +88 -0
  130. package/test/r199-native-uia-worker.test.mjs +28 -0
  131. package/test/r199-uia-identity.test.mjs +43 -0
  132. package/test/r200-remote-reconcile.test.mjs +106 -0
  133. package/test/r201-payload-boundary.test.mjs +78 -0
  134. package/test/r201-payload-fuzz.test.mjs +37 -0
  135. package/test/r201-tool-boundary-fuzz.test.mjs +120 -0
  136. package/test/r202-destination-journal.test.mjs +92 -0
  137. package/test/r203-atomic-journal.test.mjs +86 -0
  138. package/test/r205-candidate-selection-cli.test.mjs +31 -0
  139. package/test/r205-candidate-selection.test.mjs +83 -0
  140. package/test/r206-candidate-evidence.test.mjs +64 -0
  141. package/test/r206-release-contract.test.mjs +42 -0
  142. package/test/r206-release-readiness.test.mjs +23 -0
  143. package/test/r59-tool-surface-compat.test.mjs +1 -1
  144. package/test/r64-machine-fs-large-read.test.mjs +26 -12
@@ -0,0 +1,12 @@
1
+ $ErrorActionPreference='Stop'
2
+ $source='D:\Projects\deadbyte-mcp\development\deadbyte-mcp-r193-owner-uac-dev\R193-STANDARD-TOKEN-PROBE.json'
3
+ $folder='D:\Projects\deadbyte-mcp\testing\r193'
4
+ $dest=Join-Path $folder 'R193-STANDARD-TOKEN-PROBE.json'
5
+ $item=Get-Item -LiteralPath $source -Force -ErrorAction Stop
6
+ if($item.PSIsContainer -or (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0)){throw 'R193_UNSAFE_EVIDENCE'}
7
+ $before=(Get-FileHash $source).Hash.ToLowerInvariant()
8
+ if(Test-Path $dest){throw 'R193_DEST_EVIDENCE_ALREADY_EXISTS'}
9
+ New-Item -ItemType Directory -Path $folder -Force -ErrorAction Stop | Out-Null
10
+ Move-Item -LiteralPath $source -Destination $dest -ErrorAction Stop
11
+ if((Get-FileHash $dest).Hash.ToLowerInvariant() -cne $before){throw 'R193_EVIDENCE_MOVE_CHANGED'}
12
+ [pscustomobject]@{schema='deadbyte.r193-evidence-relocate.v1';state='VERIFIED';evidence_path=$dest;sha256=$before;source_absent=(-not(Test-Path $source));production_untouched=$true}|ConvertTo-Json -Compress
@@ -0,0 +1,20 @@
1
+ import {spawnSync} from 'node:child_process';
2
+ import path from 'node:path';
3
+ import {fileURLToPath} from 'node:url';
4
+ const root=fileURLToPath(new URL('..',import.meta.url));
5
+ const files=[
6
+ 'test/r188-owner-uac.test.mjs',
7
+ 'test/r188-uac-boundary.test.mjs',
8
+ 'test/r193-native-token.test.mjs'
9
+ ];
10
+ const result=spawnSync(process.execPath,['--test','--test-concurrency=1',...files],{
11
+ cwd:root,encoding:'utf8',windowsHide:true,timeout:120000,maxBuffer:1024*1024,shell:false
12
+ });
13
+ const output=(result.stdout??'')+'\n'+(result.stderr??'');
14
+ const summary=output.split(/\r?\n/).filter(x=>/^[ℹ#]\s*(tests|pass|fail|skipped)\s+/.test(x)).slice(-6);
15
+ const pass=result.status===0 && summary.some(x=>/pass\s+9\b/.test(x)) && summary.some(x=>/fail\s+0\b/.test(x));
16
+ console.log(JSON.stringify({schema:'deadbyte.r193-focused-gate.v1',
17
+ state:pass?'PASS':'FAIL',exit:result.status,summary,
18
+ output_tail:pass?null:output.slice(-11000),
19
+ runtime_source:'isolated_R193_only',release_activated:false,authority_granted:false}));
20
+ if(!pass)process.exitCode=1;
@@ -0,0 +1,14 @@
1
+ $ErrorActionPreference='Stop'
2
+ $from='D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.69-r188-uac-consent'
3
+ $into='D:\Projects\deadbyte-mcp\development\deadbyte-mcp-r193-owner-uac-dev'
4
+ $names=@('scripts\r188-owner-uac-review.ps1','scripts\r188-uac-review-preview.mjs')
5
+ foreach($n in $names){
6
+ $s=Join-Path $from $n
7
+ $d=Join-Path $into $n
8
+ if(Test-Path $d){throw "R193_IMPORT_ALREADY_EXISTS $n"}
9
+ $item=Get-Item -LiteralPath $s
10
+ if($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)){throw "R193_UNSAFE_SOURCE $n"}
11
+ Copy-Item -LiteralPath $s -Destination $d -ErrorAction Stop
12
+ if((Get-FileHash $s).Hash -cne (Get-FileHash $d).Hash){throw "R193_IMPORT_BYTES_MISMATCH $n"}
13
+ }
14
+ [pscustomobject]@{state='R188_SCRIPTS_IMPORTED';scripts=$names;overwrite=$false;production_untouched=$true}|ConvertTo-Json -Compress
@@ -0,0 +1,25 @@
1
+ $ErrorActionPreference='Stop'
2
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
3
+ $exe=Join-Path $root 'bin\deadbyte-owner-token-r193.exe'
4
+ $output=Join-Path $root 'R193-STANDARD-TOKEN-PROBE.json'
5
+ $sha='d554d732872f3d671fd2fb63c11fc0dac1f8cae377259c6d64dd0c5b3762f2b8'
6
+ if((Get-FileHash -LiteralPath $exe -Algorithm SHA256).Hash.ToLowerInvariant() -cne $sha){throw 'R193_NATIVE_BINARY_CHANGED'}
7
+ if(Test-Path -LiteralPath $output){throw 'R193_PROBE_OUTPUT_ALREADY_EXISTS'}
8
+ $json=@(& $exe '--require-standard')
9
+ $exit=$LASTEXITCODE
10
+ if($json.Count -ne 1){throw 'R193_PROBE_OUTPUT_INVALID'}
11
+ $body=($json[0]|ConvertFrom-Json)
12
+ $record=[ordered]@{
13
+ schema='deadbyte.r193-standard-token-probe.v1'
14
+ process_report=$body
15
+ probe_exit=$exit
16
+ native_binary_sha256=$sha
17
+ expected_standard=($body.status -eq 'STANDARD_TOKEN_OBSERVED' -and $exit -eq 0)
18
+ authority_granted=$false
19
+ }
20
+ $text=$record|ConvertTo-Json -Depth 6 -Compress
21
+ $utf8=New-Object Text.UTF8Encoding($false)
22
+ $bytes=$utf8.GetBytes($text)
23
+ $stream=[IO.File]::Open($output,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::None)
24
+ try{$stream.Write($bytes,0,$bytes.Length);$stream.Flush($true)}finally{$stream.Dispose()}
25
+ if(-not $record.expected_standard){exit 3}
@@ -0,0 +1,103 @@
1
+ #requires -Version 5.1
2
+ #requires -RunAsAdministrator
3
+ [CmdletBinding()]
4
+ param([switch]$Execute)
5
+ $ErrorActionPreference='Stop';Set-StrictMode -Version Latest
6
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
7
+ $program=[IO.Path]::GetFullPath($env:ProgramFiles).TrimEnd('\')+'\'
8
+ if(-not ($root.TrimEnd('\')+'\').StartsWith($program,[StringComparison]::OrdinalIgnoreCase)){
9
+ throw 'R193 Limited migration must run from an R89-protected Program Files package'
10
+ }
11
+ $state='C:\Users\DEADBYTE\.deadbyte-mcp'
12
+ $runtime=Join-Path $state 'runtime'
13
+ $pointer=Get-Content -Raw -LiteralPath (Join-Path $state 'active-release.json')|ConvertFrom-Json
14
+ $manifest=Join-Path $root 'MANIFEST.SHA256'
15
+ if((Get-FileHash $manifest).Hash.ToLowerInvariant() -cne [string]$pointer.manifest_sha256){
16
+ throw 'R193 Limited migration package is not the exact active release'
17
+ }
18
+ $controller=Join-Path $root 'controller\deadbyte-controller.ps1'
19
+ $native=Join-Path $root 'bin\deadbyte-owner-token-r193.exe'
20
+ $env:DEADBYTE_CONTROLLER_CONFIG=[string]$pointer.config_path
21
+ $env:DEADBYTE_CONTROLLER_RUNTIME_ROOT=$runtime
22
+ function Invoke-Controller([string]$Command,[switch]$Json){
23
+ $args=@('-NoLogo','-NoProfile','-NonInteractive','-ExecutionPolicy','Bypass','-File',$controller,$Command)
24
+ if($Json){$args+='-Json'}
25
+ $raw=@(& 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' @args 2>&1)-join [Environment]::NewLine
26
+ if($LASTEXITCODE -ne 0){throw "R193 controller $Command failed: $($raw.Substring(0,[Math]::Min(400,$raw.Length)))"}
27
+ if($Json){return $raw|ConvertFrom-Json}
28
+ return $raw
29
+ }
30
+ function Token([int]$PidValue){
31
+ $raw=@(& $native --inspect-pid ([string]$PidValue) 2>&1)-join [Environment]::NewLine
32
+ if($LASTEXITCODE -ne 0){throw "R193 token inspection failed for PID $PidValue"}
33
+ return $raw|ConvertFrom-Json
34
+ }
35
+ function AuthorityFingerprint($status,[string]$plane){
36
+ $p=$status.authority.$plane
37
+ return '{0}|{1}|{2}|{3}|{4}' -f [bool]$p.configured,[bool]$p.armed,[string]$p.reason,[string]$p.epoch_seq,[string]$p.epoch_sha256
38
+ }
39
+ $before=Invoke-Controller status -Json
40
+ if([string]$before.state -cne 'ONLINE' -or -not $before.supervisor.running){throw 'R193 migration requires ONLINE runtime and verified supervisor'}
41
+ foreach($plane in @('process','coding','autonomous','desktop','host')){
42
+ if([string]$before.authority.$plane.reason -eq 'unverified'){throw "R193 migration authority $plane is unverified"}
43
+ }
44
+ $plan=[ordered]@{schema='deadbyte.r193-limited-migration-plan.v1';active_release=[string]$pointer.release_id;
45
+ manifest_sha256=[string]$pointer.manifest_sha256;state='PREFLIGHT_PASS';
46
+ desktop_will_be_disarmed=$true;other_authority_will_not_be_rearmed=$true;
47
+ production_mutation_requested=[bool]$Execute}
48
+ if(-not $Execute){$plan|ConvertTo-Json -Depth 5 -Compress;exit 0}
49
+ $transient='DEADBYTE-MCP-R193-Limited-Supervisor'
50
+ $stopped=$false
51
+ try{
52
+ Invoke-Controller supervisorstop|Out-Null
53
+ Invoke-Controller stop|Out-Null
54
+ $stopped=$true
55
+ $offline=Invoke-Controller status -Json
56
+ if([string]$offline.state -cne 'OFFLINE'){throw 'R193 migration did not reach OFFLINE'}
57
+ Start-ScheduledTask -TaskName 'DEADBYTE-MCP-Runtime-Logon'
58
+ $deadline=[DateTime]::UtcNow.AddSeconds(60)
59
+ do{
60
+ Start-Sleep -Milliseconds 500
61
+ try{$online=Invoke-Controller status -Json}catch{$online=$null}
62
+ }while(($null -eq $online -or [string]$online.state -cne 'ONLINE') -and [DateTime]::UtcNow -lt $deadline)
63
+ if($null -eq $online -or [string]$online.state -cne 'ONLINE'){throw 'R193 Limited runtime task did not become ONLINE'}
64
+ $action=New-ScheduledTaskAction -Execute 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' -Argument ('-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "'+(Join-Path $state 'bin\DEADBYTE-MCP.ps1')+'" supervisorstart')
65
+ $principal=New-ScheduledTaskPrincipal -UserId ([Security.Principal.WindowsIdentity]::GetCurrent().Name) -LogonType Interactive -RunLevel Limited
66
+ Register-ScheduledTask -TaskName $transient -Action $action -Principal $principal -Force|Out-Null
67
+ Start-ScheduledTask -TaskName $transient
68
+ $deadline=[DateTime]::UtcNow.AddSeconds(30)
69
+ do{Start-Sleep -Milliseconds 500;$after=Invoke-Controller status -Json}
70
+ while(-not $after.supervisor.running -and [DateTime]::UtcNow -lt $deadline)
71
+ if(-not $after.supervisor.running){throw 'R193 Limited supervisor task did not become RUNNING'}
72
+ $supervisor=Get-Content -Raw -LiteralPath (Join-Path $runtime 'supervisor.instance.json')|ConvertFrom-Json
73
+ $tokens=@{
74
+ bridge=(Token ([int]$after.bridge.pid));core=(Token ([int]$after.core.pid));
75
+ cloud=(Token ([int]$after.cloud.pid));supervisor=(Token ([int]$supervisor.pid))
76
+ }
77
+ foreach($name in @('bridge','core','cloud','supervisor')){
78
+ $t=$tokens[$name]
79
+ if($t.elevated -or $t.admin_enabled -or [int]$t.integrity_rid -lt 8192 -or [int]$t.integrity_rid -ge 12288 -or [string]$t.token_type -cne 'primary'){
80
+ throw "R193 $name did not migrate to a Limited primary token"
81
+ }
82
+ }
83
+ foreach($plane in @('process','coding','host')){
84
+ if((AuthorityFingerprint $before $plane) -cne (AuthorityFingerprint $after $plane)){
85
+ throw "R193 migration changed $plane authority"
86
+ }
87
+ }
88
+ if($after.authority.autonomous.armed){throw 'R193 migration unexpectedly armed Autonomous'}
89
+ if($after.authority.desktop.armed -or [string]$after.authority.desktop.reason -cne 'disarmed'){
90
+ throw 'R193 migration expected supported stop to leave Desktop DISARMED'
91
+ }
92
+ [ordered]@{schema='deadbyte.r193-limited-migration-result.v1';state='MIGRATED_LIMITED';
93
+ active_release=[string]$pointer.release_id;desktop_reapproval_required=$true;
94
+ process_preserved=$true;coding_preserved=$true;host_preserved=$true;
95
+ autonomous_armed=$false;tokens=$tokens}|ConvertTo-Json -Depth 8 -Compress
96
+ }catch{
97
+ if($stopped){
98
+ try{Invoke-Controller start|Out-Null;Invoke-Controller supervisorstart|Out-Null}catch{}
99
+ }
100
+ throw
101
+ }finally{
102
+ Unregister-ScheduledTask -TaskName $transient -Confirm:$false -ErrorAction SilentlyContinue
103
+ }
@@ -0,0 +1,43 @@
1
+ // One-time protected owner key enrollment. No caller-selected paths.
2
+ import {generateKeyPairSync} from 'node:crypto';
3
+ import {lstat,open,readFile} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {fileURLToPath} from 'node:url';
6
+ import {canonicalJson} from '../src/canonical-json.mjs';
7
+ import {createR186OwnerAnchor} from '../src/r186-owner-anchor.mjs';
8
+ import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
9
+ import {inspectR193OwnerSecretAcl} from '../src/r193-owner-secret-acl.mjs';
10
+ import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
11
+ const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
12
+ const OWNER='C:\\Program Files\\DEADBYTE-OwnerAuthority';
13
+ const PRIVATE=path.win32.join(OWNER,'owner-private.der');
14
+ const PUBLIC=path.win32.join(OWNER,'owner-public.pem');
15
+ const ANCHOR=path.win32.join(OWNER,'owner-anchor.json');
16
+ async function exclusive(file,bytes){
17
+ const handle=await open(file,'wx',0o600);
18
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
19
+ }
20
+ async function main(){
21
+ if(process.platform!=='win32'||process.arch!=='x64')throw Error('R193 owner keygen requires Windows x64');
22
+ if(process.argv.length!==2)throw Error('R193 owner keygen accepts no arguments');
23
+ await inspectTrustedInstallation(['C:\\Program Files\\nodejs\\node.exe',THIS,
24
+ path.join(ROOT,'MANIFEST.SHA256'),path.join(ROOT,'src','r186-owner-anchor.mjs'),
25
+ path.join(ROOT,'src','r193-owner-secret-acl.mjs'),
26
+ path.join(ROOT,'src','privileged-install-trust-r89.mjs'),
27
+ path.join(ROOT,'src','release-slot.mjs')]);
28
+ const manifest=await readFile(path.join(ROOT,'MANIFEST.SHA256'),'utf8');
29
+ await verifyManifestTreeExact(ROOT,parseManifest(manifest));
30
+ const owner=await lstat(OWNER);
31
+ if(!owner.isDirectory()||owner.isSymbolicLink())throw Error('R193 owner directory is not a real directory');
32
+ const pair=generateKeyPairSync('ed25519');
33
+ const privateDer=pair.privateKey.export({format:'der',type:'pkcs8'});
34
+ const material=createR186OwnerAnchor(pair.publicKey.export({format:'pem',type:'spki'}).toString());
35
+ await exclusive(PRIVATE,privateDer);
36
+ await exclusive(PUBLIC,Buffer.from(material.public_key_pem,'utf8'));
37
+ await exclusive(ANCHOR,Buffer.from(canonicalJson(material.anchor)+'\n','utf8'));
38
+ const secret=await inspectR193OwnerSecretAcl([OWNER,PRIVATE]);
39
+ process.stdout.write(JSON.stringify({status:'R193_OWNER_AUTHORITY_ENROLLED',
40
+ owner_key_id:material.anchor.owner_key_id,secret_acl:secret.reason,
41
+ private_key_exported:false,authority_granted:false})+'\n');
42
+ }
43
+ main().catch(error=>{console.error(String(error?.message??error).slice(0,500));process.exitCode=2;});
@@ -0,0 +1,49 @@
1
+ // Protected, fixed-scope request generation after Limited migration.
2
+ import {createHash} from 'node:crypto';
3
+ import {lstat,open,readFile} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {fileURLToPath} from 'node:url';
6
+ import {canonicalJson} from '../src/canonical-json.mjs';
7
+ import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
8
+ import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
9
+ import {createR188OwnerUacRequest} from '../src/r188-owner-uac.mjs';
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';
14
+ const execFileAsync=promisify(execFile);
15
+ const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
16
+ const STATE='C:\\Users\\DEADBYTE\\.deadbyte-mcp',RUNTIME=path.win32.join(STATE,'runtime');
17
+ const PS='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
18
+ const sha=b=>createHash('sha256').update(b).digest('hex');
19
+ async function bounded(file,limit){const s=await lstat(file);if(!s.isFile()||s.isSymbolicLink()||s.size<1||s.size>limit)throw Error('R193 request input unsafe');return readFile(file);}
20
+ async function main(){
21
+ if(process.platform!=='win32'||process.arch!=='x64'||process.argv.length!==2)throw Error('R193 live request accepts no arguments');
22
+ const manifestPath=path.join(ROOT,'MANIFEST.SHA256');
23
+ await inspectTrustedInstallation(['C:\\Program Files\\nodejs\\node.exe',THIS,manifestPath,
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'),
26
+ path.join(ROOT,'src','privileged-install-trust-r89.mjs')]);
27
+ const manifestBytes=await bounded(manifestPath,1024*1024);
28
+ await verifyManifestTreeExact(ROOT,parseManifest(manifestBytes.toString('utf8')));
29
+ const pointer=JSON.parse((await bounded(path.win32.join(STATE,'active-release.json'),64*1024)).toString('utf8'));
30
+ if(pointer.manifest_sha256!==sha(manifestBytes))throw Error('R193 request package is not exact active release');
31
+ const codingBytes=await bounded(path.win32.join(pointer.generation_root,'coding-policy.json'),1024*1024);
32
+ const autonomousBytes=await bounded(path.win32.join(pointer.generation_root,'autonomous-policy.json'),1024*1024);
33
+ const coding=JSON.parse(codingBytes),autonomous=JSON.parse(autonomousBytes);
34
+ if(!coding.roots?.core?.path||!Array.isArray(autonomous.root_ids)||autonomous.root_ids.length!==1||autonomous.root_ids[0]!=='core')
35
+ throw Error('R193 request policy root is not the bounded core project');
36
+ const env={...process.env,DEADBYTE_CONTROLLER_CONFIG:pointer.config_path,DEADBYTE_CONTROLLER_RUNTIME_ROOT:RUNTIME};
37
+ const observation=await observeCanonicalController({stateRoot:STATE,powershell:PS,env,execFileAsync});
38
+ if(observation.state!=='ONLINE'||!observation.supervisor?.running)throw Error('R193 request requires ONLINE Limited runtime');
39
+ const machineEpoch=createR193LiveMachineEpoch({activePointer:pointer,controllerObservation:observation});
40
+ const request=createR188OwnerUacRequest({machineEpoch,releaseManifestSha256:sha(manifestBytes),
41
+ codingPolicySha256:sha(codingBytes),autonomousPolicySha256:sha(autonomousBytes),
42
+ rootId:'core',projectRoot:coding.roots.core.path,maxSeconds:600,now:new Date(),expiresInMs:300000});
43
+ const out=path.win32.join(RUNTIME,'owner-consent','r193-request-'+request.request_sha256+'.json');
44
+ const handle=await open(out,'wx',0o600);try{await handle.writeFile(canonicalJson(request)+'\n');await handle.sync();}finally{await handle.close();}
45
+ process.stdout.write(JSON.stringify({status:'R193_OWNER_REQUEST_CREATED',request_path:out,
46
+ request_sha256:request.request_sha256,review_phrase:request.review_phrase,
47
+ expires_at_utc:request.subject.expires_at_utc,authority_granted:false})+'\n');
48
+ }
49
+ main().catch(error=>{console.error(String(error?.message??error).slice(0,500));process.exitCode=2;});
@@ -0,0 +1,42 @@
1
+ #requires -Version 5.1
2
+ #requires -RunAsAdministrator
3
+ [CmdletBinding()]
4
+ param([Parameter(Mandatory=$true)][string]$RequestPath)
5
+ $ErrorActionPreference='Stop';Set-StrictMode -Version Latest
6
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
7
+ $program=[IO.Path]::GetFullPath($env:ProgramFiles).TrimEnd('\')+'\'
8
+ if(-not ($root.TrimEnd('\')+'\').StartsWith($program,[StringComparison]::OrdinalIgnoreCase)){
9
+ throw 'R193 owner broker must run from an R89-protected Program Files package'
10
+ }
11
+ if(-not [Environment]::UserInteractive){throw 'R193 owner approval requires an interactive desktop'}
12
+ $node='C:\Program Files\nodejs\node.exe'
13
+ $broker=Join-Path $root 'scripts\r193-owner-uac-broker.mjs'
14
+ $request=[IO.Path]::GetFullPath($RequestPath)
15
+ $raw=@(& $node $broker preflight $request 2>&1) -join [Environment]::NewLine
16
+ if($LASTEXITCODE -ne 0){throw ('R193 preflight blocked: '+$raw.Substring(0,[Math]::Min(500,$raw.Length)))}
17
+ $preview=$raw|ConvertFrom-Json
18
+ if([string]$preview.status -cne 'READY_FOR_OWNER_GESTURE' -or $preview.authority_granted -or $preview.owner_approved){
19
+ throw 'R193 owner preflight returned an invalid state'
20
+ }
21
+ Write-Host '';Write-Host 'DEADBYTE R193 / OWNER AUTONOMOUS APPROVAL' -ForegroundColor Yellow
22
+ Write-Host 'This signs one short-lived exact request. It does not itself arm Autonomous.'
23
+ Write-Host ('Request SHA-256: '+[string]$preview.request_sha256)
24
+ Write-Host ('Project: '+[string]$preview.project_root)
25
+ Write-Host ('Operation: '+[string]$preview.operation)
26
+ Write-Host ('Duration cap seconds: '+[string]$preview.max_seconds)
27
+ Write-Host ('Expires UTC: '+[string]$preview.expires_at_utc)
28
+ $phrase=[string]$preview.review_phrase
29
+ $entered=Read-Host ('Type '+$phrase+' to approve this exact request')
30
+ if($entered -cne $phrase){throw 'R193 owner rejected request'}
31
+ $owner='C:\Program Files\DEADBYTE-OwnerAuthority'
32
+ if(-not(Test-Path -LiteralPath $owner -PathType Container)){throw 'R193 owner authority is not enrolled'}
33
+ $gesture=[ordered]@{schema='deadbyte.r193-owner-gesture.v1';status='APPROVED';
34
+ request_sha256=[string]$preview.request_sha256;review_phrase=$phrase;
35
+ approved_at_utc=[DateTime]::UtcNow.ToString('o')}
36
+ $gesturePath=Join-Path $owner ('gesture-'+[string]$preview.request_sha256+'.json')
37
+ $bytes=(New-Object Text.UTF8Encoding($false)).GetBytes(($gesture|ConvertTo-Json -Compress)+[Environment]::NewLine)
38
+ $stream=[IO.File]::Open($gesturePath,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::None)
39
+ try{$stream.Write($bytes,0,$bytes.Length);$stream.Flush($true)}finally{$stream.Dispose()}
40
+ $out=@(& $node $broker approve $request 2>&1) -join [Environment]::NewLine
41
+ if($LASTEXITCODE -ne 0){throw ('R193 signing blocked: '+$out.Substring(0,[Math]::Min(500,$out.Length)))}
42
+ Write-Output $out
@@ -0,0 +1,139 @@
1
+ // Protected R193 owner broker. This entrypoint is intentionally fixed to the
2
+ // local DEADBYTE state and owner-authority roots; callers choose only an exact
3
+ // request file. It never issues authority. The R186 transaction remains the
4
+ // sole grant/epoch mutation boundary.
5
+ import {createHash,createPrivateKey,createPublicKey} from 'node:crypto';
6
+ import {execFile} from 'node:child_process';
7
+ import {promisify} from 'node:util';
8
+ import {lstat,mkdir,open,readFile} from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import {fileURLToPath} from 'node:url';
11
+ import {canonicalJson} from '../src/canonical-json.mjs';
12
+ import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
13
+ import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
14
+ import {buildR193LiveOwnerBoundary} from '../src/r193-live-owner-subject.mjs';
15
+ import {approveR193OwnerRequest} from '../src/r193-owner-uac-broker.mjs';
16
+ import {createR186OwnerAnchor} from '../src/r186-owner-anchor.mjs';
17
+ import {inspectR193OwnerSecretAcl} from '../src/r193-owner-secret-acl.mjs';
18
+ import {observeCanonicalController} from '../src/r195-canonical-owner-observation.mjs';
19
+
20
+ const execFileAsync=promisify(execFile);
21
+ const THIS=fileURLToPath(import.meta.url),ROOT=path.resolve(path.dirname(THIS),'..');
22
+ const STATE='C:\\Users\\DEADBYTE\\.deadbyte-mcp';
23
+ const RUNTIME=path.win32.join(STATE,'runtime');
24
+ const OWNER='C:\\Program Files\\DEADBYTE-OwnerAuthority';
25
+ const PRIVATE=path.win32.join(OWNER,'owner-private.der');
26
+ const PUBLIC=path.win32.join(OWNER,'owner-public.pem');
27
+ const ANCHOR=path.win32.join(OWNER,'owner-anchor.json');
28
+ const NATIVE=path.join(ROOT,'bin','deadbyte-owner-token-r193.exe');
29
+ const PS='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
30
+ const NODE='C:\\Program Files\\nodejs\\node.exe';
31
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
32
+ const block=reason=>{throw new Error('R193_OWNER_UAC_BROKER_BLOCKED: '+reason);};
33
+ async function bounded(file,limit){
34
+ const stat=await lstat(file);
35
+ if(!stat.isFile()||stat.isSymbolicLink()||stat.size<1||stat.size>limit)block('unsafe input: '+path.basename(file));
36
+ return readFile(file);
37
+ }
38
+ async function exclusive(file,bytes){
39
+ await mkdir(path.dirname(file),{recursive:true});
40
+ const handle=await open(file,'wx',0o600);
41
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
42
+ }
43
+ async function exactOrWrite(file,bytes){
44
+ try{await exclusive(file,bytes);return 'CREATED';}
45
+ catch(error){
46
+ if(error?.code!=='EEXIST')throw error;
47
+ if(!(await readFile(file)).equals(bytes))block('existing output differs: '+path.basename(file));
48
+ return 'ALREADY_EXACT';
49
+ }
50
+ }
51
+ async function jsonExec(file,args,options={}){
52
+ const {stdout}=await execFileAsync(file,args,{windowsHide:true,timeout:20000,
53
+ maxBuffer:1024*1024,encoding:'utf8',...options});
54
+ try{return JSON.parse(stdout);}catch{block('invalid JSON from protected child');}
55
+ }
56
+ async function uacPolicy(){
57
+ const command=`$p=Get-ItemProperty -LiteralPath 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System';[pscustomobject]@{enable_uac=([int]$p.EnableLUA -eq 1);secure_desktop=([int]$p.PromptOnSecureDesktop -eq 1);prompt_mode=$(if([int]$p.ConsentPromptBehaviorAdmin -eq 0){'silent'}else{'explicit_secure_desktop'})}|ConvertTo-Json -Compress`;
58
+ return jsonExec(PS,['-NoLogo','-NoProfile','-NonInteractive','-Command',command]);
59
+ }
60
+ async function live(request){
61
+ const manifestPath=path.join(ROOT,'MANIFEST.SHA256');
62
+ const protectedFiles=[NODE,THIS,manifestPath,NATIVE,
63
+ path.join(ROOT,'src','r193-live-owner-subject.mjs'),
64
+ path.join(ROOT,'src','r193-owner-uac-broker.mjs'),
65
+ path.join(ROOT,'src','r195-canonical-owner-observation.mjs'),
66
+ path.join(ROOT,'src','r193-uac-r70-bridge.mjs'),
67
+ path.join(ROOT,'src','r193-owner-secret-acl.mjs'),
68
+ path.join(ROOT,'src','r188-owner-uac.mjs'),
69
+ path.join(ROOT,'src','r70-owner-approval.mjs'),
70
+ path.join(ROOT,'src','canonical-json.mjs'),
71
+ path.join(ROOT,'src','privileged-install-trust-r89.mjs'),
72
+ path.join(ROOT,'src','release-slot.mjs')];
73
+ const installation=await inspectTrustedInstallation(protectedFiles);
74
+ const manifestBytes=await bounded(manifestPath,1024*1024);
75
+ await verifyManifestTreeExact(ROOT,parseManifest(manifestBytes.toString('utf8')));
76
+ const pointer=JSON.parse((await bounded(path.win32.join(STATE,'active-release.json'),64*1024)).toString('utf8'));
77
+ if(pointer.manifest_sha256!==sha(manifestBytes))block('protected package is not exact active release');
78
+ const generation=pointer.generation_root;
79
+ const codingPath=path.win32.join(generation,'coding-policy.json');
80
+ const autonomousPath=path.win32.join(generation,'autonomous-policy.json');
81
+ const configPath=pointer.config_path;
82
+ const env={...process.env,DEADBYTE_CONTROLLER_CONFIG:configPath,
83
+ DEADBYTE_CONTROLLER_RUNTIME_ROOT:RUNTIME};
84
+ const observation=await observeCanonicalController({stateRoot:STATE,powershell:PS,env,execFileAsync});
85
+ const supervisor=JSON.parse((await bounded(path.win32.join(RUNTIME,'supervisor.instance.json'),64*1024)).toString('utf8'));
86
+ const sources={bridge:observation.bridge,core:observation.core,cloud:observation.cloud,supervisor};
87
+ const processReports={};
88
+ for(const component of ['bridge','core','cloud','supervisor'])
89
+ processReports[component]=await jsonExec(NATIVE,['--inspect-pid',String(sources[component]?.pid)]);
90
+ const [codingPolicyBytes,autonomousPolicyBytes,uac]=await Promise.all([
91
+ bounded(codingPath,1024*1024),bounded(autonomousPath,1024*1024),uacPolicy()]);
92
+ const built=buildR193LiveOwnerBoundary({request,activePointer:pointer,installedManifestBytes:manifestBytes,
93
+ codingPolicyBytes,autonomousPolicyBytes,controllerObservation:observation,
94
+ supervisorLedger:supervisor,processReports,brokerR89Trusted:installation.trusted,
95
+ keyAclTrusted:false,uac,ownerGesture:'pending',now:new Date()});
96
+ return {...built,pointer,manifestBytes,codingPolicyBytes,autonomousPolicyBytes,uac};
97
+ }
98
+ async function main(){
99
+ if(process.platform!=='win32'||process.arch!=='x64')block('Windows x64 required');
100
+ const [mode,requestPath]=process.argv.slice(2);
101
+ if(!['preflight','approve'].includes(mode)||process.argv.slice(2).length!==2||
102
+ !path.win32.isAbsolute(requestPath))block('usage: <preflight|approve> <absolute-request-json>');
103
+ await inspectTrustedInstallation([NODE,THIS,path.join(ROOT,'MANIFEST.SHA256'),NATIVE]);
104
+ const request=JSON.parse((await bounded(requestPath,64*1024)).toString('utf8'));
105
+ const state=await live(request);
106
+ if(mode==='preflight'){
107
+ process.stdout.write(JSON.stringify({status:'READY_FOR_OWNER_GESTURE',
108
+ request_sha256:request.request_sha256,review_phrase:request.review_phrase,
109
+ project_root:request.subject.project_root,operation:request.subject.operation,
110
+ max_seconds:request.subject.max_seconds,expires_at_utc:request.subject.expires_at_utc,
111
+ authority_granted:false,owner_approved:false})+'\n');
112
+ return;
113
+ }
114
+ const gesturePath=path.win32.join(OWNER,'gesture-'+request.request_sha256+'.json');
115
+ const gesture=JSON.parse((await bounded(gesturePath,16*1024)).toString('utf8'));
116
+ if(gesture?.schema!=='deadbyte.r193-owner-gesture.v1'||gesture?.status!=='APPROVED'||
117
+ gesture?.request_sha256!==request.request_sha256||gesture?.review_phrase!==request.review_phrase||
118
+ typeof gesture?.approved_at_utc!=='string'||Date.now()-Date.parse(gesture.approved_at_utc)<0||
119
+ Date.now()-Date.parse(gesture.approved_at_utc)>60000)block('owner gesture missing, stale or mismatched');
120
+ const secret=await inspectR193OwnerSecretAcl([OWNER,PRIVATE]);
121
+ const [privateKeyDer,publicPem,anchorBytes]=await Promise.all([
122
+ bounded(PRIVATE,8192),bounded(PUBLIC,8192),bounded(ANCHOR,4096)]);
123
+ const privateKey=createPrivateKey({key:privateKeyDer,format:'der',type:'pkcs8'});
124
+ const derived=createR186OwnerAnchor(createPublicKey(privateKey).export({format:'pem',type:'spki'}).toString());
125
+ const anchor=JSON.parse(anchorBytes.toString('utf8'));
126
+ if(derived.public_key_pem!==publicPem.toString('utf8')||
127
+ canonicalJson(derived.anchor)!==canonicalJson(anchor))block('owner key enrollment mismatch');
128
+ const result=approveR193OwnerRequest({request,expected:state.expected,privateKeyDer,
129
+ boundary:{...state.boundary,key_acl_trusted:secret.trusted,owner_gesture:'approved'},now:new Date()});
130
+ const bytes=Buffer.from(canonicalJson(result.approval)+'\n','utf8');
131
+ const protectedApproval=path.win32.join(OWNER,'approval-'+request.request_sha256+'.json');
132
+ const runtimeApproval=path.win32.join(RUNTIME,'owner-consent','autonomous-approval.json');
133
+ const protected_state=await exactOrWrite(protectedApproval,bytes);
134
+ const runtime_state=await exactOrWrite(runtimeApproval,bytes);
135
+ process.stdout.write(JSON.stringify({...result,approval:undefined,protected_state,runtime_state,
136
+ protected_approval_sha256:sha(bytes),protected_approval_path:protectedApproval,
137
+ runtime_approval_path:runtimeApproval})+'\n');
138
+ }
139
+ main().catch(error=>{console.error(String(error?.message??error).slice(0,600));process.exitCode=2;});
@@ -0,0 +1,62 @@
1
+ #requires -Version 5.1
2
+ #requires -RunAsAdministrator
3
+ [CmdletBinding()]
4
+ param([Parameter(Mandatory=$true)][string]$RequestPath)
5
+ $ErrorActionPreference='Stop';Set-StrictMode -Version Latest
6
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
7
+ $program=[IO.Path]::GetFullPath($env:ProgramFiles).TrimEnd('\')+'\'
8
+ if(-not ($root.TrimEnd('\')+'\').StartsWith($program,[StringComparison]::OrdinalIgnoreCase)){
9
+ throw 'R193 enrollment must run from an R89-protected Program Files package'
10
+ }
11
+ if(-not [Environment]::UserInteractive){throw 'R193 enrollment requires an interactive owner desktop'}
12
+ $node='C:\Program Files\nodejs\node.exe'
13
+ $broker=Join-Path $root 'scripts\r193-owner-uac-broker.mjs'
14
+ $keygen=Join-Path $root 'scripts\r193-owner-keygen.mjs'
15
+ $request=[IO.Path]::GetFullPath($RequestPath)
16
+ $raw=@(& $node $broker preflight $request 2>&1) -join [Environment]::NewLine
17
+ if($LASTEXITCODE -ne 0){throw ('R193 enrollment preflight blocked: '+$raw.Substring(0,[Math]::Min(500,$raw.Length)))}
18
+ $preview=$raw|ConvertFrom-Json
19
+ if([string]$preview.status -cne 'READY_FOR_OWNER_GESTURE' -or $preview.authority_granted -or $preview.owner_approved){
20
+ throw 'R193 enrollment preflight returned an invalid state'
21
+ }
22
+ Write-Host '';Write-Host 'DEADBYTE R193 / ENROLL OWNER AUTHORITY' -ForegroundColor Yellow
23
+ Write-Host 'A new owner-only Ed25519 identity will be created under Program Files.'
24
+ Write-Host 'Limited DEADBYTE processes will not be able to read or use the private key.'
25
+ Write-Host ('Request SHA-256: '+[string]$preview.request_sha256)
26
+ Write-Host ('Project: '+[string]$preview.project_root)
27
+ Write-Host ('Duration cap seconds: '+[string]$preview.max_seconds)
28
+ $phrase=[string]$preview.review_phrase
29
+ $entered=Read-Host ('Type '+$phrase+' to enroll and approve this exact request')
30
+ if($entered -cne $phrase){throw 'R193 owner rejected enrollment'}
31
+ $owner='C:\Program Files\DEADBYTE-OwnerAuthority'
32
+ if(Test-Path -LiteralPath $owner){throw 'R193 owner authority already exists; use the approval-only workflow'}
33
+ $admins=New-Object Security.Principal.SecurityIdentifier('S-1-5-32-544')
34
+ $system=New-Object Security.Principal.SecurityIdentifier('S-1-5-18')
35
+ $inherit=[Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'
36
+ $none=[Security.AccessControl.PropagationFlags]::None
37
+ $allow=[Security.AccessControl.AccessControlType]::Allow
38
+ New-Item -ItemType Directory -Path $owner -ErrorAction Stop | Out-Null
39
+ $acl=New-Object Security.AccessControl.DirectorySecurity
40
+ $acl.SetAccessRuleProtection($true,$false);$acl.SetOwner($admins)
41
+ $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($admins,'FullControl',$inherit,$none,$allow)))
42
+ $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($system,'FullControl',$inherit,$none,$allow)))
43
+ Set-Acl -LiteralPath $owner -AclObject $acl
44
+ # Keygen requires the directory to exist with its final ACL. It never accepts a
45
+ # target path and creates every key file with CreateNew/no-clobber semantics.
46
+ $keyRaw=@(& $node $keygen 2>&1) -join [Environment]::NewLine
47
+ if($LASTEXITCODE -ne 0){throw ('R193 protected key enrollment blocked: '+$keyRaw.Substring(0,[Math]::Min(500,$keyRaw.Length)))}
48
+ $keyResult=$keyRaw|ConvertFrom-Json
49
+ if([string]$keyResult.status -cne 'R193_OWNER_AUTHORITY_ENROLLED' -or $keyResult.private_key_exported -or $keyResult.authority_granted){
50
+ throw 'R193 key enrollment returned an invalid state'
51
+ }
52
+ Write-Host ('Owner key fingerprint: '+[string]$keyResult.owner_key_id) -ForegroundColor Yellow
53
+ $gesture=[ordered]@{schema='deadbyte.r193-owner-gesture.v1';status='APPROVED';
54
+ request_sha256=[string]$preview.request_sha256;review_phrase=$phrase;
55
+ approved_at_utc=[DateTime]::UtcNow.ToString('o')}
56
+ $gesturePath=Join-Path $owner ('gesture-'+[string]$preview.request_sha256+'.json')
57
+ $bytes=(New-Object Text.UTF8Encoding($false)).GetBytes(($gesture|ConvertTo-Json -Compress)+[Environment]::NewLine)
58
+ $stream=[IO.File]::Open($gesturePath,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::None)
59
+ try{$stream.Write($bytes,0,$bytes.Length);$stream.Flush($true)}finally{$stream.Dispose()}
60
+ $out=@(& $node $broker approve $request 2>&1) -join [Environment]::NewLine
61
+ if($LASTEXITCODE -ne 0){throw ('R193 signing blocked after protected enrollment: '+$out.Substring(0,[Math]::Min(500,$out.Length)))}
62
+ Write-Output $out
@@ -0,0 +1,49 @@
1
+ $ErrorActionPreference='Stop'
2
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
3
+ $probe=Join-Path $root 'scripts\r193-limited-subject-probe.ps1'
4
+ $expectedSha='16317bffb0765e3856a6f64353ef728754e346636161cf2214ec0d0d3e5c7826'
5
+ if((Get-FileHash $probe).Hash.ToLowerInvariant() -cne $expectedSha){throw 'R193_PROBE_SCRIPT_CHANGED'}
6
+ $output=Join-Path $root 'R193-STANDARD-TOKEN-PROBE.json'
7
+ if(Test-Path $output){throw 'R193_EXISTING_OUTPUT - read before retest'}
8
+ $name='DEADBYTE-R193-Limited-Token-Diagnostic'
9
+ if(Get-ScheduledTask -TaskName $name -TaskPath '\' -ErrorAction SilentlyContinue){throw 'R193_TASK_ALREADY_EXISTS'}
10
+ $identity=[Security.Principal.WindowsIdentity]::GetCurrent()
11
+ $account=$identity.Name
12
+ $ps=Join-Path $env:WINDIR 'System32\WindowsPowerShell\v1.0\powershell.exe'
13
+ $arg='-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "'+$probe+'"'
14
+ $action=New-ScheduledTaskAction -Execute $ps -Argument $arg -WorkingDirectory $root
15
+ $trigger=New-ScheduledTaskTrigger -Once -At ((Get-Date).AddDays(1))
16
+ $principal=New-ScheduledTaskPrincipal -UserId $account -LogonType Interactive -RunLevel Limited
17
+ $settings=New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Minutes 1)
18
+ $registered=$false
19
+ try {
20
+ $null=Register-ScheduledTask -TaskName $name -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description 'One-shot R193 native Windows token diagnostic. No grants.' -ErrorAction Stop
21
+ $registered=$true
22
+ $task=Get-ScheduledTask -TaskName $name -ErrorAction Stop
23
+ if([string]$task.Principal.RunLevel -ne 'Limited' -or [string]$task.Principal.LogonType -ne 'Interactive'){throw 'R193_TASK_NOT_LIMITED'}
24
+ Start-ScheduledTask -TaskName $name -ErrorAction Stop
25
+ $done=$false
26
+ for($i=0;$i -lt 28;$i++){
27
+ Start-Sleep -Milliseconds 700
28
+ if(Test-Path -LiteralPath $output -PathType Leaf){$done=$true;break}
29
+ }
30
+ if(-not $done){throw 'R193_LIMITED_TASK_NO_REPORT'}
31
+ $report=Get-Content -LiteralPath $output -Raw | ConvertFrom-Json
32
+ $info=Get-ScheduledTaskInfo -TaskName $name -ErrorAction Stop
33
+ $pass=($report.expected_standard -eq $true -and $report.process_report.elevated -eq $false -and $report.process_report.admin_enabled -eq $false -and $report.authority_granted -eq $false -and $info.LastTaskResult -eq 0)
34
+ [pscustomobject]@{
35
+ schema='deadbyte.r193-limited-token-scheduler-smoke.v1'
36
+ state=$(if($pass){'PASS'}else{'FAIL'})
37
+ limited_task=$name
38
+ scheduled_runlevel=[string]$task.Principal.RunLevel
39
+ native_subject=$report.process_report
40
+ task_exit=$info.LastTaskResult
41
+ source_sha256=$expectedSha
42
+ no_grant=$true
43
+ production_untouched=$true
44
+ }|ConvertTo-Json -Depth 8 -Compress
45
+ if(-not $pass){throw 'R193_EXPECTED_STANDARD_TOKEN_MISSING'}
46
+ } finally {
47
+ if($registered){Unregister-ScheduledTask -TaskName $name -TaskPath '\' -Confirm:$false -ErrorAction Stop}
48
+ }
49
+ if(Get-ScheduledTask -TaskName $name -TaskPath '\' -ErrorAction SilentlyContinue){throw 'R193_PROBE_TASK_NOT_REMOVED'}
@@ -0,0 +1,7 @@
1
+ $ErrorActionPreference='Stop'
2
+ $o=[ordered]@{schema='deadbyte.r193-toolchain.v1';toolchain=@{};disk_free_bytes=[int64](Get-PSDrive D).Free}
3
+ foreach($name in @('cl.exe','clang++.exe','g++.exe','cmake.exe','node.exe','powershell.exe')){
4
+ $q=Get-Command $name -ErrorAction SilentlyContinue
5
+ $o.toolchain[$name]=if($null -eq $q){'MISSING'}else{[string]$q.Source}
6
+ }
7
+ $o|ConvertTo-Json -Depth 4 -Compress
@@ -0,0 +1,21 @@
1
+ import {spawnSync} from 'node:child_process';
2
+ import {fileURLToPath} from 'node:url';
3
+ const root=fileURLToPath(new URL('..',import.meta.url));
4
+ const files=[
5
+ 'test/r188-owner-uac.test.mjs',
6
+ 'test/r188-uac-boundary.test.mjs',
7
+ 'test/r186-owner-grant-broker.test.mjs',
8
+ 'test/r193-uac-r70-bridge.test.mjs'
9
+ ];
10
+ const r=spawnSync(process.execPath,['--test','--test-concurrency=1',...files],{
11
+ cwd:root,encoding:'utf8',timeout:150000,maxBuffer:1024*1024,windowsHide:true,shell:false
12
+ });
13
+ const output=(r.stdout??'')+'\n'+(r.stderr??'');
14
+ const get=n=>{const m=[...output.matchAll(new RegExp('(?:^|\\n)[ℹ#]\\s*'+n+'\\s+(\\d+)','g'))];return m.length?Number(m.at(-1)[1]):null;};
15
+ const summary={tests:get('tests'),pass:get('pass'),fail:get('fail'),skipped:get('skipped')};
16
+ const pass=r.status===0&&summary.tests>=12&&summary.fail===0&&summary.pass===summary.tests-summary.skipped;
17
+ console.log(JSON.stringify({schema:'deadbyte.r193-uac-bridge-focused.v1',
18
+ status:pass?'PASS':'FAIL',exit:r.status,summary,files,
19
+ no_real_owner_enrollment:true,authority_granted:false,
20
+ production_untouched:true,tail:pass?null:output.slice(-12000)}));
21
+ if(!pass)process.exitCode=1;
@@ -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
+ }