deadbyte-mcp 0.15.72 → 0.15.74

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 (76) hide show
  1. package/MANIFEST.SHA256 +75 -27
  2. package/PROVENANCE.json +42 -14
  3. package/README.txt +24 -18
  4. package/RELEASE.json +52 -18
  5. package/SBOM.cdx.json +14 -2
  6. package/TEST-MATRIX.json +30 -2
  7. package/bin/deadbyte-owner-token-r193.exe +0 -0
  8. package/bridge/package.json +1 -1
  9. package/controller/deadbyte-process-policy.json +4 -4
  10. package/docs/R184-package-lock.json +2 -2
  11. package/native/deadbyte-owner-token-r193.cpp +156 -0
  12. package/package.json +2 -2
  13. package/scripts/gate-windows-r193.ps1 +108 -0
  14. package/scripts/gate-windows-r194.ps1 +112 -0
  15. package/scripts/npm-interactive-r194.mjs +13 -0
  16. package/scripts/npm-publication-r65.mjs +64 -4
  17. package/scripts/npm-release-r48.mjs +58 -11
  18. package/scripts/npm-release-readiness-r193.mjs +80 -0
  19. package/scripts/npm-release-readiness-r194.mjs +80 -0
  20. package/scripts/r188-owner-uac-review.ps1 +91 -0
  21. package/scripts/r188-uac-review-preview.mjs +65 -0
  22. package/scripts/r193-compile-token.ps1 +22 -0
  23. package/scripts/r193-evidence-relocate.ps1 +12 -0
  24. package/scripts/r193-focused-gate.mjs +20 -0
  25. package/scripts/r193-import-r188-scripts.ps1 +14 -0
  26. package/scripts/r193-limited-subject-probe.ps1 +25 -0
  27. package/scripts/r193-migrate-runtime-limited.ps1 +103 -0
  28. package/scripts/r193-owner-keygen.mjs +43 -0
  29. package/scripts/r193-owner-request-live.mjs +50 -0
  30. package/scripts/r193-owner-uac-approve.ps1 +42 -0
  31. package/scripts/r193-owner-uac-broker.mjs +139 -0
  32. package/scripts/r193-owner-uac-enroll-and-approve.ps1 +62 -0
  33. package/scripts/r193-test-limited-token.ps1 +49 -0
  34. package/scripts/r193-toolchain-inventory.ps1 +7 -0
  35. package/scripts/r193-uac-bridge-focused.mjs +21 -0
  36. package/src/r188-owner-uac.mjs +105 -0
  37. package/src/r188-uac-boundary.mjs +21 -0
  38. package/src/r193-live-owner-subject.mjs +110 -0
  39. package/src/r193-owner-secret-acl.mjs +67 -0
  40. package/src/r193-owner-uac-broker.mjs +85 -0
  41. package/src/r193-uac-r70-bridge.mjs +54 -0
  42. package/src/version.mjs +1 -1
  43. package/test/process-policy-refresh.test.mjs +1 -1
  44. package/test/r130-release-security-contract.test.mjs +8 -8
  45. package/test/r132-release-identity.test.mjs +7 -7
  46. package/test/r153-prepublish-identity.test.mjs +1 -1
  47. package/test/r160-release-contract.test.mjs +3 -3
  48. package/test/r165-live-cli-skew.test.mjs +1 -1
  49. package/test/r167-release-contract.test.mjs +11 -11
  50. package/test/r168-release-contract.test.mjs +4 -4
  51. package/test/r172-release-contract.test.mjs +6 -6
  52. package/test/r173-release-contract.test.mjs +16 -16
  53. package/test/r179-release-contract.test.mjs +11 -11
  54. package/test/r188-owner-uac.test.mjs +48 -0
  55. package/test/r188-uac-boundary.test.mjs +42 -0
  56. package/test/r190-release-contract.test.mjs +10 -10
  57. package/test/r191-release-contract.test.mjs +12 -12
  58. package/test/r192-release-identity.test.mjs +10 -10
  59. package/test/r193-limited-migration-contract.test.mjs +26 -0
  60. package/test/r193-live-owner-subject.test.mjs +61 -0
  61. package/test/r193-native-process-observer.test.mjs +36 -0
  62. package/test/r193-native-token.test.mjs +43 -0
  63. package/test/r193-owner-enrollment-entrypoint.test.mjs +38 -0
  64. package/test/r193-owner-secret-acl.test.mjs +23 -0
  65. package/test/r193-owner-uac-broker.test.mjs +82 -0
  66. package/test/r193-owner-uac-entrypoint.test.mjs +36 -0
  67. package/test/r193-release-identity.test.mjs +56 -0
  68. package/test/r193-release-readiness.test.mjs +87 -0
  69. package/test/r193-uac-r70-bridge.test.mjs +88 -0
  70. package/test/r193-windows-gate.test.mjs +30 -0
  71. package/test/r194-npm-auth-recovery.test.mjs +77 -0
  72. package/test/r194-npm-preauth.test.mjs +57 -0
  73. package/test/r194-release-identity.test.mjs +43 -0
  74. package/test/r194-release-readiness.test.mjs +87 -0
  75. package/test/r194-windows-gate.test.mjs +21 -0
  76. package/test/r59-tool-surface-compat.test.mjs +1 -1
