deadbyte-mcp 0.15.47 → 0.15.48

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 (79) hide show
  1. package/MANIFEST.SHA256 +78 -41
  2. package/PROVENANCE.json +22 -11
  3. package/README.txt +11 -11
  4. package/RELEASE.json +378 -368
  5. package/TEST-MATRIX.json +1 -1
  6. package/bin/deadbyte-epoch-lock-r85.node +0 -0
  7. package/controller/deadbyte-process-policy.json +4 -4
  8. package/docs/R75-RECOVERY-HANDOFF.md +16 -0
  9. package/docs/R85-EPOCH-LOCK-BINARY.json +13 -0
  10. package/native/deadbyte-epoch-lock-r85.cpp +241 -0
  11. package/package.json +1 -1
  12. package/scripts/build-epoch-lock-r85.ps1 +34 -0
  13. package/scripts/deploy-r48.mjs +3 -1
  14. package/scripts/npm-release-r48.mjs +22 -4
  15. package/scripts/npm-release-readiness-r108.mjs +134 -0
  16. package/scripts/r75-npm-bin-integrity-gate.mjs +33 -0
  17. package/scripts/release-manifest.mjs +1 -1
  18. package/scripts/verify-r70-full-regression.ps1 +12 -2
  19. package/src/activation-authority-proof-r75.mjs +67 -0
  20. package/src/activation-continuity-engine-r65.mjs +17 -4
  21. package/src/activation-preflight-r65.mjs +13 -0
  22. package/src/authority-continuity-r65.mjs +265 -21
  23. package/src/deadbyte-cli.mjs +55 -18
  24. package/src/epoch-lock-r85.mjs +48 -0
  25. package/src/foreground-marker-cas-win32.mjs +284 -0
  26. package/src/foreground-process-identity.mjs +3 -3
  27. package/src/privileged-install-trust-r89.mjs +196 -0
  28. package/src/remote-session-guardian.mjs +9 -7
  29. package/src/runtime-update.mjs +5 -22
  30. package/src/version.mjs +1 -1
  31. package/src/windows-powershell-environment.mjs +24 -0
  32. package/test/cli-entrypoint.test.mjs +1 -1
  33. package/test/helpers/r75-authority-proof.mjs +9 -0
  34. package/test/r100-posix-owned-lock-race.test.mjs +72 -0
  35. package/test/r101-acl-probe-environment.test.mjs +51 -0
  36. package/test/r106-trusted-powershell-spawn.test.mjs +53 -0
  37. package/test/r107-updater-powershell-path.test.mjs +77 -0
  38. package/test/r33-closeout-regression.test.mjs +2 -1
  39. package/test/r54-offline-predecessor-self-exclusion.test.mjs +2 -2
  40. package/test/r55-offline-predecessor-guardian-family.test.mjs +2 -2
  41. package/test/r56-rollback-launcher-restore.test.mjs +2 -2
  42. package/test/r57-core-startup-race.test.mjs +2 -2
  43. package/test/r58-concurrent-recovery.test.mjs +10 -7
  44. package/test/r58-stale-owner.test.mjs +5 -6
  45. package/test/r59-tool-surface-compat.test.mjs +1 -1
  46. package/test/r65-activation-orchestration.test.mjs +2 -1
  47. package/test/r65-activation-preflight.test.mjs +7 -6
  48. package/test/r65-authority-epoch-recovery.test.mjs +3 -1
  49. package/test/r65-authority-restored-safe.test.mjs +2 -1
  50. package/test/r65-deploy-preflight.test.mjs +13 -14
  51. package/test/r65-epoch-native-activation-integration.test.mjs +5 -4
  52. package/test/r65-legacy-authority-migration.test.mjs +2 -1
  53. package/test/r67-npm-cross-volume.test.mjs +9 -2
  54. package/test/r71-full-verifier-artifact.test.mjs +21 -15
  55. package/test/r71-isolated-slot-rollback-restore.test.mjs +3 -1
  56. package/test/r71-release-identity.test.mjs +3 -1
  57. package/test/r74-kernel-lock.test.mjs +12 -6
  58. package/test/r74-prepublish-contract.test.mjs +1 -1
  59. package/test/r75-activation-authority-proof.test.mjs +46 -0
  60. package/test/r75-authority-evidence.test.mjs +77 -0
  61. package/test/r76-pinned-marker-cas.test.mjs +78 -0
  62. package/test/r77-epoch-grant-cas.test.mjs +51 -0
  63. package/test/r78-parent-junction-cas.test.mjs +62 -0
  64. package/test/r79-orphan-revocation-reconcile.test.mjs +88 -0
  65. package/test/r79-windows-fsync-regression.test.mjs +45 -0
  66. package/test/r80-durable-epoch-commit.test.mjs +76 -0
  67. package/test/r82-epoch-lock-owned-cas.test.mjs +93 -0
  68. package/test/r83-epoch-lock-fileid-cas.test.mjs +92 -0
  69. package/test/r84-epoch-lock-created-fileid.test.mjs +112 -0
  70. package/test/r85-epoch-lock-release-lifetime.test.mjs +25 -0
  71. package/test/r85-epoch-repeat-append.test.mjs +30 -0
  72. package/test/r86-epoch-cleanup-and-loader.test.mjs +126 -0
  73. package/test/r87-crashed-orphan-revoke-reconcile.test.mjs +110 -0
  74. package/test/r88-native-disposition-failure.test.mjs +35 -0
  75. package/test/r89-privileged-install-boundary.test.mjs +123 -0
  76. package/test/r92-acl-ace-applicability.test.mjs +45 -0
  77. package/test/r94-win32-propagation-enum.test.mjs +51 -0
  78. package/test/r99-privileged-import-closure.test.mjs +45 -0
  79. package/test/remote-session-cli.test.mjs +69 -9
