deadbyte-mcp 0.15.67 → 0.15.69
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 +85 -40
- package/PROVENANCE.json +46 -24
- package/README.txt +46 -33
- package/RELEASE.json +44 -17
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +25 -2
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +65 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R184-package-lock.json +97 -0
- package/docs/R186-OWNER-CONSENT-HANDOFF.txt +87 -0
- package/package.json +3 -2
- package/scripts/install-r186-owner-trust.ps1 +59 -0
- package/scripts/r173-protected-preflight.mjs +42 -0
- package/scripts/r175-focused-runner.mjs +38 -0
- package/scripts/r176-log-preview.mjs +18 -0
- package/scripts/r177-owner-trust-inventory.ps1 +36 -0
- package/scripts/r178-full-regression.mjs +21 -0
- package/scripts/r178-npm-ci.mjs +10 -0
- package/scripts/r178-npm-preflight.mjs +16 -0
- package/scripts/r178-release-gates-readonly.mjs +9 -0
- package/scripts/r178-shard-regression.mjs +25 -0
- package/scripts/r179-predecessor-registry.mjs +24 -0
- package/scripts/r179-protected-inventory.ps1 +21 -0
- package/scripts/r186-focused-runner.mjs +22 -0
- package/scripts/r186-owner-anchor-inspect.mjs +6 -0
- package/scripts/r186-owner-consent-check.mjs +86 -0
- package/scripts/r186-owner-grant-cli.mjs +45 -0
- package/scripts/r186-owner-key-local.mjs +22 -0
- package/scripts/r186-owner-review-export.mjs +34 -0
- package/src/activation-authority-proof-r75.mjs +28 -4
- package/src/activation-preflight-r65.mjs +2 -1
- package/src/deadbyte-cli.mjs +69 -56
- package/src/r174-owner-webauthn.mjs +176 -0
- package/src/r175-foreground-boundary.mjs +28 -0
- package/src/r186-owner-anchor.mjs +12 -0
- package/src/r186-owner-consent-preflight.mjs +63 -0
- package/src/r186-owner-grant-broker.mjs +96 -0
- package/src/r186-owner-local-signing.mjs +25 -0
- package/src/r186-owner-request.mjs +40 -0
- package/src/r186-owner-review-export.mjs +49 -0
- package/src/remote-live-log.mjs +81 -5
- package/src/remote-session-guardian.mjs +23 -0
- package/src/version.mjs +1 -1
- package/test/helpers/r175-active-pointer.mjs +28 -0
- package/test/helpers/release-lock.mjs +12 -0
- package/test/r129-sdk-security-baseline.test.mjs +2 -1
- package/test/r130-release-security-contract.test.mjs +11 -10
- package/test/r132-release-identity.test.mjs +12 -11
- package/test/r153-prepublish-identity.test.mjs +1 -1
- package/test/r155-default-live-log.test.mjs +17 -16
- package/test/r160-package-decision-manifest.test.mjs +1 -1
- package/test/r160-release-contract.test.mjs +4 -5
- package/test/r163-isolated-slot-rollback-restore.test.mjs +6 -6
- package/test/r165-live-cli-skew.test.mjs +6 -6
- package/test/r167-release-contract.test.mjs +15 -13
- package/test/r168-protected-entrypoint.test.mjs +14 -11
- package/test/r168-release-contract.test.mjs +4 -3
- package/test/r168-remote-one-shot-coherence.test.mjs +2 -1
- package/test/r172-release-contract.test.mjs +8 -8
- package/test/r173-release-contract.test.mjs +33 -0
- package/test/r174-owner-webauthn.test.mjs +144 -0
- package/test/r175-cli-flags.test.mjs +23 -0
- package/test/r175-foreground-boundary.test.mjs +87 -0
- package/test/r175-guardian-owner-boundary.test.mjs +56 -0
- package/test/r176-pretty-live-log.test.mjs +54 -0
- package/test/r177-windows-absolute-live-path.test.mjs +37 -0
- package/test/r179-absolute-path-live-log.test.mjs +40 -0
- package/test/r179-release-contract.test.mjs +62 -0
- package/test/r186-controller-owner-grant.test.mjs +20 -0
- package/test/r186-owner-consent-preflight.test.mjs +98 -0
- package/test/r186-owner-enrollment.test.mjs +20 -0
- package/test/r186-owner-grant-broker.test.mjs +85 -0
- package/test/r186-owner-local-signing.test.mjs +30 -0
- package/test/r186-owner-request.test.mjs +28 -0
- package/test/r186-owner-review-export.test.mjs +52 -0
- package/test/r48-release-contract.test.mjs +2 -1
- package/test/r51-runtime-coherence.test.mjs +4 -2
- package/test/r58-cleanup-retention.test.mjs +5 -12
- package/test/r58-concurrent-recovery.test.mjs +5 -1
- package/test/r58-stale-owner.test.mjs +9 -3
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r75-authority-evidence.test.mjs +32 -0
- package/test/remote-live-log-r37.test.mjs +2 -2
- package/test/remote-live-log-recovery-r36.test.mjs +1 -1
- package/test/remote-session-cli.test.mjs +92 -126
- package/node_modules/which/CHANGELOG.md +0 -166
|
@@ -5,6 +5,9 @@ import path from 'node:path';
|
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
6
|
import {spawn} from 'node:child_process';
|
|
7
7
|
import {setTimeout as delay} from 'node:timers/promises';
|
|
8
|
+
import {installExactActivePointer} from './helpers/r175-active-pointer.mjs';
|
|
9
|
+
|
|
10
|
+
const packageRoot=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
8
11
|
|
|
9
12
|
test('R75 simultaneous owner-unverified recovery attempts both retain authority and marker', {timeout:30000},async()=>{
|
|
10
13
|
const base='D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';await mkdir(base,{recursive:true});
|
|
@@ -41,6 +44,7 @@ switch($Command){
|
|
|
41
44
|
}
|
|
42
45
|
exit 0
|
|
43
46
|
`);
|
|
47
|
+
await installExactActivePointer({stateRoot:root,packageRoot,launcherPath:path.join(root,'bin','DEADBYTE-MCP.ps1')});
|
|
44
48
|
const children=[],outputs=[];
|
|
45
49
|
try{
|
|
46
50
|
for(let i=0;i<2;i++){
|
|
@@ -52,7 +56,7 @@ exit 0
|
|
|
52
56
|
const commands=await readFile(trace,'utf8').catch(error=>error.code==='ENOENT'?'':Promise.reject(error));
|
|
53
57
|
await writeFile(path.join(root,'observation.json'),JSON.stringify({commands,exits,outputs:outputs.map(o=>({stdout:o.stdout,stderr:o.stderr})),simulation:'concurrent owner-unverified stale marker'}),{flag:'wx'});
|
|
54
58
|
assert.ok(exits.every(code=>code!==0));
|
|
55
|
-
for(const output of outputs)assert.match(output.stderr,/
|
|
59
|
+
for(const output of outputs)assert.match(output.stderr,/R179_LEGACY_FOREGROUND_RECOVERY_REQUIRES_EXPLICIT_OWNER_COMMAND|already claimed \(startup\/recovery lock\)/i);
|
|
56
60
|
assert.equal(commands,'','neither attempt may touch authority');
|
|
57
61
|
assert.equal(JSON.parse(await readFile(markerPath,'utf8')).pid,2147483000);
|
|
58
62
|
}finally{
|
|
@@ -5,12 +5,16 @@ import path from 'node:path';
|
|
|
5
5
|
import {fileURLToPath} from 'node:url';
|
|
6
6
|
import {spawn} from 'node:child_process';
|
|
7
7
|
import {queryForegroundIdentity} from '../src/foreground-process-identity.mjs';
|
|
8
|
+
import {installExactActivePointer} from './helpers/r175-active-pointer.mjs';
|
|
9
|
+
|
|
10
|
+
const packageRoot=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
8
11
|
|
|
9
12
|
test('R58 inconsistent owner PID binding cannot trigger stale-session authority cleanup', {timeout:20000}, async()=>{
|
|
10
13
|
const base='D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';await mkdir(base,{recursive:true});
|
|
11
14
|
const root=await mkdtemp(path.join(base,'owner-binding-'));await mkdir(path.join(root,'runtime'));await mkdir(path.join(root,'bin'));
|
|
12
15
|
const trace=path.join(root,'trace.txt');
|
|
13
16
|
await writeFile(path.join(root,'bin','DEADBYTE-MCP.ps1'),`param([string]$Command)\n[IO.File]::AppendAllText('${trace.replaceAll("'","''")}',$Command+[Environment]::NewLine)\nexit 0\n`);
|
|
17
|
+
await installExactActivePointer({stateRoot:root,packageRoot,launcherPath:path.join(root,'bin','DEADBYTE-MCP.ps1')});
|
|
14
18
|
const identity=queryForegroundIdentity(process.pid);
|
|
15
19
|
const marker={schema:'deadbyte.remote-session.v2',owner_pid:process.pid,guardian_pid:0,session_nonce:'c'.repeat(64),owner_identity:{...identity,pid:process.pid+1}};
|
|
16
20
|
const markerPath=path.join(root,'runtime','remote-session.json');const bytes=JSON.stringify(marker);await writeFile(markerPath,bytes);
|
|
@@ -18,7 +22,7 @@ test('R58 inconsistent owner PID binding cannot trigger stale-session authority
|
|
|
18
22
|
let stderr='';child.stderr.on('data',b=>{stderr+=b;});child.stdout.resume();
|
|
19
23
|
const code=await new Promise(resolve=>child.once('close',resolve));
|
|
20
24
|
await writeFile(path.join(root,'observation.json'),JSON.stringify({code,stderr}),{flag:'wx'});
|
|
21
|
-
assert.notEqual(code,0);assert.match(stderr,/
|
|
25
|
+
assert.notEqual(code,0);assert.match(stderr,/R179_LEGACY_FOREGROUND_RECOVERY_REQUIRES_EXPLICIT_OWNER_COMMAND/i);
|
|
22
26
|
assert.equal(await readFile(trace,'utf8').catch(e=>e.code==='ENOENT'?'':Promise.reject(e)),'','inconsistent marker must cause no controller actions');
|
|
23
27
|
assert.equal(await readFile(markerPath,'utf8'),bytes,'retain ambiguous ownership evidence');
|
|
24
28
|
});
|
|
@@ -29,6 +33,7 @@ test('R58 live unrelated PID is not accepted as a remote foreground owner', {tim
|
|
|
29
33
|
await mkdir(path.join(root,'runtime'));await mkdir(path.join(root,'bin'));
|
|
30
34
|
const trace=path.join(root,'trace.txt');
|
|
31
35
|
await writeFile(path.join(root,'bin','DEADBYTE-MCP.ps1'),`param([string]$Command)\n[IO.File]::AppendAllText('${trace.replaceAll("'","''")}',$Command+[Environment]::NewLine)\nexit 0\n`);
|
|
36
|
+
await installExactActivePointer({stateRoot:root,packageRoot,launcherPath:path.join(root,'bin','DEADBYTE-MCP.ps1')});
|
|
32
37
|
// The test runner is alive but neither a remote CLI nor a guardian. This
|
|
33
38
|
// represents a stale numeric PID now occupied by an unrelated process.
|
|
34
39
|
const marker={schema:'deadbyte.remote-session.v2',owner_pid:process.pid,guardian_pid:process.pid,session_nonce:'a'.repeat(64),started_at_utc:'2000-01-01T00:00:00.000Z'};
|
|
@@ -41,7 +46,7 @@ test('R58 live unrelated PID is not accepted as a remote foreground owner', {tim
|
|
|
41
46
|
// Fail-closed ambiguity is acceptable; do not kill the unrelated process or
|
|
42
47
|
// mutate authority based on unverified ownership. Automatic convergence still
|
|
43
48
|
// requires separately observed exact owner/guardian identity evidence.
|
|
44
|
-
assert.match(stderr,/
|
|
49
|
+
assert.match(stderr,/R179_LEGACY_FOREGROUND_RECOVERY_REQUIRES_EXPLICIT_OWNER_COMMAND/i);
|
|
45
50
|
assert.deepEqual(JSON.parse(await readFile(path.join(root,'runtime','remote-session.json'),'utf8')),marker);
|
|
46
51
|
assert.notEqual(code,0);
|
|
47
52
|
});
|
|
@@ -52,6 +57,7 @@ test('R75 bound stale birth identity retains marker without touching a reused PI
|
|
|
52
57
|
await mkdir(path.join(root,'runtime'));await mkdir(path.join(root,'bin'));
|
|
53
58
|
const trace=path.join(root,'trace.txt');
|
|
54
59
|
await writeFile(path.join(root,'bin','DEADBYTE-MCP.ps1'),`param([string]$Command,[switch]$Json)\n[IO.File]::AppendAllText('${trace.replaceAll("'","''")}',$Command+[Environment]::NewLine)\nif ($Command -eq 'status' -and $Json) { $off=@{configured=$true;armed=$false;reason='disarmed'}; @{schema='deadbyte.controller-observation.v1';state='OFFLINE';authority=@{process=$off;coding=$off;autonomous=$off;desktop=$off;host=$off}} | ConvertTo-Json -Depth 5 -Compress }\nexit 0\n`);
|
|
60
|
+
await installExactActivePointer({stateRoot:root,packageRoot,launcherPath:path.join(root,'bin','DEADBYTE-MCP.ps1')});
|
|
55
61
|
const current=queryForegroundIdentity(process.pid);
|
|
56
62
|
const stale={...current,creation_utc:'2000-01-01T00:00:00.000Z'};
|
|
57
63
|
const marker={schema:'deadbyte.remote-session.v2',owner_pid:process.pid,guardian_pid:process.pid,session_nonce:'b'.repeat(64),owner_identity:stale,guardian_identity:stale};
|
|
@@ -62,7 +68,7 @@ test('R75 bound stale birth identity retains marker without touching a reused PI
|
|
|
62
68
|
const code=await new Promise(resolve=>child.once('close',resolve));
|
|
63
69
|
await writeFile(path.join(root,'observation.json'),JSON.stringify({code,stdout,stderr,simulation:'birth identity drift at a live unrelated numeric PID'}),{flag:'wx'});
|
|
64
70
|
assert.notEqual(code,0);
|
|
65
|
-
assert.match(stderr,/
|
|
71
|
+
assert.match(stderr,/R179_LEGACY_FOREGROUND_RECOVERY_REQUIRES_EXPLICIT_OWNER_COMMAND/i);
|
|
66
72
|
assert.equal(await readFile(trace,'utf8').catch(error=>error.code==='ENOENT'?'':Promise.reject(error)),'','identity drift must cause no authority commands');
|
|
67
73
|
assert.deepEqual(JSON.parse(await readFile(markerPath,'utf8')),marker);
|
|
68
74
|
assert.equal(foregroundAlive(),true,'unrelated live process must not be killed');
|
|
@@ -83,7 +83,7 @@ test('R72 compact baseline permits only R64 read offset and authorized coding-on
|
|
|
83
83
|
assert.deepEqual(diff.added,[]);
|
|
84
84
|
assert.deepEqual(diff.removed,[]);
|
|
85
85
|
const packageVersion=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8')).version;
|
|
86
|
-
if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49','0.15.50','0.15.51','0.15.52','0.15.53','0.15.54','0.15.55','0.15.56','0.15.57','0.15.58','0.15.59','0.15.60','0.15.61','0.15.62','0.15.63','0.15.64','0.15.65','0.15.66','0.15.67'].includes(packageVersion)){
|
|
86
|
+
if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49','0.15.50','0.15.51','0.15.52','0.15.53','0.15.54','0.15.55','0.15.56','0.15.57','0.15.58','0.15.59','0.15.60','0.15.61','0.15.62','0.15.63','0.15.64','0.15.65','0.15.66','0.15.67','0.15.68','0.15.69'].includes(packageVersion)){
|
|
87
87
|
assert.deepEqual([...diff.schema_changed].sort(),['machine_fs','native_diff_preview']);
|
|
88
88
|
assert.equal(diff.unchanged.length,41);
|
|
89
89
|
const prior=baseline.tools.find(tool=>tool.name==='machine_fs');
|
|
@@ -49,6 +49,38 @@ test('a present grant with controller armed=false is unverified, not clean',asyn
|
|
|
49
49
|
}finally{await f.cleanup();}
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
+
test('a signed transaction revoke proves epoch-revoked disarmed while captured grant bytes remain',async()=>{
|
|
53
|
+
const stateRoot=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r173-epoch-proof-'));
|
|
54
|
+
try{
|
|
55
|
+
const runtime=path.join(stateRoot,'runtime'),policies=path.join(stateRoot,'policies');
|
|
56
|
+
await mkdir(runtime);await mkdir(policies);
|
|
57
|
+
const policyPaths={},policySha256={},authority={};
|
|
58
|
+
let codingGrant=null,codingPolicyBytes=null;
|
|
59
|
+
for(const plane of planes){
|
|
60
|
+
const grant=path.join(runtime,`${plane}-grant.json`),policyPath=path.join(policies,`${plane}.json`);
|
|
61
|
+
const bytes=Buffer.from(JSON.stringify({schema:`deadbyte.${plane}-policy.v${plane==='host'?2:1}`,enabled:true,
|
|
62
|
+
[grantField[plane]]:grant,...(plane==='coding'?{roots:{project:{path:path.join(stateRoot,'project')}}}:{})}));
|
|
63
|
+
await writeFile(policyPath,bytes);policyPaths[plane]=policyPath;policySha256[plane]=sha(bytes);
|
|
64
|
+
authority[plane]={configured:true,armed:false,reason:plane==='coding'?'epoch-revoked':'disarmed'};
|
|
65
|
+
if(plane==='coding'){codingGrant=grant;codingPolicyBytes=bytes;}
|
|
66
|
+
}
|
|
67
|
+
const nonce='7'.repeat(64),grantBytes=Buffer.from(JSON.stringify({schema:'deadbyte.coding-grant.v2',
|
|
68
|
+
policy_sha256:sha(codingPolicyBytes),instance_nonce:nonce,root_ids:['project'],granted_at_utc:new Date().toISOString()}));
|
|
69
|
+
await writeFile(codingGrant,grantBytes);
|
|
70
|
+
const grantSha=sha(grantBytes),eventSha='8'.repeat(64);
|
|
71
|
+
const proof=await observeAuthorityEvidence({stateRoot,policyPaths,policySha256,authority,
|
|
72
|
+
epochStoreFactory:()=>({
|
|
73
|
+
auditHistory:async()=>({status:'PASS',verified_events:2}),
|
|
74
|
+
readHead:async()=>({action:'transaction_revoke',seq:2,event_sha256:eventSha,policy_sha256:sha(codingPolicyBytes),
|
|
75
|
+
grant_sha256:grantSha,grant_instance_nonce:nonce,update_id:'r65-'+'8'.repeat(32)}),
|
|
76
|
+
verifyGrant:async()=>({trusted:false,reason:'epoch-revoked',event_sha256:eventSha})
|
|
77
|
+
})});
|
|
78
|
+
assert.equal(proof.coding.state,'VERIFIED_DISARMED');
|
|
79
|
+
assert.equal(proof.coding.grant_absent,false);
|
|
80
|
+
assert.equal(proof.coding.transaction_revoked,true);
|
|
81
|
+
}finally{await rm(stateRoot,{recursive:true,force:true});}
|
|
82
|
+
});
|
|
83
|
+
|
|
52
84
|
test('malformed policy cannot provide disarmed proof',async()=>{
|
|
53
85
|
const f=await fixture();
|
|
54
86
|
try{
|
|
@@ -73,8 +73,8 @@ test('R40 CLI exposes explicit verbose mode while keeping default live mode comp
|
|
|
73
73
|
const src=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
|
|
74
74
|
assert.match(src,/readLiveRootPaths\(ctx\.root\)/);
|
|
75
75
|
assert.match(src,/createLiveTimelineTracker\(\{verbose,displayMode,rootPaths,trace,\.\.\.defaultForegroundTimelineOptions\(\{verbose\}\)\}\)/);
|
|
76
|
-
assert.deepEqual(live.defaultForegroundTimelineOptions({verbose:false}),{commanderStyle:
|
|
77
|
-
assert.deepEqual(live.defaultForegroundTimelineOptions({verbose:true}),{commanderStyle:false,foldHeartbeats:false});
|
|
76
|
+
assert.deepEqual(live.defaultForegroundTimelineOptions({verbose:false}),{commanderStyle:false,foldHeartbeats:true,prettyStyle:true});
|
|
77
|
+
assert.deepEqual(live.defaultForegroundTimelineOptions({verbose:true}),{commanderStyle:false,foldHeartbeats:false,prettyStyle:false});
|
|
78
78
|
assert.match(src,/createLiveTimelineFilter\(filterExpression\)/);
|
|
79
79
|
assert.match(src,/createLiveTimelineWriter\(\{stream:process\.stdout,displayMode,rewrite:false\}\)/);
|
|
80
80
|
assert.match(src,/arg==='--verbose'\|\|arg==='-v'/);
|
|
@@ -9,7 +9,7 @@ test('R36 lifecycle formatter exposes device/connect/ready/cleanup states with b
|
|
|
9
9
|
assert.equal(formatRemoteLifecycle('session_new'),'[SESSION] New foreground session');
|
|
10
10
|
assert.equal(formatRemoteLifecycle('session_restored'),'♻️ [SESSION] Previous result stream replayed');
|
|
11
11
|
assert.equal(formatRemoteLifecycle('ready'),'✅ [READY] DEADBYTE MCP online');
|
|
12
|
-
assert.equal(formatRemoteLifecycle('cleanup'),'
|
|
12
|
+
assert.equal(formatRemoteLifecycle('cleanup'),'[SESSION] Closing observation session...');
|
|
13
13
|
assert.throws(()=>formatRemoteLifecycle('invented'),/unknown remote lifecycle/i);
|
|
14
14
|
});
|
|
15
15
|
|