@@ -1,6 +1,7 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import { createHash } from 'node:crypto';
3
3
  import { reconcileNpmPublication } from './npm-publication-r65.mjs';
4
+ import { classifyNpmPublishFailure } from './npm-interactive-r194.mjs';
4
5
  import { mkdtemp, readFile, rm, unlink, mkdir } from 'node:fs/promises';
5
6
  import {preserveNpmTarball,assertVacantPackDestination} from './npm-preserve-artifact-r67.mjs';
6
7
  import {assertR67NpmPublishReady} from './npm-release-readiness-r67.mjs';
@@ -12,8 +13,10 @@ import {assertR165NpmPublishReady} from './npm-release-readiness-r165.mjs';
12
13
  import {assertR166NpmPublishReady} from './npm-release-readiness-r166.mjs';
13
14
  import {assertR167NpmPublishReady,assertR167PackedIdentity} from './npm-release-readiness-r167.mjs';
14
15
  import {assertR168NpmPublishReady,assertR168PackedIdentity} from './npm-release-readiness-r168.mjs';
16
+ import {assertR193NpmPublishReady,assertR193PackedIdentity} from './npm-release-readiness-r193.mjs';
17
+ import {assertR194NpmPublishReady,assertR194PackedIdentity} from './npm-release-readiness-r194.mjs';
15
18
  import {resumePackRecord} from '../src/npm-publication-resume-r168.mjs';
16
- import { existsSync } from 'node:fs';
19
+ import { existsSync,mkdtempSync,readdirSync,readFileSync,rmSync } from 'node:fs';
17
20
  import { resolveStateRoot } from '../src/state-root.mjs';
18
21
  import path from 'node:path';
19
22
  import os from 'node:os';
@@ -46,18 +49,39 @@ function runNpm(args, options = {}) {
46
49
  return run(node, [npmCli, ...args], options);
47
50
  }
48
51
 
52
+ function verifyNpmOwnerPreflight(){
53
+ try{
54
+ const registry=runNpm(['config','get','registry'],{timeout:30000}).trim();
55
+ if(registry!=='https://registry.npmjs.org/')return false;
56
+ const name=runNpm(['whoami','--registry=https://registry.npmjs.org/'],{timeout:30000}).trim();
57
+ if(name!=='deadbytes')return false;
58
+ const owners=runNpm(['owner','ls','deadbyte-mcp','--registry=https://registry.npmjs.org/'],{timeout:30000});
59
+ return owners.split(/\r?\n/).some(line=>/^\s*deadbytes(?:\s|$)/.test(line));
60
+ }catch{return false;}
61
+ }
62
+
49
63
  function runNpmInteractive(args, options = {}) {
50
64
  const { cwd = root, timeout = 300000 } = options;
51
- const r = spawnSync(node, [npmCli, ...args], {
52
- cwd,
53
- timeout,
54
- stdio: 'inherit',
55
- shell: false,
56
- windowsHide: false,
57
- });
58
- if (r.error) throw r.error;
59
- if (r.status !== 0) throw new Error('Interactive npm command failed (exit=' + r.status + ', cwd=' + cwd + ')');
60
- return '';
65
+ const logDir=mkdtempSync(path.join(os.tmpdir(),'deadbyte-r194-npm-diagnostic-'));
66
+ try{
67
+ // Preserve interactive browser/2FA prompts; classify failures from the
68
+ // isolated npm debug log without printing or preserving credential data.
69
+ const r=spawnSync(node,[npmCli,...args,'--logs-dir',logDir],{
70
+ cwd,timeout,stdio:'inherit',shell:false,windowsHide:false
71
+ });
72
+ if(r.error)throw r.error;
73
+ if(r.status!==0){
74
+ const debug=readdirSync(logDir).filter(name=>name.endsWith('-debug-0.log')).slice(-3)
75
+ .map(name=>readFileSync(path.join(logDir,name),'utf8').slice(-16000)).join('\n');
76
+ const reason=classifyNpmPublishFailure({exitCode:r.status,output:debug});
77
+ const error=new Error('Interactive npm publish did not complete; classified '+reason);
78
+ error.code=reason;
79
+ throw error;
80
+ }
81
+ return '';
82
+ }finally{
83
+ rmSync(logDir,{recursive:true,force:true});
84
+ }
61
85
  }
62
86
 