@@ -0,0 +1,24 @@
1
+ // Dependency-light PowerShell child environment for security-critical process
2
+ // identity and pinned-marker operations. Do not import the updater here.
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+
6
+ export function windowsPowerShellEnvironment(base=process.env){
7
+ const systemRoot=base.SystemRoot||base.SYSTEMROOT||'C:\\Windows';
8
+ const userProfile=base.USERPROFILE||os.homedir();
9
+ const programFiles=base.ProgramFiles||base.PROGRAMFILES||'C:\\Program Files';
10
+ const hasWindir=Object.keys(base).some(key=>key.toLowerCase()==='windir');
11
+ const environment={...base};
12
+ const inherited=Object.entries(base).filter(([key])=>key.toLowerCase()==='psmodulepath')
13
+ .flatMap(([,value])=>String(value??'').split(';')).filter(Boolean);
14
+ for(const key of Object.keys(environment))if(['psmodulepath','systemroot','windir'].includes(key.toLowerCase()))delete environment[key];
15
+ environment.SystemRoot=systemRoot;
16
+ if(hasWindir)environment.WINDIR=systemRoot;
17
+ const modules=[path.join(systemRoot,'System32','WindowsPowerShell','v1.0','Modules'),
18
+ path.join(userProfile,'Documents','WindowsPowerShell','Modules'),
19
+ path.join(programFiles,'WindowsPowerShell','Modules'),...inherited];
20
+ const seen=new Set();
21
+ return {...environment,PSModulePath:modules.filter(item=>{
22
+ const key=item.toLowerCase();if(seen.has(key))return false;seen.add(key);return true;
23
+ }).join(';')};
24
+ }
@@ -44,7 +44,7 @@ test('npx CLI exposes local supervisor lifecycle without any supervisor arm comm
44
44
  assert.match(source,/supervisorstop/);
45
45
  assert.match(source,/supervisorstatus/);
46
46
  assert.match(source,/supervisorrecover/);
47
- const mapping=source.match(/const SUPERVISOR_COMMANDS=.*?;\n/s)?.[0]??'';
47
+ const mapping=source.match(/const SUPERVISOR_COMMANDS=[^;]*;/s)?.[0]??'';
48
48
  assert.doesNotMatch(mapping,/arm(?:coding|autonomous|process|host)/i);
49
49
  assert.match(source,/npx -y \$\{exact\} supervisor status/);
50
50
  });
