deadbyte-mcp 0.15.46 → 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 (98) hide show
  1. package/MANIFEST.SHA256 +97 -45
  2. package/PROVENANCE.json +22 -11
  3. package/README.txt +18 -18
  4. package/RELEASE.json +378 -369
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +2 -2
  7. package/bin/deadbyte-epoch-lock-r85.node +0 -0
  8. package/bin/deadbyte-kernel-lock-r74.exe +0 -0
  9. package/bridge/package.json +1 -1
  10. package/controller/deadbyte-process-policy.json +7 -7
  11. package/docs/R73-CAPABILITY-GAP-MATRIX.json +17 -0
  12. package/docs/R73-EXECUTION-CONTRACT.md +11 -0
  13. package/docs/R73-IMPLEMENTATION-CHANGELOG.md +12 -0
  14. package/docs/R73-REMAINING-DEFECTS.md +9 -0
  15. package/docs/R74-KERNEL-LOCK-BINARY.json +11 -0
  16. package/docs/R75-RECOVERY-HANDOFF.md +16 -0
  17. package/docs/R85-EPOCH-LOCK-BINARY.json +13 -0
  18. package/native/deadbyte-epoch-lock-r85.cpp +241 -0
  19. package/native/deadbyte-kernel-lock-r74.cpp +65 -0
  20. package/package.json +1 -1
  21. package/scripts/build-epoch-lock-r85.ps1 +34 -0
  22. package/scripts/build-kernel-lock-r74.ps1 +28 -0
  23. package/scripts/deploy-r48.mjs +3 -1
  24. package/scripts/gate-windows-r72.ps1 +2 -2
  25. package/scripts/npm-prepublish-contract-r74.mjs +113 -0
  26. package/scripts/npm-release-r48.mjs +24 -4
  27. package/scripts/npm-release-readiness-r108.mjs +134 -0
  28. package/scripts/npm-release-readiness-r74.mjs +46 -0
  29. package/scripts/r73-atomic-benchmark.mjs +39 -0
  30. package/scripts/r75-npm-bin-integrity-gate.mjs +33 -0
  31. package/scripts/release-manifest.mjs +1 -1
  32. package/scripts/verify-r70-full-regression.ps1 +12 -2
  33. package/src/activation-authority-proof-r75.mjs +67 -0
  34. package/src/activation-continuity-engine-r65.mjs +17 -4
  35. package/src/activation-preflight-r65.mjs +13 -0
  36. package/src/atomic-mutation.mjs +99 -9
  37. package/src/authority-continuity-r65.mjs +265 -21
  38. package/src/deadbyte-cli.mjs +55 -18
  39. package/src/epoch-lock-r85.mjs +48 -0
  40. package/src/foreground-marker-cas-win32.mjs +284 -0
  41. package/src/foreground-process-identity.mjs +3 -3
  42. package/src/kernel-lock-r74.mjs +125 -0
  43. package/src/privileged-install-trust-r89.mjs +196 -0
  44. package/src/remote-session-guardian.mjs +9 -7
  45. package/src/runtime-update.mjs +5 -22
  46. package/src/version.mjs +1 -1
  47. package/src/windows-powershell-environment.mjs +24 -0
  48. package/test/atomic-mutation.test.mjs +68 -2
  49. package/test/cli-entrypoint.test.mjs +1 -1
  50. package/test/commander-schema-differential-r48.test.mjs +1 -1
  51. package/test/helpers/r75-authority-proof.mjs +9 -0
  52. package/test/r100-posix-owned-lock-race.test.mjs +72 -0
  53. package/test/r101-acl-probe-environment.test.mjs +51 -0
  54. package/test/r106-trusted-powershell-spawn.test.mjs +53 -0
  55. package/test/r107-updater-powershell-path.test.mjs +77 -0
  56. package/test/r33-closeout-regression.test.mjs +2 -1
  57. package/test/r54-offline-predecessor-self-exclusion.test.mjs +2 -2
  58. package/test/r55-offline-predecessor-guardian-family.test.mjs +2 -2
  59. package/test/r56-rollback-launcher-restore.test.mjs +2 -2
  60. package/test/r57-core-startup-race.test.mjs +2 -2
  61. package/test/r58-concurrent-recovery.test.mjs +10 -7
  62. package/test/r58-stale-owner.test.mjs +5 -6
  63. package/test/r59-tool-surface-compat.test.mjs +1 -1
  64. package/test/r65-activation-orchestration.test.mjs +2 -1
  65. package/test/r65-activation-preflight.test.mjs +7 -6
  66. package/test/r65-authority-epoch-recovery.test.mjs +3 -1
  67. package/test/r65-authority-restored-safe.test.mjs +2 -1
  68. package/test/r65-deploy-preflight.test.mjs +13 -14
  69. package/test/r65-epoch-native-activation-integration.test.mjs +5 -4
  70. package/test/r65-legacy-authority-migration.test.mjs +2 -1
  71. package/test/r67-npm-cross-volume.test.mjs +9 -2
  72. package/test/r71-full-verifier-artifact.test.mjs +21 -15
  73. package/test/r71-isolated-slot-rollback-restore.test.mjs +3 -1
  74. package/test/r71-release-identity.test.mjs +3 -1
  75. package/test/r73-package-boundary.test.mjs +22 -0
  76. package/test/r74-kernel-lock.test.mjs +156 -0
  77. package/test/r74-prepublish-contract.test.mjs +89 -0
  78. package/test/r75-activation-authority-proof.test.mjs +46 -0
  79. package/test/r75-authority-evidence.test.mjs +77 -0
  80. package/test/r76-pinned-marker-cas.test.mjs +78 -0
  81. package/test/r77-epoch-grant-cas.test.mjs +51 -0
  82. package/test/r78-parent-junction-cas.test.mjs +62 -0
  83. package/test/r79-orphan-revocation-reconcile.test.mjs +88 -0
  84. package/test/r79-windows-fsync-regression.test.mjs +45 -0
  85. package/test/r80-durable-epoch-commit.test.mjs +76 -0
  86. package/test/r82-epoch-lock-owned-cas.test.mjs +93 -0
  87. package/test/r83-epoch-lock-fileid-cas.test.mjs +92 -0
  88. package/test/r84-epoch-lock-created-fileid.test.mjs +112 -0
  89. package/test/r85-epoch-lock-release-lifetime.test.mjs +25 -0
  90. package/test/r85-epoch-repeat-append.test.mjs +30 -0
  91. package/test/r86-epoch-cleanup-and-loader.test.mjs +126 -0
  92. package/test/r87-crashed-orphan-revoke-reconcile.test.mjs +110 -0
  93. package/test/r88-native-disposition-failure.test.mjs +35 -0
  94. package/test/r89-privileged-install-boundary.test.mjs +123 -0
  95. package/test/r92-acl-ace-applicability.test.mjs +45 -0
  96. package/test/r94-win32-propagation-enum.test.mjs +51 -0
  97. package/test/r99-privileged-import-closure.test.mjs +45 -0
  98. package/test/remote-session-cli.test.mjs +69 -9
