deadbyte-mcp 0.15.44 → 0.15.45
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 +69 -131
- package/PROVENANCE.json +257 -243
- package/README.txt +18 -18
- package/RELEASE.json +348 -334
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +503 -491
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +1857 -1769
- package/controller/deadbyte-desktop-policy.json +6 -6
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R68-COMPAT-HOST-EXEC-CANDIDATE.md +63 -0
- package/docs/R69-LIVE-OUTCOME-R70-POLICY-TRANSFER.md +136 -0
- package/docs/R70-CODING-DIGEST-SUPERVISOR-CHECKPOINT-20261013.md +42 -0
- package/docs/R70-FINITE-GRANT-OWNER-BOUNDARY-20261013.md +80 -0
- package/docs/R70-OWNER-BOOTSTRAP-CHECKPOINT-20261013.md +60 -0
- package/docs/R70-REFERENCE-MECHANISMS.json +95 -0
- package/docs/R70-TRUST-GUARD-EXPIRY-CHECKPOINT-20261013.md +47 -0
- package/package.json +2 -2
- package/scripts/benchmark-l0-r71.mjs +76 -0
- package/scripts/gate-windows-r71.ps1 +64 -0
- package/scripts/npm-release-r48.mjs +2 -0
- package/scripts/npm-release-readiness-r71.mjs +21 -0
- package/scripts/verify-r70-full-regression.ps1 +72 -0
- package/src/authority-continuity-r65.mjs +28 -8
- package/src/autonomous-mcp-tools.mjs +1 -1
- package/src/autonomous-output-contracts.mjs +4 -1
- package/src/autonomous-policy.mjs +54 -7
- package/src/capability-ledger.mjs +1 -1
- package/src/capability-resolver.mjs +2 -1
- package/src/commander-compat-runtime.mjs +30 -2
- package/src/deadbyte-cli.mjs +8 -6
- package/src/native-diff-v2.mjs +18 -5
- package/src/native-diff.mjs +21 -5
- package/src/r70-owner-approval.mjs +78 -0
- package/src/remote-live-log.mjs +48 -14
- package/src/remote-result-journal.mjs +1 -1
- package/src/runtime-update.mjs +2051 -1891
- package/src/tool-audit.mjs +2 -0
- package/src/version.mjs +1 -1
- package/test/autonomous-local-supervisor.test.mjs +2 -1
- package/test/autonomous-output-contract.test.mjs +17 -1
- package/test/autonomous-supervisor-integration.test.mjs +2 -1
- package/test/capability-resolver.test.mjs +17 -0
- package/test/codex-autonomous-r44.test.mjs +1 -1
- package/test/commander-compat-runtime.test.mjs +42 -0
- package/test/controller-policy-preflight-r59.test.mjs +1 -0
- package/test/native-diff-topology-r36.test.mjs +35 -2
- package/test/native-diff.test.mjs +83 -3
- package/test/r59-tool-surface-compat.test.mjs +9 -5
- package/test/r65-authority-runtime-epoch.test.mjs +9 -1
- package/test/r67-isolated-slot-rollback-restore.test.mjs +2 -1
- package/test/r67-npm-publish-gate.test.mjs +4 -2
- package/test/r67-release-contract.test.mjs +8 -7
- package/test/r69-live-outcome.test.mjs +137 -0
- package/test/r70-autonomous-grant-expiry.test.mjs +89 -0
- package/test/r70-autonomous-policy-bootstrap.test.mjs +166 -0
- package/test/r70-controller-autonomous-root.test.mjs +104 -0
- package/test/r70-controller-grant-subset.test.mjs +28 -0
- package/test/r70-controller-owner-issue-boundary.test.mjs +80 -0
- package/test/r70-controller-policy-snapshot.test.mjs +66 -0
- package/test/r70-owner-approval.test.mjs +67 -0
- package/test/r71-full-verifier-artifact.test.mjs +28 -0
- package/test/r71-isolated-slot-rollback-restore.test.mjs +62 -0
- package/test/r71-native-diff-mcp-wire.test.mjs +75 -0
- package/test/r71-publish-fence.test.mjs +38 -0
- package/test/r71-release-identity.test.mjs +31 -0
- package/test/remote-result-journal.test.mjs +12 -0
- package/test/remote-session-cli.test.mjs +2 -1
- package/test/standing-grants.test.mjs +2 -2
- package/test/tool-audit.test.mjs +14 -0
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-desktop-input-r40.obj +0 -0
- package/bin/deadbyte-desktop-observer-r40.obj +0 -0
- package/bin/deadbyte-desktop-uia-r40.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/bin/deadbyte-native-inspect-r67.obj +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/conpty-input-observer.obj +0 -0
- package/miniconpty.obj +0 -0
- package/proof/CONTAINMENT-BUILD.txt +0 -163
- package/proof/MCP-SMOKE-STATUS.txt +0 -9
- package/proof/NODE-SYNTAX.txt +0 -4
- package/proof/PROOF.txt +0 -6
- package/proof/R34-TASK8-SUPERVISOR-CHECKPOINT.json +0 -29
- package/proof/R34-TASK9-MCP-SURFACE-CHECKPOINT.json +0 -28
- package/proof/SECRET-SCAN.txt +0 -4
- package/proof/SOURCE-GATES.txt +0 -16
- package/proof/STATUS.txt +0 -11
- package/proof/TARGET-V0313-CONTAINMENT-PASS.sha256 +0 -1
- package/proof/TARGET-V0313-CONTAINMENT-PASS.txt +0 -215
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.sha256 +0 -1
- package/proof/TARGET-V040-CONTAINED-IPC-FAIL.txt +0 -299
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.txt +0 -311
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.txt +0 -313
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
- package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.txt +0 -308
- package/proof/TARGET-V044-CONTAINED-PASS.sha256 +0 -1
- package/proof/TARGET-V044-CONTAINED-PASS.txt +0 -432
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.sha256 +0 -1
- package/proof/TARGET-V045-DUAL-OPERATION-PASS.txt +0 -481
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.sha256 +0 -1
- package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.txt +0 -610
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.sha256 +0 -1
- package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.txt +0 -642
- package/proof/TARGET-V050-BATCH-GATE-PASS.sha256 +0 -1
- package/proof/TARGET-V050-BATCH-GATE-PASS.txt +0 -713
- package/proof/TESTS.txt +0 -686
- package/proof/TRUST-EPHEMERAL.txt +0 -4
- package/proof/V03-FREEZE.txt +0 -27
- package/proof/V041-IPC-HOTFIX.txt +0 -16
- package/proof/V042-ENV-HOTFIX.txt +0 -15
- package/proof/V043-DRIVE-CWD-HOTFIX.txt +0 -14
- package/proof/V044-LOCALAPPDATA-HOTFIX.txt +0 -18
- package/proof/V045-OPERATION-REGISTRY.txt +0 -7
- package/proof/V046-WORKER-REGISTRY.txt +0 -12
- package/proof/V047-WORKER-MANIFEST.txt +0 -18
- package/proof/V050-BATCH-TRUST-CLOSURE.txt +0 -21
- package/proof/V060-ACTIVE-NETWORK-AUTHORITY.txt +0 -29
- package/proof/V070-NODE-SYNTAX.txt +0 -36
- package/proof/V070-NODE-TESTS.txt +0 -752
- package/proof/V070-PACK-DRY-RUN.txt +0 -126
- package/proof/V070-SOURCE-GATE.txt +0 -30
- package/proof/V070-STATIC-SCAN.txt +0 -4
- package/proof/V070-WINDOWS-GATE-PENDING.txt +0 -25
- package/proof/V071-NODE-SYNTAX.txt +0 -1
- package/proof/V071-NODE-TESTS.txt +0 -796
- package/proof/V071-PACK-DRY-RUN.json +0 -656
- package/proof/V071-SOURCE-GATE.txt +0 -16
- package/proof/V071-WINDOWS-GATE-PENDING.txt +0 -24
- package/proof/V073-NODE-SYNTAX.txt +0 -4
- package/proof/V073-SOURCE-GATE.txt +0 -21
- package/proof/V073-STATIC-SCAN.txt +0 -10
- package/proof/V073-WINDOWS-GATE-PENDING.txt +0 -5
- package/proof/VERIFY.txt +0 -7
- package/proof/WINDOWS-CONTAINED-STATUS.txt +0 -5
- package/proof/WINDOWS-CONTAINMENT-STATUS.txt +0 -3
- package/proof/commander-closure-20260927/CONTINUATION.json +0 -43
- package/proof/commander-closure-20260927/RESULT.json +0 -30
- package/proof/commander-closure-20260927/SEARCH-CONTINUATION.json +0 -30
- package/proof/commander-closure-20260927/XLS-REFERENCE-PROBE.json +0 -13
- package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +0 -122
- package/proof/r59-full-regression-current.json +0 -13
- package/proof/r59-full-regression-current.stderr.log +0 -0
- package/proof/r59-full-regression-current.stdout.log +0 -1268
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# R70 owner trust guard + expiring grant checkpoint — 2026-10-13
|
|
2
|
+
|
|
3
|
+
## Status (candidate only)
|
|
4
|
+
No deploy, npm publish, change to active release, generation switch, owner key enrollment, policy broadening, or new Coding/Autonomous grant. Mutable Windows candidate root:
|
|
5
|
+
`D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.44-r67`
|
|
6
|
+
|
|
7
|
+
Production known-good `v0.15.44-9f500af433df3e77`. Initial active release manifest SHA-256 `9f500af433df3e7778d4f11acf418526d5889f478114c955c8c72c0077a0636e`; generation manifest `c35f6ccca58083acd53484a983ef401ee18f28b11185cd02c7b1eb3e29028c71`.
|
|
8
|
+
|
|
9
|
+
Existing R70 updater approval verifier is NOT equivalent to independent controller owner approval; real trust-anchor enrollment is absent. Existing Coding grant includes broad `local_c`/`local_d`, Autonomous grant remains scoped only to `core`.
|
|
10
|
+
|
|
11
|
+
## New observed RED->GREEN (verified Windows)
|
|
12
|
+
1. RED: updater accepts project approval while Coding policy `exec:true` remains enabled, permitting OS-level execution without a filesystem sandbox.
|
|
13
|
+
- Fix `src/runtime-update.mjs`: reject any selected Coding root with `exec:true` in `verifyAutonomousOwnerBootstrap`, while retaining rejection of writable owner-key paths.
|
|
14
|
+
- Focused related Windows policy/controller/updater tests: 59 PASS / 0 FAIL / 0 SKIP; exit code 0, stdout SHA-256 `0f859c250fc9bf31aee6edb89b94a3d0abafc28604ac6287e294c2f515eb90ce`.
|
|
15
|
+
2. RED: `Arm-Autonomous` accepts arbitrary new project policy and reaches grant creation without owner approval.
|
|
16
|
+
- Controller candidate `controller/deadbyte-controller.ps1` has R70 fail-closed MIGRATION FENCE: exact known-good legacy policy SHA-256 `6274492644c303b38117541cc22a59e88e6ff5fdef7051a5d57ad336f45765f5` with the single `core` root retains existing explicit manual arm route; all successor policy digests and project root selections fail `R70_OWNER_ENROLLMENT_REQUIRED` before any grant writes.
|
|
17
|
+
- `test/r70-controller-owner-issue-boundary.test.mjs`: RED 1 PASS / 1 FAIL, GREEN 2 PASS / 0 FAIL; fake `Ensure-Directory` prevents real grant I/O in the test.
|
|
18
|
+
- Broader Windows regression with 24 test files `r70-*`, `autonomous-*`, `runtime-self-update.test.mjs`: 174 PASS / 0 FAIL / 1 historical SKIP, exit 0, stdout SHA-256 `d0a27d691c5e2268744dc2c97b242581888edf49b64a8f2bd66645cc6a87c9dc`. **This predates the optional-expiry edit below.**
|
|
19
|
+
|
|
20
|
+
## New expiration RED and unverified candidate edit
|
|
21
|
+
3. `test/r70-autonomous-grant-expiry.test.mjs`: before change, RED 0 PASS / 2 FAIL: a v2 signed grant with expired `expires_at_utc` was still reported ARMED by controller, and `inspectAutonomousStandingWindow` helper did not exist.
|
|
22
|
+
4. Candidate edit made AFTER that RED:
|
|
23
|
+
- `src/autonomous-policy.mjs` adds `inspectAutonomousStandingWindow` with canonical UTC, positive lifetime <=1 hour, not-yet-valid/expired/reject cases and calls it before live v2 standing authority validation; grants without `expires_at_utc` retain legacy behavior.
|
|
24
|
+
- `controller/deadbyte-controller.ps1` checks same optional expiry and lifetime before `Get-AuthorityEpochStatus`; legacy without field remains unchanged.
|
|
25
|
+
- **NOT VERIFIED GREEN**. Direct authorized Windows test execution was blocked by the platform safety layer immediately after the edits. Do NOT route via a different executor, claim PASS, freeze, deploy or publish; check this test only if a future normally authorized test execution succeeds. Signed mutation receipts and file hashes alone DO NOT prove runtime test correctness.
|
|
26
|
+
- This optional field has NOT been issued in a real owner-signed grant. Wall-clock rollback resistance and independent controller owner trust are not solved.
|
|
27
|
+
|
|
28
|
+
## Exact final candidate file hashes (read-only)
|
|
29
|
+
- `src/runtime-update.mjs`: `bcf90f70cfc8316f7d3aac033a772ba8c048061e83e76cacd4a290cc0e307c6c`
|
|
30
|
+
- `src/autonomous-policy.mjs`: `4eb2070a3c25fe5299c42ced065ba652ee0ec95549bb366d46f691e64248f73d`
|
|
31
|
+
- `controller/deadbyte-controller.ps1`: `0f378871888962cc24b0e89873699ecd0de21d0d89fa9147b049765cd21fee1a`
|
|
32
|
+
- `test/r70-autonomous-grant-expiry.test.mjs`: `94a4ca838f4b67a14f1873a5497419e0853306bf60150b5c76024813cc95b85c`
|
|
33
|
+
|
|
34
|
+
## Byte-identical rollback snapshots
|
|
35
|
+
- `proof/R70-TRUST-EXEC-GUARD-UPDATER-PREIMAGE.mjs.txt` SHA-256 `3328bbbc11a7ee09d8bb4bd88d16626f9160b889511014e82ad480b4fb2e6fd0`
|
|
36
|
+
- `proof/R70-CONTROLLER-OWNER-ISSUE-PREIMAGE.ps1.txt` SHA-256 `f034be2ca85e3380491758cef3efef78121139d2488a5b3407167cbe9bf22b5c`
|
|
37
|
+
- `proof/R70-GRANT-EXPIRY-AUTO-PREIMAGE.mjs.txt` SHA-256 `4df3073b9070617a31068ddf7bdab4bb8b6e669aa843f1f2072650f004f9439e`
|
|
38
|
+
- `proof/R70-GRANT-EXPIRY-CONTROLLER-PREIMAGE.ps1.txt` SHA-256 `1c0b1d8814fcb393fc2658f3586b897688c3df399bf033d5e2c281b70f60e9f4`
|
|
39
|
+
- `proof/R70-TRUST-EXEC-GUARD-TEST-PREIMAGE.mjs.txt` SHA-256 `676eb1a34d50bd4f326064c79ce56c3f3ee333e73a4d949e7f30de3f59820bb8`
|
|
40
|
+
|
|
41
|
+
Restore only with current hash preconditions and signed receipts; never overwrite parallel work. No Git repository metadata in candidate folder.
|
|
42
|
+
|
|
43
|
+
## Still blocked
|
|
44
|
+
- Real independently held owner signing key and trusted, non-agent-writable owner key enrollment; the public key under stateRoot/trust does not establish this by itself.
|
|
45
|
+
- Positive scoped owner authorization at controller issuance: current R70 fence DENIES new project grants until trustworthy verifier is integrated.
|
|
46
|
+
- Finite grant issuance and authority epoch expiry/revoke test; optional expiry validator source still unverified.
|
|
47
|
+
- Full candidate manifest freeze, full Windows regression, benchmark, immutable hot-swap crash/reconciliation and ChatGPT/MCP remote client round trip.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deadbyte-mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.45",
|
|
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.",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
|
|
43
43
|
"contained:smoke": "node src/contained-smoke.mjs",
|
|
44
44
|
"mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
|
|
45
|
-
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-
|
|
45
|
+
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r71.ps1",
|
|
46
46
|
"authority:smoke": "node src/authority-smoke.mjs",
|
|
47
47
|
"mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
|
|
48
48
|
"mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {randomBytes,createHash} from 'node:crypto';
|
|
2
|
+
import {mkdir,mkdtemp,readFile,rm,writeFile} from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import {loadCodingPolicy,codingSessionStatus} from '../src/coding-plane.mjs';
|
|
7
|
+
import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
|
|
8
|
+
import {registerAutonomousTools} from '../src/autonomous-mcp-tools.mjs';
|
|
9
|
+
import {classifyRemoteOperation} from '../bridge/src/remote-dispatch-r60.mjs';
|
|
10
|
+
import {prepareAuthorityTestTrust} from '../test/r65-authority-test-trust.mjs';
|
|
11
|
+
|
|
12
|
+
const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
13
|
+
const evidenceDir=path.join(root,'testing','r71-l0-benchmark');
|
|
14
|
+
const samples=100_000;
|
|
15
|
+
const warmup=5_000;
|
|
16
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
17
|
+
const percentile=(sorted,p)=>Number(sorted[Math.min(sorted.length-1,Math.ceil(sorted.length*p)-1)]/1e6).toFixed(6);
|
|
18
|
+
|
|
19
|
+
await mkdir(evidenceDir,{recursive:true});
|
|
20
|
+
const state=await mkdtemp(path.join(evidenceDir,'state-'));
|
|
21
|
+
try{
|
|
22
|
+
const runtime=await prepareAuthorityTestTrust(state);
|
|
23
|
+
const project=path.join(state,'project');
|
|
24
|
+
await mkdir(project);
|
|
25
|
+
const policyPath=path.join(state,'coding-policy.json');
|
|
26
|
+
const grantFile=path.join(runtime,'coding-grant.json');
|
|
27
|
+
await writeFile(policyPath,JSON.stringify({schema:'deadbyte.coding-policy.v1',enabled:true,
|
|
28
|
+
lease_file:grantFile,evidence_dir:path.join(state,'evidence'),
|
|
29
|
+
roots:{project:{path:project,read:true,write:false,exec:false,deny_paths:[]}},commands:{}}));
|
|
30
|
+
const policy=await loadCodingPolicy(policyPath);
|
|
31
|
+
const grant={schema:'deadbyte.coding-grant.v2',policy_sha256:policy.policy_sha256,
|
|
32
|
+
instance_nonce:randomBytes(32).toString('hex'),root_ids:['project'],granted_at_utc:new Date().toISOString()};
|
|
33
|
+
await writeFile(grantFile,JSON.stringify(grant));
|
|
34
|
+
const grantBytes=await readFile(grantFile);
|
|
35
|
+
const store=createAuthorityEpochStore({runtimeDir:runtime,policyBytes:await readFile(policyPath)});
|
|
36
|
+
await store.append({plane:'coding',action:'grant',grantBytes,grantInstanceNonce:grant.instance_nonce,updateId:null});
|
|
37
|
+
const contracts=new Map();
|
|
38
|
+
registerAutonomousTools({registerTool:(name,contract)=>contracts.set(name,contract)},
|
|
39
|
+
{autonomousRuntime:{},nativeDiffRuntime:{}});
|
|
40
|
+
const schema=contracts.get('native_diff_preview')?.inputSchema;
|
|
41
|
+
if(!schema)throw new Error('native_diff_preview schema unavailable');
|
|
42
|
+
const request={root_id:'project',title:'L0 read-only probe',operations:[{kind:'write',path:'scratch.txt',
|
|
43
|
+
content:'x',encoding:'utf8',expected_sha256:'absent'}]};
|
|
44
|
+
const observed=new Float64Array(samples);
|
|
45
|
+
const execute=async()=>{
|
|
46
|
+
const parsed=schema.parse(request);
|
|
47
|
+
if(classifyRemoteOperation({name:'native_diff_preview'},parsed)!=='read_only')throw new Error('dispatch classification drift');
|
|
48
|
+
const authority=await codingSessionStatus(policy);
|
|
49
|
+
if(authority.armed!==true||authority.authority_epoch?.trusted!==true||
|
|
50
|
+
!authority.root_ids.includes(parsed.root_id)||policy.roots[parsed.root_id]?.read!==true)
|
|
51
|
+
throw new Error('signed Coding authority decision failed');
|
|
52
|
+
};
|
|
53
|
+
for(let i=0;i<warmup;i++)await execute();
|
|
54
|
+
const started=process.hrtime.bigint();
|
|
55
|
+
for(let i=0;i<samples;i++){
|
|
56
|
+
const tick=process.hrtime.bigint();
|
|
57
|
+
await execute();
|
|
58
|
+
observed[i]=Number(process.hrtime.bigint()-tick);
|
|
59
|
+
}
|
|
60
|
+
const elapsedMs=Number(process.hrtime.bigint()-started)/1e6;
|
|
61
|
+
observed.sort();
|
|
62
|
+
const result={schema:'deadbyte.r71-l0-benchmark.v1',created_at_utc:new Date().toISOString(),
|
|
63
|
+
scope:'native_diff_preview input validation + remote dispatch classification + real isolated signed Coding grant/epoch decision; excludes IPC, filesystem operation, native execution and ChatGPT',
|
|
64
|
+
clock:'process.hrtime.bigint',warmup,samples,elapsed_ms:elapsedMs,
|
|
65
|
+
p50_ms:Number(percentile(observed,0.50)),p95_ms:Number(percentile(observed,0.95)),
|
|
66
|
+
p99_ms:Number(percentile(observed,0.99)),max_ms:Number((observed.at(-1)/1e6).toFixed(6)),
|
|
67
|
+
threshold_p95_ms:1,pass:observed[Math.ceil(samples*0.95)-1]<1e6,
|
|
68
|
+
coding_policy_sha256:policy.policy_sha256,source_manifest_sha256:sha(await readFile(path.join(root,'MANIFEST.SHA256')))};
|
|
69
|
+
const bytes=Buffer.from(JSON.stringify(result)+'\n');
|
|
70
|
+
const output=path.join(evidenceDir,`result-${Date.now()}-${randomBytes(4).toString('hex')}.json`);
|
|
71
|
+
await writeFile(output,bytes,{flag:'wx'});
|
|
72
|
+
process.stdout.write(JSON.stringify({...result,evidence_path:output,evidence_sha256:sha(bytes)})+'\n');
|
|
73
|
+
if(!result.pass)process.exitCode=1;
|
|
74
|
+
}finally{
|
|
75
|
+
await rm(state,{recursive:true,force:true});
|
|
76
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[ValidateSet('preflight','focused','full','manifest','doctor','all')]
|
|
3
|
+
[string]$Stage='preflight'
|
|
4
|
+
)
|
|
5
|
+
$ErrorActionPreference='Stop'
|
|
6
|
+
Set-StrictMode -Version Latest
|
|
7
|
+
$root=Split-Path -Parent $PSScriptRoot
|
|
8
|
+
$state=Join-Path $env:USERPROFILE '.deadbyte-mcp'
|
|
9
|
+
$parent=Join-Path $state 'releases\v0.15.44-9f500af433df3e77'
|
|
10
|
+
$expected='9f500af433df3e7778d4f11acf418526d5889f478114c955c8c72c0077a0636e'
|
|
11
|
+
$generation='c35f6ccca58083acd53484a983ef401ee18f28b11185cd02c7b1eb3e29028c71'
|
|
12
|
+
$releaseId='v0.15.44-9f500af433df3e77'
|
|
13
|
+
function Sha256-File([string]$File){
|
|
14
|
+
$algorithm=[System.Security.Cryptography.SHA256]::Create()
|
|
15
|
+
try{
|
|
16
|
+
$stream=[System.IO.File]::OpenRead($File)
|
|
17
|
+
try{return ([BitConverter]::ToString($algorithm.ComputeHash($stream))).Replace('-','').ToLowerInvariant()}
|
|
18
|
+
finally{$stream.Dispose()}
|
|
19
|
+
}finally{$algorithm.Dispose()}
|
|
20
|
+
}
|
|
21
|
+
if(!(Test-Path -LiteralPath $parent -PathType Container)){throw 'R71 sealed predecessor slot missing'}
|
|
22
|
+
if((Sha256-File (Join-Path $parent 'MANIFEST.SHA256')) -ne $expected){throw 'R71 predecessor manifest mismatch'}
|
|
23
|
+
$pointer=Get-Content -LiteralPath (Join-Path $state 'active-release.json') -Raw | ConvertFrom-Json
|
|
24
|
+
if($pointer.release_id -ne $releaseId -or $pointer.manifest_sha256 -ne $expected -or
|
|
25
|
+
$pointer.generation_manifest_sha256 -ne $generation){throw 'R71 active predecessor pointer mismatch'}
|
|
26
|
+
$pkg=Get-Content -LiteralPath (Join-Path $root 'package.json') -Raw | ConvertFrom-Json
|
|
27
|
+
if($pkg.version -ne '0.15.45'){throw 'R71 package version mismatch'}
|
|
28
|
+
Write-Output 'R71_PREDECESSOR_PREFLIGHT=PASS'
|
|
29
|
+
if($Stage -eq 'preflight'){return}
|
|
30
|
+
function Invoke-Node([string]$Label,[string[]]$Arguments){
|
|
31
|
+
Write-Output "R71_STAGE_START=$Label"
|
|
32
|
+
& node @Arguments
|
|
33
|
+
if($LASTEXITCODE -ne 0){throw "R71 stage $Label exit=$LASTEXITCODE"}
|
|
34
|
+
Write-Output "R71_STAGE_PASS=$Label"
|
|
35
|
+
}
|
|
36
|
+
if($Stage -eq 'focused' -or $Stage -eq 'all'){
|
|
37
|
+
Invoke-Node 'focused' @('--test','test/native-diff.test.mjs','test/native-diff-topology-r36.test.mjs',
|
|
38
|
+
'test/capability-resolver.test.mjs','test/capability-ledger-r36.test.mjs',
|
|
39
|
+
'test/r70-owner-approval.test.mjs','test/r70-autonomous-policy-bootstrap.test.mjs',
|
|
40
|
+
'test/r71-publish-fence.test.mjs','test/r71-release-identity.test.mjs',
|
|
41
|
+
'test/r71-full-verifier-artifact.test.mjs','test/r71-native-diff-mcp-wire.test.mjs')
|
|
42
|
+
if($Stage -eq 'focused'){return}
|
|
43
|
+
}
|
|
44
|
+
if($Stage -eq 'full' -or $Stage -eq 'all'){
|
|
45
|
+
Write-Output 'R71_STAGE_START=full'
|
|
46
|
+
& powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $root 'scripts\verify-r70-full-regression.ps1')
|
|
47
|
+
if($LASTEXITCODE -ne 0){throw "R71 full regression exit=$LASTEXITCODE"}
|
|
48
|
+
Write-Output 'R71_STAGE_PASS=full'
|
|
49
|
+
if($Stage -eq 'full'){return}
|
|
50
|
+
}
|
|
51
|
+
if($Stage -eq 'manifest' -or $Stage -eq 'all'){
|
|
52
|
+
Invoke-Node 'manifest' @('scripts/release-manifest.mjs','verify')
|
|
53
|
+
if($Stage -eq 'manifest'){return}
|
|
54
|
+
}
|
|
55
|
+
if($Stage -eq 'doctor' -or $Stage -eq 'all'){
|
|
56
|
+
$previous=$env:DEADBYTE_STATE_ROOT
|
|
57
|
+
$isolated='D:\Projects\deadbyte-mcp\testing\0.15.45-r71\doctor-isolated-empty'
|
|
58
|
+
if(Test-Path -LiteralPath (Join-Path $isolated 'active-release.json')){throw 'R71 isolated doctor state has an unexpected pointer'}
|
|
59
|
+
try{
|
|
60
|
+
$env:DEADBYTE_STATE_ROOT=$isolated
|
|
61
|
+
Invoke-Node 'isolated-doctor' @('src/deadbyte-cli.mjs','doctor')
|
|
62
|
+
}finally{$env:DEADBYTE_STATE_ROOT=$previous}
|
|
63
|
+
}
|
|
64
|
+
Write-Output 'R71_WINDOWS_GATE=PASS_PREDEPLOY_CANDIDATE'
|
|
@@ -4,6 +4,7 @@ import { reconcileNpmPublication } from './npm-publication-r65.mjs';
|
|
|
4
4
|
import { mkdtemp, readFile, rm, unlink, mkdir } from 'node:fs/promises';
|
|
5
5
|
import {preserveNpmTarball,assertVacantPackDestination} from './npm-preserve-artifact-r67.mjs';
|
|
6
6
|
import {assertR67NpmPublishReady} from './npm-release-readiness-r67.mjs';
|
|
7
|
+
import {assertR71NpmPublishReady} from './npm-release-readiness-r71.mjs';
|
|
7
8
|
import { existsSync } from 'node:fs';
|
|
8
9
|
import { resolveStateRoot } from '../src/state-root.mjs';
|
|
9
10
|
import path from 'node:path';
|
|
@@ -89,6 +90,7 @@ async function main() {
|
|
|
89
90
|
throw new Error(`PROVENANCE.json version mismatch: package=${version} provenance=${provenance.version}`);
|
|
90
91
|
}
|
|
91
92
|
if (!isVerifyOnly && version==='0.15.44') assertR67NpmPublishReady(release);
|
|
93
|
+
if (!isVerifyOnly && version==='0.15.45') assertR71NpmPublishReady(release);
|
|
92
94
|
if (release.parent?.release_id !== provenance.parent_release_id ||
|
|
93
95
|
release.parent?.manifest_sha256 !== provenance.parent_manifest_sha256 ||
|
|
94
96
|
release.parent?.generation_manifest_sha256 !== provenance.parent_generation_manifest_sha256) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Publication fence for the exact R71 successor, not an execution receipt. */
|
|
2
|
+
export function assertR71NpmPublishReady(release){
|
|
3
|
+
if(release?.version!=='0.15.45'||release?.train!=='R71'||
|
|
4
|
+
release?.parent?.release_id!=='v0.15.44-9f500af433df3e77'||
|
|
5
|
+
release?.parent?.manifest_sha256!=='9f500af433df3e7778d4f11acf418526d5889f478114c955c8c72c0077a0636e'||
|
|
6
|
+
release?.parent?.generation_manifest_sha256!=='c35f6ccca58083acd53484a983ef401ee18f28b11185cd02c7b1eb3e29028c71'){
|
|
7
|
+
throw new Error('PUBLISH_BLOCKED R71 release or sealed predecessor identity mismatch');
|
|
8
|
+
}
|
|
9
|
+
const state=release.r71_candidate;
|
|
10
|
+
const required={status:'CANDIDATE_SEALED',full_regression:'PASS',manifest:'PASS',
|
|
11
|
+
windows_gate:'PASS',hot_swap:'PASS',package_acceptance:'PASS',
|
|
12
|
+
local_coding_preview:'PASS_CODING_READ_ONLY_NO_AUTONOMOUS_APPLY',
|
|
13
|
+
public_catalog:'PASS_43_TOOLS',signed_public_mcp:'PASS',performance_l0:'PASS'};
|
|
14
|
+
for(const [field,expected] of Object.entries(required)){
|
|
15
|
+
if(state?.[field]!==expected) throw new Error(`PUBLISH_BLOCKED R71 ${field}=${String(state?.[field]??'MISSING')}; require ${expected}`);
|
|
16
|
+
}
|
|
17
|
+
if(!['PASS_OWNER_ENROLLED','DISABLED_FAIL_CLOSED_NO_OWNER_ENROLLMENT'].includes(state?.owner_independent_project_grant)){
|
|
18
|
+
throw new Error('PUBLISH_BLOCKED R71 owner project grant must be proven or explicitly fail-closed disabled');
|
|
19
|
+
}
|
|
20
|
+
return {status:'R71_METADATA_GATES_MATCH',policy:'PUBLISH_REQUIRES_INDEPENDENT_RELEASE_EVIDENCE'};
|
|
21
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#requires -Version 5.1
|
|
2
|
+
# R70 verifier artifact: runs the candidate test suite without altering release manifests.
|
|
3
|
+
param([switch]$SelfTest)
|
|
4
|
+
Set-StrictMode -Version Latest
|
|
5
|
+
$ErrorActionPreference = 'Continue'
|
|
6
|
+
Set-Location -LiteralPath (Split-Path -Parent $PSScriptRoot)
|
|
7
|
+
$timer = [System.Diagnostics.Stopwatch]::StartNew()
|
|
8
|
+
if ($SelfTest) {
|
|
9
|
+
$lines = @('tests 1', 'pass 0', 'fail 1', 'skipped 0', 'hash mismatch: SYNTHETIC_TEST')
|
|
10
|
+
$exitCode = 1
|
|
11
|
+
} else {
|
|
12
|
+
$lines = @(& npm.cmd test 2>&1 | ForEach-Object { [string]$_ })
|
|
13
|
+
$exitCode = [int]$LASTEXITCODE
|
|
14
|
+
}
|
|
15
|
+
$timer.Stop()
|
|
16
|
+
$utf8 = New-Object System.Text.UTF8Encoding($false)
|
|
17
|
+
$stdoutBytes = $utf8.GetBytes(($lines -join "`n"))
|
|
18
|
+
$sha = [System.Security.Cryptography.SHA256]::Create()
|
|
19
|
+
try {
|
|
20
|
+
$hash = ([BitConverter]::ToString($sha.ComputeHash($stdoutBytes))).Replace('-', '').ToLowerInvariant()
|
|
21
|
+
} finally {
|
|
22
|
+
$sha.Dispose()
|
|
23
|
+
}
|
|
24
|
+
Write-Output 'R70_FULL_TEST_SCHEMA=deadbyte.verifier-output.r70.v1'
|
|
25
|
+
Write-Output ('R70_FULL_TEST_EXIT_CODE=' + $exitCode)
|
|
26
|
+
Write-Output ('R70_FULL_TEST_ELAPSED_MS=' + [math]::Round($timer.Elapsed.TotalMilliseconds))
|
|
27
|
+
Write-Output ('R70_FULL_TEST_STDOUT_SHA256=' + $hash)
|
|
28
|
+
Write-Output ('R70_FULL_TEST_LINE_COUNT=' + $lines.Count)
|
|
29
|
+
$selected = @($lines | Where-Object {
|
|
30
|
+
$_ -match '(?i)(?:^|\s)(?:tests|pass|fail|skipped|cancelled|duration_ms)\s+[0-9.]+' -or
|
|
31
|
+
$_ -match '^✖' -or
|
|
32
|
+
$_ -match '^ (Error|AssertionError|SyntaxError):' -or
|
|
33
|
+
$_ -match 'hash mismatch:' -or
|
|
34
|
+
$_ -match '^# (tests|pass|fail|skipped) '
|
|
35
|
+
})
|
|
36
|
+
$summary = @($selected | Select-Object -Last 140 | ForEach-Object {
|
|
37
|
+
if ($_.Length -gt 512) { $_.Substring(0, 512) } else { $_ }
|
|
38
|
+
})
|
|
39
|
+
$artifactDir = Join-Path (Get-Location).Path 'testing\r70-verifier'
|
|
40
|
+
if (-not (Test-Path -LiteralPath $artifactDir -PathType Container)) {
|
|
41
|
+
New-Item -ItemType Directory -Path $artifactDir -Force | Out-Null
|
|
42
|
+
}
|
|
43
|
+
$artifact = Join-Path $artifactDir ('result-{0}-{1}.json' -f (Get-Date -Format 'yyyyMMdd-HHmmss'), [Guid]::NewGuid().ToString('N'))
|
|
44
|
+
$stdoutPath = [System.IO.Path]::ChangeExtension($artifact, '.stdout.txt')
|
|
45
|
+
$stdoutStream = New-Object System.IO.FileStream($stdoutPath, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
|
|
46
|
+
try { $stdoutStream.Write($stdoutBytes, 0, $stdoutBytes.Length); $stdoutStream.Flush($true) } finally { $stdoutStream.Dispose() }
|
|
47
|
+
$record = [ordered]@{
|
|
48
|
+
schema = 'deadbyte.r70-full-regression-result.v1'
|
|
49
|
+
mode = if ($SelfTest) { 'synthetic-selftest' } else { 'candidate-full-regression' }
|
|
50
|
+
created_at_utc = [DateTime]::UtcNow.ToString('o')
|
|
51
|
+
exit_code = $exitCode
|
|
52
|
+
elapsed_ms = [math]::Round($timer.Elapsed.TotalMilliseconds)
|
|
53
|
+
stdout_sha256 = $hash
|
|
54
|
+
stdout_path = $stdoutPath
|
|
55
|
+
total_line_count = $lines.Count
|
|
56
|
+
summary = $summary
|
|
57
|
+
}
|
|
58
|
+
$json = ($record | ConvertTo-Json -Depth 5 -Compress) + "`n"
|
|
59
|
+
$bytes = $utf8.GetBytes($json)
|
|
60
|
+
$stream = New-Object System.IO.FileStream($artifact, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)
|
|
61
|
+
try { $stream.Write($bytes, 0, $bytes.Length); $stream.Flush($true) } finally { $stream.Dispose() }
|
|
62
|
+
$artifactHashAlgorithm = [System.Security.Cryptography.SHA256]::Create()
|
|
63
|
+
try {
|
|
64
|
+
$artifactStream = [System.IO.File]::OpenRead($artifact)
|
|
65
|
+
try { $artifactSha = ([BitConverter]::ToString($artifactHashAlgorithm.ComputeHash($artifactStream))).Replace('-', '').ToLowerInvariant() }
|
|
66
|
+
finally { $artifactStream.Dispose() }
|
|
67
|
+
} finally { $artifactHashAlgorithm.Dispose() }
|
|
68
|
+
Write-Output ('R70_FULL_TEST_ARTIFACT=' + $artifact)
|
|
69
|
+
Write-Output ('R70_FULL_TEST_ARTIFACT_SHA256=' + $artifactSha)
|
|
70
|
+
foreach ($line in $summary) { Write-Output $line }
|
|
71
|
+
if ($SelfTest) { exit 0 }
|
|
72
|
+
exit $exitCode
|
|
@@ -207,6 +207,10 @@ const DURABLE_EPOCH_ACTIONS=new Set(['grant','transaction_revoke','user_revoke',
|
|
|
207
207
|
const DURABLE_EPOCH_SCHEMA='deadbyte.authority-epoch-event.r65.v1';
|
|
208
208
|
const DURABLE_HEAD_SCHEMA='deadbyte.authority-epoch-head.r65.v1';
|
|
209
209
|
const DURABLE_EPOCH_DOMAIN=Buffer.from('DEADBYTE-AUTHORITY-DURABLE-EPOCH-R65-V1\0','utf8');
|
|
210
|
+
// Cache parsed public keys by the exact bytes read from disk, never by path.
|
|
211
|
+
// A changed trust file is re-read and yields a different entry immediately.
|
|
212
|
+
const DURABLE_PUBLIC_KEY_CACHE_LIMIT=8;
|
|
213
|
+
const durablePublicKeys=new Map();
|
|
210
214
|
const RESTORE_BINDING_FIELDS=Object.freeze(['prior_grant_sha256','prior_grant_instance_nonce','predecessor_policy_envelope_sha256','successor_policy_envelope_sha256','candidate_manifest_sha256','continuity_subject_sha256']);
|
|
211
215
|
function normalizeRestoreBinding(value,{required=false}={}){
|
|
212
216
|
if(value===undefined||value===null){if(required)throw new Error('authority epoch transaction restore binding required');return null;}
|
|
@@ -218,9 +222,19 @@ function normalizeRestoreBinding(value,{required=false}={}){
|
|
|
218
222
|
|
|
219
223
|
async function durableEpochKeys(runtimeDir,{privateRequired=false}={}){
|
|
220
224
|
const trust=path.join(path.dirname(path.resolve(runtimeDir)),'trust');
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
225
|
+
const publicBytes=await readFile(path.join(trust,'ed25519-public.pem'));
|
|
226
|
+
const publicSha=hashBytes(publicBytes);
|
|
227
|
+
let cached=durablePublicKeys.get(publicSha);
|
|
228
|
+
if(!cached){
|
|
229
|
+
const publicKey=createPublicKey(publicBytes);
|
|
230
|
+
if(publicKey.asymmetricKeyType!=='ed25519')throw new Error('authority epoch trust public key invalid');
|
|
231
|
+
const keyId=hashBytes(Buffer.from(publicKey.export({format:'der',type:'spki'})));
|
|
232
|
+
cached={publicKey,keyId};
|
|
233
|
+
if(durablePublicKeys.size>=DURABLE_PUBLIC_KEY_CACHE_LIMIT)
|
|
234
|
+
durablePublicKeys.delete(durablePublicKeys.keys().next().value);
|
|
235
|
+
durablePublicKeys.set(publicSha,cached);
|
|
236
|
+
}
|
|
237
|
+
const {publicKey,keyId}=cached;
|
|
224
238
|
if(!privateRequired)return {publicKey,keyId};
|
|
225
239
|
const privateKey=createPrivateKey(await readFile(path.join(trust,'ed25519-private.pem')));
|
|
226
240
|
if(privateKey.asymmetricKeyType!=='ed25519'||
|
|
@@ -315,7 +329,14 @@ async function readDurableHead(runtimeDir,plane){
|
|
|
315
329
|
if(head.action!=='transaction_restore'&&headRestoreBinding!==null)throw new Error('authority epoch unexpected restore binding');
|
|
316
330
|
const expectedName=durableEventName(head.seq,head.event_sha256);
|
|
317
331
|
if(head.event_file!==expectedName)throw new Error('authority epoch head event name mismatch');
|
|
318
|
-
|
|
332
|
+
// These are independent observations of one immutable event identity.
|
|
333
|
+
// Read them concurrently, then validate the complete set before trusting
|
|
334
|
+
// the head. The head remains freshly read on every authority decision.
|
|
335
|
+
const [eventNames,eventRead,keys]=await Promise.all([
|
|
336
|
+
readdir(path.join(dir,'events')),
|
|
337
|
+
readFile(path.join(dir,'events',head.event_file)).then(bytes=>({bytes}),()=>({bytes:null})),
|
|
338
|
+
durableEpochKeys(runtimeDir)
|
|
339
|
+
]);
|
|
319
340
|
if(eventNames.length>10000)throw new Error('authority epoch event budget exceeded');
|
|
320
341
|
for(const name of eventNames){
|
|
321
342
|
const match=/^(\d{16})-([0-9a-f]{64})\.json$/.exec(name);
|
|
@@ -324,13 +345,12 @@ async function readDurableHead(runtimeDir,plane){
|
|
|
324
345
|
if(!Number.isSafeInteger(seq)||seq>head.seq||(seq===head.seq&&name!==head.event_file))
|
|
325
346
|
throw new Error('authority epoch head replay or incomplete write');
|
|
326
347
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
catch{throw new Error('authority epoch event missing');}
|
|
348
|
+
const eventBytes=eventRead.bytes;
|
|
349
|
+
if(!eventBytes)throw new Error('authority epoch event missing');
|
|
330
350
|
if(hashBytes(eventBytes)!==head.event_sha256)throw new Error('authority epoch event hash mismatch');
|
|
331
351
|
let event;
|
|
332
352
|
try{event=JSON.parse(decodeUtf8Strict(eventBytes));}catch{throw new Error('authority epoch event invalid');}
|
|
333
|
-
const {publicKey,keyId}=
|
|
353
|
+
const {publicKey,keyId}=keys;
|
|
334
354
|
if(!verifyDurableEvent(event,publicKey,keyId))throw new Error('authority epoch event signature invalid');
|
|
335
355
|
for(const key of ['schema','plane','seq','action','update_id','grant_sha256','grant_instance_nonce','previous_event_sha256']){
|
|
336
356
|
const expected=key==='schema'?DURABLE_EPOCH_SCHEMA:head[key];
|
|
@@ -48,7 +48,7 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
|
|
|
48
48
|
catch(error){ return fail(autonomousSessionStatusOutputSchema,error); } });
|
|
49
49
|
|
|
50
50
|
server.registerTool('native_diff_preview',{
|
|
51
|
-
description:'
|
|
51
|
+
description:'Validate exact file SHA-256 preconditions. With Coding read authority alone, return a read-only preview_only result that cannot be applied; a signed applicable diff additionally requires Autonomous authority. No Git metadata is used.',
|
|
52
52
|
inputSchema:z.strictObject({ root_id:id, title:z.string().max(160).default(''), operations:z.array(nativeOperation).min(1).max(32) }),
|
|
53
53
|
outputSchema:nativeDiffPreviewOutputSchema
|
|
54
54
|
},async({root_id,title,operations})=>{ try { return result(nativeDiffPreviewOutputSchema,
|
|
@@ -83,10 +83,13 @@ export const autonomousSessionStatusOutputSchema = statusContract({
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
export const nativeDiffPreviewOutputSchema = statusContract({
|
|
86
|
-
statuses:['ready','failed'], success:['ready'], required:['
|
|
86
|
+
statuses:['ready','preview_only','failed'], success:['ready','preview_only'], required:['root_id','operation_count','payload_bytes','paths','operations'],
|
|
87
87
|
shape:{ schema:z.enum(['deadbyte.native-diff.v1','deadbyte.native-diff.v2']).optional(), diff_id:hex64.optional(), root_id:z.string().min(1).max(64).optional(), operation_count:z.number().int().min(1).max(32).optional(),
|
|
88
88
|
payload_bytes:z.number().int().min(0).optional(), paths:z.array(z.string()).max(64).optional(),
|
|
89
89
|
operations:z.array(jsonObject).max(32).optional() }
|
|
90
|
+
}).superRefine((value,ctx)=>{
|
|
91
|
+
if(value.status==='ready'&&value.diff_id===undefined) ctx.addIssue({code:'custom',path:['diff_id'],message:'signed ready diff requires diff_id'});
|
|
92
|
+
if(value.status==='preview_only'&&value.diff_id!==undefined) ctx.addIssue({code:'custom',path:['diff_id'],message:'coding-only preview must not have an applicable diff_id'});
|
|
90
93
|
});
|
|
91
94
|
export const nativeDiffApplyOutputSchema = statusContract({
|
|
92
95
|
statuses:['committed','existing','failed'], success:['committed','existing'],
|
|
@@ -80,11 +80,11 @@ function normalizePlanner(raw,codingPolicy,rootIds) {
|
|
|
80
80
|
}
|
|
81
81
|
return provider;
|
|
82
82
|
}
|
|
83
|
-
function normalizeProfile(id, raw, codingPolicy) {
|
|
83
|
+
function normalizeProfile(id, raw, codingPolicy, rootIds) {
|
|
84
84
|
if (!ID_RE.test(id)) throw new Error(`invalid autonomous profile '${id}'`);
|
|
85
85
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error(`autonomous profile '${id}' malformed`);
|
|
86
86
|
if (!['command','benchmark'].includes(raw.kind)) throw new Error(`autonomous profile '${id}' kind invalid`);
|
|
87
|
-
if (!ID_RE.test(raw.root_id ?? '') || !codingPolicy.roots[raw.root_id]) throw new Error(`autonomous profile '${id}' root invalid`);
|
|
87
|
+
if (!ID_RE.test(raw.root_id ?? '') || !codingPolicy.roots[raw.root_id] || !rootIds.includes(raw.root_id)) throw new Error(`autonomous profile '${id}' root invalid`);
|
|
88
88
|
if (!ID_RE.test(raw.command_id ?? '') || !codingPolicy.commands[raw.command_id]) throw new Error(`autonomous profile '${id}' command invalid`);
|
|
89
89
|
validatePortableRelativePath(raw.script_path);
|
|
90
90
|
if (!SHA256_RE.test(raw.script_sha256 ?? '')) throw new Error(`autonomous profile '${id}' script hash invalid`);
|
|
@@ -130,7 +130,7 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
|
|
|
130
130
|
const rootIds = Array.isArray(raw.root_ids) ? [...new Set(raw.root_ids)] : [];
|
|
131
131
|
if (rootIds.length < 1 || rootIds.some(id => !ID_RE.test(id) || !codingPolicy.roots[id])) throw new Error('autonomous root_ids invalid');
|
|
132
132
|
const profiles = {};
|
|
133
|
-
for (const [id, value] of Object.entries(raw.profiles ?? {})) profiles[id] = normalizeProfile(id, value, codingPolicy);
|
|
133
|
+
for (const [id, value] of Object.entries(raw.profiles ?? {})) profiles[id] = normalizeProfile(id, value, codingPolicy, rootIds);
|
|
134
134
|
const limits = raw.limits ?? {};
|
|
135
135
|
const policy = {
|
|
136
136
|
schema: AUTONOMOUS_POLICY_SCHEMA, enabled: true, policy_path: absolute,
|
|
@@ -154,6 +154,43 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
|
|
|
154
154
|
return Object.freeze(policy);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
export function inspectAutonomousStandingWindow(lease,now=new Date()){
|
|
158
|
+
// v2 legacy standing grants have no expiry. New bounded grants must be
|
|
159
|
+
// checked on every authority observation, including after a runtime restart.
|
|
160
|
+
if(!lease||typeof lease!=='object'||Array.isArray(lease)){
|
|
161
|
+
return {ok:false,reason:'expiry-invalid',expires_at_utc:null,remaining_ms:null};
|
|
162
|
+
}
|
|
163
|
+
if(!Object.hasOwn(lease,'expires_at_utc')){
|
|
164
|
+
return {ok:true,reason:null,expires_at_utc:null,remaining_ms:null};
|
|
165
|
+
}
|
|
166
|
+
const canonical=value=>typeof value==='string'&&
|
|
167
|
+
/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3,7}Z$/.test(value);
|
|
168
|
+
const expiry=lease.expires_at_utc;
|
|
169
|
+
const issued=lease.granted_at_utc;
|
|
170
|
+
if(!canonical(expiry)||!canonical(issued)){
|
|
171
|
+
return {ok:false,reason:'expiry-invalid',expires_at_utc:null,remaining_ms:null};
|
|
172
|
+
}
|
|
173
|
+
const end=Date.parse(expiry),start=Date.parse(issued);
|
|
174
|
+
if(!Number.isFinite(end)||!Number.isFinite(start)){
|
|
175
|
+
return {ok:false,reason:'expiry-invalid',expires_at_utc:null,remaining_ms:null};
|
|
176
|
+
}
|
|
177
|
+
const duration=end-start;
|
|
178
|
+
if(duration<=0||duration>3_600_000){
|
|
179
|
+
return {ok:false,reason:'expiry-window-invalid',expires_at_utc:expiry,remaining_ms:null};
|
|
180
|
+
}
|
|
181
|
+
const observed=now instanceof Date?now.getTime():NaN;
|
|
182
|
+
if(!Number.isFinite(observed)){
|
|
183
|
+
return {ok:false,reason:'clock-invalid',expires_at_utc:expiry,remaining_ms:null};
|
|
184
|
+
}
|
|
185
|
+
if(observed<start){
|
|
186
|
+
return {ok:false,reason:'not-yet-valid',expires_at_utc:expiry,remaining_ms:null};
|
|
187
|
+
}
|
|
188
|
+
if(observed>=end){
|
|
189
|
+
return {ok:false,reason:'expired',expires_at_utc:expiry,remaining_ms:0};
|
|
190
|
+
}
|
|
191
|
+
return {ok:true,reason:null,expires_at_utc:expiry,remaining_ms:end-observed};
|
|
192
|
+
}
|
|
193
|
+
|
|
157
194
|
export async function autonomousSessionStatus(policy, now = new Date()) {
|
|
158
195
|
let lease,leaseBytes;
|
|
159
196
|
try { leaseBytes=await readFile(policy.lease_file); lease = JSON.parse(decodeUtf8Strict(leaseBytes)); }
|
|
@@ -164,15 +201,25 @@ export async function autonomousSessionStatus(policy, now = new Date()) {
|
|
|
164
201
|
return { configured:true, armed:false, reason:'lease-schema', expires_at_utc:null };
|
|
165
202
|
}
|
|
166
203
|
if (lease.policy_sha256 !== policy.policy_sha256) return { configured:true, armed:false, reason:'policy-digest', expires_at_utc:null };
|
|
204
|
+
// Controller and runtime must agree on the exact Coding authority policy
|
|
205
|
+
// for every signed v2 Autonomous grant, including after generation changes.
|
|
206
|
+
if (lease.schema === AUTONOMOUS_GRANT_SCHEMA &&
|
|
207
|
+
lease.coding_policy_sha256 !== policy.coding_policy_sha256) {
|
|
208
|
+
return { configured:true, armed:false, reason:'coding-policy-digest', expires_at_utc:null };
|
|
209
|
+
}
|
|
167
210
|
if (typeof lease.instance_nonce !== 'string' || !SHA256_RE.test(lease.instance_nonce)) return { configured:true, armed:false, reason:'nonce-invalid', expires_at_utc:null };
|
|
168
211
|
const roots = Array.isArray(lease.root_ids) ? [...new Set(lease.root_ids)] : [];
|
|
169
212
|
if (roots.length < 1 || roots.some(id => !policy.root_ids.includes(id))) return { configured:true, armed:false, reason:'roots-invalid', expires_at_utc:null };
|
|
170
213
|
if (lease.schema === AUTONOMOUS_GRANT_SCHEMA) {
|
|
214
|
+
const window=inspectAutonomousStandingWindow(lease,now);
|
|
215
|
+
if(!window.ok) return {configured:true,armed:false,reason:window.reason,
|
|
216
|
+
expires_at_utc:window.expires_at_utc,remaining_ms:window.remaining_ms,
|
|
217
|
+
standing:false,instance_nonce:lease.instance_nonce,root_ids:roots};
|
|
171
218
|
const epoch=await verifyStandingGrantEpoch({plane:'autonomous',grantFile:policy.lease_file,grantBytes:leaseBytes,grantInstanceNonce:lease.instance_nonce,policyPath:policy.policy_path});
|
|
172
|
-
if(!epoch.trusted)return { configured:true,armed:false,reason:epoch.reason,expires_at_utc:
|
|
173
|
-
remaining_ms:
|
|
174
|
-
return { configured:true, armed:true, reason:'standing-grant', expires_at_utc:
|
|
175
|
-
remaining_ms:
|
|
219
|
+
if(!epoch.trusted)return { configured:true,armed:false,reason:epoch.reason,expires_at_utc:window.expires_at_utc,
|
|
220
|
+
remaining_ms:window.remaining_ms,standing:false,instance_nonce:lease.instance_nonce,root_ids:roots };
|
|
221
|
+
return { configured:true, armed:true, reason:'standing-grant', expires_at_utc:window.expires_at_utc,
|
|
222
|
+
remaining_ms:window.remaining_ms, standing:true, instance_nonce:lease.instance_nonce, root_ids:roots, authority_epoch:epoch };
|
|
176
223
|
}
|
|
177
224
|
const expires = Date.parse(lease.expires_at_utc);
|
|
178
225
|
if (!Number.isFinite(expires)) return { configured:true, armed:false, reason:'expiry-invalid', expires_at_utc:null };
|
|
@@ -152,7 +152,7 @@ export const R36_CAPABILITY_ENTRIES=Object.freeze([
|
|
|
152
152
|
gateway('desktop.action','desktop_action','desktop_control','action','DEADBYTE_DESKTOP_RUNTIME','desktop',{mutating:true,receipt_class:'desktop'}),
|
|
153
153
|
|
|
154
154
|
direct('autonomous.session_status','autonomous_session_status','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{receipt_class:'autonomous'}),
|
|
155
|
-
direct('native_diff.preview','native_diff_preview','DEADBYTE_AUTONOMOUS_RUNTIME','
|
|
155
|
+
direct('native_diff.preview','native_diff_preview','DEADBYTE_AUTONOMOUS_RUNTIME','coding',{receipt_class:'native_diff'}),
|
|
156
156
|
direct('native_diff.apply','native_diff_apply','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{mutating:true,receipt_class:'native_diff'}),
|
|
157
157
|
direct('native_diff.verify','native_diff_verify','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{receipt_class:'verification'}),
|
|
158
158
|
direct('autonomous.goal_submit','autonomous_goal_submit','DEADBYTE_AUTONOMOUS_RUNTIME','autonomous',{mutating:true,receipt_class:'autonomous'}),
|
|
@@ -3,7 +3,8 @@ import { assertHostArmed } from './host-plane.mjs';
|
|
|
3
3
|
|
|
4
4
|
const CODING_ARMED_READ_CAPABILITIES = new Set([
|
|
5
5
|
'coding.tree','coding.stat','coding.search','coding.files_read','coding.file_read',
|
|
6
|
-
'semantic.outline','semantic.definition','semantic.references','semantic.diagnostics','semantic.implementations','semantic.rename_preview'
|
|
6
|
+
'semantic.outline','semantic.definition','semantic.references','semantic.diagnostics','semantic.implementations','semantic.rename_preview',
|
|
7
|
+
'native_diff.preview'
|
|
7
8
|
]);
|
|
8
9
|
|
|
9
10
|
export const CAPABILITY_STATES = Object.freeze({
|
|
@@ -20,7 +20,7 @@ const CONTRACTS = Object.freeze({
|
|
|
20
20
|
get_recent_tool_calls:{native:'operation_history.recent',required:[],mutation:false},
|
|
21
21
|
get_usage_stats:{native:'operation_history.stats',required:[],mutation:false},
|
|
22
22
|
give_feedback_to_desktop_commander:{native:'commander.feedback',required:['message'],mutation:true},
|
|
23
|
-
host_exec:{native:'host.exec',required:['
|
|
23
|
+
host_exec:{native:'host.exec',required:['root_id'],mutation:true},
|
|
24
24
|
host_file_read:{native:'host.file_read',required:['path'],mutation:false},
|
|
25
25
|
host_file_write:{native:'host.file_write',required:['path','content','expected_sha256'],mutation:true},
|
|
26
26
|
interact_with_process:{native:'process.input',required:['session_id','input'],mutation:true},
|
|
@@ -53,13 +53,41 @@ export function commanderCompatibilityContract(name) {
|
|
|
53
53
|
return CONTRACTS[name] ?? {native:DEADBYTE_NATIVE_TOOLS[name] ?? null,required:[],mutation:false};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function validateHostExecRequest(args) {
|
|
57
|
+
const mode=args.mode??'script';
|
|
58
|
+
const common=['mode','root_id','cwd','timeout_ms'];
|
|
59
|
+
let required, allowed;
|
|
60
|
+
if(mode==='script'){
|
|
61
|
+
required=['root_id','command_id','script_path','script_sha256'];
|
|
62
|
+
allowed=[...common,'command_id','script_path','script_sha256','args'];
|
|
63
|
+
}else if(mode==='inline'){
|
|
64
|
+
required=['root_id','command_id','command'];
|
|
65
|
+
allowed=[...common,'command_id','command'];
|
|
66
|
+
}else if(mode==='native'){
|
|
67
|
+
required=['root_id','executable','executable_sha256'];
|
|
68
|
+
allowed=[...common,'executable','executable_sha256','args'];
|
|
69
|
+
}else{
|
|
70
|
+
throw new Error('host_exec mode must be script, inline, or native');
|
|
71
|
+
}
|
|
72
|
+
const missing=required.filter(k=>!own(args,k)||args[k]===undefined||args[k]===null||args[k]==='');
|
|
73
|
+
if(missing.length) throw new Error(`missing required fields: ${missing.join(', ')}`);
|
|
74
|
+
const unknown=Object.keys(args).filter(k=>!allowed.includes(k));
|
|
75
|
+
if(unknown.length) throw new Error(`host_exec ${mode} unexpected fields: ${unknown.join(', ')}`);
|
|
76
|
+
const id=/^[A-Za-z0-9._-]{1,64}$/;
|
|
77
|
+
if(typeof args.root_id!=='string'||!id.test(args.root_id)) throw new Error('host_exec root_id invalid');
|
|
78
|
+
if(mode!=='native'&&(typeof args.command_id!=='string'||!id.test(args.command_id))) throw new Error('host_exec command_id invalid');
|
|
79
|
+
if(mode==='inline'&&(typeof args.command!=='string'||args.command.length>262144||args.command.includes(String.fromCharCode(0)))) throw new Error('host_exec inline command invalid');
|
|
80
|
+
if(mode==='script'&&!/^[0-9a-f]{64}$/.test(args.script_sha256)) throw new Error('host_exec script_sha256 invalid');
|
|
81
|
+
if(mode==='native'&&!/^[0-9a-f]{64}$/.test(args.executable_sha256)) throw new Error('host_exec executable_sha256 invalid');
|
|
82
|
+
}
|
|
83
|
+
|
|
56
84
|
export function validateCommanderRequest(name,args={}) {
|
|
57
85
|
const c=commanderCompatibilityContract(name);
|
|
58
86
|
if (!args || typeof args!=='object' || Array.isArray(args)) throw new Error('request arguments must be an object');
|
|
59
87
|
const missing=c.required.filter(k=>!own(args,k)||args[k]===undefined||args[k]===null||args[k]==='');
|
|
60
88
|
if(missing.length) throw new Error(`missing required fields: ${missing.join(', ')}`);
|
|
61
89
|
if(c.mutation && !['create_directory','start_process','force_terminate','kill_process','interact_with_process','host_exec'].includes(name) && !('expected_sha256' in args) && !('expected_source_identity' in args)) throw new Error('mutation requires an explicit precondition');
|
|
62
|
-
if(
|
|
90
|
+
if(name==='host_exec') validateHostExecRequest(args);
|
|
63
91
|
return Object.freeze({commander_tool:name,native_tool:c.native,mutation:c.mutation,args});
|
|
64
92
|
}
|
|
65
93
|
|