@@ -0,0 +1,9 @@
1
+ // Unit fixtures use synthetic observations; integration tests verify real policy/grant files.
2
+ export function withAuthorityProof(observation){
3
+ const authority_proof=Object.fromEntries(Object.entries(observation.authority).map(([plane,entry])=>{
4
+ const armed=typeof entry==='boolean'?entry:entry.armed;
5
+ return [plane,{state:armed?'VERIFIED_ARMED':'VERIFIED_DISARMED',
6
+ policy_sha256:observation.policy_sha256[plane],grant_absent:!armed}];
7
+ }));
8
+ return {...observation,authority_proof};
9
+ }
@@ -0,0 +1,72 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {generateKeyPairSync,randomBytes} from 'node:crypto';
4
+ import {mkdtemp,mkdir,writeFile,readFile,rename,rm,access} from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import os from 'node:os';
7
+ import {pathToFileURL} from 'node:url';
8
+
9
+ const source=process.env.R100_BASELINE_SOURCE
10
+ ?pathToFileURL(process.env.R100_BASELINE_SOURCE)
11
+ :new URL('../src/authority-continuity-r65.mjs',import.meta.url);
12
+ const {createAuthorityEpochStore}=await import(source.href);
13
+
14
+ test('R100 POSIX owned release cannot unlink a byte-identical successor lock',
15
+ {skip:process.platform==='win32'},async()=>{
16
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r100-posix-'));
17
+ try{
18
+ const runtimeDir=path.join(root,'runtime'),trust=path.join(root,'trust');
19
+ await mkdir(runtimeDir);await mkdir(trust);
20
+ const keys=generateKeyPairSync('ed25519');
21
+ await writeFile(path.join(trust,'ed25519-private.pem'),keys.privateKey.export({type:'pkcs8',format:'pem'}),{flag:'wx'});
22
+ await writeFile(path.join(trust,'ed25519-public.pem'),keys.publicKey.export({type:'spki',format:'pem'}),{flag:'wx'});
23
+ const nonce=randomBytes(32).toString('hex');
24
+ const grantBytes=Buffer.from(JSON.stringify({instance_nonce:nonce}));
25
+ const lock=path.join(runtimeDir,'authority-epochs','process','.lock');
26
+ let replaced=0,successor;
27
+ const store=createAuthorityEpochStore({runtimeDir,onLockDispositionStage:async(stage,file)=>{
28
+ if(stage!=='release_before_cas')return;
29
+ assert.equal(file,lock);
30
+ successor=await readFile(lock);
31
+ const other=lock+'.successor';
32
+ await writeFile(other,successor,{flag:'wx'});
33
+ await rename(other,lock);
34
+ replaced++;
35
+ }});
36
+ await assert.rejects(store.append({plane:'process',action:'grant',grantBytes,
37
+ grantInstanceNonce:nonce}),/authority epoch lock changed|ownership lost|POSIX.*unsupported/);
38
+ if(replaced===0){
39
+ await assert.rejects(access(path.join(runtimeDir,'authority-epochs','process','head.json')),{code:'ENOENT'});
40
+ }else{
41
+ assert.equal(replaced,1,'replacement interleave must execute at most once');
42
+ assert.deepEqual(await readFile(lock),successor,'byte-identical successor lock must survive');
43
+ }
44
+ }finally{await rm(root,{recursive:true,force:true});}
45
+ });
46
+
47
+ test('R100 POSIX unsupported mutation makes no epoch directory and preserves an existing lock',
48
+ {skip:process.platform==='win32'},async()=>{
49
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r100-no-side-effect-'));
50
+ try{
51
+ const runtimeDir=path.join(root,'runtime');
52
+ const trust=path.join(root,'trust');
53
+ await mkdir(runtimeDir);await mkdir(trust);
54
+ const keys=generateKeyPairSync('ed25519');
55
+ await writeFile(path.join(trust,'ed25519-private.pem'),keys.privateKey.export({type:'pkcs8',format:'pem'}),{flag:'wx'});
56
+ await writeFile(path.join(trust,'ed25519-public.pem'),keys.publicKey.export({type:'spki',format:'pem'}),{flag:'wx'});
57
+ const nonce=randomBytes(32).toString('hex');
58
+ const grantBytes=Buffer.from(JSON.stringify({instance_nonce:nonce}));
59
+ const operation=()=>createAuthorityEpochStore({runtimeDir}).append({plane:'process',action:'grant',
60
+ grantBytes,grantInstanceNonce:nonce});
61
+ await assert.rejects(operation,/authority epoch POSIX mutation unsupported/);
62
+ const epochDir=path.join(runtimeDir,'authority-epochs','process');
63
+ await assert.rejects(access(epochDir),{code:'ENOENT'});
64
+ assert.equal(await createAuthorityEpochStore({runtimeDir}).readHead({plane:'process'}),null,
65
+ 'read-only empty-head inspection remains available');
66
+ await mkdir(epochDir,{recursive:true});
67
+ const lock=path.join(epochDir,'.lock'),original=Buffer.from('not-an-owned-lock');
68
+ await writeFile(lock,original,{flag:'wx'});
69
+ await assert.rejects(operation,/authority epoch POSIX mutation unsupported/);
70
+ assert.deepEqual(await readFile(lock),original);
71
+ }finally{await rm(root,{recursive:true,force:true});}
72
+ });
@@ -0,0 +1,51 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {spawnSync} from 'node:child_process';
4
+ import {createRequire, syncBuiltinESMExports} from 'node:module';
5
+ import {pathToFileURL} from 'node:url';
6
+ import path from 'node:path';
7
+
8
+ const require=createRequire(import.meta.url);
9
+
10
+ test('R101 privileged ACL probe excludes inherited module roots at child dispatch',
11
+ {skip:process.platform!=='win32'}, async()=>{
12
+ const childProcess=require('node:child_process');
13
+ const originalExecFile=childProcess.execFile;
14
+ const originalModulePath=process.env.PSModulePath;
15
+ const originalSystemRoot=process.env.SystemRoot;
16
+ let captured;
17
+ try {
18
+ childProcess.execFile=(executable,args,options,callback)=>{
19
+ captured={executable,args,environment:options.env};
20
+ callback(Object.assign(new Error('test stopped child before execution'),{code:'TEST_STOP'}));
21
+ };
22
+ syncBuiltinESMExports();
23
+ process.env.PSModulePath='C:\\r101-poisoned-module-root';
24
+ process.env.SystemRoot='C:\\r101-false-windows-root';
25
+ const target=process.env.R101_BASELINE_SOURCE
26
+ ? pathToFileURL(path.join(process.env.R101_BASELINE_SOURCE,'src','privileged-install-trust-r89.mjs'))
27
+ : new URL('../src/privileged-install-trust-r89.mjs',import.meta.url);
28
+ const {inspectTrustedInstallation}=await import(`${target.href}?r101-acl-probe`);
29
+ await assert.rejects(inspectTrustedInstallation(['C:\\Program Files\\Deadbyte\\bin\\addon.node']),
30
+ {code:'EPOCH_NATIVE_SLOT_UNTRUSTED'});
31
+ assert.ok(captured,'ACL child must have been dispatched');
32
+ assert.equal(captured.executable,'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe');
33
+ assert.equal(captured.environment.PSModulePath,
34
+ 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\Modules');
35
+ assert.equal(captured.environment.SystemRoot,'C:\\Windows');
36
+ assert.equal(captured.environment.WINDIR,'C:\\Windows');
37
+ const observed=spawnSync(captured.executable,['-NoLogo','-NoProfile','-NonInteractive',
38
+ '-Command',"(Get-Command Get-Acl -ErrorAction Stop).Module.Path"],
39
+ {env:captured.environment,encoding:'utf8',timeout:12000,windowsHide:true});
40
+ assert.equal(observed.status,0,observed.stderr);
41
+ assert.match(observed.stdout.trim(),
42
+ /^C:\\Windows\\System32\\WindowsPowerShell\\v1\.0\\Modules\\Microsoft\.PowerShell\.Security\\/i);
43
+ } finally {
44
+ childProcess.execFile=originalExecFile;
45
+ syncBuiltinESMExports();
46
+ if(originalModulePath===undefined)delete process.env.PSModulePath;
47
+ else process.env.PSModulePath=originalModulePath;
48
+ if(originalSystemRoot===undefined)delete process.env.SystemRoot;
49
+ else process.env.SystemRoot=originalSystemRoot;
50
+ }
51
+ });
@@ -0,0 +1,53 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import childProcess from 'node:child_process';
4
+ import {syncBuiltinESMExports} from 'node:module';
5
+ import {windowsPowerShellEnvironment} from '../src/windows-powershell-environment.mjs';
6
+
7
+ const TRUSTED_POWERSHELL='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
8
+
9
+ test('PowerShell child environment collapses case-variant Windows root keys',()=>{
10
+ const environment=windowsPowerShellEnvironment({
11
+ SystemRoot:'C:\\Windows',SYSTEMROOT:'C:\\untrusted-root',
12
+ WINDIR:'C:\\Windows',windir:'C:\\untrusted-root',
13
+ PSModulePath:'C:\\custom-modules'
14
+ });
15
+ assert.deepEqual(Object.keys(environment).filter(key=>key.toLowerCase()==='systemroot'),['SystemRoot']);
16
+ assert.deepEqual(Object.keys(environment).filter(key=>key.toLowerCase()==='windir'),['WINDIR']);
17
+ assert.equal(environment.SystemRoot,'C:\\Windows');
18
+ assert.equal(environment.WINDIR,'C:\\Windows');
19
+ });
20
+
21
+ test('security-sensitive Windows probes cannot select PowerShell via caller environment',
22
+ {skip:process.platform!=='win32',concurrency:false},async()=>{
23
+ const originalSpawn=childProcess.spawnSync;
24
+ const originalRoot=process.env.SystemRoot;
25
+ const originalWindir=process.env.WINDIR;
26
+ const calls=[];
27
+ try{
28
+ process.env.SystemRoot='C:\\untrusted-root';
29
+ process.env.WINDIR='C:\\untrusted-root';
30
+ childProcess.spawnSync=(file,args,options)=>{
31
+ calls.push({file,options});
32
+ return {status:0,stdout:calls.length===1?'MISSING\n':'null\n',stderr:''};
33
+ };
34
+ syncBuiltinESMExports();
35
+ const marker=await import('../src/foreground-marker-cas-win32.mjs');
36
+ const identity=await import('../src/foreground-process-identity.mjs');
37
+ assert.equal(marker.readPinnedEpochLockSnapshot('C:\\scratch\\lock.json'),null);
38
+ assert.equal(identity.queryForegroundIdentity(12345),null);
39
+ assert.equal(calls.length,2);
40
+ for(const call of calls){
41
+ assert.equal(call.file,TRUSTED_POWERSHELL);
42
+ assert.equal(call.options.env.SystemRoot,'C:\\Windows');
43
+ assert.equal(call.options.env.WINDIR,'C:\\Windows');
44
+ }
45
+ }finally{
46
+ childProcess.spawnSync=originalSpawn;
47
+ syncBuiltinESMExports();
48
+ if(originalRoot===undefined)delete process.env.SystemRoot;
49
+ else process.env.SystemRoot=originalRoot;
50
+ if(originalWindir===undefined)delete process.env.WINDIR;
51
+ else process.env.WINDIR=originalWindir;
52
+ }
53
+ });
@@ -0,0 +1,77 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import childProcess from 'node:child_process';
4
+ import {syncBuiltinESMExports} from 'node:module';
5
+ import {mkdtemp,writeFile,rm} from 'node:fs/promises';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ import {loadPowerShellDataFile,runControllerStartNoCapture,windowsPowerShellEnvironment} from '../src/runtime-update.mjs';
9
+
10
+ test('updater PowerShell environment rejects case-colliding Windows root keys',()=>{
11
+ const environment=windowsPowerShellEnvironment({
12
+ SystemRoot:'C:\\Windows',SYSTEMROOT:'C:\\untrusted-root',
13
+ WINDIR:'C:\\Windows',windir:'C:\\untrusted-root'
14
+ });
15
+ assert.deepEqual(Object.keys(environment).filter(key=>key.toLowerCase()==='systemroot'),['SystemRoot']);
16
+ assert.deepEqual(Object.keys(environment).filter(key=>key.toLowerCase()==='windir'),['WINDIR']);
17
+ assert.equal(environment.SystemRoot,'C:\\Windows');
18
+ assert.equal(environment.WINDIR,'C:\\Windows');
19
+ });
20
+
21
+ test('real updater PowerShell still loads read-only config under poisoned Windows roots',
22
+ {skip:process.platform!=='win32',concurrency:false},async()=>{
23
+ const scratch=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r107-ps-'));
24
+ const priorRoot=process.env.SystemRoot;
25
+ const priorWindir=process.env.WINDIR;
26
+ try{
27
+ const config=path.join(scratch,'config.psd1');
28
+ await writeFile(config,"@{ Schema = 'r107.test'; Enabled = $true }\n",{flag:'wx'});
29
+ process.env.SystemRoot='C:\\untrusted-root';
30
+ process.env.WINDIR='C:\\untrusted-root';
31
+ assert.deepEqual(await loadPowerShellDataFile(config),{Enabled:true,Schema:'r107.test'});
32
+ }finally{
33
+ if(priorRoot===undefined)delete process.env.SystemRoot;
34
+ else process.env.SystemRoot=priorRoot;
35
+ if(priorWindir===undefined)delete process.env.WINDIR;
36
+ else process.env.WINDIR=priorWindir;
37
+ await rm(scratch,{recursive:true,force:true});
38
+ }
39
+ });
40
+
41
+ test('runtime updater cannot launch caller-selected PowerShell for config and controller work',
42
+ {skip:process.platform!=='win32',concurrency:false},async()=>{
43
+ const originalSpawn=childProcess.spawnSync;
44
+ const originalRoot=process.env.SystemRoot;
45
+ const originalWindir=process.env.WINDIR;
46
+ let call=null;
47
+ try{
48
+ process.env.SystemRoot='C:\\untrusted-root';
49
+ process.env.WINDIR='C:\\untrusted-root';
50
+ childProcess.spawnSync=(file,args,options)=>{
51
+ call={file,args,options};
52
+ return {status:0,signal:null,error:null,stdout:'{}\n',stderr:''};
53
+ };
54
+ syncBuiltinESMExports();
55
+ assert.deepEqual(await loadPowerShellDataFile('C:\\scratch\\controller.psd1'),{});
56
+ assert.ok(call,'updater must dispatch its PowerShell subprocess');
57
+ assert.equal(call.file,'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe');
58
+ assert.equal(call.options.env.SystemRoot,'C:\\Windows');
59
+ assert.equal(call.options.env.WINDIR,'C:\\Windows');
60
+ assert.equal(call.options.shell,undefined);
61
+ call=null;
62
+ const started=runControllerStartNoCapture({kind:'legacy',
63
+ controller_path:'C:\\scratch\\deadbyte-controller.ps1',cwd:'C:\\scratch'},1000);
64
+ assert.equal(started.status,0);
65
+ assert.equal(call.file,'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe');
66
+ assert.ok(call.args.includes('start'));
67
+ assert.equal(call.options.env.SystemRoot,'C:\\Windows');
68
+ assert.equal(call.options.env.WINDIR,'C:\\Windows');
69
+ }finally{
70
+ childProcess.spawnSync=originalSpawn;
71
+ syncBuiltinESMExports();
72
+ if(originalRoot===undefined)delete process.env.SystemRoot;
73
+ else process.env.SystemRoot=originalRoot;
74
+ if(originalWindir===undefined)delete process.env.WINDIR;
75
+ else process.env.WINDIR=originalWindir;
76
+ }
77
+ });
@@ -4,13 +4,14 @@ import { createHash } from 'node:crypto';
4
4
  import { mkdtemp, mkdir, readFile, rm, writeFile, readdir } from 'node:fs/promises';
5
5
  import os from 'node:os';
6
6
  import path from 'node:path';
7
+ import {fileURLToPath} from 'node:url';
7
8
  import { spawn } from 'node:child_process';
8
9
  import * as parity from '../scripts/release-parity-r39.mjs';
9
10
  import { createToolAudit } from '../src/tool-audit.mjs';
10
11
  import { verifyAuditChain } from '../src/audit-verify.mjs';
11
12
  import { generateTrustKeypair } from '../src/trust.mjs';
12
13
 
13
- const root = path.resolve(new URL('../', import.meta.url).pathname.replace(/^\/(?:([A-Za-z]:))/,'$1'));
14
+ const root = path.resolve(fileURLToPath(new URL('../', import.meta.url)));
14
15
  const sha256 = bytes => createHash('sha256').update(bytes).digest('hex');
15
16
  const temp = prefix => mkdtemp(path.join(os.tmpdir(), prefix));
16
17
  const run = (command,args,options={}) => new Promise((resolve,reject)=>{
@@ -1,11 +1,11 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { pathToFileURL } from 'node:url';
3
+ import { fileURLToPath,pathToFileURL } from 'node:url';
4
4
  import path from 'node:path';
5
5
 
6
6
  const target=process.env.R54_RUNTIME_UPDATE_PATH
7
7
  ? path.resolve(process.env.R54_RUNTIME_UPDATE_PATH)
8
- : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
8
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
9
9
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r54='+Date.now());
10
10
 
11
11
  test('R54 exposes behavior-testable offline recovery blocker selection',()=>{
@@ -1,11 +1,11 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { pathToFileURL } from 'node:url';
3
+ import { fileURLToPath,pathToFileURL } from 'node:url';
4
4
  import path from 'node:path';
5
5
 
6
6
  const target=process.env.R55_RUNTIME_UPDATE_PATH
7
7
  ? path.resolve(process.env.R55_RUNTIME_UPDATE_PATH)
8
- : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
8
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
9
9
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r55='+Date.now());
10
10
  const nonce='a'.repeat(64);
11
11
 
@@ -2,13 +2,13 @@ import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { createHash } from 'node:crypto';
4
4
  import { readFile } from 'node:fs/promises';
5
- import { pathToFileURL } from 'node:url';
5
+ import { fileURLToPath,pathToFileURL } from 'node:url';
6
6
  import os from 'node:os';
7
7
  import path from 'node:path';
8
8
 
9
9
  const target=process.env.R56_RUNTIME_UPDATE_PATH
10
10
  ? path.resolve(process.env.R56_RUNTIME_UPDATE_PATH)
11
- : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
11
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
12
12
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r56='+Date.now());
13
13
  const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
14
14
  const stateRoot=path.resolve(process.env.R56_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
@@ -1,12 +1,12 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { readFile } from 'node:fs/promises';
4
- import { pathToFileURL } from 'node:url';
4
+ import { fileURLToPath,pathToFileURL } from 'node:url';
5
5
  import path from 'node:path';
6
6
 
7
7
  const target=process.env.R57_RUNTIME_UPDATE_PATH
8
8
  ? path.resolve(process.env.R57_RUNTIME_UPDATE_PATH)
9
- : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
9
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
10
10
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r57='+Date.now());
11
11
  const coreRoot='C:\\slot\\core';
12
12
  const bridge={pid:20396,component:'bridge',script_path:'C:\\slot\\bridge\\src\\bridge.mjs',script_sha256:'a'.repeat(64)};
@@ -6,7 +6,7 @@ import {fileURLToPath} from 'node:url';
6
6
  import {spawn} from 'node:child_process';
7
7
  import {setTimeout as delay} from 'node:timers/promises';
8
8
 
9
- test('R58 simultaneous stale recovery cannot both revoke the shared authority', {timeout:90000},async()=>{
9
+ test('R75 simultaneous owner-unverified recovery attempts both retain authority and marker', {timeout:30000},async()=>{
10
10
  const base='D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';await mkdir(base,{recursive:true});
11
11
  const root=await mkdtemp(path.join(base,'concurrent-recovery-'));await mkdir(path.join(root,'bin'));await mkdir(path.join(root,'runtime'));
12
12
  const trace=path.join(root,'trace.txt'),markerPath=path.join(root,'runtime','remote-session.json');
@@ -47,14 +47,17 @@ exit 0
47
47
  const c=spawn(process.execPath,[fileURLToPath(new URL('../src/deadbyte-cli.mjs',import.meta.url)),'remote'],{env:{...process.env,DEADBYTE_STATE_ROOT:root},stdio:['pipe','pipe','pipe'],windowsHide:true});
48
48
  const o={stdout:'',stderr:''};c.stdout.on('data',b=>{o.stdout+=b;});c.stderr.on('data',b=>{o.stderr+=b;});o.exit=new Promise(resolve=>c.once('exit',resolve));children.push(c);outputs.push(o);
49
49
  }
50
- const until=Date.now()+45000;let commands=[];
51
- while(Date.now()<until){try{commands=(await readFile(trace,'utf8')).trim().split(/\r?\n/);}catch{}if(outputs.some(o=>o.stdout.includes('[READY]')))break;await delay(50);}
52
- await writeFile(path.join(root,'observation.json'),JSON.stringify({commands,outputs:outputs.map(o=>({stdout:o.stdout,stderr:o.stderr})),simulation:'concurrent stale marker recovery with delayed second park'}),{flag:'wx'});
53
- assert.ok(outputs.some(o=>o.stdout.includes('[READY]')),'a recovered foreground must become ready');
54
- for(const cmd of ['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost'])assert.equal(commands.filter(x=>x===cmd).length,1,`stale recovery must serialize ${cmd}`);
50
+ const exits=await Promise.race([Promise.all(outputs.map(o=>o.exit)),delay(15000,null,{ref:false}).then(()=>null)]);
51
+ assert.ok(exits,'both owner-unverified attempts must terminate');
52
+ const commands=await readFile(trace,'utf8').catch(error=>error.code==='ENOENT'?'':Promise.reject(error));
53
+ await writeFile(path.join(root,'observation.json'),JSON.stringify({commands,exits,outputs:outputs.map(o=>({stdout:o.stdout,stderr:o.stderr})),simulation:'concurrent owner-unverified stale marker'}),{flag:'wx'});
54
+ assert.ok(exits.every(code=>code!==0));
55
+ for(const output of outputs)assert.match(output.stderr,/ownership unverified.*marker retained|already claimed \(startup\/recovery lock\)/i);
56
+ assert.equal(commands,'','neither attempt may touch authority');
57
+ assert.equal(JSON.parse(await readFile(markerPath,'utf8')).pid,2147483000);
55
58
  }finally{
56
59
  for(const c of children)if(c.exitCode===null)c.stdin.end();
57
- await Promise.race([Promise.all(outputs.map(o=>o.exit)),delay(30000)]);
60
+ await Promise.race([Promise.all(outputs.map(o=>o.exit)),delay(30000,null,{ref:false})]);
58
61
  for(const c of children)if(c.exitCode===null&&c.signalCode===null)c.kill();
59
62
  }
60
63
  });
@@ -46,7 +46,7 @@ test('R58 live unrelated PID is not accepted as a remote foreground owner', {tim
46
46
  assert.notEqual(code,0);
47
47
  });
48
48
 
49
- test('R58 bound stale birth identity reconciles on the first invocation without killing a reused PID', {timeout:60000}, async()=>{
49
+ test('R75 bound stale birth identity retains marker without touching a reused PID or authority', {timeout:60000}, async()=>{
50
50
  const base='D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';
51
51
  await mkdir(base,{recursive:true});const root=await mkdtemp(path.join(base,'stale-birth-'));
52
52
  await mkdir(path.join(root,'runtime'));await mkdir(path.join(root,'bin'));
@@ -61,11 +61,10 @@ test('R58 bound stale birth identity reconciles on the first invocation without
61
61
  let stdout='',stderr='';child.stdout.on('data',b=>{stdout+=b;});child.stderr.on('data',b=>{stderr+=b;});
62
62
  const code=await new Promise(resolve=>child.once('close',resolve));
63
63
  await writeFile(path.join(root,'observation.json'),JSON.stringify({code,stdout,stderr,simulation:'birth identity drift at a live unrelated numeric PID'}),{flag:'wx'});
64
- assert.match(stdout,/Stale remote session/);
65
- assert.doesNotMatch(stderr,/already active|ownership unverified/);
66
- assert.deepEqual((await readFile(trace,'utf8')).trim().split(/\r?\n/).slice(0,7),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','park']);
67
- assert.match(stderr,/without a verified ONLINE runtime/,'fixture deliberately has no real runtime; recovery must already have converged');
68
- await assert.rejects(readFile(markerPath),{code:'ENOENT'});
64
+ assert.notEqual(code,0);
65
+ assert.match(stderr,/owner identity mismatch; marker retained/i);
66
+ assert.equal(await readFile(trace,'utf8').catch(error=>error.code==='ENOENT'?'':Promise.reject(error)),'','identity drift must cause no authority commands');
67
+ assert.deepEqual(JSON.parse(await readFile(markerPath,'utf8')),marker);
69
68
  assert.equal(foregroundAlive(),true,'unrelated live process must not be killed');
70
69
  function foregroundAlive(){try{process.kill(process.pid,0);return true;}catch{return false;}}
71
70
  });
@@ -83,7 +83,7 @@ test('R72 compact baseline permits only R64 read offset and authorized coding-on
83
83
  assert.deepEqual(diff.added,[]);
84
84
  assert.deepEqual(diff.removed,[]);
85
85
  const packageVersion=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8')).version;
86
- if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47'].includes(packageVersion)){
86
+ if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48'].includes(packageVersion)){
87
87
  assert.deepEqual([...diff.schema_changed].sort(),['machine_fs','native_diff_preview']);
88
88
  assert.equal(diff.unchanged.length,41);
89
89
  const prior=baseline.tools.find(tool=>tool.name==='machine_fs');
@@ -1,6 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {orchestrateActivation} from '../src/activation-preflight-r65.mjs';
4
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
4
5
 
5
6
  const parent={release_id:'v0.15.41-63a78ad159ad3003',version:'0.15.41',manifest_sha256:'63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e',generation_manifest_sha256:'19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'};
6
7
  const candidate={version:'0.15.42',manifest_sha256:'a'.repeat(64)};
@@ -19,7 +20,7 @@ function fixture(initial={}){
19
20
  let current={state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},authority:authorityEntries(initialVector,initial.epochNative===true),policy_sha256:policies,
20
21
  active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,active_generation_manifest_sha256:parent.generation_manifest_sha256,...initial};
21
22
  if(initial.authority)current={...current,authority:authorityEntries(initial.authority,initial.epochNative===true)};
22
- return {calls,observe:async()=>current,command:async name=>{
23
+ return {calls,observe:async()=>withAuthorityProof(current),command:async name=>{
23
24
  calls.push(name);
24
25
  if(name.startsWith('disarm')){
25
26
  const plane=name.slice(6);
@@ -1,6 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {classifyActivationPreflight,authorityTransitionPlan} from '../src/activation-preflight-r65.mjs';
4
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
4
5
 
5
6
  const parent={release_id:'v0.15.41-63a78ad159ad3003',version:'0.15.41',manifest_sha256:'63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e',generation_manifest_sha256:'19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'};
6
7
  const candidate={version:'0.15.42',manifest_sha256:'a'.repeat(64)};
@@ -8,7 +9,7 @@ const authority={process:true,coding:true,autonomous:true,desktop:false,host:fal
8
9
  const policies={process:'1'.repeat(64),coding:'2'.repeat(64),autonomous:'3'.repeat(64),desktop:'4'.repeat(64),host:'5'.repeat(64)};
9
10
  const online={state:'ONLINE',local_ready:true,bridge:{alive:true,reason:'verified',pid:10},core:{alive:true,reason:'verified',pid:11},cloud:{alive:true,reason:'verified',pid:12},supervisor:{running:true},authority,policy_sha256:policies,
10
11
  active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,active_generation_manifest_sha256:parent.generation_manifest_sha256};
11
- const input={pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,observation:online};
12
+ const input={pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,observation:withAuthorityProof(online)};
12
13
 
13
14
  test('preflight accepts exact online predecessor with full observed identity and authority vector',()=>{
14
15
  const result=classifyActivationPreflight(input);
@@ -19,7 +20,7 @@ test('preflight accepts exact online predecessor with full observed identity and
19
20
 
20
21
  test('host armed is not safe; plan only disarms Host and restores exact captured vector',()=>{
21
22
  const armed={...authority,host:true};
22
- const result=classifyActivationPreflight({...input,observation:{...online,authority:armed}});
23
+ const result=classifyActivationPreflight({...input,observation:withAuthorityProof({...online,authority:armed})});
23
24
  assert.equal(result.state,'ONLINE_HOST_ARMED');assert.equal(result.safe_to_activate,false);
24
25
  const plan=authorityTransitionPlan(result.authority);
25
26
  assert.deepEqual(plan.before,['disarmhost']);
@@ -27,9 +28,9 @@ test('host armed is not safe; plan only disarms Host and restores exact captured
27
28
  });
28
29
 
29
30
  test('parked dirty, generation drift and identity loss fail closed without an activation command',()=>{
30
- assert.equal(classifyActivationPreflight({...input,observation:{...online,state:'PARKED'}}).state,'PARKED_DIRTY');
31
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,state:'PARKED'})}).state,'PARKED_DIRTY');
31
32
  assert.equal(classifyActivationPreflight({...input,pointer:{...parent,generation_manifest_sha256:'b'.repeat(64)}}).state,'POINTER_DRIFT');
32
- assert.equal(classifyActivationPreflight({...input,observation:{...online,active_release_id:'wrong'}}).state,'POINTER_DRIFT');
33
- assert.equal(classifyActivationPreflight({...input,observation:{...online,policy_sha256:{...policies,host:null}}}).state,'UNKNOWN');
34
- assert.equal(classifyActivationPreflight({...input,observation:{...online,cloud:{alive:false,reason:'missing'}}}).state,'RUNTIME_DRIFT');
33
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,active_release_id:'wrong'})}).state,'POINTER_DRIFT');
34
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,policy_sha256:{...policies,host:null}})}).state,'UNKNOWN');
35
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,cloud:{alive:false,reason:'missing'}})}).state,'RUNTIME_DRIFT');
35
36
  });
@@ -19,7 +19,9 @@ test('dead-owner epoch lock is recovered but a live-owner lock is never stolen',
19
19
  const runtime=await prepareAuthorityTestTrust(root);
20
20
  const dir=path.join(runtime,'authority-epochs','coding');
21
21
  await mkdir(dir,{recursive:true});
22
- await writeFile(path.join(dir,'.lock'),JSON.stringify({schema:'deadbyte.authority-epoch-lock.r65.v1',pid:2147483647,token:'dead',created_at_utc:'2026-10-06T00:00:00Z'}));
22
+ await writeFile(path.join(dir,'.lock'),JSON.stringify({schema:'deadbyte.authority-epoch-lock.r65.v1',pid:2147483647,token:'dead',created_at_utc:'2026-10-06T00:00:00Z',
23
+ owner_identity:{schema:'deadbyte.foreground-process.v1',pid:2147483647,parent_pid:0,creation_utc:'2026-01-01T00:00:00Z',
24
+ executable_path:process.execPath,command_line_sha256:'0'.repeat(64)}}));
23
25
  const store=createAuthorityEpochStore({runtimeDir:runtime});
24
26
  const nonce='1'.repeat(64),grant=grantBytes(nonce);
25
27
  const head=await store.append({plane:'coding',action:'grant',grantBytes:grant,grantInstanceNonce:nonce,updateId:null});
@@ -7,6 +7,7 @@ import path from 'node:path';
7
7
  import {orchestrateActivation} from '../src/activation-preflight-r65.mjs';
8
8
  import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
9
9
  import {createEpochNativeContinuityEngine} from '../src/activation-continuity-engine-r65.mjs';
10
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
10
11
 
11
12
  const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
12
13
  const parent={release_id:'v0.15.41-parent',version:'0.15.41',manifest_sha256:'a'.repeat(64),generation_manifest_sha256:'b'.repeat(64)};
@@ -26,7 +27,7 @@ test('orchestrator reports RESTORED_SAFE when all restored authority is safe but
26
27
  return {authority_outcomes:{process:'RESTORED_SAFE',coding:'NOT_APPLICABLE',autonomous:'NOT_APPLICABLE',desktop:'NOT_APPLICABLE',host:'NOT_APPLICABLE'},restored_nonces:{process:'8'.repeat(64)},reauth_planes:[]};}
27
28
  };
28
29
  const result=await orchestrateActivation({pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,
29
- observe:async()=>current,command:async()=>{throw new Error('generic command forbidden');},
30
+ observe:async()=>withAuthorityProof(current),command:async()=>{throw new Error('generic command forbidden');},
30
31
  activate:async()=>({verified:true,release_id:'v0.15.42-candidate'}),continuityEngine});
31
32
  assert.equal(result.state,'ACTIVATED');
32
33
  assert.equal(result.authority_continuity,'RESTORED_SAFE');
@@ -11,8 +11,9 @@ const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
11
11
  test('deploy dry preflight observes isolated authority without opening an update transaction', {skip:process.platform!=='win32'},async()=>{
12
12
  const isolated=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r65-deploy-preflight-'));
13
13
  try{
14
- const state=path.join(isolated,'state'),bin=path.join(state,'bin');
14
+ const state=path.join(isolated,'state'),bin=path.join(state,'bin'),runtime=path.join(state,'runtime');
15
15
  await mkdir(bin,{recursive:true});
16
+ await mkdir(runtime,{recursive:true});
16
17
  const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
17
18
  const parent=release.parent;
18
19
  const generationRoot=path.join(state,'generations',`${parent.release_id}-fixture`);
@@ -20,9 +21,11 @@ test('deploy dry preflight observes isolated authority without opening an update
20
21
  await mkdir(generationRoot,{recursive:true});await mkdir(policyRoot,{recursive:true});
21
22
  const fields={process:'ProcessPolicyFile',coding:'CodingPolicyFile',autonomous:'AutonomousPolicyFile',desktop:'DesktopPolicyFile',host:'HostPolicyFile'};
22
23
  const policyLines=[];
24
+ const grantField={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
23
25
  for(const [plane,key] of Object.entries(fields)){
24
26
  const file=path.join(policyRoot,`${plane}.json`);
25
- await writeFile(file,JSON.stringify({schema:`fixture.${plane}`,enabled:true}));
27
+ await writeFile(file,JSON.stringify({schema:`deadbyte.${plane}-policy.v${plane==='host'?2:1}`,enabled:true,
28
+ [grantField[plane]]:path.join(runtime,`${plane}-grant.json`)}));
26
29
  policyLines.push(`${key} = '${file.replaceAll("'","''")}'`);
27
30
  }
28
31
  await writeFile(path.join(generationRoot,'controller-config.psd1'),`@{ ${policyLines.join('; ')} }\n`);
@@ -30,26 +33,22 @@ test('deploy dry preflight observes isolated authority without opening an update
30
33
  release_root:path.join(state,'releases',parent.release_id),generation_root:generationRoot,
31
34
  launcher_sha256:'a'.repeat(64),config_path:path.join(generationRoot,'controller-config.psd1')}));
32
35
  const ps1=`param([string]$Command,[switch]$Json)\nif($Command -ne 'status' -or -not $Json){throw 'unexpected mutating command'}\n@{schema='deadbyte.controller-observation.v1';state='ONLINE';local_ready=$true;bridge=@{alive=$true;reason='verified';pid=10};core=@{alive=$true;reason='verified';pid=11};cloud=@{alive=$true;reason='verified';pid=12};supervisor=@{running=$true};authority=@{process=@{armed=$true;configured=$true;reason='fixture'};coding=@{armed=$true;configured=$true;reason='fixture'};autonomous=@{armed=$true;configured=$true;reason='fixture'};desktop=@{armed=$false;configured=$true;reason='fixture'};host=@{armed=$false;configured=$true;reason='fixture'}}} | ConvertTo-Json -Depth 6 -Compress\n`;
33
- await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),ps1);
36
+ const cleanPs1=ps1.replaceAll('armed=$true','armed=$false').replaceAll("reason='fixture'","reason='disarmed'");
37
+ await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),cleanPs1);
34
38
  const run=spawnSync(process.execPath,[path.join(root,'scripts','deploy-r48.mjs'),'--preflight'],{
35
39
  env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:root,encoding:'utf8',timeout:20000,windowsHide:true});