@@ -0,0 +1,156 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {copyFile,mkdir,mkdtemp,readFile,rm,writeFile} from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import {fileURLToPath,pathToFileURL} from 'node:url';
7
+ import {acquireKernelExclusiveLock, verifyKernelLockBinary} from '../src/kernel-lock-r74.mjs';
8
+
9
+ const checkout=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
10
+
11
+ async function safeRm(dir) {
12
+ for (let i = 0; i < 15; i++) {
13
+ try {
14
+ await rm(dir, {recursive: true, force: true});
15
+ return;
16
+ } catch (err) {
17
+ if (err.code !== 'EBUSY' && err.code !== 'EPERM') throw err;
18
+ await new Promise(r => setTimeout(r, 40));
19
+ }
20
+ }
21
+ await rm(dir, {recursive: true, force: true});
22
+ }
23
+
24
+ test('kernel lock binary is verified and hash-pinned', async () => {
25
+ const verified = await verifyKernelLockBinary();
26
+ assert.equal(verified.ok, true, verified.reason);
27
+ assert.ok(/^[0-9a-f]{64}$/.test(verified.sha256));
28
+ });
29
+
30
+ test('kernel exclusive lock can be acquired and released normally', async () => {
31
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-lock-basic-'));
32
+ const lock = path.join(root, 'target.lock');
33
+ try {
34
+ const release = await acquireKernelExclusiveLock(lock);
35
+ assert.equal(typeof release, 'function');
36
+ assert.ok(Number.isSafeInteger(release.pid));
37
+ await release();
38
+ const content = await readFile(lock, 'utf8');
39
+ assert.match(content, /^deadbyte\.kernel-lock\.r74:pid=\d+/);
40
+ } finally {
41
+ await safeRm(root);
42
+ }
43
+ });
44
+
45
+ test('concurrent writer is blocked while lock is held by another process', async () => {
46
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-lock-contention-'));
47
+ const lock = path.join(root, 'target.lock');
48
+ try {
49
+ const release = await acquireKernelExclusiveLock(lock);
50
+ let error = null;
51
+ try {
52
+ await acquireKernelExclusiveLock(lock, {timeoutMs: 100, pollMs: 15});
53
+ } catch (err) {
54
+ error = err;
55
+ }
56
+ assert.ok(error, 'second writer should have been blocked');
57
+ assert.match(error.message, /atomic mutation lock timed out/);
58
+ await release();
59
+ } finally {
60
+ await safeRm(root);
61
+ }
62
+ });
63
+
64
+ test('crash-safe recovery: killed owner releases handle via OS, successor acquires without deleting lock pathname', async () => {
65
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-lock-crash-'));
66
+ const lock = path.join(root, 'target.lock');
67
+ try {
68
+ const releaseFirst = await acquireKernelExclusiveLock(lock);
69
+ const lockPid = releaseFirst.pid;
70
+ assert.ok(Number.isSafeInteger(lockPid));
71
+
72
+ // Abrupt termination (simulating crash)
73
+ process.kill(lockPid, 'SIGKILL');
74
+
75
+ // Wait a brief moment for Windows kernel to close the handle
76
+ await new Promise(r => setTimeout(r, 60));
77
+
78
+ // Successor MUST be able to acquire the lock immediately WITHOUT deleting the lock file!
79
+ const releaseSecond = await acquireKernelExclusiveLock(lock, {timeoutMs: 1000});
80
+ assert.equal(typeof releaseSecond, 'function');
81
+
82
+ // Clean release
83
+ await releaseSecond();
84
+ } finally {
85
+ await safeRm(root);
86
+ }
87
+ });
88
+
89
+ test('dead PID or stale on-disk marker does not block new acquisition when no handle is held', async () => {
90
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-lock-pidreuse-'));
91
+ const lock = path.join(root, 'target.lock');
92
+ try {
93
+ // Write a stale/foreign PID into the lock file
94
+ await writeFile(lock, 'deadbyte.kernel-lock.r74:pid=999999999\n');
95
+
96
+ // Because no live kernel handle holds the file, acquisition must succeed immediately
97
+ const release = await acquireKernelExclusiveLock(lock, {timeoutMs: 500});
98
+ assert.equal(typeof release, 'function');
99
+ await release();
100
+ } finally {
101
+ await safeRm(root);
102
+ }
103
+ });
104
+
105
+ test('concurrent recovery: exactly one worker acquires lock, others are serialized', async () => {
106
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-lock-concurrent-'));
107
+ const lock = path.join(root, 'target.lock');
108
+ const sequence = [];
109
+ try {
110
+ const runWorker = async (id) => {
111
+ const release = await acquireKernelExclusiveLock(lock, {timeoutMs: 5000, pollMs: 10});
112
+ sequence.push(`enter_${id}`);
113
+ await new Promise(r => setTimeout(r, 20));
114
+ sequence.push(`exit_${id}`);
115
+ await release();
116
+ };
117
+
118
+ // Run 3 workers concurrently
119
+ await Promise.all([runWorker(1), runWorker(2), runWorker(3)]);
120
+
121
+ assert.equal(sequence.length, 6);
122
+ // Every enter must be followed by its matching exit before next enter
123
+ for (let i = 0; i < sequence.length; i += 2) {
124
+ const enter = sequence[i];
125
+ const exit = sequence[i + 1];
126
+ const id = enter.split('_')[1];
127
+ assert.equal(exit, `exit_${id}`, `non-exclusive execution detected: ${enter} followed by ${exit}`);
128
+ }
129
+ } finally {
130
+ await safeRm(root);
131
+ }
132
+ });
133
+
134
+ test('replaced binary negative: tampered executable fails closed with recovery blocked', async () => {
135
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-lock-tampered-'));
136
+ const lock = path.join(root, 'target.lock');
137
+ try {
138
+ for(const dir of ['src','docs','bin'])await mkdir(path.join(root,dir));
139
+ for(const rel of ['src/kernel-lock-r74.mjs','docs/R74-KERNEL-LOCK-BINARY.json',
140
+ 'bin/deadbyte-kernel-lock-r74.exe'])
141
+ await copyFile(path.join(checkout,rel),path.join(root,rel));
142
+ const fixture=await import(pathToFileURL(path.join(root,'src','kernel-lock-r74.mjs')).href);
143
+ const metaPath=path.join(root,'docs','R74-KERNEL-LOCK-BINARY.json');
144
+ const originalMeta = await readFile(metaPath, 'utf8');
145
+ const tampered = JSON.parse(originalMeta);
146
+ tampered.sha256 = '0'.repeat(64);
147
+ await writeFile(metaPath, JSON.stringify(tampered, null, 2) + '\n');
148
+
149
+ await assert.rejects(
150
+ fixture.acquireKernelExclusiveLock(lock, {timeoutMs: 200}),
151
+ /atomic mutation lock recovery blocked: native exclusive locking unavailable/
152
+ );
153
+ } finally {
154
+ await safeRm(root);
155
+ }
156
+ });
@@ -0,0 +1,89 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdtemp, readFile, rm, cp, writeFile} from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import {fileURLToPath} from 'node:url';
7
+ import {verifyR74PrepublishContract} from '../scripts/npm-prepublish-contract-r74.mjs';
8
+
9
+ const repoRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
10
+
11
+ test('R74 prepublish contract: positive path succeeds and verifies identities', async () => {
12
+ const result = await verifyR74PrepublishContract({rootPath: repoRoot});
13
+ assert.equal(result.schema, 'deadbyte.r74-prepublish-contract.v1');
14
+ assert.equal(result.valid, true);
15
+ assert.equal(result.checks.predecessors_distinct, true);
16
+ assert.equal(result.checks.manifest_exists, true);
17
+ assert.equal(result.checks.manifest_verified, true);
18
+ assert.equal(result.checks.package_leak_check.ok, true);
19
+ assert.equal(result.checks.no_self_referential_tarball_hash, true);
20
+ assert.equal(result.identities.package_name, 'deadbyte-mcp');
21
+ assert.equal(result.identities.package_version, '0.15.48');
22
+ assert.equal(result.identities.target_train, 'R74');
23
+ assert.equal(result.identities.published_source_predecessor, '0.15.46');
24
+ assert.notEqual(result.identities.published_source_predecessor, result.identities.runtime_predecessor);
25
+ });
26
+
27
+ test('R74 prepublish contract: negative - tampered native binary hash fails closed', async () => {
28
+ const sandbox = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-prepub-tamper-'));
29
+ try {
30
+ // Copy minimal required files to sandbox
31
+ await cp(path.join(repoRoot, 'package.json'), path.join(sandbox, 'package.json'));
32
+ await cp(path.join(repoRoot, 'RELEASE.json'), path.join(sandbox, 'RELEASE.json'));
33
+ await cp(path.join(repoRoot, 'MANIFEST.SHA256'), path.join(sandbox, 'MANIFEST.SHA256'));
34
+ await cp(path.join(repoRoot, 'docs'), path.join(sandbox, 'docs'), {recursive: true});
35
+ await cp(path.join(repoRoot, 'bin'), path.join(sandbox, 'bin'), {recursive: true});
36
+
37
+ // Tamper with binary
38
+ const exePath = path.join(sandbox, 'bin', 'deadbyte-kernel-lock-r74.exe');
39
+ await writeFile(exePath, 'TAMPERED_BYTES_R74');
40
+
41
+ await assert.rejects(
42
+ async () => {
43
+ await verifyR74PrepublishContract({rootPath: sandbox});
44
+ },
45
+ /Prepublish contract failed: native binary .* hash mismatch/
46
+ );
47
+ } finally {
48
+ await rm(sandbox, {recursive: true, force: true}).catch(() => {});
49
+ }
50
+ });
51
+
52
+ test('R74 prepublish contract: negative - predecessor collision fails closed', async () => {
53
+ const sandbox = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r74-prepub-collision-'));
54
+ try {
55
+ const pkg = JSON.parse(await readFile(path.join(repoRoot, 'package.json'), 'utf8'));
56
+ const release = JSON.parse(await readFile(path.join(repoRoot, 'RELEASE.json'), 'utf8'));
57
+
58
+ // Set runtime predecessor to match published source predecessor (0.15.46)
59
+ release.parent = release.parent || {};
60
+ release.parent.version = '0.15.46';
61
+
62
+ await writeFile(path.join(sandbox, 'package.json'), JSON.stringify(pkg, null, 2));
63
+ await writeFile(path.join(sandbox, 'RELEASE.json'), JSON.stringify(release, null, 2));
64
+
65
+ await assert.rejects(
66
+ async () => {
67
+ await verifyR74PrepublishContract({rootPath: sandbox});
68
+ },
69
+ /Prepublish contract failed: published source and runtime predecessor must be distinct/
70
+ );
71
+ } finally {
72
+ await rm(sandbox, {recursive: true, force: true}).catch(() => {});
73
+ }
74
+ });
75
+
76
+ test('R74 prepublish contract: negative - package leakage fails closed', async () => {
77
+ // Verify that filter catches testing/, references/, .git, .env
78
+ const leakedNames = ['testing/secret.json', 'references/doc.md', '.git/config', '.env'];
79
+ for (const name of leakedNames) {
80
+ const isLeaked = /^(?:testing|references|\.git)(?:\/|$)|(?:^|\/)\.env(?:\.|$)/i.test(name);
81
+ assert.equal(isLeaked, true, `Expected ${name} to be detected as leaked`);
82
+ }
83
+ });
84
+
85
+ test('R74 prepublish contract: non-self-referential tarball check', async () => {
86
+ // Verify that RELEASE.json does NOT contain a prospective hash of the tarball that contains it
87
+ const release = JSON.parse(await readFile(path.join(repoRoot, 'RELEASE.json'), 'utf8'));
88
+ assert.equal(release.tarball_sha256, undefined, 'RELEASE.json must not claim self-referential tarball hash');
89
+ });
@@ -0,0 +1,46 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {classifyActivationPreflight} from '../src/activation-preflight-r65.mjs';
4
+
5
+ const planes=['process','coding','autonomous','desktop','host'];
6
+ const parent={release_id:'v-parent',version:'0.15.45',manifest_sha256:'a'.repeat(64),generation_manifest_sha256:'b'.repeat(64)};
7
+ const candidate={version:'0.15.47',manifest_sha256:'c'.repeat(64)};
8
+ const policy_sha256=Object.fromEntries(planes.map((plane,index)=>[plane,String(index+1).repeat(64)]));
9
+ const disarmed=Object.fromEntries(planes.map(plane=>[plane,{configured:true,armed:false,reason:'disarmed'}]));
10
+ const proof=Object.fromEntries(planes.map(plane=>[plane,{state:'VERIFIED_DISARMED',policy_sha256:policy_sha256[plane],grant_absent:true}]));
11
+ const observation={state:'OFFLINE',authority:disarmed,authority_proof:proof,policy_sha256,
12
+ bridge:{alive:false},core:{alive:false},cloud:{alive:false},supervisor:{running:false},
13
+ active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,
14
+ active_generation_manifest_sha256:parent.generation_manifest_sha256};
15
+ const classify=observed=>classifyActivationPreflight({pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,observation:observed});
16
+
17
+ test('verified absent grants and exact disarmed observation allow offline preflight',()=>{
18
+ const result=classify(observation);
19
+ assert.equal(result.state,'OFFLINE_CLEAN');
20
+ assert.equal(result.safe_to_activate,true);
21
+ });
22
+
23
+ test('Autonomous armed=false with an unverified reason is not activation-safe',()=>{
24
+ const result=classify({...observation,authority:{...disarmed,autonomous:{configured:true,armed:false,reason:'coding policy contains a broad filesystem root'}}});
25
+ assert.equal(result.safe_to_activate,false);
26
+ assert.equal(result.state,'AUTHORITY_UNVERIFIED');
27
+ });
28
+
29
+ test('a missing direct grant proof cannot be inferred safe from armed=false',()=>{
30
+ const result=classify({...observation,authority_proof:{...proof,autonomous:{state:'UNVERIFIED',policy_sha256:policy_sha256.autonomous,grant_absent:false}}});
31
+ assert.equal(result.safe_to_activate,false);
32
+ assert.equal(result.state,'AUTHORITY_UNVERIFIED');
33
+ });
34
+
35
+ test('controller object observations without direct grant proof cannot activate',()=>{
36
+ const result=classify({...observation,authority_proof:undefined});
37
+ assert.equal(result.safe_to_activate,false);
38
+ assert.equal(result.state,'AUTHORITY_UNVERIFIED');
39
+ });
40
+
41
+ test('legacy Boolean authority observations without direct proof cannot activate',()=>{
42
+ const legacy=Object.fromEntries(planes.map(plane=>[plane,false]));
43
+ const result=classify({...observation,authority:legacy,authority_proof:undefined});
44
+ assert.equal(result.safe_to_activate,false);
45
+ assert.equal(result.state,'AUTHORITY_UNVERIFIED');
46
+ });
@@ -0,0 +1,77 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {mkdtemp,mkdir,writeFile,rm} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {observeAuthorityEvidence} from '../src/activation-authority-proof-r75.mjs';
8
+
9
+ const planes=['process','coding','autonomous','desktop','host'];
10
+ const grantField={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
11
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
12
+
13
+ async function fixture({broadCodingRoot=false,hostSchema=2}={}){
14
+ const stateRoot=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r75-authority-'));
15
+ const runtime=path.join(stateRoot,'runtime'),policies=path.join(stateRoot,'policies');
16
+ await mkdir(runtime);await mkdir(policies);
17
+ const policyPaths={},policySha256={},grantPaths={};
18
+ for(const plane of planes){
19
+ const grant=path.join(runtime,`${plane}-grant.json`),policyPath=path.join(policies,`${plane}.json`);
20
+ const bytes=Buffer.from(JSON.stringify({schema:`deadbyte.${plane}-policy.v${plane==='host'?hostSchema:1}`,enabled:true,
21
+ [grantField[plane]]:grant,...(plane==='coding'&&broadCodingRoot?{roots:{broad:{path:path.parse(stateRoot).root}}}:{})}));
22
+ await writeFile(policyPath,bytes);
23
+ policyPaths[plane]=policyPath;policySha256[plane]=sha(bytes);grantPaths[plane]=grant;
24
+ }
25
+ const authority=Object.fromEntries(planes.map(plane=>[plane,{configured:true,armed:false,reason:'disarmed'}]));
26
+ return {stateRoot,policyPaths,policySha256,grantPaths,authority,cleanup:()=>rm(stateRoot,{recursive:true,force:true})};
27
+ }
28
+
29
+ test('direct policy-bound grant absence proves clean disarmed despite broad issuance root',async()=>{
30
+ const f=await fixture({broadCodingRoot:true});
31
+ try{
32
+ const proof=await observeAuthorityEvidence(f);
33
+ for(const plane of planes){assert.equal(proof[plane].state,'VERIFIED_DISARMED');assert.equal(proof[plane].grant_absent,true);}
34
+ }finally{await f.cleanup();}
35
+ });
36
+
37
+ test('legacy host-policy.v1 accepted by the controller remains eligible for proof',async()=>{
38
+ const f=await fixture({hostSchema:1});
39
+ try{assert.equal((await observeAuthorityEvidence(f)).host.state,'VERIFIED_DISARMED');}
40
+ finally{await f.cleanup();}
41
+ });
42
+
43
+ test('a present grant with controller armed=false is unverified, not clean',async()=>{
44
+ const f=await fixture();
45
+ try{
46
+ await writeFile(f.grantPaths.autonomous,'{}');
47
+ const proof=await observeAuthorityEvidence(f);
48
+ assert.equal(proof.autonomous.state,'UNVERIFIED');
49
+ }finally{await f.cleanup();}
50
+ });
51
+
52
+ test('malformed policy cannot provide disarmed proof',async()=>{
53
+ const f=await fixture();
54
+ try{
55
+ await writeFile(f.policyPaths.autonomous,'not-json');
56
+ await assert.rejects(observeAuthorityEvidence(f),/policy/i);
57
+ }finally{await f.cleanup();}
58
+ });
59
+
60
+ test('policy-bound grant path outside isolated runtime cannot provide disarmed proof',async()=>{
61
+ const f=await fixture();
62
+ try{
63
+ const bytes=Buffer.from(JSON.stringify({schema:'deadbyte.autonomous-policy.v1',enabled:true,
64
+ lease_file:path.join(os.tmpdir(),'outside-autonomous-grant.json')}));
65
+ await writeFile(f.policyPaths.autonomous,bytes);
66
+ f.policySha256.autonomous=sha(bytes);
67
+ await assert.rejects(observeAuthorityEvidence(f),/outside runtime/);
68
+ }finally{await f.cleanup();}
69
+ });
70
+
71
+ test('policy digest drift cannot provide stale disarmed proof',async()=>{
72
+ const f=await fixture();
73
+ try{
74
+ await writeFile(f.policyPaths.autonomous,'{}');
75
+ await assert.rejects(observeAuthorityEvidence(f),/digest changed/);
76
+ }finally{await f.cleanup();}
77
+ });
@@ -0,0 +1,78 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {mkdtemp,mkdir,readFile,writeFile,open,rm} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {readRemoteMarkerSnapshot,deletePinnedRemoteMarker} from '../src/foreground-marker-cas-win32.mjs';
8
+
9
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
10
+ const marker={schema:'deadbyte.remote-session.v2',owner_pid:14445,guardian_pid:0,session_nonce:'a'.repeat(64)};
11
+
12
+ async function fixture(run){
13
+ const root=await mkdtemp(path.join(os.tmpdir(),'r76-marker-cas-'));
14
+ const file=path.join(root,'remote-session.json');
15
+ try{return await run(file);}finally{await rm(root,{recursive:true,force:true});}
16
+ }
17
+
18
+ test('snapshot binds exact bytes and rejects untrusted marker shapes',async()=>fixture(async file=>{
19
+ assert.equal(await readRemoteMarkerSnapshot(file),null);
20
+ const raw=JSON.stringify(marker)+'\n';
21
+ await writeFile(file,raw);
22
+ const snapshot=await readRemoteMarkerSnapshot(file);
23
+ assert.deepEqual(snapshot.marker,marker);
24
+ assert.equal(snapshot.sha256,sha(Buffer.from(raw)));
25
+ await writeFile(file,'{malformed');
26
+ await assert.rejects(()=>readRemoteMarkerSnapshot(file),/marker JSON invalid/);
27
+ }));
28
+
29
+ test('native disposition never silently falls back to pathname removal',async()=>fixture(async file=>{
30
+ await writeFile(file,JSON.stringify(marker));
31
+ if(process.platform!=='win32'){
32
+ assert.throws(()=>deletePinnedRemoteMarker(file,'a'.repeat(64)),/Windows-only/);
33
+ assert.deepEqual(JSON.parse(await readFile(file,'utf8')),marker);
34
+ }
35
+ }));
36
+
37
+ const winTest=process.platform==='win32'?test:test.skip;
38
+
39
+ winTest('Windows: pinned handle removes the exact marker, but not a missing marker',async()=>fixture(async file=>{
40
+ await writeFile(file,JSON.stringify(marker)+'\n');
41
+ const snapshot=await readRemoteMarkerSnapshot(file);
42
+ assert.equal(deletePinnedRemoteMarker(file,snapshot.sha256),'REMOVED');
43
+ await assert.rejects(readFile(file),{code:'ENOENT'});
44
+ assert.equal(deletePinnedRemoteMarker(file,snapshot.sha256),'MISSING');
45
+ }));
46
+
47
+ winTest('Windows: replacement between snapshot and disposition is never removed',async()=>fixture(async file=>{
48
+ await writeFile(file,JSON.stringify(marker));
49
+ const snapshot=await readRemoteMarkerSnapshot(file);
50
+ const replaced={...marker,session_nonce:'b'.repeat(64)};
51
+ await writeFile(file,JSON.stringify(replaced));
52
+ assert.equal(deletePinnedRemoteMarker(file,snapshot.sha256),'CHANGED');
53
+ assert.deepEqual(JSON.parse(await readFile(file,'utf8')),replaced);
54
+ }));
55
+
56
+ winTest('Windows: concurrent writable handle makes native deletion fail closed',async()=>fixture(async file=>{
57
+ await writeFile(file,JSON.stringify(marker));
58
+ const snapshot=await readRemoteMarkerSnapshot(file);
59
+ const writer=await open(file,'r+');
60
+ try{
61
+ assert.throws(()=>deletePinnedRemoteMarker(file,snapshot.sha256),/failed closed/);
62
+ assert.deepEqual(JSON.parse(await readFile(file,'utf8')),marker);
63
+ }finally{await writer.close();}
64
+ assert.equal(deletePinnedRemoteMarker(file,snapshot.sha256),'REMOVED');
65
+ }));
66
+
67
+ winTest('Windows: malformed or unreadable marker remains intact',async()=>fixture(async file=>{
68
+ await writeFile(file,'{bad json');
69
+ await assert.rejects(()=>readRemoteMarkerSnapshot(file),/marker JSON invalid/);
70
+ assert.equal(await readFile(file,'utf8'),'{bad json');
71
+ }));
72
+
73
+ // Cross-platform guard: node --check cannot detect undeclared names inside a function.
74
+ // The Windows hard-kill guardian integration test separately proves runtime cleanup.
75
+ test('guardian imports its pinned marker snapshot and native disposer explicitly',async()=>{
76
+ const guardian=await readFile(new URL('../src/remote-session-guardian.mjs',import.meta.url),'utf8');
77
+ assert.match(guardian,/import\s*\{\s*readRemoteMarkerSnapshot\s*,\s*deletePinnedRemoteMarker\s*\}\s*from\s*['"]\.\/foreground-marker-cas-win32\.mjs['"]/);
78
+ });
@@ -0,0 +1,51 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {mkdtemp,open,readFile,rm,writeFile} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {fileURLToPath} from 'node:url';
8
+ import {deletePinnedRemoteMarker} from '../src/foreground-marker-cas-win32.mjs';
9
+
10
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
11
+
12
+ // Source contract: restore must use the same native CAS boundary as error cleanup.
13
+ test('R77 restore never removes a previously examined grant by pathname',async()=>{
14
+ const current=await readFile(new URL('../src/activation-continuity-engine-r65.mjs',import.meta.url),'utf8');
15
+ assert.match(current,/const removed=await removeIfExact\(file,record\.grant_sha256\)/);
16
+ assert.match(current,/deletePinnedRemoteMarker\(file,expectedSha256\)/);
17
+ assert.doesNotMatch(current,/if\(sha\(existing\)!==record\.grant_sha256\)[\s\S]{0,100}await rm\(file/);
18
+ });
19
+
20
+ async function withGrantFixture(callback){
21
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r77-epoch-cas-'));
22
+ const file=path.join(root,'coding-grant.json');
23
+ const old=Buffer.from(JSON.stringify({schema:'deadbyte.coding-grant.v2',instance_nonce:'1'.repeat(64)}));
24
+ try {await writeFile(file,old);await callback({file,old,root});}
25
+ finally {await rm(root,{recursive:true,force:true});}
26
+ }
27
+
28
+ test('Windows: grant file exact SHA disposition succeeds', {skip:process.platform!=='win32'},async()=>{
29
+ await withGrantFixture(async({file,old})=>{
30
+ assert.equal(deletePinnedRemoteMarker(file,sha(old)),'REMOVED');
31
+ await assert.rejects(readFile(file),{code:'ENOENT'});
32
+ });
33
+ });
34
+
35
+ test('Windows: replaced grant is not removed by stale SHA', {skip:process.platform!=='win32'},async()=>{
36
+ await withGrantFixture(async({file,old})=>{
37
+ const replacement=Buffer.from(JSON.stringify({schema:'deadbyte.coding-grant.v2',instance_nonce:'2'.repeat(64)}));
38
+ await writeFile(file,replacement);
39
+ assert.equal(deletePinnedRemoteMarker(file,sha(old)),'CHANGED');
40
+ assert.deepEqual(await readFile(file),replacement);
41
+ });
42
+ });
43
+
44
+ test('Windows: a concurrent writable grant handle blocks disposition', {skip:process.platform!=='win32'},async()=>{
45
+ await withGrantFixture(async({file,old})=>{
46
+ const live=await open(file,'r+');
47
+ try {assert.throws(()=>deletePinnedRemoteMarker(file,sha(old)),/failed closed/);}
48
+ finally {await live.close();}
49
+ assert.deepEqual(await readFile(file),old);
50
+ });
51
+ });
@@ -0,0 +1,62 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash,randomBytes} from 'node:crypto';
4
+ import {mkdtemp,mkdir,readFile,rm,symlink,unlink,writeFile} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {deletePinnedRemoteMarker} from '../src/foreground-marker-cas-win32.mjs';
8
+
9
+ const digest=bytes=>createHash('sha256').update(bytes).digest('hex');
10
+ const winTest=process.platform==='win32'?test:test.skip;
11
+
12
+ // Does not establish native protection alone; verifies the intended source contract.
13
+ test('R78 source pins every ancestor handle and rejects reparse parents before leaf disposition',async()=>{
14
+ const source=await readFile(new URL('../src/foreground-marker-cas-win32.mjs',import.meta.url),'utf8');
15
+ assert.match(source,/static void PinAncestor\(/);
16
+ assert.match(source,/FILE_FLAG_BACKUP_SEMANTICS\|FILE_FLAG_OPEN_REPARSE_POINT/);
17
+ assert.match(source,/FILE_ATTRIBUTE_REPARSE_POINT/);
18
+ assert.match(source,/PinAncestor\(current,pins\)/);
19
+ assert.match(source,/for\(int i=pins\.Count-1;i>=0;i--\)pins\[i\]\.Dispose\(\)/);
20
+ assert.doesNotMatch(source,/await rm\(file/);
21
+ });
22
+
23
+ async function withFixture(cb){
24
+ const fixture=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r78-parent-cas-'));
25
+ const inside=path.join(fixture,'state','runtime');
26
+ const outside=path.join(fixture,'outside');
27
+ const bytes=Buffer.from(JSON.stringify({schema:'deadbyte.r78.fixture.v1',nonce:randomBytes(24).toString('hex')}));
28
+ await mkdir(inside,{recursive:true});await mkdir(outside,{recursive:true});
29
+ const sentinel=path.join(outside,'sentinel.json');
30
+ await writeFile(sentinel,bytes,{flag:'wx'});
31
+ let junction=null;
32
+ try{return await cb({fixture,inside,outside,sentinel,bytes,setJunction:v=>junction=v});}
33
+ finally{
34
+ // Remove the junction *first* so no recursive clean-up can walk outside.
35
+ if(junction){await unlink(junction);}
36
+ await rm(fixture,{recursive:true,force:true});
37
+ }
38
+ }
39
+
40
+ winTest('Windows: parent junction to outside cannot delete target fixture',async()=>withFixture(async({inside,outside,sentinel,bytes,setJunction})=>{
41
+ const link=path.join(inside,'escape');
42
+ await symlink(outside,link,'junction');setJunction(link);
43
+ assert.throws(()=>deletePinnedRemoteMarker(path.join(link,'sentinel.json'),digest(bytes)),/failed closed/);
44
+ assert.deepEqual(await readFile(sentinel),bytes);
45
+ }));
46
+
47
+ winTest('Windows: nested parent junction cannot delete outside target fixture',async()=>withFixture(async({inside,outside,sentinel,bytes,setJunction})=>{
48
+ const nested=path.join(inside,'a','b');
49
+ await mkdir(nested,{recursive:true});
50
+ const link=path.join(nested,'escape');
51
+ await symlink(outside,link,'junction');setJunction(link);
52
+ assert.throws(()=>deletePinnedRemoteMarker(path.join(link,'sentinel.json'),digest(bytes)),/failed closed/);
53
+ assert.deepEqual(await readFile(sentinel),bytes);
54
+ }));
55
+
56
+ winTest('Windows: ordinary parent path still permits exact-hash disposition',async()=>withFixture(async({inside,bytes})=>{
57
+ const file=path.join(inside,'normal.json');
58
+ await writeFile(file,bytes,{flag:'wx'});
59
+ assert.equal(deletePinnedRemoteMarker(file,digest(bytes)),'REMOVED');
60
+ await assert.rejects(readFile(file),{code:'ENOENT'});
61
+ assert.equal(deletePinnedRemoteMarker(file,digest(bytes)),'MISSING');
62
+ }));
@@ -0,0 +1,88 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash,generateKeyPairSync} from 'node:crypto';
4
+ import {mkdtemp,mkdir,readFile,readdir,writeFile,rm} from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import os from 'node:os';
7
+ import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
8
+ const hash=b=>createHash('sha256').update(b).digest('hex');
9
+ const nonce=c=>c.repeat(64);
10
+ const grant=c=>Buffer.from(JSON.stringify({schema:'deadbyte.coding-grant.v2',policy_sha256:'a'.repeat(64),instance_nonce:nonce(c),root_ids:['core'],granted_at_utc:'2026-10-16T00:00:00.000Z'}));
11
+ const bind=old=>({prior_grant_sha256:hash(old),prior_grant_instance_nonce:nonce('a'),predecessor_policy_envelope_sha256:nonce('1'),successor_policy_envelope_sha256:nonce('2'),candidate_manifest_sha256:nonce('3'),continuity_subject_sha256:nonce('4')});
12
+ async function fixture(action,fn){
13
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r79-explicit-recovery-'));
14
+ try{
15
+ const runtime=path.join(root,'runtime'),trust=path.join(root,'trust');
16
+ await mkdir(runtime);await mkdir(trust);
17
+ const keys=generateKeyPairSync('ed25519');
18
+ await writeFile(path.join(trust,'ed25519-private.pem'),keys.privateKey.export({type:'pkcs8',format:'pem'}),{flag:'wx'});
19
+ await writeFile(path.join(trust,'ed25519-public.pem'),keys.publicKey.export({type:'spki',format:'pem'}),{flag:'wx'});
20
+ const store=createAuthorityEpochStore({runtimeDir:runtime});
21
+ const old=grant('a'),next=grant('b');
22
+ const armed=await store.append({plane:'coding',action:'grant',grantBytes:old,grantInstanceNonce:nonce('a')});
23
+ let prior=armed;
24
+ if(action==='transaction_restore')prior=await store.append({plane:'coding',action:'transaction_revoke',grantBytes:old,grantInstanceNonce:nonce('a'),updateId:'r79-explicit',expectedHeadSha256:armed.event_sha256});
25
+ const headFile=path.join(runtime,'authority-epochs','coding','head.json');
26
+ const priorHeadBytes=await readFile(headFile);
27
+ let orphan;
28
+ if(action==='transaction_restore')orphan=await store.append({plane:'coding',action,grantBytes:next,grantInstanceNonce:nonce('b'),updateId:'r79-explicit',expectedHeadSha256:prior.event_sha256,restoreBinding:bind(old)});
29
+ else orphan=await store.append({plane:'coding',action,grantBytes:old,grantInstanceNonce:nonce('a'),updateId:action==='transaction_revoke'?'r79-explicit':null,...(action==='transaction_revoke'?{expectedHeadSha256:prior.event_sha256}:{})});
30
+ await writeFile(headFile,priorHeadBytes);
31
+ await fn({store,headFile,runtime,old,next,prior,orphan});
32
+ }finally{await rm(root,{recursive:true,force:true});}
33
+ }
34
+ test('R79 explicit signed orphan transaction revoke re-commits ONLY revocation, never standing grant',()=>fixture('transaction_revoke',async({store,headFile,old,prior,orphan})=>{
35
+ await assert.rejects(store.readHead({plane:'coding'}),/replay or incomplete write/);
36
+ assert.equal((await store.verifyGrant({plane:'coding',grantBytes:old,grantInstanceNonce:nonce('a')})).trusted,false);
37
+ const oldBytes=await readFile(headFile);
38
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256}),/explicit operator confirmation/);
39
+ assert.deepEqual(await readFile(headFile),oldBytes);
40
+ const result=await store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true});
41
+ assert.equal(result.status,'REVOKED_ONLY_RECONCILED');assert.equal(result.standing_grant_authorized,false);
42
+ assert.equal((await store.readHead({plane:'coding'})).event_sha256,orphan.event_sha256);
43
+ assert.equal((await store.verifyGrant({plane:'coding',grantBytes:old,grantInstanceNonce:nonce('a')})).trusted,false);
44
+ const user=await store.append({plane:'coding',action:'user_revoke',grantBytes:old,grantInstanceNonce:nonce('a')});
45
+ assert.equal((await store.readHead({plane:'coding'})).event_sha256,user.event_sha256);
46
+ }));
47
+ test('R79 explicit orphaned user revoke can be reconciled as disarmed without granting',()=>fixture('user_revoke',async({store,old,prior,orphan})=>{
48
+ const result=await store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true});
49
+ assert.equal(result.action,'user_revoke');
50
+ assert.equal((await store.verifyGrant({plane:'coding',grantBytes:old,grantInstanceNonce:nonce('a')})).trusted,false);
51
+ }));
52
+ test('R79 orphaned restore is NEVER auto-committed, even with explicit operator confirmation',()=>fixture('transaction_restore',async({store,headFile,prior,orphan,next})=>{
53
+ const before=await readFile(headFile);
54
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true}),/revocation binding invalid/);
55
+ assert.deepEqual(await readFile(headFile),before);
56
+ assert.equal((await store.verifyGrant({plane:'coding',grantBytes:next,grantInstanceNonce:nonce('b')})).trusted,false);
57
+ }));
58
+ test('R79 mismatched expected head/orphan identities do not commit an orphan',()=>fixture('transaction_revoke',async({store,headFile,prior,orphan})=>{
59
+ const before=await readFile(headFile);
60
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:'f'.repeat(64),expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true}),/previous head mismatch/);
61
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:'f'.repeat(64),operatorConfirmed:true}),/orphan identity mismatch/);
62
+ assert.deepEqual(await readFile(headFile),before);
63
+ }));
64
+ test('R79 modified signed event bytes are refused and no head is committed',()=>fixture('transaction_revoke',async({store,headFile,runtime,prior,orphan})=>{
65
+ const before=await readFile(headFile);
66
+ const file=path.join(runtime,'authority-epochs','coding','events',orphan.event_file);
67
+ await writeFile(file,'{}');
68
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true}),/orphan bytes mismatch/);
69
+ assert.deepEqual(await readFile(headFile),before);
70
+ }));
71
+ test('R79 competing/orphan extra event cannot be reconciled',()=>fixture('transaction_revoke',async({store,headFile,runtime,prior,orphan})=>{
72
+ const before=await readFile(headFile);
73
+ const events=path.join(runtime,'authority-epochs','coding','events');
74
+ const orphanFile=path.join(events,orphan.event_file);
75
+ await writeFile(path.join(events,`${String(orphan.seq).padStart(16,'0')}-${'f'.repeat(64)}.json`),await readFile(orphanFile));
76
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true}),/exactly one orphan event/);
77
+ assert.deepEqual(await readFile(headFile),before);
78
+ }));
79
+
80
+ test('R79 stale PID lock is never unlinked by the new recovery operation',()=>fixture('transaction_revoke',async({store,headFile,runtime,prior,orphan})=>{
81
+ const before=await readFile(headFile);
82
+ const lock=path.join(runtime,'authority-epochs','coding','.lock');
83
+ const content=JSON.stringify({schema:'deadbyte.authority-epoch-lock.r65.v1',pid:2147483647,token:'another-owner',created_at_utc:'2026-10-16T00:00:00Z'});
84
+ await writeFile(lock,content,{flag:'wx'});
85
+ await assert.rejects(store.reconcileOrphanedRevocation({plane:'coding',expectedHeadSha256:prior.event_sha256,expectedOrphanSha256:orphan.event_sha256,operatorConfirmed:true}),/mutation locked/);
86
+ assert.equal(await readFile(lock,'utf8'),content);
87
+ assert.deepEqual(await readFile(headFile),before);
88
+ }));