deadbyte-mcp 0.15.48 → 0.15.49
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/MANIFEST.SHA256 +48 -22
- package/PROVENANCE.json +11 -22
- package/README.txt +18 -18
- package/RELEASE.json +368 -378
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +2 -2
- package/bench/r121-epoch-readhead.mjs +54 -0
- package/bench/r124-epoch-predecessor.mjs +53 -0
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/HARNESS2-ADAPTATION-20261020.md +24 -0
- package/docs/R128-RELEASE-CANDIDATE.md +26 -0
- package/package.json +1 -1
- package/scripts/npm-release-r48.mjs +0 -4
- package/scripts/verify-authority-epoch-history.mjs +38 -0
- package/src/activation-continuity-engine-r65.mjs +9 -15
- package/src/agent-eval-r42.mjs +30 -0
- package/src/authority-continuity-r65.mjs +182 -13
- package/src/autonomous-local-supervisor.mjs +77 -47
- package/src/deadbyte-cli.mjs +18 -28
- package/src/remote-live-log.mjs +15 -8
- package/src/remote-log-decode-r60.mjs +65 -0
- package/src/remote-session-guardian.mjs +4 -5
- package/src/version.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +1 -1
- package/test/harness2-eval-context-isolation.test.mjs +90 -0
- package/test/r108-remote-powershell-path.test.mjs +59 -0
- package/test/r110-supervisor-powershell-path.test.mjs +28 -0
- package/test/r111-supervisor-marker-cas.test.mjs +116 -0
- package/test/r112-supervisor-claim-cas.test.mjs +63 -0
- package/test/r113-supervisor-cleanup-terminality.test.mjs +100 -0
- package/test/r114-supervisor-absence-proof.test.mjs +45 -0
- package/test/r115-posix-continuity-entrypoint.test.mjs +17 -0
- package/test/r116-authority-crash-matrix.test.mjs +83 -0
- package/test/r117-concurrent-orphan-recovery.test.mjs +54 -0
- package/test/r118-cross-process-orphan-recovery.test.mjs +99 -0
- package/test/r119-recovery-crash-after-commit.test.mjs +91 -0
- package/test/r120-authority-history-audit.test.mjs +103 -0
- package/test/r121-signed-transition-invariant.test.mjs +132 -0
- package/test/r122-epoch-bounded-read.test.mjs +58 -0
- package/test/r123-recovery-bounded-read.test.mjs +64 -0
- package/test/r124-live-log-integrity.test.mjs +66 -0
- package/test/r124-live-log-tail-boundaries.test.mjs +57 -0
- package/test/r124-signed-predecessor-shape.test.mjs +66 -0
- package/test/r125-restore-binding-types.test.mjs +63 -0
- package/test/r126-restore-policy-envelope.test.mjs +89 -0
- package/test/r127-restore-append-policy-boundary.test.mjs +25 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r65-authority-epoch-store.test.mjs +9 -6
- package/test/r74-prepublish-contract.test.mjs +3 -1
- package/scripts/npm-release-readiness-r108.mjs +0 -134
package/SBOM.cdx.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.6",
|
|
4
|
-
"serialNumber": "urn:cdx:deadbyte-mcp:
|
|
4
|
+
"serialNumber": "urn:cdx:deadbyte-mcp:r128:0.15.49",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
7
|
"component": {
|
|
8
8
|
"type": "application",
|
|
9
9
|
"name": "deadbyte-mcp",
|
|
10
|
-
"version": "0.15.
|
|
10
|
+
"version": "0.15.49"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
"components": [
|
package/TEST-MATRIX.json
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {generateKeyPairSync, randomBytes} from 'node:crypto';
|
|
2
|
+
import {mkdtemp, mkdir, writeFile, rm} from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {pathToFileURL} from 'node:url';
|
|
6
|
+
|
|
7
|
+
const oldSource = process.env.DEADBYTE_R121_BASELINE_EPOCH_MODULE;
|
|
8
|
+
const writerSource = process.env.DEADBYTE_TEST_PROTECTED_EPOCH_MODULE;
|
|
9
|
+
if(!oldSource||!writerSource)throw new Error('R121 benchmark requires exact baseline and protected writer modules');
|
|
10
|
+
const currentSource = new URL('../src/authority-continuity-r65.mjs', import.meta.url).href;
|
|
11
|
+
const [baseline,current,writer] = await Promise.all([
|
|
12
|
+
import(pathToFileURL(oldSource).href), import(currentSource), import(pathToFileURL(writerSource).href)
|
|
13
|
+
]);
|
|
14
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r121-readhead-bench-'));
|
|
15
|
+
const quantile=(values,p)=>{
|
|
16
|
+
const sorted=[...values].sort((a,b)=>a-b);
|
|
17
|
+
return Number(sorted[Math.min(sorted.length-1,Math.floor(p*(sorted.length-1)))].toFixed(4));
|
|
18
|
+
};
|
|
19
|
+
try{
|
|
20
|
+
const runtimeDir=path.join(root,'runtime'),trust=path.join(root,'trust');
|
|
21
|
+
await mkdir(runtimeDir);await mkdir(trust);
|
|
22
|
+
const keys=generateKeyPairSync('ed25519');
|
|
23
|
+
await writeFile(path.join(trust,'ed25519-private.pem'),keys.privateKey.export({type:'pkcs8',format:'pem'}),{flag:'wx'});
|
|
24
|
+
await writeFile(path.join(trust,'ed25519-public.pem'),keys.publicKey.export({type:'spki',format:'pem'}),{flag:'wx'});
|
|
25
|
+
const nonce=randomBytes(32).toString('hex');
|
|
26
|
+
const grant=Buffer.from(JSON.stringify({instance_nonce:nonce,fixture:'R121 benchmark'}));
|
|
27
|
+
await writer.createAuthorityEpochStore({runtimeDir}).append({plane:'process',action:'grant',
|
|
28
|
+
grantBytes:grant,grantInstanceNonce:nonce});
|
|
29
|
+
const stores={baseline:baseline.createAuthorityEpochStore({runtimeDir}),
|
|
30
|
+
candidate:current.createAuthorityEpochStore({runtimeDir})};
|
|
31
|
+
for(let i=0;i<100;i++){
|
|
32
|
+
await stores.baseline.readHead({plane:'process'});
|
|
33
|
+
await stores.candidate.readHead({plane:'process'});
|
|
34
|
+
}
|
|
35
|
+
const durations={baseline:[],candidate:[]};
|
|
36
|
+
const rssBefore=process.memoryUsage().rss;
|
|
37
|
+
for(let i=0;i<600;i++){
|
|
38
|
+
const order=i%2?['candidate','baseline']:['baseline','candidate'];
|
|
39
|
+
for(const name of order){
|
|
40
|
+
const start=process.hrtime.bigint();
|
|
41
|
+
const head=await stores[name].readHead({plane:'process'});
|
|
42
|
+
if(head.action!=='grant')throw new Error('R121 benchmark head changed');
|
|
43
|
+
durations[name].push(Number(process.hrtime.bigint()-start)/1e6);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const result={schema:'deadbyte.r121-epoch-readhead-benchmark.v1',samples_per_variant:600,
|
|
47
|
+
workload:'read-only signed head and predecessor verification, one grant event',
|
|
48
|
+
baseline:{p50_ms:quantile(durations.baseline,.5),p95_ms:quantile(durations.baseline,.95),
|
|
49
|
+
max_ms:quantile(durations.baseline,1)},
|
|
50
|
+
candidate:{p50_ms:quantile(durations.candidate,.5),p95_ms:quantile(durations.candidate,.95),
|
|
51
|
+
max_ms:quantile(durations.candidate,1)},
|
|
52
|
+
rss_delta_bytes:process.memoryUsage().rss-rssBefore};
|
|
53
|
+
process.stdout.write(JSON.stringify(result)+'\n');
|
|
54
|
+
}finally{await rm(root,{recursive:true,force:true,maxRetries:8,retryDelay:100});}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {generateKeyPairSync, randomBytes} from 'node:crypto';
|
|
2
|
+
import {mkdtemp, mkdir, writeFile, rm} from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {pathToFileURL} from 'node:url';
|
|
6
|
+
|
|
7
|
+
const oldSource = process.env.DEADBYTE_R124_BASELINE_EPOCH_MODULE;
|
|
8
|
+
const writerSource = process.env.DEADBYTE_TEST_PROTECTED_EPOCH_MODULE;
|
|
9
|
+
if (!oldSource || !writerSource) throw new Error('R124 benchmark requires exact R123 baseline and protected writer modules');
|
|
10
|
+
const [baseline, current, writer] = await Promise.all([
|
|
11
|
+
import(pathToFileURL(oldSource).href),
|
|
12
|
+
import(new URL('../src/authority-continuity-r65.mjs', import.meta.url).href),
|
|
13
|
+
import(pathToFileURL(writerSource).href),
|
|
14
|
+
]);
|
|
15
|
+
const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r124-bench-'));
|
|
16
|
+
const percentile = (values, p) => {
|
|
17
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
18
|
+
return Number(sorted[Math.min(sorted.length - 1, Math.floor(p * (sorted.length - 1)))].toFixed(4));
|
|
19
|
+
};
|
|
20
|
+
try {
|
|
21
|
+
const runtimeDir = path.join(root, 'runtime');
|
|
22
|
+
const trust = path.join(root, 'trust');
|
|
23
|
+
await mkdir(runtimeDir); await mkdir(trust);
|
|
24
|
+
const keys = generateKeyPairSync('ed25519');
|
|
25
|
+
await writeFile(path.join(trust, 'ed25519-private.pem'), keys.privateKey.export({type:'pkcs8', format:'pem'}), {flag:'wx'});
|
|
26
|
+
await writeFile(path.join(trust, 'ed25519-public.pem'), keys.publicKey.export({type:'spki', format:'pem'}), {flag:'wx'});
|
|
27
|
+
const store = writer.createAuthorityEpochStore({runtimeDir});
|
|
28
|
+
for (let i = 0; i < 2; i++) {
|
|
29
|
+
const nonce = randomBytes(32).toString('hex');
|
|
30
|
+
await store.append({plane:'process', action:'grant', grantBytes:Buffer.from(JSON.stringify({instance_nonce:nonce, fixture:`r124-${i}`})), grantInstanceNonce:nonce});
|
|
31
|
+
}
|
|
32
|
+
const stores = {baseline:baseline.createAuthorityEpochStore({runtimeDir}), candidate:current.createAuthorityEpochStore({runtimeDir})};
|
|
33
|
+
for (let i = 0; i < 100; i++) {
|
|
34
|
+
await stores.baseline.readHead({plane:'process'});
|
|
35
|
+
await stores.candidate.readHead({plane:'process'});
|
|
36
|
+
}
|
|
37
|
+
const samples = {baseline:[], candidate:[]};
|
|
38
|
+
for (let i = 0; i < 600; i++) {
|
|
39
|
+
const order = i % 2 ? ['candidate', 'baseline'] : ['baseline', 'candidate'];
|
|
40
|
+
for (const name of order) {
|
|
41
|
+
const start = process.hrtime.bigint();
|
|
42
|
+
const head = await stores[name].readHead({plane:'process'});
|
|
43
|
+
if (head.seq !== 2) throw new Error('R124 benchmark head changed');
|
|
44
|
+
samples[name].push(Number(process.hrtime.bigint() - start) / 1e6);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
console.log(JSON.stringify({schema:'deadbyte.r124-epoch-predecessor-benchmark.v1', samples_per_variant:600,
|
|
48
|
+
workload:'read-only signed two-event head with predecessor verification',
|
|
49
|
+
baseline:{p50_ms:percentile(samples.baseline,.5), p95_ms:percentile(samples.baseline,.95), max_ms:percentile(samples.baseline,1)},
|
|
50
|
+
candidate:{p50_ms:percentile(samples.candidate,.5), p95_ms:percentile(samples.candidate,.95), max_ms:percentile(samples.candidate,1)}}));
|
|
51
|
+
} finally {
|
|
52
|
+
await rm(root, {recursive:true, force:true, maxRetries:8, retryDelay:100});
|
|
53
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "deadbyte.process-policy.v1",
|
|
3
3
|
"enabled": true,
|
|
4
|
-
"grant_file": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-
|
|
5
|
-
"state_dir": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-
|
|
4
|
+
"grant_file": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-epoch-transition-audit-dev\\controller\\runtime\\process-grant.json",
|
|
5
|
+
"state_dir": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-epoch-transition-audit-dev\\controller\\runtime\\process-state",
|
|
6
6
|
"native_host": {
|
|
7
|
-
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-
|
|
7
|
+
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-epoch-transition-audit-dev\\bin\\deadbyte-process-host.exe",
|
|
8
8
|
"sha256": "daf9cfb371bee88cafbf5597eaa507fec504dbe0b0ddd40d0c3c2e02817f49e4"
|
|
9
9
|
},
|
|
10
10
|
"roots": {
|
|
11
11
|
"core": {
|
|
12
|
-
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-
|
|
12
|
+
"path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-epoch-transition-audit-dev",
|
|
13
13
|
"deny_paths": [
|
|
14
14
|
"node_modules",
|
|
15
15
|
"controller/runtime",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Harness2 mechanism review — isolated development only
|
|
2
|
+
|
|
3
|
+
Source: `D:/Projects/deadbyte-mcp/references/harness2-main` (Apache-2.0). This work uses behavior patterns only; no donor source bytes, Python dependencies, benchmark runner, or third-party assets were copied. Source parent: `D:/Projects/deadbyte-mcp/development/deadbyte-mcp-0.15.48-r108-remote-shell-dev`. The separate, unfinished 0.15.49 release candidate and production remain untouched.
|
|
4
|
+
|
|
5
|
+
| Donor mechanism and source | DEADBYTE comparison | Decision |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| Context tripwires in `harness2/core/context.py` reject answer-key paths and grader verdicts before a model sees them. | `src/agent-eval-r42.mjs` already constructs separate generator/judge inputs, but a nested secret or verdict object in `allowed_context` passed directly to the generator. | ADAPT: reject judge-only secret/token values and known judge-result structures before generator invocation. No public API or authority change. |
|
|
8
|
+
| Completion mark bound to harness fingerprint in `harness2/core/runmark.py`; `tests/test_workflow.py` tests resume invalidation after harness drift. | `src/r67-regression-shards.mjs` and `test/r67-regression-shards.test.mjs` already bind regression evidence to source/test fingerprint; R42 evaluation evidence binds suite and subject manifest hashes. | KEEP-OURS: no second completion-marker format. |
|
|
9
|
+
| Bounded rollout/session accounting and duplicate-label rejection in `harness2/core/ledger.py`. | `src/agent-runtime.mjs` already bounds retries; R67 shard planner/reconciler detects duplicate coverage and nonterminal outcomes. | KEEP-OURS: do not graft recursive rollout budget into runtime. |
|
|
10
|
+
| Anonymized candidate selection and evidence-first comparison in `harness2/core/selection.py`; judge isolation in `harness2/core/judge.py`. | `src/agent-eval-r42.mjs` uses generator/judge separation and advisory judge triage; DEADBYTE's task flow does not require a recursive candidate tournament. | DEFER: evaluate only if a future bounded multi-candidate workflow is approved. |
|
|
11
|
+
|
|
12
|
+
RED: `node --test test/harness2-eval-context-isolation.test.mjs` returned 1 pass, 1 fail. The missing rejection allowed a generator-visible context to carry a judge-only token; the generator ran and evaluation returned normally.
|
|
13
|
+
|
|
14
|
+
GREEN after the first fix: focused R42/eval tests returned 9 pass, 0 fail, 0 skip. A later adversarial test proved a second RED: explicit judge-only secrets shorter than 16 characters still reached the generator (3 pass, 1 fail). The minimum-length exemption was removed; identical focused suite now returns 10 pass, 0 fail, 0 skip. Nested and short secrets, task/acceptance leakage and redacted errors are covered. Ordinary shared acceptance terms remain allowed.
|
|
15
|
+
|
|
16
|
+
Adversarial RED 3: a nested `hidden_oracle`/judge-verdict object in `allowed_context` still reached generator dispatch (4 pass, 1 fail). The context-key tripwire rejects only known judge-only structures, not ordinary `expected`/task text. Identical focused suite is GREEN 11 pass, 0 fail, 0 skip.
|
|
17
|
+
|
|
18
|
+
Full-regression attempt: `npm test` returned exit 1 in the ordinary D: development checkout. The observed failing native authority tests reported `EPOCH_NATIVE_SLOT_UNTRUSTED` / `UNTRUSTED_WRITE_ACE` from `src/privileged-install-trust-r89.mjs`; this checkout lacks the protected Windows installation ACL required by those tests. A UAC-approved protected isolated fixture subsequently verified its 2,342-file manifest and ran 1,627 pass / 0 fail / 48 skip / 1,675 total, TAP SHA-256 `41141fee766c5ae94893c869f5d7aa9767c1984827e13c06da30aae496ca0c0a`. That run predates the short-secret repair and is **not** final-byte full-regression proof. Its verify-only package gate passed (2,343 members, isolated doctor/version; transient tarball SHA-256 `2367c95380793ac48629ecfe8296b3d7436cb8672fa11f7b84c877b384fc8fbd`), also on pre-repair bytes.
|
|
19
|
+
|
|
20
|
+
Changed source SHA-256: `src/agent-eval-r42.mjs` = `4e8e442497a15bce43b7d02ade497403d80b86e307473d26c172a0fba3a6d4ea`.
|
|
21
|
+
New test SHA-256: `test/harness2-eval-context-isolation.test.mjs` = `32806f49cf8988bf0c6ff2059759cc7ed1b299ead68124140a68d9d91e52d3eb`.
|
|
22
|
+
Candidate-only process policy root SHA-256: `ae29ee73d118538659aef60385065786ac238f4548d8aeb3ae13b9558761c51f`.
|
|
23
|
+
|
|
24
|
+
This is not release evidence. The 0.15.49 publish path is paused at the user's request; no npm submission, production activation, production grant change, or sealed-slot edit is part of this adaptation.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# DEADBYTE MCP 0.15.49 / R128 (isolated candidate)
|
|
2
|
+
|
|
3
|
+
Status: **INCOMPLETE / NOT RELEASE READY** until independent protected-native Windows full gate, exact package acceptance, and npm authorization.
|
|
4
|
+
|
|
5
|
+
Source lineage:
|
|
6
|
+
- R125 (protected Windows development checkpoint, 1684 PASS / 0 FAIL / 49 historical SKIP, 54 PASS / 0 FAIL / 2 SKIP focused).
|
|
7
|
+
- R126 RED reproduced for incorrectly bound predecessor/successor policy envelopes.
|
|
8
|
+
- R127: read-path checks signed transaction_restore predecessor and successor envelope SHA-256 against present signed event policy envelopes; append rejects mismatched observed predecessor and successor policy envelopes before committing. Early successor mismatch preflight rejects before native lock or event creation.
|
|
9
|
+
- Live Logs: merge of independently hash-checked R124 live-log implementation; missing audit outcomes do not imply success, stream reset warnings, bounded handle-pinned tail reads, partial UTF-8/UTF-16LE, and corrupted audit JSON rejection.
|
|
10
|
+
- R128: version metadata update only in isolated staging for package 0.15.49. Production active pointer stays v0.15.45-34aa8d1241cfb8bf.
|
|
11
|
+
|
|
12
|
+
Observed tests inherited from development only:
|
|
13
|
+
- Live-log regressions 55 PASS / 0 FAIL / 0 SKIP.
|
|
14
|
+
- R126 signed restore reader 3 PASS / 0 FAIL.
|
|
15
|
+
- R127 wrong successor envelope prelock test PASS.
|
|
16
|
+
- R120/R121/R122/R125/R126 focused subset 12 PASS / 0 FAIL. These are not a complete protected-native Windows suite for exact R128 bytes.
|
|
17
|
+
|
|
18
|
+
Unresolved and blocking:
|
|
19
|
+
- R128 must pass its own full protected-native Windows gate, preferably with hash-pinned installed test fixture and independent read-only review.
|
|
20
|
+
- Historical fixtures without policy envelope SHA fields remain supported; they do not prove strict envelope matching.
|
|
21
|
+
- R127 append predecessor check runs after native lock; no successful exact-R128 protected-native append/restore regression yet.
|
|
22
|
+
- Full log rollover cross-gap detection, Windows directory durability, physical power loss and authority hot path performance acceptance remain open.
|
|
23
|
+
- The npm CLI currently returned E401 Unauthorized from npm whoami; owner authentication is necessary before publishing.
|
|
24
|
+
- No production deploy, activation, grant change, npm publish, or dist-tag mutation has been executed by this candidate setup.
|
|
25
|
+
|
|
26
|
+
The previous protected R125 fixture and R125/R126/R127 parent trees must be kept unchanged. Package --verify-only success alone is not release proof.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deadbyte-mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.49",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Authenticated MCP agentic runtime with signed skills, persistent model backends, identity-bound remote devices, durable job supervision, immutable release slots, and separately revocable machine authority.",
|
|
@@ -95,10 +95,6 @@ async function main() {
|
|
|
95
95
|
if (!isVerifyOnly && version==='0.15.45') assertR71NpmPublishReady(release);
|
|
96
96
|
if (!isVerifyOnly && version==='0.15.46') await assertR72NpmPublishReady(release,{root});
|
|
97
97
|
if (!isVerifyOnly && version==='0.15.47') await assertR74NpmPublishReady(release,{root});
|
|
98
|
-
if (version==='0.15.48') {
|
|
99
|
-
const {assertR108NpmPublishReady} = await import('./npm-release-readiness-r108.mjs');
|
|
100
|
-
await assertR108NpmPublishReady(release,{root,provenance});
|
|
101
|
-
}
|
|
102
98
|
if (release.parent?.release_id !== provenance.parent_release_id ||
|
|
103
99
|
release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
|
|
104
100
|
release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {lstat} from 'node:fs/promises';
|
|
4
|
+
import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
|
|
5
|
+
|
|
6
|
+
const planes = new Set(['process', 'coding', 'autonomous', 'desktop', 'host']);
|
|
7
|
+
const sha256 = /^[0-9a-f]{64}$/;
|
|
8
|
+
|
|
9
|
+
function parse(argv) {
|
|
10
|
+
if(argv.length!==6)throw new Error('expected --runtime-dir, --plane, and --expected-head');
|
|
11
|
+
const args = {};
|
|
12
|
+
for(let i=0;i<argv.length;i+=2){
|
|
13
|
+
const flag=argv[i],value=argv[i+1];
|
|
14
|
+
if(!['--runtime-dir','--plane','--expected-head'].includes(flag)||
|
|
15
|
+
Object.hasOwn(args,flag)||typeof value!=='string'||value.length===0)
|
|
16
|
+
throw new Error('authority history audit arguments invalid');
|
|
17
|
+
args[flag]=value;
|
|
18
|
+
}
|
|
19
|
+
const runtimeDir=args['--runtime-dir'],plane=args['--plane'],expectedHead=args['--expected-head'];
|
|
20
|
+
if(!path.isAbsolute(runtimeDir)||!planes.has(plane)||!sha256.test(expectedHead))
|
|
21
|
+
throw new Error('authority history audit subject invalid');
|
|
22
|
+
return {runtimeDir,plane,expectedHead};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function main() {
|
|
26
|
+
const {runtimeDir,plane,expectedHead}=parse(process.argv.slice(2));
|
|
27
|
+
const stat=await lstat(runtimeDir);
|
|
28
|
+
if(!stat.isDirectory()||stat.isSymbolicLink())throw new Error('authority history audit runtime root invalid');
|
|
29
|
+
const result=await createAuthorityEpochStore({runtimeDir}).auditHistory({plane});
|
|
30
|
+
if(result.status!=='PASS'||result.event_sha256!==expectedHead)
|
|
31
|
+
throw new Error('authority history audit expected head mismatch');
|
|
32
|
+
process.stdout.write(JSON.stringify(result)+'\n');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch(error=>{
|
|
36
|
+
process.stderr.write(`AUTHORITY_HISTORY_AUDIT_FAIL ${String(error?.message??error)}\n`);
|
|
37
|
+
process.exitCode=1;
|
|
38
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {createHash,randomBytes} from 'node:crypto';
|
|
2
|
-
import {open,readFile
|
|
2
|
+
import {open,readFile} from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import {canonicalJson} from './canonical-json.mjs';
|
|
5
5
|
import {decodeUtf8Strict} from './text-policy.mjs';
|
|
@@ -44,20 +44,12 @@ async function writeExclusive(file,bytes){
|
|
|
44
44
|
async function removeIfExact(file,expectedSha256){
|
|
45
45
|
// The Windows native disposition pins a single handle from read/hash through deletion.
|
|
46
46
|
// Never use a pathname removal after confirming only a previous snapshot.
|
|
47
|
-
if(process.platform
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
// Legacy non-Windows behavior is retained for source/test compatibility.
|
|
55
|
-
// It is NOT a cross-platform pinned-deletion security guarantee.
|
|
56
|
-
const current=await readOptional(file);
|
|
57
|
-
if(current===null)return {removed:false,reason:'absent'};
|
|
58
|
-
if(sha(current)!==expectedSha256)return {removed:false,reason:'replacement'};
|
|
59
|
-
await rm(file,{force:true});
|
|
60
|
-
return {removed:true,reason:'matched'};
|
|
47
|
+
if(process.platform!=='win32')throw new Error('authority grant POSIX disposition unsupported');
|
|
48
|
+
const verdict=deletePinnedRemoteMarker(file,expectedSha256);
|
|
49
|
+
if(verdict==='REMOVED')return {removed:true,reason:'matched'};
|
|
50
|
+
if(verdict==='MISSING')return {removed:false,reason:'absent'};
|
|
51
|
+
if(verdict==='CHANGED')return {removed:false,reason:'replacement'};
|
|
52
|
+
throw new Error('authority grant native deletion verdict invalid');
|
|
61
53
|
}
|
|
62
54
|
function validateCapture(capture){
|
|
63
55
|
if(!plain(capture)||typeof capture.update_id!=='string'||!Array.isArray(capture.planes)||!plain(capture.records))throw new Error('authority continuity capture invalid');
|
|
@@ -100,6 +92,8 @@ function classifyConflict(head,record,updateId){
|
|
|
100
92
|
}
|
|
101
93
|
|
|
102
94
|
export function createEpochNativeContinuityEngine({stateRoot,predecessorPolicyPaths,successorPolicyPaths,updateId}={}){
|
|
95
|
+
if(process.platform!=='win32')
|
|
96
|
+
throw new Error('authority continuity POSIX mutation unsupported: native disposition unavailable');
|
|
103
97
|
const state=path.resolve(String(stateRoot??''));
|
|
104
98
|
if(!stateRoot||!plain(predecessorPolicyPaths)||typeof successorPolicyPaths!=='function'||
|
|
105
99
|
typeof updateId!=='string'||!/^[A-Za-z0-9._-]{1,96}$/.test(updateId))
|
package/src/agent-eval-r42.mjs
CHANGED
|
@@ -4,6 +4,11 @@ import { canonicalJson } from './canonical-json.mjs';
|
|
|
4
4
|
const HEX64=/^[0-9a-f]{64}$/;
|
|
5
5
|
const ID=/^[A-Za-z0-9._-]{1,96}$/;
|
|
6
6
|
const SEVERITY=new Set(['info','low','medium','high','critical']);
|
|
7
|
+
const JUDGE_ONLY_KEY=/(?:secret|token|password|answer[_-]?key|ground[_-]?truth)/i;
|
|
8
|
+
const JUDGE_ONLY_CONTEXT_KEYS=new Set([
|
|
9
|
+
'hidden_oracle','judge_result','grader_verdict','deterministic_eval_result',
|
|
10
|
+
'deterministic_eval_summary','judge_scope_and_deterministic_status'
|
|
11
|
+
]);
|
|
7
12
|
const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
|
|
8
13
|
function object(value,label){if(!value||typeof value!=='object'||Array.isArray(value))throw new Error(`${label} invalid`);return value;}
|
|
9
14
|
function keys(value,allowed,label){const extra=Object.keys(value).filter(key=>!allowed.includes(key));if(extra.length)throw new Error(`${label} unknown field '${extra[0]}'`);}
|
|
@@ -11,6 +16,30 @@ function id(value,label){if(typeof value!=='string'||!ID.test(value))throw new E
|
|
|
11
16
|
function text(value,label,max=8192){if(typeof value!=='string'||value.length<1||value.length>max||value.includes('\0'))throw new Error(`${label} invalid`);return value;}
|
|
12
17
|
function textList(value,label,maxItems=32,maxLength=1024){if(!Array.isArray(value)||value.length>maxItems||value.some(item=>typeof item!=='string'||item.length<1||item.length>maxLength))throw new Error(`${label} invalid`);return [...value];}
|
|
13
18
|
|
|
19
|
+
function assertNoJudgeOnlyContextLeak(core){
|
|
20
|
+
const checkKeys=(value,depth=0)=>{
|
|
21
|
+
if(depth>32)throw new Error('eval visible context nesting exceeds safe limit');
|
|
22
|
+
if(Array.isArray(value)){for(const item of value)checkKeys(item,depth+1);return;}
|
|
23
|
+
if(value&&typeof value==='object')for(const [key,item] of Object.entries(value)){
|
|
24
|
+
if(JUDGE_ONLY_CONTEXT_KEYS.has(key.toLowerCase()))throw new Error('judge-only result leaked into generator context');
|
|
25
|
+
checkKeys(item,depth+1);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
checkKeys(core.allowed_context);
|
|
29
|
+
const visible=canonicalJson({task:core.task,allowed_context:core.allowed_context,acceptance:core.acceptance});
|
|
30
|
+
const visit=(value,secretKey=false,depth=0)=>{
|
|
31
|
+
if(depth>32)throw new Error('eval hidden oracle nesting exceeds safe limit');
|
|
32
|
+
if(typeof value==='string'){
|
|
33
|
+
if(secretKey&&value.length>0&&visible.includes(JSON.stringify(value).slice(1,-1)))
|
|
34
|
+
throw new Error('judge-only oracle value leaked into generator context');
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if(Array.isArray(value)){for(const item of value)visit(item,secretKey,depth+1);return;}
|
|
38
|
+
if(value&&typeof value==='object')for(const [key,item] of Object.entries(value))visit(item,secretKey||JUDGE_ONLY_KEY.test(key),depth+1);
|
|
39
|
+
};
|
|
40
|
+
visit(core.hidden_oracle);
|
|
41
|
+
}
|
|
42
|
+
|
|
14
43
|
function normalizeCase(raw){
|
|
15
44
|
const value=object(raw,'agent eval case');keys(value,['schema','case_id','task','allowed_context','hidden_oracle','acceptance'],'agent eval case');
|
|
16
45
|
if(value.schema!=='deadbyte.agent-eval-case.v1')throw new Error('agent eval case schema invalid');
|
|
@@ -18,6 +47,7 @@ function normalizeCase(raw){
|
|
|
18
47
|
allowed_context:structuredClone(object(value.allowed_context,'eval allowed_context')),
|
|
19
48
|
hidden_oracle:structuredClone(object(value.hidden_oracle,'eval hidden_oracle')),
|
|
20
49
|
acceptance:textList(value.acceptance,'eval acceptance')};
|
|
50
|
+
assertNoJudgeOnlyContextLeak(core);
|
|
21
51
|
return Object.freeze({...core,case_sha256:sha(core)});
|
|
22
52
|
}
|
|
23
53
|
|