deadbyte-mcp 0.15.0 → 0.15.1
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 +76 -41
- package/PROVENANCE.json +10 -0
- package/R45-PARENT.json +18 -0
- package/README.txt +14 -14
- package/RELEASE.json +37 -0
- package/SBOM.cdx.json +46 -0
- package/TEST-MATRIX.json +31 -0
- package/bin/deadbyte-hardware-observer-r45.exe +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/controller/README.TXT +2 -2
- package/controller/deadbyte-controller.ps1 +2 -2
- package/docs/ARCHITECTURE.md +1 -1
- package/native/deadbyte-hardware-observer.cpp +308 -0
- package/package.json +12 -7
- package/scripts/autonomous-tests.ps1 +2 -2
- package/scripts/build-hardware-r45.ps1 +71 -0
- package/scripts/deferred-slot-operation-r45.mjs +126 -0
- package/scripts/derive-r45-parent.mjs +24 -0
- package/scripts/derive-r45-release.mjs +72 -0
- package/scripts/derive-r45-tests.mjs +20 -0
- package/scripts/final-closure-r45.mjs +121 -0
- package/scripts/final-closure-verify-r45.mjs +220 -0
- package/scripts/finalize-r45.mjs +219 -0
- package/scripts/full-regression-r45.mjs +20 -0
- package/scripts/full-regression-summary-r45.mjs +14 -0
- package/scripts/gate-windows-r45.ps1 +44 -0
- package/scripts/init-host-policy.ps1 +39 -1
- package/scripts/inspect-active-release-r45.mjs +20 -0
- package/scripts/release-manifest.mjs +3 -1
- package/scripts/release-parity-r45.mjs +253 -0
- package/scripts/release-parity-tests-r45.ps1 +8 -0
- package/scripts/verify-r45-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r45.mjs +60 -0
- package/src/autonomous-runtime.mjs +12 -7
- package/src/capability-ledger.mjs +1 -0
- package/src/compact-gateway-mcp-tools.mjs +4 -2
- package/src/deadbyte-cli.mjs +17 -9
- package/src/doctor-r45.mjs +65 -0
- package/src/host-plane.mjs +133 -85
- package/src/mcp-server.mjs +64 -23
- package/src/native-diff-v2.mjs +9 -4
- package/src/native-diff.mjs +29 -7
- package/src/observation-mcp-tools.mjs +5 -1
- package/src/observation-output-contracts.mjs +8 -0
- package/src/observation-runtime.mjs +33 -2
- package/src/observation-smoke-client.mjs +6 -2
- package/src/output-contracts.mjs +27 -11
- package/src/r45-compact-disarmed-probe.mjs +74 -0
- package/src/r45-full-surface-probe.mjs +34 -0
- package/src/release-generation.mjs +1 -0
- package/src/remote-mcp-r45-parity-client.mjs +206 -0
- package/src/runtime-update.mjs +36 -8
- package/src/version.mjs +1 -1
- package/test/agent-runtime.test.mjs +1 -0
- package/test/autonomous-loop.test.mjs +24 -0
- package/test/autonomous-runtime.test.mjs +1 -0
- package/test/cli-entrypoint.test.mjs +4 -4
- package/test/coding-plane.test.mjs +1 -0
- package/test/compact-max-catalog-r45.test.mjs +99 -0
- package/test/contained.test.mjs +23 -11
- package/test/controller.test.mjs +5 -1
- package/test/core.test.mjs +1 -1
- package/test/full-max-catalog-r45.test.mjs +91 -0
- package/test/hardware-observation-r45.test.mjs +44 -0
- package/test/host-inline-r45.test.mjs +67 -0
- package/test/machine-mcp-integration.test.mjs +1 -0
- package/test/observation-mcp-tools.test.mjs +4 -3
- package/test/output-schema.test.mjs +1 -0
- package/test/package-boundary.test.mjs +1 -1
- package/test/production-docs.test.mjs +3 -3
- package/test/r33-closeout-regression.test.mjs +20 -19
- package/test/r33-finalization.test.mjs +3 -3
- package/test/r45-autonomous-quick-test.test.mjs +10 -0
- package/test/r45-finalization.test.mjs +84 -0
- package/test/release-generation.test.mjs +1 -0
- package/test/release-version.test.mjs +52 -41
- package/test/runtime-host-bootstrap-r45.test.mjs +46 -0
package/src/version.mjs
CHANGED
|
@@ -147,6 +147,30 @@ test('R24 autonomous goal diagnoses a failing test, replans with native diff, be
|
|
|
147
147
|
}
|
|
148
148
|
});
|
|
149
149
|
|
|
150
|
+
test('historical autonomous release verification survives source drift and disarmed mutation authority', async () => {
|
|
151
|
+
const f = await fixture();
|
|
152
|
+
try {
|
|
153
|
+
const submitted = await f.runtime.submit({ submissionId:'historical-release-verify', rootId:'project',
|
|
154
|
+
title:'repair program', goal:'make exported value equal fixed', acceptance:'release evidence must remain verifiable',
|
|
155
|
+
maxIterations:10 });
|
|
156
|
+
const result = await f.runtime.run({ goalId:submitted.goal_id, maxCycles:16 });
|
|
157
|
+
assert.equal(result.status,'completed');
|
|
158
|
+
assert.equal((await f.runtime.verify({ goalId:submitted.goal_id })).ok,true);
|
|
159
|
+
|
|
160
|
+
await writeFile(f.program,"export const value = 'rolled-back';\n");
|
|
161
|
+
await rm(f.codingRuntime.policy.lease_file);
|
|
162
|
+
await rm(f.policy.lease_file);
|
|
163
|
+
|
|
164
|
+
const verified = await f.runtime.verify({ goalId:submitted.goal_id });
|
|
165
|
+
assert.equal(verified.ok,true);
|
|
166
|
+
assert.equal(verified.native_diffs_verified,2);
|
|
167
|
+
assert.equal(verified.required_profiles_verified,3);
|
|
168
|
+
} finally {
|
|
169
|
+
await new Promise(resolve => f.planner.server.close(resolve));
|
|
170
|
+
await rm(f.root,{recursive:true,force:true});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
150
174
|
test('autonomous profile execution is capped by the absolute autonomous lease without changing coding request identity', async () => {
|
|
151
175
|
const calls=[];
|
|
152
176
|
const f=await fixture([],{
|
|
@@ -68,6 +68,7 @@ async function fixture() {
|
|
|
68
68
|
command:process.execPath, args:[serverPath], cwd:repoRoot,
|
|
69
69
|
env:{ ...getDefaultEnvironment(), DEADBYTE_WORKSPACE_ROOT:workspaceRoot,
|
|
70
70
|
DEADBYTE_SIGNING_KEY:keys.privateKeyPath, DEADBYTE_VERIFY_KEY:keys.publicKeyPath,
|
|
71
|
+
DEADBYTE_PRIVILEGED_POLICY:'',
|
|
71
72
|
DEADBYTE_AGENT_RUNTIME:'1', DEADBYTE_CODING_RUNTIME:'1',
|
|
72
73
|
DEADBYTE_CODING_POLICY:codingPolicyPath, DEADBYTE_AUTONOMOUS_RUNTIME:'1',
|
|
73
74
|
DEADBYTE_AUTONOMOUS_POLICY:autonomousPolicyPath }, stderr:'pipe'
|
|
@@ -21,7 +21,7 @@ test('npx CLI reports the canonical package version through --version, -v and ve
|
|
|
21
21
|
for(const arg of ['--version','-v','version']){
|
|
22
22
|
const result=spawnSync(process.execPath,[cliPath,arg],{cwd:root,encoding:'utf8',windowsHide:true});
|
|
23
23
|
assert.equal(result.status,0,result.stderr);
|
|
24
|
-
assert.equal(result.stdout.trim(),'0.15.
|
|
24
|
+
assert.equal(result.stdout.trim(),'0.15.1');
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -45,11 +45,11 @@ test('npx CLI exposes local supervisor lifecycle without any supervisor arm comm
|
|
|
45
45
|
assert.match(source,/supervisorrecover/);
|
|
46
46
|
const mapping=source.match(/const SUPERVISOR_COMMANDS=.*?;\n/s)?.[0]??'';
|
|
47
47
|
assert.doesNotMatch(mapping,/arm(?:coding|autonomous|process|host)/i);
|
|
48
|
-
assert.match(source,/npx
|
|
48
|
+
assert.match(source,/npx -y \$\{exact\} supervisor status/);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
test('README makes npx the primary operator UX',async()=>{
|
|
52
52
|
const readme=await readFile(path.join(root,'README.txt'),'utf8');
|
|
53
|
-
assert.match(readme,/npx deadbyte-mcp@
|
|
54
|
-
assert.match(readme,/npx deadbyte-mcp@
|
|
53
|
+
assert.match(readme,/npx -y deadbyte-mcp@0\.15\.1 remote/);
|
|
54
|
+
assert.match(readme,/npx -y deadbyte-mcp@0\.15\.1 audit verify/);
|
|
55
55
|
});
|
|
@@ -60,6 +60,7 @@ async function fixture() {
|
|
|
60
60
|
DEADBYTE_WORKSPACE_ROOT: workspaceRoot,
|
|
61
61
|
DEADBYTE_SIGNING_KEY: keys.privateKeyPath,
|
|
62
62
|
DEADBYTE_VERIFY_KEY: keys.publicKeyPath,
|
|
63
|
+
DEADBYTE_PRIVILEGED_POLICY: '',
|
|
63
64
|
DEADBYTE_AGENT_RUNTIME: '1',
|
|
64
65
|
DEADBYTE_CODING_RUNTIME: '1',
|
|
65
66
|
DEADBYTE_CODING_POLICY: policyPath
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
8
|
+
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
|
|
9
|
+
import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
|
|
10
|
+
|
|
11
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const repoRoot=path.resolve(here,'..');
|
|
13
|
+
const serverPath=path.join(repoRoot,'src','mcp-server.mjs');
|
|
14
|
+
const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy.json');
|
|
15
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
16
|
+
const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
|
|
17
|
+
|
|
18
|
+
test('R45 real max-runtime compact stdio catalog is exactly 43 with verified skill_catalog while all authority remains disarmed',async()=>{
|
|
19
|
+
const f=await createR34Fixture({authority:'disarmed'});
|
|
20
|
+
const processPolicyPath=path.join(f.root,'process-policy.json');
|
|
21
|
+
const processGrant=path.join(f.root,'process-grant.json');
|
|
22
|
+
const processState=path.join(f.root,'process-state');
|
|
23
|
+
const hostPolicyPath=path.join(f.root,'host-policy.json');
|
|
24
|
+
const hostArm=path.join(f.root,'host-arm.json');
|
|
25
|
+
const nodeSha=sha(await readFile(process.execPath));
|
|
26
|
+
await mkdir(processState,{recursive:true});
|
|
27
|
+
await writeFile(processPolicyPath,JSON.stringify({
|
|
28
|
+
schema:'deadbyte.process-policy.v1',enabled:true,grant_file:processGrant,state_dir:processState,
|
|
29
|
+
native_host:{path:process.execPath,sha256:nodeSha},
|
|
30
|
+
roots:{core:{path:f.project,deny_paths:[]}},
|
|
31
|
+
profiles:{node:{executable:process.execPath,executable_sha256:nodeSha,root_ids:['core'],
|
|
32
|
+
prefix_args:[],transport:'pipe',max_args:8,max_arg_bytes:1024,max_sessions:2,
|
|
33
|
+
max_input_bytes:65536,max_retained_output_bytes:262144,env_allow:['PATH','TEMP','TMP'],
|
|
34
|
+
input_actions:{ping:'PING\r\n'}}}
|
|
35
|
+
},null,2));
|
|
36
|
+
await writeFile(hostPolicyPath,JSON.stringify({
|
|
37
|
+
schema:'deadbyte.host-policy.v1',enabled:true,arm_file:hostArm,max_read_bytes:262144,max_write_bytes:1048576,
|
|
38
|
+
roots:{core:{path:f.project,read:true,write:true,exec:true}},
|
|
39
|
+
commands:{node_script:{kind:'script',executable:process.execPath,executable_sha256:nodeSha,
|
|
40
|
+
root_ids:['core'],prefix_args:[],extensions:['.mjs'],timeout_ms:5000,max_output_bytes:65536}}
|
|
41
|
+
},null,2));
|
|
42
|
+
|
|
43
|
+
const desktopRaw=JSON.parse(await readFile(desktopPolicyPath,'utf8'));
|
|
44
|
+
const desktopGrant=desktopRaw.grant_file;
|
|
45
|
+
const codingLease=f.codingPolicy.lease_file;
|
|
46
|
+
const autonomousLease=f.policy.lease_file;
|
|
47
|
+
for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority unexpectedly armed before start: '+q);
|
|
48
|
+
|
|
49
|
+
const client=new Client({name:'deadbyte-r40-max-catalog',version:'0.12.0'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
|
|
50
|
+
const env={
|
|
51
|
+
...getDefaultEnvironment(),
|
|
52
|
+
DEADBYTE_CAPABILITY_PROFILE:'compact',
|
|
53
|
+
DEADBYTE_AUDIT_RUNTIME:'0',
|
|
54
|
+
DEADBYTE_STATE_ROOT:path.join(f.root,'state'),
|
|
55
|
+
DEADBYTE_WORKSPACE_ROOT:f.root,
|
|
56
|
+
DEADBYTE_SIGNING_KEY:f.keys.privateKeyPath,
|
|
57
|
+
DEADBYTE_VERIFY_KEY:f.keys.publicKeyPath,
|
|
58
|
+
DEADBYTE_PRIVILEGED_POLICY:hostPolicyPath,
|
|
59
|
+
DEADBYTE_MACHINE_RUNTIME:'1',
|
|
60
|
+
DEADBYTE_AGENT_RUNTIME:'0',
|
|
61
|
+
DEADBYTE_PROCESS_RUNTIME:'1',
|
|
62
|
+
DEADBYTE_PROCESS_POLICY:processPolicyPath,
|
|
63
|
+
DEADBYTE_CODING_RUNTIME:'1',
|
|
64
|
+
DEADBYTE_CODING_POLICY:path.join(f.root,'coding-policy.json'),
|
|
65
|
+
DEADBYTE_MACHINE_FS_RUNTIME:'1',
|
|
66
|
+
DEADBYTE_OBSERVATION_RUNTIME:'1',
|
|
67
|
+
DEADBYTE_DESKTOP_RUNTIME:'1',
|
|
68
|
+
DEADBYTE_DESKTOP_POLICY:desktopPolicyPath,
|
|
69
|
+
DEADBYTE_AUTONOMOUS_RUNTIME:'1',
|
|
70
|
+
DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
|
|
71
|
+
DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
|
|
72
|
+
};
|
|
73
|
+
const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
|
|
74
|
+
try{
|
|
75
|
+
await client.connect(transport);
|
|
76
|
+
const listed=await client.listTools();
|
|
77
|
+
const names=listed.tools.map(t=>t.name).sort();
|
|
78
|
+
assert.equal(names.length,43,'expected exact compact max catalog 43, got '+names.length+': '+names.join(','));
|
|
79
|
+
for(const name of ['capability_manifest','desktop_control','coding_inspect','machine_fs','machine_observe','process_session',
|
|
80
|
+
'host_file_read','host_file_write','host_exec','skill_catalog']) assert.ok(names.includes(name),'missing '+name);
|
|
81
|
+
const manifest=await client.callTool({name:'capability_manifest',arguments:{}});
|
|
82
|
+
assert.equal(manifest.isError,false);
|
|
83
|
+
const m=manifest.structuredContent.result;
|
|
84
|
+
assert.equal(m.schema,'deadbyte.capability-manifest.v2');
|
|
85
|
+
assert.equal(m.profile,'compact');
|
|
86
|
+
assert.equal(m.tool_count,43);
|
|
87
|
+
assert.deepEqual(m.tool_catalog,names);
|
|
88
|
+
assert.match(m.catalog_sha256,/^[0-9a-f]{64}$/);
|
|
89
|
+
const hardware=m.capabilities.find(item=>item.id==='observation.hardware_query');
|
|
90
|
+
assert.ok(hardware);assert.equal(hardware.authority,'none');assert.equal(hardware.compact_tool,'machine_observe');assert.equal(hardware.compact_op,'hardware_query');
|
|
91
|
+
const skill=m.capabilities.find(item=>item.id==='skill.catalog');
|
|
92
|
+
assert.ok(skill);assert.equal(skill.authority,'none');assert.equal(skill.mutating,false);
|
|
93
|
+
console.log(JSON.stringify({tool_count:m.tool_count,catalog_sha256:m.catalog_sha256,ledger_sha256:m.ledger_sha256,desktop:true,hardware_query:true,skill:true,authority:'DISARMED'}));
|
|
94
|
+
} finally {
|
|
95
|
+
await client.close().catch(()=>{});
|
|
96
|
+
for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority file appeared during catalog probe: '+q);
|
|
97
|
+
await f.cleanup();
|
|
98
|
+
}
|
|
99
|
+
});
|
package/test/contained.test.mjs
CHANGED
|
@@ -352,6 +352,10 @@ test('contained execution source has a compile-time worker registry and no user
|
|
|
352
352
|
const executor = await readFile(fileURLToPath(new URL('../src/contained-executor.mjs', import.meta.url)), 'utf8');
|
|
353
353
|
const registry = await readFile(fileURLToPath(new URL('../src/worker-registry.mjs', import.meta.url)), 'utf8');
|
|
354
354
|
const server = await readFile(fileURLToPath(new URL('../src/mcp-server.mjs', import.meta.url)), 'utf8');
|
|
355
|
+
const containedStart = server.indexOf("toolServer.registerTool(\n 'contained_transform'");
|
|
356
|
+
const containedEnd = server.indexOf('toolServer.registerTool(', containedStart + 1);
|
|
357
|
+
const contained = server.slice(containedStart, containedEnd);
|
|
358
|
+
assert.ok(containedStart >= 0 && containedEnd > containedStart);
|
|
355
359
|
assert.match(registry, /contained-transform-worker\.exe/);
|
|
356
360
|
assert.match(registry, /contained-reverse-worker\.exe/);
|
|
357
361
|
assert.match(registry, /CONTAINED_EXECUTION_REGISTRY/);
|
|
@@ -360,9 +364,9 @@ test('contained execution source has a compile-time worker registry and no user
|
|
|
360
364
|
assert.match(registry, /lowercase_ascii/);
|
|
361
365
|
assert.match(registry, /reverse_bytes/);
|
|
362
366
|
assert.match(executor, /loadVerifiedWorkerRegistry/);
|
|
363
|
-
assert.match(
|
|
364
|
-
assert.match(
|
|
365
|
-
assert.doesNotMatch(
|
|
367
|
+
assert.match(contained, /'contained_transform'/);
|
|
368
|
+
assert.match(contained, /z\.enum\(CONTAINED_TRANSFORM_OPERATIONS\)/);
|
|
369
|
+
assert.doesNotMatch(contained, /executable:\s*z\./);
|
|
366
370
|
assert.doesNotMatch(executor, /--worker/);
|
|
367
371
|
assert.doesNotMatch(server, /registerTool\(\s*['"](?:command_run|shell_execute|powershell_run)['"]/);
|
|
368
372
|
});
|
|
@@ -706,12 +710,16 @@ test('contained execution validator rejects missing or altered worker manifest e
|
|
|
706
710
|
|
|
707
711
|
test('MCP contained_transform schema is a compile-time operation enum with no executable or invocation-control surface', async () => {
|
|
708
712
|
const server = await readFile(fileURLToPath(new URL('../src/mcp-server.mjs', import.meta.url)), 'utf8');
|
|
709
|
-
|
|
710
|
-
|
|
713
|
+
const containedStart = server.indexOf("toolServer.registerTool(\n 'contained_transform'");
|
|
714
|
+
const containedEnd = server.indexOf('toolServer.registerTool(', containedStart + 1);
|
|
715
|
+
const contained = server.slice(containedStart, containedEnd);
|
|
716
|
+
assert.ok(containedStart >= 0 && containedEnd > containedStart);
|
|
717
|
+
assert.match(contained, /z\.enum\(CONTAINED_TRANSFORM_OPERATIONS\)/);
|
|
718
|
+
assert.match(contained, /inputSchema: z\.strictObject\(\{/);
|
|
711
719
|
assert.match(server, /if \(hostPolicy\)/);
|
|
712
720
|
for (const name of ['host_file_read', 'host_file_write', 'host_exec']) assert.match(server, new RegExp(`'${name}'`));
|
|
713
|
-
assert.doesNotMatch(
|
|
714
|
-
assert.doesNotMatch(
|
|
721
|
+
assert.doesNotMatch(contained, /inputSchema: z\.object\(\{/);
|
|
722
|
+
assert.doesNotMatch(contained, /executable:\s*z\.|argv:\s*z\.|environment:\s*z\.|challenge:\s*z\.|request_digest:\s*z\.|worker_id:\s*z\./);
|
|
715
723
|
});
|
|
716
724
|
|
|
717
725
|
test('R27 Windows batch gate builds native payload before freezing and verifying the candidate', async () => {
|
|
@@ -914,13 +922,17 @@ test('contained execution validator fails closed on active network evidence', ()
|
|
|
914
922
|
|
|
915
923
|
test('execution authority is strict at MCP and native argv boundaries', async () => {
|
|
916
924
|
const server = await readFile(fileURLToPath(new URL('../src/mcp-server.mjs', import.meta.url)), 'utf8');
|
|
925
|
+
const containedStart = server.indexOf("toolServer.registerTool(\n 'contained_transform'");
|
|
926
|
+
const containedEnd = server.indexOf('toolServer.registerTool(', containedStart + 1);
|
|
927
|
+
const contained = server.slice(containedStart, containedEnd);
|
|
917
928
|
const launcher = await readFile(fileURLToPath(new URL('../native/deadbyte-exec.cpp', import.meta.url)), 'utf8');
|
|
918
929
|
const helper = await readFile(fileURLToPath(new URL('../native/contained-network-proof.h', import.meta.url)), 'utf8');
|
|
919
930
|
const authority = await readFile(fileURLToPath(new URL('../src/authority-smoke.mjs', import.meta.url)), 'utf8');
|
|
920
|
-
assert.
|
|
921
|
-
assert.
|
|
922
|
-
assert.doesNotMatch(
|
|
923
|
-
assert.doesNotMatch(
|
|
931
|
+
assert.ok(containedStart >= 0 && containedEnd > containedStart);
|
|
932
|
+
assert.match(contained, /inputSchema: z\.strictObject\(/);
|
|
933
|
+
assert.doesNotMatch(contained, /worker_id:\s*z\./);
|
|
934
|
+
assert.doesNotMatch(contained, /executable:\s*z\./);
|
|
935
|
+
assert.doesNotMatch(contained, /argv:\s*z\./);
|
|
924
936
|
assert.match(launcher, /argc != 7/);
|
|
925
937
|
assert.match(launcher, /invalid fixed argument contract/);
|
|
926
938
|
assert.match(helper, /HasExactContainedWorkerArguments/);
|
package/test/controller.test.mjs
CHANGED
|
@@ -82,11 +82,15 @@ test('controller keeps privileged policy optional and propagates it only to the
|
|
|
82
82
|
|
|
83
83
|
test('Windows host policy bootstrap pins executables and creates only explicit local roots', async () => {
|
|
84
84
|
const init = await readFile(fileURLToPath(new URL('../scripts/init-host-policy.ps1', import.meta.url)), 'utf8');
|
|
85
|
-
assert.match(init, /deadbyte\.host-policy\.
|
|
85
|
+
assert.match(init, /deadbyte\.host-policy\.v2/);
|
|
86
86
|
assert.match(init, /Get-FileHash/);
|
|
87
87
|
assert.match(init, /powershell_script/);
|
|
88
88
|
assert.match(init, /cmd_script/);
|
|
89
89
|
assert.match(init, /node_script/);
|
|
90
|
+
assert.match(init, /powershell_inline/);
|
|
91
|
+
assert.match(init, /cmd_inline/);
|
|
92
|
+
assert.match(init, /node_inline/);
|
|
93
|
+
assert.match(init, /native_exec/);
|
|
90
94
|
assert.match(init, /D:\\Projects/);
|
|
91
95
|
assert.match(init, /State\s+: DISARMED/);
|
|
92
96
|
});
|
package/test/core.test.mjs
CHANGED
|
@@ -105,7 +105,7 @@ test('proof execution creates deterministic output and signed verifiable receipt
|
|
|
105
105
|
assert.equal(result.receipt.request.schema, 'deadbyte.request.v1');
|
|
106
106
|
assert.match(result.receipt.request.nonce, /^[0-9a-f]{64}$/);
|
|
107
107
|
assert.match(result.receipt.request.sha256, /^[0-9a-f]{64}$/);
|
|
108
|
-
assert.equal(result.receipt.runtime.package_version, '0.15.
|
|
108
|
+
assert.equal(result.receipt.runtime.package_version, '0.15.1');
|
|
109
109
|
assert.match(result.receipt.runtime.mcp_ingress_adapter, /^(?:none|tunnel-stdio-probe-compat-v1)$/);
|
|
110
110
|
assert.match(result.receipt.runtime.mcp_ingress_adapter_sha256, /^[0-9a-f]{64}$/);
|
|
111
111
|
assert.match(result.receipt.runtime.mcp_ingress_mode_source_sha256, /^[0-9a-f]{64}$/);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
8
|
+
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
|
|
9
|
+
import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
|
|
10
|
+
|
|
11
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const repoRoot=path.resolve(here,'..');
|
|
13
|
+
const serverPath=path.join(repoRoot,'src','mcp-server.mjs');
|
|
14
|
+
const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy.json');
|
|
15
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
16
|
+
const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
|
|
17
|
+
|
|
18
|
+
test('R45 real max-runtime full stdio catalog is exactly 82 with skill and four Desktop primitives while authority remains disarmed',async()=>{
|
|
19
|
+
const f=await createR34Fixture({authority:'disarmed'});
|
|
20
|
+
const processPolicyPath=path.join(f.root,'process-policy.json');
|
|
21
|
+
const processGrant=path.join(f.root,'process-grant.json');
|
|
22
|
+
const processState=path.join(f.root,'process-state');
|
|
23
|
+
const hostPolicyPath=path.join(f.root,'host-policy.json');
|
|
24
|
+
const hostArm=path.join(f.root,'host-arm.json');
|
|
25
|
+
const nodeSha=sha(await readFile(process.execPath));
|
|
26
|
+
await mkdir(processState,{recursive:true});
|
|
27
|
+
await writeFile(processPolicyPath,JSON.stringify({
|
|
28
|
+
schema:'deadbyte.process-policy.v1',enabled:true,grant_file:processGrant,state_dir:processState,
|
|
29
|
+
native_host:{path:process.execPath,sha256:nodeSha},
|
|
30
|
+
roots:{core:{path:f.project,deny_paths:[]}},
|
|
31
|
+
profiles:{node:{executable:process.execPath,executable_sha256:nodeSha,root_ids:['core'],
|
|
32
|
+
prefix_args:[],transport:'pipe',max_args:8,max_arg_bytes:1024,max_sessions:2,
|
|
33
|
+
max_input_bytes:65536,max_retained_output_bytes:262144,env_allow:['PATH','TEMP','TMP'],
|
|
34
|
+
input_actions:{ping:'PING\r\n'}}}
|
|
35
|
+
},null,2));
|
|
36
|
+
await writeFile(hostPolicyPath,JSON.stringify({
|
|
37
|
+
schema:'deadbyte.host-policy.v1',enabled:true,arm_file:hostArm,max_read_bytes:262144,max_write_bytes:1048576,
|
|
38
|
+
roots:{core:{path:f.project,read:true,write:true,exec:true}},
|
|
39
|
+
commands:{node_script:{kind:'script',executable:process.execPath,executable_sha256:nodeSha,
|
|
40
|
+
root_ids:['core'],prefix_args:[],extensions:['.mjs'],timeout_ms:5000,max_output_bytes:65536}}
|
|
41
|
+
},null,2));
|
|
42
|
+
|
|
43
|
+
const desktopRaw=JSON.parse(await readFile(desktopPolicyPath,'utf8'));
|
|
44
|
+
const desktopGrant=desktopRaw.grant_file;
|
|
45
|
+
const codingLease=f.codingPolicy.lease_file;
|
|
46
|
+
const autonomousLease=f.policy.lease_file;
|
|
47
|
+
for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority unexpectedly armed before start: '+q);
|
|
48
|
+
|
|
49
|
+
const client=new Client({name:'deadbyte-r45-full-catalog',version:'0.15.1'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
|
|
50
|
+
const env={
|
|
51
|
+
...getDefaultEnvironment(),
|
|
52
|
+
DEADBYTE_CAPABILITY_PROFILE:'full',
|
|
53
|
+
DEADBYTE_AUDIT_RUNTIME:'0',
|
|
54
|
+
DEADBYTE_STATE_ROOT:path.join(f.root,'state'),
|
|
55
|
+
DEADBYTE_WORKSPACE_ROOT:f.root,
|
|
56
|
+
DEADBYTE_SIGNING_KEY:f.keys.privateKeyPath,
|
|
57
|
+
DEADBYTE_VERIFY_KEY:f.keys.publicKeyPath,
|
|
58
|
+
DEADBYTE_PRIVILEGED_POLICY:hostPolicyPath,
|
|
59
|
+
DEADBYTE_MACHINE_RUNTIME:'1',
|
|
60
|
+
DEADBYTE_AGENT_RUNTIME:'1',
|
|
61
|
+
DEADBYTE_PROCESS_RUNTIME:'1',
|
|
62
|
+
DEADBYTE_PROCESS_POLICY:processPolicyPath,
|
|
63
|
+
DEADBYTE_CODING_RUNTIME:'1',
|
|
64
|
+
DEADBYTE_CODING_POLICY:path.join(f.root,'coding-policy.json'),
|
|
65
|
+
DEADBYTE_MACHINE_FS_RUNTIME:'1',
|
|
66
|
+
DEADBYTE_OBSERVATION_RUNTIME:'1',
|
|
67
|
+
DEADBYTE_DESKTOP_RUNTIME:'1',
|
|
68
|
+
DEADBYTE_DESKTOP_POLICY:desktopPolicyPath,
|
|
69
|
+
DEADBYTE_AUTONOMOUS_RUNTIME:'1',
|
|
70
|
+
DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
|
|
71
|
+
DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
|
|
72
|
+
};
|
|
73
|
+
const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
|
|
74
|
+
try{
|
|
75
|
+
await client.connect(transport);
|
|
76
|
+
const listed=await client.listTools();
|
|
77
|
+
const names=listed.tools.map(t=>t.name).sort();
|
|
78
|
+
const {R45_EXPECTED_TOOLS}=await import('../src/remote-mcp-r45-parity-client.mjs');
|
|
79
|
+
assert.equal(names.length,82,'expected exact full R45 catalog 82, got '+names.length+': '+names.join(','));
|
|
80
|
+
assert.deepEqual(names,R45_EXPECTED_TOOLS);
|
|
81
|
+
for(const name of ['machine_hardware_query','desktop_status','desktop_observe','desktop_target','desktop_action',
|
|
82
|
+
'host_file_read','host_file_write','host_exec','skill_catalog']) assert.ok(names.includes(name),'missing '+name);
|
|
83
|
+
for(const tool of listed.tools) assert.equal(tool.outputSchema?.additionalProperties,false,'non-strict output '+tool.name);
|
|
84
|
+
const catalog_sha256=sha(Buffer.from(JSON.stringify(names),'utf8'));
|
|
85
|
+
console.log(JSON.stringify({tool_count:names.length,catalog_sha256,desktop_tools:4,skill:true,authority:'DISARMED'}));
|
|
86
|
+
} finally {
|
|
87
|
+
await client.close().catch(()=>{});
|
|
88
|
+
for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority file appeared during catalog probe: '+q);
|
|
89
|
+
await f.cleanup();
|
|
90
|
+
}
|
|
91
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtemp, mkdir, writeFile } from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { generateTrustKeypair } from '../src/trust.mjs';
|
|
7
|
+
import { loadCodingPolicy } from '../src/coding-plane.mjs';
|
|
8
|
+
import { createObservationRuntime, verifyObservationReceiptFile } from '../src/observation-runtime.mjs';
|
|
9
|
+
|
|
10
|
+
async function fixture(){
|
|
11
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-hardware-query-r45-'));
|
|
12
|
+
const project=path.join(root,'project');await mkdir(project);
|
|
13
|
+
const policyPath=path.join(root,'coding-policy.json');
|
|
14
|
+
await writeFile(policyPath,JSON.stringify({schema:'deadbyte.coding-policy.v1',enabled:true,
|
|
15
|
+
lease_file:path.join(root,'coding-grant.json'),evidence_dir:path.join(root,'evidence'),
|
|
16
|
+
roots:{project:{path:project,read:true,write:false,exec:false,deny_paths:[]}},commands:{},
|
|
17
|
+
max_read_bytes:65536,max_write_bytes:65536}));
|
|
18
|
+
const policy=await loadCodingPolicy(policyPath);
|
|
19
|
+
const keys=await generateTrustKeypair({privateKeyPath:path.join(root,'private.pem'),publicKeyPath:path.join(root,'public.pem')});
|
|
20
|
+
const calls=[];
|
|
21
|
+
const hardwareSnapshotProvider=async query=>{calls.push(query);return {schema:'deadbyte.hardware-query.v1',query,
|
|
22
|
+
data:query==='cpu'?{brand:'TEST CPU',logical_processors:16}:{fixture:true}};};
|
|
23
|
+
const runtime=createObservationRuntime({policy,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath,
|
|
24
|
+
stateRoot:root,processSnapshotProvider:async()=>[],systemSnapshotProvider:async()=>({hostname:'x',platform:'win32',architecture:'x64',
|
|
25
|
+
uptime_seconds:1,total_memory_bytes:1,free_memory_bytes:1,cpu_count:1,load_average:[0,0,0]}),
|
|
26
|
+
ownedRuntimePidProvider:async()=>new Set(),hardwareSnapshotProvider});
|
|
27
|
+
return {root,policy,keys,runtime,calls};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
test('R45 hardware query is typed read-only observation with signed evidence and no host authority',async()=>{
|
|
31
|
+
const f=await fixture();
|
|
32
|
+
const out=await f.runtime.hardwareQuery({query:'cpu'});
|
|
33
|
+
assert.equal(out.query,'cpu');assert.equal(out.data.brand,'TEST CPU');assert.deepEqual(f.calls,['cpu']);
|
|
34
|
+
assert.match(out.request_sha256,/^[0-9a-f]{64}$/);assert.match(out.result_head_sha256,/^[0-9a-f]{64}$/);
|
|
35
|
+
assert.match(out.receipt_id,/^[0-9a-f]{24}$/);assert.match(out.receipt_sha256,/^[0-9a-f]{64}$/);
|
|
36
|
+
const verified=await verifyObservationReceiptFile({policy:f.policy,verifyKeyPath:f.keys.publicKeyPath,receiptId:out.receipt_id});
|
|
37
|
+
assert.equal(verified.ok,true);assert.equal(verified.signature_valid,true);assert.equal(verified.kind,'machine_hardware_query');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('R45 hardware query rejects untyped arbitrary query names before provider dispatch',async()=>{
|
|
41
|
+
const f=await fixture();
|
|
42
|
+
await assert.rejects(()=>f.runtime.hardwareQuery({query:'run_powershell'}),/hardware query/i);
|
|
43
|
+
assert.deepEqual(f.calls,[]);
|
|
44
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
4
|
+
import { mkdtemp, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {
|
|
8
|
+
HOST_GRANT_SCHEMA, HOST_POLICY_SCHEMA_V2, hostExecInline, hostExecNative, loadHostPolicy
|
|
9
|
+
} from '../src/host-plane.mjs';
|
|
10
|
+
|
|
11
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
12
|
+
|
|
13
|
+
async function fixture(){
|
|
14
|
+
const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-host-inline-r45-'));
|
|
15
|
+
const root=path.join(dir,'root');await mkdir(root);
|
|
16
|
+
const arm=path.join(dir,'arm.json'), policyPath=path.join(dir,'policy.json');
|
|
17
|
+
const exeSha=sha(await readFile(process.execPath));
|
|
18
|
+
const raw={
|
|
19
|
+
schema:HOST_POLICY_SCHEMA_V2,enabled:true,arm_file:arm,
|
|
20
|
+
roots:{core:{path:root,read:true,write:true,exec:true}},
|
|
21
|
+
commands:{
|
|
22
|
+
node_inline:{kind:'inline',executable:process.execPath,executable_sha256:exeSha,root_ids:['core'],
|
|
23
|
+
prefix_args:['-e'],timeout_ms:5000,max_output_bytes:65536,max_command_chars:32768}
|
|
24
|
+
},
|
|
25
|
+
native_exec:{enabled:true,root_ids:['core'],timeout_ms:5000,max_output_bytes:65536,max_args:64,max_arg_chars:8192},
|
|
26
|
+
max_read_bytes:262144,max_write_bytes:1048576
|
|
27
|
+
};
|
|
28
|
+
await writeFile(policyPath,JSON.stringify(raw,null,2));
|
|
29
|
+
const policy=await loadHostPolicy(policyPath);
|
|
30
|
+
await writeFile(arm,JSON.stringify({schema:HOST_GRANT_SCHEMA,policy_sha256:policy.policy_sha256,
|
|
31
|
+
instance_nonce:randomBytes(32).toString('hex'),armed_at_utc:new Date().toISOString()},null,2));
|
|
32
|
+
return {dir,root,arm,policy,exeSha};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
test('R45 host inline executes in argv memory with zero staging artifact and hashes command/output',async t=>{
|
|
36
|
+
const f=await fixture();t.after(()=>rm(f.dir,{recursive:true,force:true}));
|
|
37
|
+
const before=(await readdir(f.root)).sort();
|
|
38
|
+
const command='process.stdout.write("INLINE_OK")';
|
|
39
|
+
const out=await hostExecInline(f.policy,{commandId:'node_inline',rootId:'core',command,cwd:'.',timeoutMs:2000});
|
|
40
|
+
const after=(await readdir(f.root)).sort();
|
|
41
|
+
assert.deepEqual(after,before,'inline execution must not stage a script file');
|
|
42
|
+
assert.equal(out.exit_code,0);assert.equal(out.stdout,'INLINE_OK');assert.equal(out.stderr,'');
|
|
43
|
+
assert.equal(out.command_sha256,sha(Buffer.from(command,'utf8')));
|
|
44
|
+
assert.equal(out.stdout_sha256,sha(Buffer.from('INLINE_OK','utf8')));
|
|
45
|
+
assert.equal(out.stderr_sha256,sha(Buffer.alloc(0)));
|
|
46
|
+
assert.match(out.argv_sha256,/^[0-9a-f]{64}$/);assert.equal(out.executable_sha256,f.exeSha);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('R45 native argv execution accepts arbitrary absolute hash-pinned executable only while Host is armed',async t=>{
|
|
50
|
+
const f=await fixture();t.after(()=>rm(f.dir,{recursive:true,force:true}));
|
|
51
|
+
const before=(await readdir(f.root)).sort();
|
|
52
|
+
const out=await hostExecNative(f.policy,{rootId:'core',executable:process.execPath,executableSha256:f.exeSha,
|
|
53
|
+
args:['-e','process.stdout.write("NATIVE_OK")'],cwd:'.',timeoutMs:2000});
|
|
54
|
+
assert.equal(out.exit_code,0);assert.equal(out.stdout,'NATIVE_OK');
|
|
55
|
+
assert.deepEqual((await readdir(f.root)).sort(),before,'native argv execution must not create staging files');
|
|
56
|
+
await assert.rejects(()=>hostExecNative(f.policy,{rootId:'core',executable:process.execPath,executableSha256:'f'.repeat(64),
|
|
57
|
+
args:['--version'],cwd:'.'}),/executable hash mismatch/i);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('R45 inline execution observes authority revocation during a live child and fails closed',async t=>{
|
|
61
|
+
const f=await fixture();t.after(()=>rm(f.dir,{recursive:true,force:true}));
|
|
62
|
+
const running=hostExecInline(f.policy,{commandId:'node_inline',rootId:'core',
|
|
63
|
+
command:'setTimeout(()=>process.stdout.write("SHOULD_NOT_COMPLETE"),1500)',cwd:'.',timeoutMs:4000,authorityPollMs:50});
|
|
64
|
+
await new Promise(r=>setTimeout(r,150));
|
|
65
|
+
await rm(f.arm,{force:true});
|
|
66
|
+
await assert.rejects(()=>running,/host authority changed during operation/i);
|
|
67
|
+
});
|
|
@@ -51,6 +51,7 @@ async function fixture() {
|
|
|
51
51
|
env: {
|
|
52
52
|
...getDefaultEnvironment(), DEADBYTE_STATE_ROOT: root, DEADBYTE_MACHINE_RUNTIME: '1',
|
|
53
53
|
DEADBYTE_SIGNING_KEY: keys.privateKeyPath, DEADBYTE_VERIFY_KEY: keys.publicKeyPath,
|
|
54
|
+
DEADBYTE_PRIVILEGED_POLICY: '',
|
|
54
55
|
DEADBYTE_AGENT_RUNTIME: '0', DEADBYTE_CODING_RUNTIME: '0', DEADBYTE_AUTONOMOUS_RUNTIME: '0'
|
|
55
56
|
}, stderr: 'pipe'
|
|
56
57
|
});
|
|
@@ -15,14 +15,15 @@ function runtime(){
|
|
|
15
15
|
searchStatus:async()=>({status:'ok',search_id:hex('a'),state:'completed',result_count:0,files_scanned:0,bytes_scanned:0,truncated:false,request_sha256:hex('b'),result_head_sha256:hex('c'),receipt_id:receipt,receipt_sha256:hex('d'),error:null}),
|
|
16
16
|
searchCancel:async()=>({status:'ok',search_id:hex('a'),state:'cancelled',cancel_requested:true}),
|
|
17
17
|
processList:async()=>({status:'ok',snapshot_id:hex('e'),observed_at_utc:new Date(0).toISOString(),processes:[],next_cursor:null,request_sha256:hex('b'),result_head_sha256:hex('c'),receipt_id:receipt,receipt_sha256:hex('d')}),
|
|
18
|
-
systemStatus:async()=>({status:'ok',observed_at_utc:new Date(0).toISOString(),hostname:'x',platform:'win32',architecture:'x64',uptime_seconds:1,total_memory_bytes:2,free_memory_bytes:1,cpu_count:1,load_average:[0,0,0],request_sha256:hex('b'),result_head_sha256:hex('c'),receipt_id:receipt,receipt_sha256:hex('d')})
|
|
18
|
+
systemStatus:async()=>({status:'ok',observed_at_utc:new Date(0).toISOString(),hostname:'x',platform:'win32',architecture:'x64',uptime_seconds:1,total_memory_bytes:2,free_memory_bytes:1,cpu_count:1,load_average:[0,0,0],request_sha256:hex('b'),result_head_sha256:hex('c'),receipt_id:receipt,receipt_sha256:hex('d')}),
|
|
19
|
+
hardwareQuery:async({query})=>({status:'ok',query,observed_at_utc:new Date(0).toISOString(),observer_sha256:hex('e'),data:{vendor:'x'},request_sha256:hex('b'),result_head_sha256:hex('c'),receipt_id:receipt,receipt_sha256:hex('d')})
|
|
19
20
|
};
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
test('
|
|
23
|
+
test('R45 registers exactly seven bounded observation tools including typed native hardware',()=>{
|
|
23
24
|
const server=new FakeServer(); registerObservationTools(server,{runtime:runtime()});
|
|
24
25
|
assert.deepEqual([...server.tools.keys()].sort(),[
|
|
25
|
-
'machine_process_list','machine_search_cancel','machine_search_page','machine_search_start','machine_search_status','machine_system_status'
|
|
26
|
+
'machine_hardware_query','machine_process_list','machine_search_cancel','machine_search_page','machine_search_start','machine_search_status','machine_system_status'
|
|
26
27
|
]);
|
|
27
28
|
for(const [name,tool] of server.tools){ assert.ok(tool.spec.inputSchema,`${name} input`); assert.ok(tool.spec.outputSchema,`${name} output`); }
|
|
28
29
|
});
|
|
@@ -39,6 +39,6 @@ test('R28 package boundary contains only immutable workspace seed files', () =>
|
|
|
39
39
|
|
|
40
40
|
test('publish boundary excludes live state, private keys, grants and non-example controller secrets',()=>{
|
|
41
41
|
const files=packFiles();
|
|
42
|
-
const forbidden=files.filter(rel
|
|
42
|
+
const forbidden=files.filter(rel=>rel.startsWith('tmp/')||rel.startsWith('.deadbyte-machine-fs-recovery/')||/(^|\/)(active-release\.json|runtime\/|audit\/|evidence\/)|\.pem$|(^|\/)deadbyte-controller\.config\.psd1$|(^|\/)deadbyte-host-policy\.json$|(^|\/)[^/]*(?:grant|arm)\.json$/i.test(rel));
|
|
43
43
|
assert.deepEqual(forbidden,[]);
|
|
44
44
|
});
|
|
@@ -9,9 +9,9 @@ const readme=()=>readFile(path.join(root,'README.txt'),'utf8');
|
|
|
9
9
|
|
|
10
10
|
test('production README documents one-command stdio configs for major MCP clients',async()=>{
|
|
11
11
|
const text=await readme();
|
|
12
|
-
assert.match(text,/npx -y deadbyte-mcp@0\.
|
|
12
|
+
assert.match(text,/npx -y deadbyte-mcp@0\.15\.1 mcp/);
|
|
13
13
|
assert.match(text,/CLAUDE DESKTOP/);
|
|
14
|
-
assert.match(text,/"mcpServers"[\s\S]*?"command"\s*:\s*"npx"[\s\S]*?"-y"[\s\S]*?"deadbyte-mcp@0\.
|
|
14
|
+
assert.match(text,/"mcpServers"[\s\S]*?"command"\s*:\s*"npx"[\s\S]*?"-y"[\s\S]*?"deadbyte-mcp@0\.15\.1"[\s\S]*?"mcp"/);
|
|
15
15
|
assert.match(text,/CURSOR/);
|
|
16
16
|
assert.match(text,/\.cursor\/mcp\.json/);
|
|
17
17
|
assert.match(text,/VS CODE/);
|
|
@@ -20,7 +20,7 @@ test('production README documents one-command stdio configs for major MCP client
|
|
|
20
20
|
assert.match(text,/CODEX/);
|
|
21
21
|
assert.match(text,/\[mcp_servers\.deadbyte\]/);
|
|
22
22
|
assert.match(text,/command\s*=\s*"npx"/);
|
|
23
|
-
assert.match(text,/args\s*=\s*\["-y",\s*"deadbyte-mcp@0\.
|
|
23
|
+
assert.match(text,/args\s*=\s*\["-y",\s*"deadbyte-mcp@0\.15\.1",\s*"mcp"\]/);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
test('production README records tracer bullet, semantic scope, remote UX, safety and document extension',async()=>{
|
|
@@ -86,23 +86,24 @@ test('audit restart reconciles an orphan request with an explicit interrupted re
|
|
|
86
86
|
}finally{await rm(stateRoot,{recursive:true,force:true});}
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
test('Windows current
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
test('Windows current R45 gate binds exact sealed R44 parent and machine-freedom evidence contract', async()=>{
|
|
90
|
+
const gate=await readFile(path.join(root,'scripts','gate-windows-r45.ps1'),'utf8');
|
|
91
|
+
const evidenceSource=await readFile(path.join(root,'scripts','windows-gate-evidence-r45.mjs'),'utf8');
|
|
92
|
+
const parent=JSON.parse(await readFile(path.join(root,'R45-PARENT.json'),'utf8'));
|
|
93
|
+
assert.match(gate,/windows-gate-evidence-r45\.mjs/);
|
|
94
|
+
assert.match(gate,/r45-parent-verify/);
|
|
95
|
+
assert.match(gate,/host-policy-refresh/);
|
|
96
|
+
assert.match(gate,/hardware-build/);
|
|
97
|
+
assert.match(gate,/doctor/);
|
|
98
|
+
assert.match(evidenceSource,/deadbyte\.r45-windows-gate\.v1/);
|
|
99
|
+
assert.match(evidenceSource,/version:'0\.15\.1'/);
|
|
100
|
+
assert.match(evidenceSource,/DEADBYTE V0\.15\.1 \/ R45 MACHINE FREEDOM WINDOWS BATCH GATE: PASS/);
|
|
101
|
+
for(const key of ['host_inline_native','native_hardware_observation','doctor_release_truth']) assert.match(evidenceSource,new RegExp(key+':true'));
|
|
102
|
+
assert.equal(parent.parent_release_id,'v0.15.0-c15fa41719be61b3');
|
|
103
|
+
assert.equal(parent.parent_manifest_sha256,'c15fa41719be61b3186e49b2367a5f4c057365cfb465102dbefb7d7355f45483');
|
|
104
|
+
assert.equal(parent.parent_generation_manifest_sha256,'6d7429c050b7fe893492e102f00282019116e0c9e54e4f25a5791defa1661d30');
|
|
105
|
+
assert.equal(parent.parent_final_closure_sha256,'533b7e0ff9ded04086dd90ed34e3b87bc427acc3c55c25bb9f4ec66cb448e667');
|
|
106
|
+
const historical=await readFile(path.join(root,'scripts','windows-gate-evidence-r44.mjs'),'utf8');
|
|
107
|
+
assert.match(historical,/version:'0\.15\.0'/);
|
|
108
|
+
assert.match(historical,/deadbyte\.r44-windows-gate\.v1/);
|
|
108
109
|
});
|