63
87
  function parseJson(text) {
@@ -123,6 +147,16 @@ async function main() {
123
147
  if (!publishOnly) throw new Error('PUBLISH_BLOCKED R168 requires --publish-only; activation is separate');
124
148
  r168Readiness=await assertR168NpmPublishReady(release,{root});
125
149
  }
150
+ let r193Readiness=null;
151
+ if (!isVerifyOnly && version==='0.15.73') {
152
+ if (!publishOnly) throw new Error('PUBLISH_BLOCKED R193 requires --publish-only; owner enrollment, runtime migration, and activation are separate authority boundaries');
153
+ r193Readiness=await assertR193NpmPublishReady(release,{root});
154
+ }
155
+ let r194Readiness=null;
156
+ if (!isVerifyOnly && version==='0.15.74') {
157
+ if (!publishOnly) throw new Error('PUBLISH_BLOCKED R194 requires --publish-only; activation remains separately authorized');
158
+ r194Readiness=await assertR194NpmPublishReady(release,{root});
159
+ }
126
160
  if (release.parent?.release_id !== provenance.parent_release_id ||
127
161
  release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
128
162
  release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
@@ -262,10 +296,23 @@ async function main() {
262
296
  ...r168Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
263
297
  observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
264
298
  });
299
+ if(r193Readiness)assertR193PackedIdentity({
300
+ ...r193Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
301
+ observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
302
+ });
303
+ if(r194Readiness)assertR194PackedIdentity({
304
+ ...r194Readiness,observedSha256:createHash('sha256').update(localBytes).digest('hex'),
305
+ observedIntegrity:localIntegrity,observedShasum:packRecord.shasum
306
+ });
265
307
 
266
308
  console.log('[6/7] Publishing artifact to npm registry...');
267
309
  publishAttempted = true;
310
+ const ownerAuth=async subject=>
311
+ subject.version===version&&subject.manifest_sha256===manifestSha256&&
312
+ subject.tarball_sha256===createHash('sha256').update(localBytes).digest('hex')&&
313
+ verifyNpmOwnerPreflight();
268
314
  const reconciliation=await reconcileNpmPublication({recordPath:publicationDir,version,manifestSha256,localBytes,
315
+ authorizePublish:ownerAuth,authorizeAuthRetry:ownerAuth,
269
316
  publish:async()=>runNpmInteractive(['publish',publishTarball,'--access','public','--auth-type=web'],{timeout:300000}),
270
317
  lookup:async()=>{
271
318
  try{
@@ -0,0 +1,80 @@
1
+ import {createHash} from 'node:crypto';
2
+ import {lstat,readFile} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+
5
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
6
+ const hex64=value=>typeof value==='string'&&/^[0-9a-f]{64}$/.test(value);
7
+ const fail=message=>{throw new Error(`PUBLISH_BLOCKED R193 ${message}`);};
8
+ const required=(value,message)=>{if(!value)fail(message);};
9
+
10
+ async function checkedFile(file,expected,{maxBytes=64*1024*1024}={}){
11
+ required(hex64(expected),'evidence digest missing');
12
+ let info;try{info=await lstat(file);}catch{fail('evidence file absent');}
13
+ required(info.isFile()&&!info.isSymbolicLink()&&info.size>0&&info.size<=maxBytes,'evidence file invalid');
14
+ const bytes=await readFile(file);
15
+ required(sha256(bytes)===expected,'evidence digest differs');
16
+ return bytes;
17
+ }
18
+
19
+ function tapSummary(text,label){
20
+ const summaries=[...text.matchAll(/^# tests (\d+)\s*\r?\n# suites (\d+)\s*\r?\n# pass (\d+)\s*\r?\n# fail (\d+)\s*\r?\n# cancelled (\d+)\s*\r?\n# skipped (\d+)/gm)];
21
+ required(summaries.length>0,`${label} TAP summary absent`);
22
+ const last=summaries.at(-1);
23
+ return {tests:Number(last[1]),passes:Number(last[3]),fails:Number(last[4]),cancelled:Number(last[5]),skips:Number(last[6])};
24
+ }
25
+
26
+ export function assertR193PackedIdentity({tarball_sha256,tarball_integrity,tarball_shasum,observedSha256,observedIntegrity,observedShasum}={}){
27
+ required(hex64(tarball_sha256)&&typeof tarball_integrity==='string'&&tarball_integrity.startsWith('sha512-')&&
28
+ typeof tarball_shasum==='string'&&/^[0-9a-f]{40}$/.test(tarball_shasum),'verified tarball identity invalid');
29
+ required(observedSha256===tarball_sha256&&observedIntegrity===tarball_integrity&&observedShasum===tarball_shasum,
30
+ 'repacked tarball differs from verified closure bytes');
31
+ return true;
32
+ }
33
+
34
+ export async function assertR193NpmPublishReady(release,{root,closureRoot=process.env.DEADBYTE_R193_CLOSURE_ROOT}={}){
35
+ required(release?.version==='0.15.73'&&release?.train==='R193'&&
36
+ release?.r193?.scope==='PROTECTED_OWNER_AUTHORIZATION_AND_LIMITED_RUNTIME_MIGRATION','candidate metadata invalid');
37
+ required(release?.r193?.public_tool_delta===0&&release?.r193?.authority_scope_delta===0,'public authority surface widened');
38
+ required(release?.parent?.version==='0.15.72'&&
39
+ release?.parent?.release_id==='v0.15.72-0a5d9436e06e2d9e'&&
40
+ release?.parent?.manifest_sha256==='0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90'&&
41
+ release?.parent?.generation_manifest_sha256==='aec7b998306a3bbbcc59088648e7bc46ca7e203d749d4550b5b5f372032f92b0','lineage mismatch');
42
+ required(root&&path.isAbsolute(root)&&closureRoot&&path.isAbsolute(closureRoot),'closure root absent');
43
+ const expected=path.resolve(root,'..','..','testing','r193-final-closure');
44
+ required(path.resolve(closureRoot).toLowerCase()===expected.toLowerCase(),'closure root outside scoped testing folder');
45
+
46
+ let closure;try{closure=JSON.parse(await readFile(path.join(closureRoot,'closure.json'),'utf8'));}catch{fail('closure unreadable');}
47
+ required(closure?.schema==='deadbyte.r193-release-closure.v1'&&closure.status==='RELEASE_READY'&&
48
+ closure.version==='0.15.73'&&closure.train==='R193','closure status mismatch');
49
+ required(closure.production_release_id===release.parent.release_id&&
50
+ closure.production_manifest_sha256===release.parent.manifest_sha256&&
51
+ closure.production_generation_manifest_sha256===release.parent.generation_manifest_sha256,'production predecessor mismatch');
52
+ required(hex64(closure.manifest_sha256)&&closure.manifest_sha256===sha256(await readFile(path.join(root,'MANIFEST.SHA256'))),'final manifest drift');
53
+ required(closure.compact_tools===43&&closure.full_tools===117,'catalog count mismatch');
54
+ required(closure.owner_enrollment==='NOT_RUN'&&closure.limited_runtime_migration==='NOT_RUN'&&
55
+ closure.production_activation==='NOT_RUN','prepublication closure crossed production authority boundary');
56
+
57
+ const receipt=JSON.parse((await checkedFile(path.join(closureRoot,'protected-install-receipt.json'),closure.protected_receipt_sha256)).toString('utf8'));
58
+ required(receipt?.status==='PASS'&&receipt.package_version==='0.15.73'&&
59
+ receipt.source_manifest_sha256===closure.manifest_sha256&&receipt.protected_manifest_sha256===closure.manifest_sha256,
60
+ 'protected exact-byte receipt mismatch');
61
+ const focused=(await checkedFile(path.join(closureRoot,'windows-focused.stdout.log'),closure.focused_stdout_sha256)).toString('utf8');
62
+ const full=(await checkedFile(path.join(closureRoot,'windows-full.stdout.log'),closure.full_stdout_sha256)).toString('utf8');
63
+ const verify=(await checkedFile(path.join(closureRoot,'npm-verify.stdout.log'),closure.verify_stdout_sha256)).toString('utf8');
64
+ required(focused.includes('R193_STAGE_PASS=focused'),'focused protected gate incomplete');
65
+ const focusedSummary=tapSummary(focused,'focused');
66
+ required(focusedSummary.fails===0&&focusedSummary.cancelled===0&&focusedSummary.passes>=60&&focusedSummary.skips<=2,'focused regression count mismatch');
67
+ required(full.includes('R193_STAGE_PASS=full'),'full protected gate incomplete');
68
+ const summary=tapSummary(full,'full');
69
+ required(summary.tests>=2150&&summary.passes>=2100&&summary.fails===0&&summary.cancelled===0&&summary.skips<=70&&summary.passes+summary.skips===summary.tests,
70
+ 'full regression count mismatch');
71
+ required(verify.includes('VERIFY-ONLY PIPELINE PASS')&&verify.includes('Artifact isolation gate PASS')&&verify.includes('VERIFIED_TARBALL '),
72
+ 'npm exact-artifact verification incomplete');
73
+ const line=verify.split(/\r?\n/).find(value=>value.startsWith('VERIFIED_TARBALL '));
74
+ let artifact;try{artifact=JSON.parse(line.slice('VERIFIED_TARBALL '.length));}catch{fail('tarball evidence malformed');}
75
+ required(artifact.filename==='deadbyte-mcp-0.15.73.tgz'&&artifact.bytes>0&&artifact.sha256===closure.tarball_sha256&&
76
+ artifact.integrity===closure.tarball_integrity&&artifact.shasum===closure.tarball_shasum,'tarball identity mismatch');
77
+ return Object.freeze({status:'R193_RELEASE_READY_EVIDENCE_BOUND',manifest_sha256:closure.manifest_sha256,
78
+ tarball_sha256:artifact.sha256,tarball_integrity:artifact.integrity,tarball_shasum:artifact.shasum,
79
+ tests:summary.tests,passes:summary.passes,skips:summary.skips});
80
+ }
@@ -0,0 +1,80 @@
1
+ import {createHash} from 'node:crypto';
2
+ import {lstat,readFile} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+
5
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
6
+ const hex64=value=>typeof value==='string'&&/^[0-9a-f]{64}$/.test(value);
7
+ const fail=message=>{throw new Error(`PUBLISH_BLOCKED R194 ${message}`);};
8
+ const required=(value,message)=>{if(!value)fail(message);};
9
+
10
+ async function checkedFile(file,expected,{maxBytes=64*1024*1024}={}){
11
+ required(hex64(expected),'evidence digest missing');
12
+ let info;try{info=await lstat(file);}catch{fail('evidence file absent');}
13
+ required(info.isFile()&&!info.isSymbolicLink()&&info.size>0&&info.size<=maxBytes,'evidence file invalid');
14
+ const bytes=await readFile(file);
15
+ required(sha256(bytes)===expected,'evidence digest differs');
16
+ return bytes;
17
+ }
18
+
19
+ function tapSummary(text,label){
20
+ const summaries=[...text.matchAll(/^# tests (\d+)\s*\r?\n# suites (\d+)\s*\r?\n# pass (\d+)\s*\r?\n# fail (\d+)\s*\r?\n# cancelled (\d+)\s*\r?\n# skipped (\d+)/gm)];
21
+ required(summaries.length>0,`${label} TAP summary absent`);
22
+ const last=summaries.at(-1);
23
+ return {tests:Number(last[1]),passes:Number(last[3]),fails:Number(last[4]),cancelled:Number(last[5]),skips:Number(last[6])};
24
+ }
25
+
26
+ export function assertR194PackedIdentity({tarball_sha256,tarball_integrity,tarball_shasum,observedSha256,observedIntegrity,observedShasum}={}){
27
+ required(hex64(tarball_sha256)&&typeof tarball_integrity==='string'&&tarball_integrity.startsWith('sha512-')&&
28
+ typeof tarball_shasum==='string'&&/^[0-9a-f]{40}$/.test(tarball_shasum),'verified tarball identity invalid');
29
+ required(observedSha256===tarball_sha256&&observedIntegrity===tarball_integrity&&observedShasum===tarball_shasum,
30
+ 'repacked tarball differs from verified closure bytes');
31
+ return true;
32
+ }
33
+
34
+ export async function assertR194NpmPublishReady(release,{root,closureRoot=process.env.DEADBYTE_R194_CLOSURE_ROOT}={}){
35
+ required(release?.version==='0.15.74'&&release?.train==='R194'&&
36
+ release?.r194?.scope==='NPM_AUTH_RECOVERY_AND_OWNER_AUTHORIZATION','candidate metadata invalid');
37
+ required(release?.r194?.public_tool_delta===0&&release?.r194?.authority_scope_delta===0,'public authority surface widened');
38
+ required(release?.parent?.version==='0.15.72'&&
39
+ release?.parent?.release_id==='v0.15.72-0a5d9436e06e2d9e'&&
40
+ release?.parent?.manifest_sha256==='0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90'&&
41
+ release?.parent?.generation_manifest_sha256==='aec7b998306a3bbbcc59088648e7bc46ca7e203d749d4550b5b5f372032f92b0','lineage mismatch');
42
+ required(root&&path.isAbsolute(root)&&closureRoot&&path.isAbsolute(closureRoot),'closure root absent');
43
+ const expected=path.resolve(root,'..','..','testing','r194-final-closure');
44
+ required(path.resolve(closureRoot).toLowerCase()===expected.toLowerCase(),'closure root outside scoped testing folder');
45
+
46
+ let closure;try{closure=JSON.parse(await readFile(path.join(closureRoot,'closure.json'),'utf8'));}catch{fail('closure unreadable');}
47
+ required(closure?.schema==='deadbyte.r194-release-closure.v1'&&closure.status==='RELEASE_READY'&&
48
+ closure.version==='0.15.74'&&closure.train==='R194','closure status mismatch');
49
+ required(closure.production_release_id===release.parent.release_id&&
50
+ closure.production_manifest_sha256===release.parent.manifest_sha256&&
51
+ closure.production_generation_manifest_sha256===release.parent.generation_manifest_sha256,'production predecessor mismatch');
52
+ required(hex64(closure.manifest_sha256)&&closure.manifest_sha256===sha256(await readFile(path.join(root,'MANIFEST.SHA256'))),'final manifest drift');
53
+ required(closure.compact_tools===43&&closure.full_tools===117,'catalog count mismatch');
54
+ required(closure.owner_enrollment==='NOT_RUN'&&closure.limited_runtime_migration==='NOT_RUN'&&
55
+ closure.production_activation==='NOT_RUN','prepublication closure crossed production authority boundary');
56
+
57
+ const receipt=JSON.parse((await checkedFile(path.join(closureRoot,'protected-install-receipt.json'),closure.protected_receipt_sha256)).toString('utf8'));
58
+ required(receipt?.status==='PASS'&&receipt.package_version==='0.15.74'&&
59
+ receipt.source_manifest_sha256===closure.manifest_sha256&&receipt.protected_manifest_sha256===closure.manifest_sha256,
60
+ 'protected exact-byte receipt mismatch');
61
+ const focused=(await checkedFile(path.join(closureRoot,'windows-focused.stdout.log'),closure.focused_stdout_sha256)).toString('utf8');
62
+ const full=(await checkedFile(path.join(closureRoot,'windows-full.stdout.log'),closure.full_stdout_sha256)).toString('utf8');
63
+ const verify=(await checkedFile(path.join(closureRoot,'npm-verify.stdout.log'),closure.verify_stdout_sha256)).toString('utf8');
64
+ required(focused.includes('R194_STAGE_PASS=focused'),'focused protected gate incomplete');
65
+ const focusedSummary=tapSummary(focused,'focused');
66
+ required(focusedSummary.fails===0&&focusedSummary.cancelled===0&&focusedSummary.passes>=60&&focusedSummary.skips<=2,'focused regression count mismatch');
67
+ required(full.includes('R194_STAGE_PASS=full'),'full protected gate incomplete');
68
+ const summary=tapSummary(full,'full');
69
+ required(summary.tests>=2150&&summary.passes>=2100&&summary.fails===0&&summary.cancelled===0&&summary.skips<=70&&summary.passes+summary.skips===summary.tests,
70
+ 'full regression count mismatch');
71
+ required(verify.includes('VERIFY-ONLY PIPELINE PASS')&&verify.includes('Artifact isolation gate PASS')&&verify.includes('VERIFIED_TARBALL '),
72
+ 'npm exact-artifact verification incomplete');
73
+ const line=verify.split(/\r?\n/).find(value=>value.startsWith('VERIFIED_TARBALL '));
74
+ let artifact;try{artifact=JSON.parse(line.slice('VERIFIED_TARBALL '.length));}catch{fail('tarball evidence malformed');}
75
+ required(artifact.filename==='deadbyte-mcp-0.15.74.tgz'&&artifact.bytes>0&&artifact.sha256===closure.tarball_sha256&&
76
+ artifact.integrity===closure.tarball_integrity&&artifact.shasum===closure.tarball_shasum,'tarball identity mismatch');
77
+ return Object.freeze({status:'R194_RELEASE_READY_EVIDENCE_BOUND',manifest_sha256:closure.manifest_sha256,
78
+ tarball_sha256:artifact.sha256,tarball_integrity:artifact.integrity,tarball_shasum:artifact.shasum,
79
+ tests:summary.tests,passes:summary.passes,skips:summary.skips});
80
+ }
@@ -0,0 +1,91 @@
1
+ #requires -Version 5.1
2
+ #requires -RunAsAdministrator
3
+ # R188: owner-operated elevated REVIEW receipt only. Never issues an agent grant.
4
+ # Invoke by hand from a trusted interactive desktop; not through an agent or MCP.
5
+ [CmdletBinding()]
6
+ param([Parameter(Mandatory=$true)][string]$RequestPath)
7
+ $ErrorActionPreference='Stop'
8
+ Set-StrictMode -Version Latest
9
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
10
+ $program=[IO.Path]::GetFullPath($env:ProgramFiles).TrimEnd('\')+'\'
11
+ if(-not ($root.TrimEnd('\')+'\').StartsWith($program,[StringComparison]::OrdinalIgnoreCase)){
12
+ throw 'R188 must run from an installed Program Files release, not a writable development directory'
13
+ }
14
+ $settings=Get-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
15
+ if([int]$settings.EnableLUA -ne 1 -or [int]$settings.PromptOnSecureDesktop -ne 1 -or
16
+ [int]$settings.ConsentPromptBehaviorAdmin -eq 0){
17
+ throw 'R188 UAC secure desktop and nonautomatic admin consent must be enabled'
18
+ }
19
+ if(-not [Environment]::UserInteractive){throw 'R188 requires a local interactive owner session'}
20
+ $node='C:\Program Files\nodejs\node.exe'
21
+ if(-not (Test-Path -LiteralPath $node -PathType Leaf)){throw 'R188 trusted Node executable missing'}
22
+ $request=[IO.Path]::GetFullPath($RequestPath)
23
+ $preflight=Join-Path $root 'scripts\r188-uac-review-preview.mjs'
24
+ $raw=(& $node $preflight $request 2>&1 | Out-String)
25
+ if($LASTEXITCODE -ne 0){throw ('R188 preflight blocked: '+$raw.Substring(0,[Math]::Min(300,$raw.Length)))}
26
+ $preview=$raw|ConvertFrom-Json
27
+ if([string]$preview.status -cne 'R188_PROTECTED_REVIEW_PREVIEW_ONLY' -or
28
+ [bool]$preview.authority_granted -or [bool]$preview.owner_approved -or
29
+ [bool]$preview.live_epoch_verified -or [bool]$preview.live_policies_verified){
30
+ throw 'R188 preview unexpectedly claims grant/authorization'
31
+ }
32
+ $phrase=[string]$preview.review_phrase
33
+ if($phrase -cnotmatch '^APPROVE-[A-F0-9]{12}$'){throw 'R188 owner review phrase invalid'}
34
+ Write-Host ''
35
+ Write-Host 'DEADBYTE R188 / OWNER UAC REVIEW' -ForegroundColor Yellow
36
+ Write-Host 'This is a read-only scope REVIEW. It will NOT arm Autonomous.'
37
+ Write-Host ('Request SHA-256: '+[string]$preview.request_sha256)
38
+ Write-Host ('Project: '+[string]$preview.project_root)
39
+ Write-Host ('Action: '+[string]$preview.operation)
40
+ Write-Host ('Duration cap seconds: '+[string]$preview.max_seconds)
41
+ Write-Host ('Expires UTC: '+[string]$preview.expires_at_utc)
42
+ Write-Host ('Release manifest SHA-256: '+[string]$preview.installed_manifest_sha256)
43
+ Write-Host 'Coding policy and live machine epoch still require an independent trusted runtime read.'
44
+ Write-Host 'Do not approve requests you did not initiate and inspect yourself.'
45
+ $entered=Read-Host ('If you recognize this exact request, type '+$phrase+' (anything else rejects)')
46
+ if($entered -cne $phrase){throw 'R188 owner rejected request'}
47
+ $target='C:\Program Files\DEADBYTE-R188-OwnerReview'
48
+ if(-not (Test-Path -LiteralPath $target -PathType Container)){
49
+ $admins=New-Object Security.Principal.SecurityIdentifier('S-1-5-32-544')
50
+ $system=New-Object Security.Principal.SecurityIdentifier('S-1-5-18')
51
+ $users=New-Object Security.Principal.SecurityIdentifier('S-1-5-32-545')
52
+ New-Item -ItemType Directory -Path $target -ErrorAction Stop | Out-Null
53
+ $acl=New-Object Security.AccessControl.DirectorySecurity
54
+ $acl.SetAccessRuleProtection($true,$false)
55
+ $acl.SetOwner($admins)
56
+ $inherit=[Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'
57
+ $none=[Security.AccessControl.PropagationFlags]::None
58
+ $allow=[Security.AccessControl.AccessControlType]::Allow
59
+ $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($admins,'FullControl',$inherit,$none,$allow)))
60
+ $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($system,'FullControl',$inherit,$none,$allow)))
61
+ $acl.AddAccessRule((New-Object Security.AccessControl.FileSystemAccessRule($users,'ReadAndExecute',$inherit,$none,$allow)))
62
+ Set-Acl -LiteralPath $target -AclObject $acl
63
+ }
64
+ $receipt=[ordered]@{
65
+ schema='deadbyte.r188-uac-owner-review.v1'
66
+ status='REVIEWED_NO_GRANT'
67
+ request_sha256=[string]$preview.request_sha256
68
+ release_manifest_sha256=[string]$preview.installed_manifest_sha256
69
+ reviewed_scope=[string]$preview.operation
70
+ project_root=[string]$preview.project_root
71
+ duration_cap_seconds=[int]$preview.max_seconds
72
+ reviewed_at_utc=[DateTime]::UtcNow.ToString('o')
73
+ live_epoch_verified=$false
74
+ live_policies_verified=$false
75
+ owner_reviewed=$true
76
+ authority_granted=$false
77
+ grant_issued=$false
78
+ }
79
+ $name=([string]$preview.request_sha256)+'.review.json'
80
+ $dest=Join-Path $target $name
81
+ $text=$receipt|ConvertTo-Json -Compress
82
+ $utf8=New-Object Text.UTF8Encoding($false)
83
+ $stream=[IO.File]::Open($dest,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::None)
84
+ try{
85
+ $bytes=$utf8.GetBytes($text+[Environment]::NewLine)
86
+ $stream.Write($bytes,0,$bytes.Length)
87
+ $stream.Flush($true)
88
+ }finally{$stream.Dispose()}
89
+ Write-Host 'R188_OWNER_REVIEWED_NO_GRANT' -ForegroundColor Yellow
90
+ Write-Host ('Receipt: '+$dest)
91
+ Write-Host 'No PEM, Windows Hello, Autonomous grant, npm publish, or production activation performed.'
@@ -0,0 +1,65 @@
1
+ // Protected owner's manual UAC review: verify a request without granting.
2
+ // Requested policy / epoch hashes are UNTRUSTED previews until a protected
3
+ // runtime reader binds them; never interpret this as an authorization token.
4
+ import {readFile,lstat} from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import {fileURLToPath} from 'node:url';
7
+ import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
8
+ import {parseManifest,verifyManifestTreeExact} from '../src/release-slot.mjs';
9
+ import {verifyR188OwnerUacRequest} from '../src/r188-owner-uac.mjs';
10
+ const thisFile=fileURLToPath(import.meta.url);
11
+ const root=path.resolve(path.dirname(thisFile),'..');
12
+ const args=process.argv.slice(2);
13
+ function block(reason){throw Error('R188_UAC_REVIEW_BLOCKED '+reason);}
14
+ async function bounded(file,max){
15
+ const st=await lstat(file);
16
+ if(!st.isFile()||st.isSymbolicLink()||st.size<1||st.size>max)block('UNSAFE_FILE');
17
+ return readFile(file);
18
+ }
19
+ async function main(){
20
+ if(process.platform!=='win32'||process.arch!=='x64')block('WINDOWS_X64_REQUIRED');
21
+ if(args.length!==1||!path.win32.isAbsolute(args[0]))block('ABSOLUTE_REQUEST_REQUIRED');
22
+ const os=await inspectTrustedInstallation([
23
+ process.execPath,thisFile,
24
+ path.join(root,'MANIFEST.SHA256'),
25
+ path.join(root,'src','r188-owner-uac.mjs'),
26
+ path.join(root,'src','canonical-json.mjs'),
27
+ path.join(root,'src','privileged-install-trust-r89.mjs')
28
+ ]);
29
+ if(!os.trusted)block('R89_PROTECTED_INSTALLATION_REQUIRED');
30
+ const manifestBytes=await bounded(path.join(root,'MANIFEST.SHA256'),512*1024);
31
+ const manifest=parseManifest(manifestBytes.toString('utf8'));
32
+ await verifyManifestTreeExact(root,manifest);
33
+ const request=JSON.parse((await bounded(args[0],64*1024)).toString('utf8'));
34
+ const subject=request.subject;
35
+ if(!subject||typeof subject!=='object')block('SUBJECT_MISSING');
36
+ const expected={
37
+ machineEpoch:subject.machine_epoch,
38
+ releaseManifestSha256:subject.release_manifest_sha256,
39
+ codingPolicySha256:subject.coding_policy_sha256,
40
+ autonomousPolicySha256:subject.autonomous_policy_sha256,
41
+ rootId:subject.root_id,projectRoot:subject.project_root,
42
+ maxSeconds:subject.max_seconds
43
+ };
44
+ // Strict self-consistency proof, NOT yet verification of the live epoch/policy.
45
+ const verified=verifyR188OwnerUacRequest({request,expected,now:new Date()});
46
+ const {createHash}=await import('node:crypto');
47
+ const actualManifest=createHash('sha256').update(manifestBytes).digest('hex');
48
+ if(subject.release_manifest_sha256!==actualManifest)block('INSTALLED_RELEASE_NOT_REVIEWED_RELEASE');
49
+ process.stdout.write(JSON.stringify({
50
+ status:'R188_PROTECTED_REVIEW_PREVIEW_ONLY',
51
+ request_sha256:verified.request_sha256,
52
+ review_phrase:verified.review_phrase,
53
+ root_id:subject.root_id,project_root:subject.project_root,
54
+ max_seconds:subject.max_seconds,operation:subject.operation,
55
+ expires_at_utc:subject.expires_at_utc,
56
+ requested_machine_epoch:subject.machine_epoch,
57
+ requested_coding_policy_sha256:subject.coding_policy_sha256,
58
+ requested_autonomous_policy_sha256:subject.autonomous_policy_sha256,
59
+ installed_manifest_sha256:actualManifest,
60
+ os_acl_trusted:true,
61
+ live_epoch_verified:false,live_policies_verified:false,
62
+ authority_granted:false,owner_approved:false
63
+ })+'\n');
64
+ }
65
+ main().catch(e=>{console.error(String(e?.message||e).slice(0,320));process.exitCode=2;});
@@ -0,0 +1,22 @@
1
+ $ErrorActionPreference='Stop'
2
+ $root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
3
+ $source=Join-Path $root 'native\deadbyte-owner-token-r193.cpp'
4
+ $dest=Join-Path $root 'bin\deadbyte-owner-token-r193.exe'
5
+ $sourceDigest='99d1ec196e3e3242a9d44a6445d60abd1b3fbbd53dc9be126d4cc5bb91074099'
6
+ if ((Get-FileHash $source).Hash.ToLowerInvariant() -cne $sourceDigest) { throw 'R193_SOURCE_DRIFT' }
7
+ $gpp='C:\Users\DEADBYTE\scoop\apps\w64devkit\current\bin\g++.exe'
8
+ if(-not(Test-Path $gpp -PathType Leaf)){throw 'R193_TOOLCHAIN_MISSING'}
9
+ if(Test-Path $dest){throw 'R193_BINARY_EXISTS - do not overwrite without explicit inspection'}
10
+ & $gpp -std=c++17 -O2 -Wall -Wextra -Werror -static -s -o $dest $source -ladvapi32
11
+ if($LASTEXITCODE -ne 0){throw "R193_COMPILER_FAILED exit=$LASTEXITCODE"}
12
+ $raw=@(& $dest --report)
13
+ if($LASTEXITCODE -ne 0){throw "R193_REPORT_FAILED exit=$LASTEXITCODE"}
14
+ $report=($raw -join [Environment]::NewLine)|ConvertFrom-Json
15
+ if($report.schema -cne 'deadbyte.r193-native-token.v1' -or $report.authority_granted -or $report.owner_approved -or $report.parent_independence_verified){throw 'R193_INVALID_TOKEN_REPORT'}
16
+ $strictRaw=@(& $dest --require-standard)
17
+ $strictExit=$LASTEXITCODE
18
+ $strict=($strictRaw -join [Environment]::NewLine) | ConvertFrom-Json
19
+ if($report.status -cne $strict.status){throw 'R193_SUBJECT_STATUS_CHANGED'}
20
+ if($report.status -eq 'BLOCKED' -and $strictExit -ne 3){throw 'R193_FAIL_CLOSED_EXPECTED_EXIT3'}
21
+ if($report.status -eq 'STANDARD_TOKEN_OBSERVED' -and $strictExit -ne 0){throw 'R193_STANDARD_EXPECTED_EXIT0'}
22
+ [pscustomobject]@{schema='deadbyte.r193-native-token-acceptance.v1';status='PASS';source_sha256=$sourceDigest;binary_sha256=(Get-FileHash $dest).Hash.ToLowerInvariant();binary_bytes=(Get-Item $dest).Length;native_report=$report;strict_exit=$strictExit;no_grant=$true}|ConvertTo-Json -Depth 7 -Compress
@@ -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
+ }