deadbyte-mcp 0.15.41 → 0.15.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DEADBYTE-MCP.cmd +8 -4
- package/MANIFEST.SHA256 +88 -43
- package/PROVENANCE.json +66 -15
- package/README.txt +27 -18
- package/RELEASE.json +55 -15
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +117 -14
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +132 -12
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R65-AUTHORITY-CONTINUITY-DESIGN.json +27 -0
- package/docs/R65-REFERENCE-GAP-MATRIX.json +22 -0
- package/package.json +6 -4
- package/scripts/deploy-r48.mjs +123 -7
- package/scripts/gate-windows-r65-prepublish.ps1 +65 -0
- package/scripts/gate-windows-r66-prepublish.ps1 +65 -0
- package/scripts/npm-publication-r65.mjs +139 -0
- package/scripts/npm-release-r48.mjs +56 -37
- package/scripts/r65-canonical-full.mjs +45 -0
- package/scripts/r65-focused.mjs +37 -0
- package/scripts/verify-r65-parent-source.mjs +75 -0
- package/src/activation-continuity-engine-r65.mjs +225 -0
- package/src/activation-lock-r65.mjs +155 -0
- package/src/activation-preflight-r65.mjs +197 -0
- package/src/authority-continuity-r65.mjs +541 -0
- package/src/authority-epoch-cli-r65.mjs +10 -0
- package/src/autonomous-policy.mjs +7 -3
- package/src/coding-plane.mjs +12 -3
- package/src/desktop-policy-r40.mjs +6 -3
- package/src/doctor-runtime-r58.mjs +3 -1
- package/src/doctor-transactions-r58.mjs +1 -1
- package/src/host-plane.mjs +9 -3
- package/src/process-policy.mjs +7 -4
- package/src/remote-authority.mjs +10 -1
- package/src/runtime-update.mjs +15 -5
- package/src/version.mjs +1 -1
- package/test/audit-context.test.mjs +15 -4
- package/test/autonomous-local-supervisor.test.mjs +7 -6
- package/test/autonomous-supervisor-integration.test.mjs +8 -7
- package/test/capability-resolver.test.mjs +11 -5
- package/test/codex-autonomous-r44.test.mjs +7 -6
- package/test/coding-observation.test.mjs +4 -3
- package/test/commander-real-parity-r47.test.mjs +5 -4
- package/test/commander-torture-r47.test.mjs +5 -4
- package/test/desktop-policy-r40.test.mjs +6 -4
- package/test/desktop-runtime-r40.test.mjs +8 -3
- package/test/host-inline-r45.test.mjs +4 -3
- package/test/machine-fs-runtime.test.mjs +4 -3
- package/test/process-longrun-r36.test.mjs +3 -2
- package/test/process-policy.test.mjs +10 -6
- package/test/process-runtime.test.mjs +9 -6
- package/test/r52-host-revocation.test.mjs +1 -0
- package/test/r58-doctor-runtime.test.mjs +18 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r64-release-contract.test.mjs +2 -1
- package/test/r65-activation-lock-recovery.test.mjs +72 -0
- package/test/r65-activation-lock.test.mjs +59 -0
- package/test/r65-activation-orchestration.test.mjs +179 -0
- package/test/r65-activation-preflight.test.mjs +35 -0
- package/test/r65-authority-continuity-decision.test.mjs +58 -0
- package/test/r65-authority-durable-policy-binding.test.mjs +34 -0
- package/test/r65-authority-epoch-cli.test.mjs +125 -0
- package/test/r65-authority-epoch-races.test.mjs +87 -0
- package/test/r65-authority-epoch-recovery.test.mjs +82 -0
- package/test/r65-authority-epoch-store.test.mjs +94 -0
- package/test/r65-authority-fixture.mjs +41 -0
- package/test/r65-authority-grant-capture.test.mjs +37 -0
- package/test/r65-authority-observation-epoch.test.mjs +25 -0
- package/test/r65-authority-policy-envelope.test.mjs +46 -0
- package/test/r65-authority-restored-safe.test.mjs +75 -0
- package/test/r65-authority-runtime-epoch.test.mjs +115 -0
- package/test/r65-authority-runtime-policy-binding.test.mjs +29 -0
- package/test/r65-authority-test-trust.mjs +20 -0
- package/test/r65-cli-invocation.test.mjs +38 -0
- package/test/r65-controller-authority-epoch-live.test.mjs +100 -0
- package/test/r65-controller-authority-epoch.test.mjs +37 -0
- package/test/r65-deploy-preflight.test.mjs +55 -0
- package/test/r65-epoch-native-activation-integration.test.mjs +141 -0
- package/test/r65-epoch-native-continuity-engine.test.mjs +112 -0
- package/test/r65-epoch-native-cross-plane.test.mjs +95 -0
- package/test/r65-legacy-authority-migration.test.mjs +63 -0
- package/test/r65-legacy-auto-restore-rejection.test.mjs +17 -0
- package/test/r65-npm-publication.test.mjs +114 -0
- package/test/r65-parent-source-verifier.test.mjs +63 -0
- package/test/r65-release-contract.test.mjs +75 -0
- package/test/r65-transaction-precondition.test.mjs +36 -0
- package/test/r66-release-contract.test.mjs +56 -0
- package/test/remote-session-cli.test.mjs +6 -6
- package/test/standing-grants.test.mjs +20 -4
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
const read=rel=>readFile(new URL('../'+rel,import.meta.url),'utf8');
|
|
6
|
+
const json=async rel=>JSON.parse((await read(rel)).replace(/^\uFEFF/,''));
|
|
7
|
+
const currentPackage=await json('package.json');
|
|
8
|
+
const PARENT={
|
|
9
|
+
version:'0.15.41',
|
|
10
|
+
release_id:'v0.15.41-63a78ad159ad3003',
|
|
11
|
+
manifest_sha256:'63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e',
|
|
12
|
+
generation_manifest_sha256:'19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
test('R65 release identity binds exact production R64 parent and durable authority-continuity train',{skip:currentPackage.version!=='0.15.42'},async()=>{
|
|
16
|
+
const [pkg,lock,bridge,release,provenance,matrix,sbom,version,gate,gaps,design]=await Promise.all([
|
|
17
|
+
json('package.json'),json('package-lock.json'),json('bridge/package.json'),json('RELEASE.json'),
|
|
18
|
+
json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs'),
|
|
19
|
+
read('scripts/gate-windows-r65-prepublish.ps1'),json('docs/R65-REFERENCE-GAP-MATRIX.json'),
|
|
20
|
+
json('docs/R65-AUTHORITY-CONTINUITY-DESIGN.json')
|
|
21
|
+
]);
|
|
22
|
+
assert.equal(pkg.version,'0.15.42');
|
|
23
|
+
assert.equal(lock.version,pkg.version);
|
|
24
|
+
assert.equal(lock.packages[''].version,pkg.version);
|
|
25
|
+
assert.equal(bridge.version,pkg.version);
|
|
26
|
+
assert.match(version,/DEADBYTE_VERSION = '0\.15\.42'/);
|
|
27
|
+
assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r65-prepublish.ps1');
|
|
28
|
+
assert.equal(pkg.scripts['r65:focused:test'],'node scripts/r65-focused.mjs');
|
|
29
|
+
|
|
30
|
+
assert.equal(release.version,pkg.version);
|
|
31
|
+
assert.equal(release.train,'R65');
|
|
32
|
+
assert.equal(release.parent.version,PARENT.version);
|
|
33
|
+
assert.equal(release.parent.release_id,PARENT.release_id);
|
|
34
|
+
assert.equal(release.parent.manifest_sha256,PARENT.manifest_sha256);
|
|
35
|
+
assert.equal(release.parent.generation_manifest_sha256,PARENT.generation_manifest_sha256);
|
|
36
|
+
assert.deepEqual(release.runtime_predecessor,{
|
|
37
|
+
release_id:PARENT.release_id,
|
|
38
|
+
manifest_sha256:PARENT.manifest_sha256,
|
|
39
|
+
generation_manifest_sha256:PARENT.generation_manifest_sha256
|
|
40
|
+
});
|
|
41
|
+
assert.equal(release.source_predecessor.version,PARENT.version);
|
|
42
|
+
assert.equal(release.source_predecessor.manifest_file_sha256,PARENT.manifest_sha256);
|
|
43
|
+
assert.equal(release.source_predecessor.release_status,'PRODUCTION_RELEASED');
|
|
44
|
+
assert.equal(release.r65_release_control_hardening.new_public_tools,0);
|
|
45
|
+
assert.equal(release.r65_release_control_hardening.new_authority_scopes,0);
|
|
46
|
+
assert.equal(release.r65_release_control_hardening.legacy_r64_auto_restore,false);
|
|
47
|
+
assert.equal(release.r65_release_control_hardening.epoch_native_restore_requires_continuity_proof,true);
|
|
48
|
+
assert.equal(release.r65_release_control_hardening.explicit_revoke_wins,true);
|
|
49
|
+
assert.equal(release.r65_release_control_hardening.revoked_nonce_resurrection,false);
|
|
50
|
+
assert.equal(release.r65_release_control_hardening.stable_final_claim,false);
|
|
51
|
+
|
|
52
|
+
assert.equal(provenance.version,pkg.version);
|
|
53
|
+
assert.equal(provenance.parent_release_id,PARENT.release_id);
|
|
54
|
+
assert.equal(provenance.parent_manifest_sha256,PARENT.manifest_sha256);
|
|
55
|
+
assert.equal(provenance.parent_generation_manifest_sha256,PARENT.generation_manifest_sha256);
|
|
56
|
+
assert.equal(provenance.source_predecessor_version,PARENT.version);
|
|
57
|
+
assert.equal(provenance.source_predecessor_manifest_file_sha256,PARENT.manifest_sha256);
|
|
58
|
+
assert.equal(provenance.r65.production_mutations,0);
|
|
59
|
+
assert.equal(provenance.r65.npm_publications,0);
|
|
60
|
+
|
|
61
|
+
assert.equal(matrix.version,pkg.version);
|
|
62
|
+
assert.equal(matrix.train,'R65');
|
|
63
|
+
assert.ok(matrix.required.some(row=>row.id==='r65-focused'));
|
|
64
|
+
assert.ok(matrix.required.some(row=>row.id==='r65-full-regression'));
|
|
65
|
+
assert.equal(sbom.metadata.component.version,pkg.version);
|
|
66
|
+
assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r65:0.15.42');
|
|
67
|
+
assert.equal(gaps.decisions.length,7);
|
|
68
|
+
assert.equal(design.selected_method.r64_predecessor_continuity.includes('REAUTH_REQUIRED'),true);
|
|
69
|
+
|
|
70
|
+
assert.match(gate,/v0\.15\.41-63a78ad159ad3003/);
|
|
71
|
+
assert.match(gate,/63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e/);
|
|
72
|
+
assert.match(gate,/19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5/);
|
|
73
|
+
assert.match(gate,/r65:focused:test/);
|
|
74
|
+
assert.doesNotMatch(gate,/npm\.cmd publish|--publish-only/);
|
|
75
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {generateKeyPairSync} from 'node:crypto';
|
|
4
|
+
import {mkdtemp,mkdir,readFile,rm,writeFile,unlink} from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {performSlotUpdate,verifySlotUpdateEnvelope} from '../src/runtime-update.mjs';
|
|
8
|
+
import {inspectDoctorTransactions} from '../src/doctor-transactions-r58.mjs';
|
|
9
|
+
|
|
10
|
+
test('deterministic candidate precondition rejection is a signed terminal phase, not unresolved residue',async()=>{
|
|
11
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r65-precondition-'));
|
|
12
|
+
try{
|
|
13
|
+
const state=path.join(root,'state'),trust=path.join(state,'trust');
|
|
14
|
+
await mkdir(trust,{recursive:true});
|
|
15
|
+
const {privateKey,publicKey}=generateKeyPairSync('ed25519');
|
|
16
|
+
await writeFile(path.join(trust,'ed25519-private.pem'),privateKey.export({type:'pkcs8',format:'pem'}));
|
|
17
|
+
await writeFile(path.join(trust,'ed25519-public.pem'),publicKey.export({type:'spki',format:'pem'}));
|
|
18
|
+
const stage=path.join(root,'missing-candidate');
|
|
19
|
+
let failure;
|
|
20
|
+
try{await performSlotUpdate({stage,developmentRoot:path.join(root,'dev'),expectedVersion:'0.15.42',expectedManifest:'a'.repeat(64),stateRoot:state});}
|
|
21
|
+
catch(error){failure=error;}
|
|
22
|
+
assert.ok(failure?.statePath,'expected isolated precondition failure evidence');
|
|
23
|
+
const journal=JSON.parse(await readFile(failure.statePath,'utf8'));
|
|
24
|
+
assert.equal(journal.phase,'precondition_rejected');
|
|
25
|
+
const receipt=JSON.parse(await readFile(failure.failureReceiptPath,'utf8'));
|
|
26
|
+
assert.equal(receipt.body.result,'PRECONDITION_REJECTED');
|
|
27
|
+
assert.equal(verifySlotUpdateEnvelope(receipt,publicKey),true);
|
|
28
|
+
const doctor=await inspectDoctorTransactions(state);
|
|
29
|
+
assert.equal(doctor.status,'PASS');
|
|
30
|
+
assert.equal(doctor.findings.at(-1).evidence.unresolved_transactions,0);
|
|
31
|
+
await unlink(failure.failureReceiptPath);
|
|
32
|
+
const missing=await inspectDoctorTransactions(state);
|
|
33
|
+
assert.equal(missing.status,'FAIL');
|
|
34
|
+
assert.ok(missing.findings.some(item=>item.evidence?.check==='missing_failure_receipt'));
|
|
35
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
36
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
const read=rel=>readFile(new URL('../'+rel,import.meta.url),'utf8');
|
|
6
|
+
const json=async rel=>JSON.parse((await read(rel)).replace(/^\uFEFF/,''));
|
|
7
|
+
const PARENT={
|
|
8
|
+
version:'0.15.42',
|
|
9
|
+
release_id:'v0.15.42-1b4754103dd4ca43',
|
|
10
|
+
manifest_sha256:'1b4754103dd4ca43eb81f8e33cf188b36eee3051cb182396ccc6abe2a6e6c250',
|
|
11
|
+
generation_manifest_sha256:'62dc68be55ad627f8d872b8be8c1369ecca0edf08fdedc8336c9ccee2d2809fb'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
test('R66 identity is an exact prepublish doctor hotfix of sealed R65',async()=>{
|
|
15
|
+
const [pkg,lock,bridge,release,provenance,matrix,sbom,version,gate]=await Promise.all([
|
|
16
|
+
json('package.json'),json('package-lock.json'),json('bridge/package.json'),json('RELEASE.json'),
|
|
17
|
+
json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs'),
|
|
18
|
+
read('scripts/gate-windows-r66-prepublish.ps1')
|
|
19
|
+
]);
|
|
20
|
+
assert.equal(pkg.version,'0.15.43');
|
|
21
|
+
assert.equal(lock.version,pkg.version);
|
|
22
|
+
assert.equal(lock.packages[''].version,pkg.version);
|
|
23
|
+
assert.equal(bridge.version,pkg.version);
|
|
24
|
+
assert.match(version,/DEADBYTE_VERSION = '0\.15\.43'/);
|
|
25
|
+
assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r66-prepublish.ps1');
|
|
26
|
+
assert.match(pkg.scripts['r66:focused:test'],/test\/r58-doctor-runtime\.test\.mjs/);
|
|
27
|
+
assert.equal(release.version,pkg.version);
|
|
28
|
+
assert.equal(release.train,'R66');
|
|
29
|
+
for(const [key,value] of Object.entries(PARENT))assert.equal(release.parent[key],value);
|
|
30
|
+
assert.deepEqual(release.runtime_predecessor,{
|
|
31
|
+
release_id:PARENT.release_id,
|
|
32
|
+
manifest_sha256:PARENT.manifest_sha256,
|
|
33
|
+
generation_manifest_sha256:PARENT.generation_manifest_sha256
|
|
34
|
+
});
|
|
35
|
+
assert.equal(release.source_predecessor.version,PARENT.version);
|
|
36
|
+
assert.equal(release.source_predecessor.manifest_file_sha256,PARENT.manifest_sha256);
|
|
37
|
+
assert.equal(release.r66_doctor_epoch_hotfix.doctor_epoch_observation_compatibility,true);
|
|
38
|
+
assert.equal(release.r66_doctor_epoch_hotfix.new_public_tools,0);
|
|
39
|
+
assert.equal(release.r66_doctor_epoch_hotfix.new_authority_scopes,0);
|
|
40
|
+
assert.equal(release.r66_doctor_epoch_hotfix.prepublish_only,true);
|
|
41
|
+
assert.equal(provenance.version,pkg.version);
|
|
42
|
+
assert.equal(provenance.parent_release_id,PARENT.release_id);
|
|
43
|
+
assert.equal(provenance.parent_manifest_sha256,PARENT.manifest_sha256);
|
|
44
|
+
assert.equal(provenance.parent_generation_manifest_sha256,PARENT.generation_manifest_sha256);
|
|
45
|
+
assert.equal(provenance.r66.new_public_tools,0);
|
|
46
|
+
assert.equal(provenance.r66.new_authority_scopes,0);
|
|
47
|
+
assert.equal(matrix.version,pkg.version);
|
|
48
|
+
assert.equal(matrix.train,'R66');
|
|
49
|
+
assert.ok(matrix.required.some(row=>row.id==='r66-focused'));
|
|
50
|
+
assert.equal(sbom.metadata.component.version,pkg.version);
|
|
51
|
+
assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r66:0.15.43');
|
|
52
|
+
assert.match(gate,/v0\.15\.42-1b4754103dd4ca43/);
|
|
53
|
+
assert.match(gate,/62dc68be55ad627f8d872b8be8c1369ecca0edf08fdedc8336c9ccee2d2809fb/);
|
|
54
|
+
assert.match(gate,/r66:focused:test/);
|
|
55
|
+
assert.doesNotMatch(gate,/npm\.cmd publish|--publish-only/);
|
|
56
|
+
});
|
|
@@ -182,7 +182,7 @@ winTest('remote refuses READY when public signed MCP execution probe fails',asyn
|
|
|
182
182
|
try{
|
|
183
183
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
184
184
|
const output=await collect(child);
|
|
185
|
-
const ended=await Promise.race([output.closed,sleep(
|
|
185
|
+
const ended=await Promise.race([output.closed,sleep(12000).then(()=>({timeout:true}))]);
|
|
186
186
|
assert.equal(ended.timeout,undefined,'remote did not fail closed after execution probe failure');
|
|
187
187
|
assert.notEqual(ended.code,0);
|
|
188
188
|
assert.doesNotMatch(output.stdout,/\[READY\]|\[OK\] ONLINE/);
|
|
@@ -201,8 +201,8 @@ winTest('remote refuses READY when controller snapshot lies about Host enforceme
|
|
|
201
201
|
try{
|
|
202
202
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
203
203
|
const output=await collect(child);
|
|
204
|
-
const ended=await Promise.race([output.closed,sleep(
|
|
205
|
-
assert.equal(ended.timeout,undefined
|
|
204
|
+
const ended=await Promise.race([output.closed,sleep(12000).then(()=>({timeout:true}))]);
|
|
205
|
+
assert.equal(ended.timeout,undefined,`remote did not reject split authority truth; stdout=${output.stdout.slice(-1200)} stderr=${output.stderr.slice(-1200)} trace=${(await traceCommands(fx.trace)).join(',')}`);
|
|
206
206
|
assert.notEqual(ended.code,0);
|
|
207
207
|
assert.doesNotMatch(output.stdout,/\[READY\]|\[OK\] ONLINE/);
|
|
208
208
|
assert.match(output.stderr,/machinetest|enforcement/i);
|
|
@@ -394,7 +394,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
|
|
|
394
394
|
const liveIndex=secondOutput.stdout.indexOf('[LOG] Human live timeline');
|
|
395
395
|
assert.ok(callReplayIndex>=0&&resultReplayIndex>callReplayIndex&&liveIndex>resultReplayIndex,'resume ordering must be call -> result -> live tail');
|
|
396
396
|
second.stdin.end();
|
|
397
|
-
const secondEnded=await Promise.race([secondOutput.closed,sleep(
|
|
397
|
+
const secondEnded=await Promise.race([secondOutput.closed,sleep(12000).then(()=>({timeout:true}))]);
|
|
398
398
|
assert.equal(secondEnded.timeout,undefined);
|
|
399
399
|
assert.equal(secondEnded.code,0,secondOutput.stderr);
|
|
400
400
|
}finally{
|
|
@@ -502,8 +502,8 @@ winTest('bare remote rolls back authority and parks if one plane fails to arm',a
|
|
|
502
502
|
try{
|
|
503
503
|
const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
|
|
504
504
|
const output=await collect(child);
|
|
505
|
-
const ended=await Promise.race([output.closed,sleep(
|
|
506
|
-
assert.equal(ended.timeout,undefined
|
|
505
|
+
const ended=await Promise.race([output.closed,sleep(12000).then(()=>({timeout:true}))]);
|
|
506
|
+
assert.equal(ended.timeout,undefined,`failed startup did not terminate; stdout=${output.stdout.slice(-1200)} stderr=${output.stderr.slice(-1200)} trace=${(await traceCommands(fx.trace)).join(',')}`);
|
|
507
507
|
assert.notEqual(ended.code,0);
|
|
508
508
|
const commands=await traceCommands(fx.trace);
|
|
509
509
|
assert.deepEqual(commands.slice(0,6),['status','start','status','status','armprocess','armcoding']);
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { mkdtemp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { loadCodingPolicy, codingSessionStatus } from '../src/coding-plane.mjs';
|
|
7
7
|
import { assertAutonomousArmed, loadAutonomousPolicy, autonomousSessionStatus, recheckAutonomousAuthority } from '../src/autonomous-policy.mjs';
|
|
8
8
|
import { loadHostPolicy, assertHostArmed } from '../src/host-plane.mjs';
|
|
9
9
|
import { createHash } from 'node:crypto';
|
|
10
|
+
import { createAuthorityEpochStore } from '../src/authority-continuity-r65.mjs';
|
|
11
|
+
import { prepareAuthorityTestTrust } from './r65-authority-test-trust.mjs';
|
|
10
12
|
|
|
11
13
|
const sha = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
12
14
|
const farFuture = new Date('2099-01-01T00:00:00Z');
|
|
13
15
|
|
|
14
16
|
async function fixture() {
|
|
15
17
|
const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-standing-'));
|
|
18
|
+
await prepareAuthorityTestTrust(root);
|
|
16
19
|
const project = path.join(root, 'project');
|
|
17
20
|
await mkdir(project);
|
|
18
21
|
const codingPath = path.join(root, 'coding.json');
|
|
19
22
|
await writeFile(codingPath, JSON.stringify({ schema:'deadbyte.coding-policy.v1', enabled:true,
|
|
20
|
-
lease_file:path.join(root,'coding-grant.json'), evidence_dir:path.join(root,'coding-evidence'),
|
|
23
|
+
lease_file:path.join(root,'runtime','coding-grant.json'), evidence_dir:path.join(root,'coding-evidence'),
|
|
21
24
|
roots:{ project:{ path:project, read:true, write:true, exec:false, deny_paths:[] } }, commands:{} }));
|
|
22
25
|
const coding = await loadCodingPolicy(codingPath);
|
|
23
26
|
return { root, project, coding, codingPath };
|
|
@@ -27,6 +30,10 @@ test('coding standing grant remains armed until explicit revocation', async () =
|
|
|
27
30
|
await writeFile(coding.lease_file, JSON.stringify({ schema:'deadbyte.coding-grant.v2',
|
|
28
31
|
policy_sha256:coding.policy_sha256, instance_nonce:'a'.repeat(64), root_ids:['project'],
|
|
29
32
|
granted_at_utc:'2026-09-04T00:00:00Z' }));
|
|
33
|
+
const codingBytes=await readFile(coding.lease_file);
|
|
34
|
+
await createAuthorityEpochStore({runtimeDir:path.dirname(coding.lease_file),policyBytes:await readFile(coding.policy_path)}).append({
|
|
35
|
+
plane:'coding',action:'grant',grantBytes:codingBytes,grantInstanceNonce:'a'.repeat(64),updateId:null
|
|
36
|
+
});
|
|
30
37
|
const status = await codingSessionStatus(coding, farFuture);
|
|
31
38
|
assert.equal(status.armed, true);
|
|
32
39
|
assert.equal(status.reason, 'standing-grant');
|
|
@@ -37,13 +44,17 @@ test('autonomous standing grant remains armed until explicit revocation', async
|
|
|
37
44
|
const { root, coding } = await fixture();
|
|
38
45
|
const policyPath = path.join(root, 'autonomous.json');
|
|
39
46
|
await writeFile(policyPath, JSON.stringify({ schema:'deadbyte.autonomous-policy.v1', enabled:true,
|
|
40
|
-
lease_file:path.join(root,'autonomous-grant.json'), evidence_dir:path.join(root,'autonomous-evidence'),
|
|
47
|
+
lease_file:path.join(root,'runtime','autonomous-grant.json'), evidence_dir:path.join(root,'autonomous-evidence'),
|
|
41
48
|
coding_policy_sha256:coding.policy_sha256, root_ids:['project'], planner:{backend:'client_sampling'},
|
|
42
49
|
limits:{max_iterations:4,max_mutations:4,max_wall_ms:null}, profiles:{} }));
|
|
43
50
|
const policy = await loadAutonomousPolicy(policyPath, coding);
|
|
44
51
|
await writeFile(policy.lease_file, JSON.stringify({ schema:'deadbyte.autonomous-grant.v2',
|
|
45
52
|
policy_sha256:policy.policy_sha256, coding_policy_sha256:coding.policy_sha256,
|
|
46
53
|
instance_nonce:'b'.repeat(64), root_ids:['project'], granted_at_utc:'2026-09-04T00:00:00Z' }));
|
|
54
|
+
const autonomousBytes=await readFile(policy.lease_file);
|
|
55
|
+
await createAuthorityEpochStore({runtimeDir:path.dirname(policy.lease_file),policyBytes:await readFile(policy.policy_path)}).append({
|
|
56
|
+
plane:'autonomous',action:'grant',grantBytes:autonomousBytes,grantInstanceNonce:'b'.repeat(64),updateId:null
|
|
57
|
+
});
|
|
47
58
|
const status = await autonomousSessionStatus(policy, farFuture);
|
|
48
59
|
assert.equal(status.armed, true);
|
|
49
60
|
assert.equal(status.reason, 'standing-grant');
|
|
@@ -55,15 +66,20 @@ test('autonomous standing grant remains armed until explicit revocation', async
|
|
|
55
66
|
});
|
|
56
67
|
test('host standing grant remains armed until explicit revocation', async () => {
|
|
57
68
|
const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-host-standing-'));
|
|
69
|
+
await prepareAuthorityTestTrust(root);
|
|
58
70
|
const project = path.join(root, 'project');
|
|
59
71
|
await mkdir(project);
|
|
60
72
|
const policyPath = path.join(root, 'host.json');
|
|
61
73
|
await writeFile(policyPath, JSON.stringify({ schema:'deadbyte.host-policy.v1', enabled:true,
|
|
62
|
-
arm_file:path.join(root,'host-grant.json'), roots:{ project:{path:project,read:true,write:true,exec:false} },
|
|
74
|
+
arm_file:path.join(root,'runtime','host-grant.json'), roots:{ project:{path:project,read:true,write:true,exec:false} },
|
|
63
75
|
commands:{} }));
|
|
64
76
|
const policy = await loadHostPolicy(policyPath);
|
|
65
77
|
await writeFile(policy.arm_file, JSON.stringify({ schema:'deadbyte.host-grant.v2',
|
|
66
78
|
policy_sha256:policy.policy_sha256, instance_nonce:'c'.repeat(64), granted_at_utc:'2026-09-04T00:00:00Z' }));
|
|
79
|
+
const hostBytes=await readFile(policy.arm_file);
|
|
80
|
+
await createAuthorityEpochStore({runtimeDir:path.dirname(policy.arm_file),policyBytes:await readFile(policy.policy_path)}).append({
|
|
81
|
+
plane:'host',action:'grant',grantBytes:hostBytes,grantInstanceNonce:'c'.repeat(64),updateId:null
|
|
82
|
+
});
|
|
67
83
|
const status = await assertHostArmed(policy, farFuture);
|
|
68
84
|
assert.equal(status.standing, true);
|
|
69
85
|
assert.equal(status.remaining_ms, null);
|