36
40
  assert.equal(run.status,0,run.stderr);
37
41
  const result=JSON.parse(run.stdout.trim());
38
42
  assert.equal(result.state,'ONLINE_READY');
39
- assert.equal(result.authority_continuity,'REAUTH_REQUIRED');
40
- assert.deepEqual(result.reauth_planes,['process','coding','autonomous']);
41
- const hostOnly=ps1.replace('process=@{armed=$true','process=@{armed=$false')
42
- .replace('coding=@{armed=$true','coding=@{armed=$false')
43
- .replace('autonomous=@{armed=$true','autonomous=@{armed=$false')
44
- .replace('host=@{armed=$false','host=@{armed=$true');
45
- await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),hostOnly);
43
+ assert.equal(result.authority_continuity,'NOT_APPLICABLE');
44
+ assert.deepEqual(result.reauth_planes,[]);
45
+ const unverified=cleanPs1.replace("host=@{armed=$false;configured=$true;reason='disarmed'", "host=@{armed=$false;configured=$true;reason='unverified'");
46
+ await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),unverified);
46
47
  const hostRun=spawnSync(process.execPath,[path.join(root,'scripts','deploy-r48.mjs'),'--preflight'],{
47
48
  env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:root,encoding:'utf8',timeout:20000,windowsHide:true});
48
49
  assert.equal(hostRun.status,0,hostRun.stderr);
49
50
  const hostResult=JSON.parse(hostRun.stdout.trim());
50
- assert.equal(hostResult.state,'ONLINE_HOST_ARMED');
51
- assert.equal(hostResult.authority_continuity,'REAUTH_REQUIRED');
52
- assert.deepEqual(hostResult.reauth_planes,['host']);
53
- assert.deepEqual((await readdir(state)).sort(),['active-release.json','bin','generations','policies']);
51
+ assert.equal(hostResult.state,'AUTHORITY_UNVERIFIED');
52
+ assert.deepEqual((await readdir(state)).sort(),['active-release.json','bin','generations','policies','runtime']);
54
53
  }finally{await rm(isolated,{recursive:true,force:true});}
55
54
  });