deadbyte-mcp 0.15.59 → 0.15.61

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.
@@ -0,0 +1,58 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash,generateKeyPairSync,sign as signBytes} from 'node:crypto';
4
+ import {mkdtemp,mkdir,writeFile,rm} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {canonicalJson} from '../src/canonical-json.mjs';
8
+ import {createActivationClaimManager} from '../src/activation-lock-r65.mjs';
9
+
10
+ const sha=buffer=>createHash('sha256').update(buffer).digest('hex');
11
+ const domain=Buffer.from('DEADBYTE-R27-SLOT-UPDATE-V1\0','utf8');
12
+ const now=()=>new Date().toISOString();
13
+ function seal(body,key,pub){
14
+ const payload=Buffer.from(canonicalJson(body));
15
+ const signature=signBytes(null,Buffer.concat([domain,payload]),key).toString('base64');
16
+ const e={body,body_sha256:sha(payload),attestation:{algorithm:'ed25519',domain:'DEADBYTE-R27-SLOT-UPDATE-V1',
17
+ key_id:sha(pub.export({type:'spki',format:'der'})),signature_base64:signature}};
18
+ return {...e,receipt_sha256:sha(Buffer.from(canonicalJson(e)))};
19
+ }
20
+
21
+ test('signed R27 initial precondition reject safely reconciles R65 unknown claim',async()=>{
22
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r153-precondition-'));
23
+ try{
24
+ const updates=path.join(root,'evidence','updates');
25
+ await mkdir(updates,{recursive:true});await mkdir(path.join(root,'trust'),{recursive:true});
26
+ const {privateKey,publicKey}=generateKeyPairSync('ed25519');
27
+ await writeFile(path.join(root,'trust','ed25519-public.pem'),publicKey.export({type:'spki',format:'pem'}));
28
+ const manager=createActivationClaimManager({stateRoot:root}),claim=await manager.claim('a'.repeat(64));
29
+ const pointer={schema:'deadbyte.active-release.v1',release_id:'predecessor-r153',version:'0.15.45',
30
+ manifest_sha256:'b'.repeat(64),generation_manifest_sha256:'c'.repeat(64)};
31
+ await writeFile(path.join(root,'active-release.json'),JSON.stringify(pointer));
32
+ const dir=path.join(updates,'r27-'+'d'.repeat(16)+'-synthetic');
33
+ await mkdir(dir);
34
+ const failure=seal({schema:'deadbyte.r27-slot-update-failure.v1',update_id:path.basename(dir),
35
+ release_version:'0.15.61',candidate_manifest_sha256:'d'.repeat(64),failed_at_utc:now(),
36
+ result:'PRECONDITION_REJECTED',phase:'initial',error:{name:'Error',message:"host command 'powershell_script' executable pin drift detected; explicit approval required"},
37
+ prior_pointer:pointer,attempted_pointer:null,rollback:{attempted:false,errors:[]}},privateKey,publicKey);
38
+ await writeFile(path.join(dir,'failure-receipt.json'),JSON.stringify(failure));
39
+ await writeFile(path.join(updates,'r65-activation-outcome-test.json'),JSON.stringify({
40
+ schema:'deadbyte.r65-activation-outcome.v1',claim_operation_id:claim.operation_id,
41
+ preflight_subject_sha256:claim.subject_sha256,candidate_version:'0.15.61',
42
+ candidate_manifest_sha256:'d'.repeat(64),predecessor_release_id:pointer.release_id,
43
+ outcome:{state:'ACTIVATION_OUTCOME_UNKNOWN'},update_id:null,continuity_update_id:null,state_path:null,observed_at_utc:now()
44
+ }));
45
+ // A tampered signed envelope must not authorize reclaim.
46
+ const failurePath=path.join(dir,'failure-receipt.json');
47
+ await writeFile(failurePath,JSON.stringify({...failure,body:{...failure.body,phase:'committing'}}));
48
+ await assert.rejects(()=>manager.claim('e'.repeat(64)),/unresolved|in progress/);
49
+ await writeFile(failurePath,JSON.stringify(failure));
50
+ // Even a valid signature cannot authorize reclaim if the live pointer changed.
51
+ await writeFile(path.join(root,'active-release.json'),JSON.stringify({...pointer,release_id:'foreign-runtime'}));
52
+ await assert.rejects(()=>manager.claim('e'.repeat(64)),/unresolved|in progress/);
53
+ await writeFile(path.join(root,'active-release.json'),JSON.stringify(pointer));
54
+ const next=await manager.claim('e'.repeat(64));
55
+ assert.notEqual(next.operation_id,claim.operation_id);
56
+ await next.release();
57
+ }finally{await rm(root,{recursive:true,force:true})}
58
+ });
@@ -20,28 +20,39 @@ test('R153 Windows ACL reproduction rejects stripped leaf ACE and restores direc
20
20
  $root = Join-Path $env:TEMP ('r153-native-acl-test-' + [guid]::NewGuid().ToString('N'))
21
21
  $sid = [Security.Principal.WindowsIdentity]::GetCurrent().User.Value
22
22
  $leaf = Join-Path $root 'child\file.txt'
23
+ function Read-Digest([string]$Path) {
24
+ try {
25
+ $sha = [Security.Cryptography.SHA256]::Create()
26
+ try { return ([BitConverter]::ToString($sha.ComputeHash([IO.File]::ReadAllBytes($Path)))).Replace('-','') }
27
+ finally { $sha.Dispose() }
28
+ } catch [UnauthorizedAccessException] { return $null }
29
+ }
23
30
  try {
24
31
  New-Item -ItemType Directory -Path (Split-Path -Parent $leaf) -Force | Out-Null
25
32
  [IO.File]::WriteAllText($leaf,'read-only regression fixture')
26
33
  & icacls.exe $root '/inheritance:r' '/grant:r' ('*'+$sid+':(OI)(CI)(F)') '/T' '/C' | Out-Null
27
34
  if($LASTEXITCODE -ne 0){throw 'REPRO_SETUP_FAILED'}
28
- $blocked = Get-FileHash -LiteralPath $leaf -Algorithm SHA256 -ErrorAction SilentlyContinue
35
+ $blocked = Read-Digest $leaf
29
36
  if($null -ne $blocked){throw 'REPRO_DID_NOT_STRIP_LEAF_ACE'}
30
37
  & icacls.exe $root '/grant' ('*'+$sid+':(F)') '/T' '/C' | Out-Null
31
38
  if($LASTEXITCODE -ne 0){throw 'LEAF_REPAIR_FAILED'}
32
- $restored = Get-FileHash -LiteralPath $leaf -Algorithm SHA256
33
- if($null -eq $restored -or $restored.Hash.Length -ne 64){throw 'LEAF_NOT_READABLE_AFTER_REPAIR'}
34
- $acl = Get-Acl -LiteralPath $leaf
35
- $allow=@($acl.Access | Where-Object {$_.AccessControlType -eq 'Allow'})
39
+ $restored = Read-Digest $leaf
40
+ if($null -eq $restored -or $restored.Length -ne 64){throw 'LEAF_NOT_READABLE_AFTER_REPAIR'}
41
+ $acl = [IO.File]::GetAccessControl($leaf)
42
+ $allow=@($acl.GetAccessRules($true,$true,[Security.Principal.SecurityIdentifier]) | Where-Object {$_.AccessControlType -eq 'Allow'})
36
43
  if($allow.Count -ne 1){throw 'LEAF_HAS_UNEXPECTED_ALLOW_ACE_COUNT'}
37
- if($allow[0].IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value -ne $sid){throw 'LEAF_HAS_UNEXPECTED_TRUSTEE'}
44
+ if($allow[0].IdentityReference.Value -ne $sid){throw 'LEAF_HAS_UNEXPECTED_TRUSTEE'}
38
45
  Write-Output 'R153_WIN32_LEAF_ACL_REPAIR_PASS'
39
46
  } finally {
40
- if(Test-Path -LiteralPath $root){Remove-Item -LiteralPath $root -Force -Recurse}
47
+ if(Test-Path -LiteralPath $root){
48
+ & icacls.exe $root '/reset' '/T' '/C' | Out-Null
49
+ & icacls.exe $root '/inheritance:e' '/grant:r' ('*'+$sid+':(OI)(CI)(F)') '/T' '/C' | Out-Null
50
+ Remove-Item -LiteralPath $root -Force -Recurse
51
+ }
41
52
  }`;
42
53
  const encoded=Buffer.from(ps,'utf16le').toString('base64');
43
54
  const result=spawnSync('powershell.exe',['-NoLogo','-NoProfile','-NonInteractive','-EncodedCommand',encoded],
44
55
  {encoding:'utf8',timeout:30000,maxBuffer:256*1024});
45
56
  assert.equal(result.status,0,result.stderr||result.stdout||String(result.error));
46
57
  assert.match(result.stdout,/R153_WIN32_LEAF_ACL_REPAIR_PASS/);
47
- });
58
+ });
@@ -4,12 +4,13 @@ import {createUacApproval,verifyUacApproval,validateApprovalWindow,requireTruste
4
4
  import {readFileSync} from 'node:fs';
5
5
  import {fileURLToPath} from 'node:url';
6
6
  const h=(n)=>n.repeat(64);
7
- const base=()=>({stateRoot:'C:\\Users\\DEADBYTE\\.deadbyte-mcp',candidateRoot:'C:\\Program Files\\DEADBYTE-R153-TEST',candidateVersion:'0.15.59',candidateManifestSha256:h('a'),tarballSha256:h('b'),markerReceiptSha256:h('c'),predecessorPointerSha256:h('d'),predecessorPolicySha256:{process:h('1'),coding:h('2'),autonomous:h('3'),desktop:h('4'),host:h('5')},preflightSubjectSha256:h('e'),nodeSha256:h('f'),deployScriptSha256:h('0'),nonce:h('6'),issuedAt:'2026-10-24T00:00:00.000Z',expiresAt:'2026-10-24T00:05:00.000Z'});
7
+ const base=()=>({stateRoot:'C:\\Users\\DEADBYTE\\.deadbyte-mcp',candidateRoot:'C:\\Program Files\\DEADBYTE-R153-TEST',candidateVersion:'0.15.61',candidateManifestSha256:h('a'),tarballSha256:h('b'),markerReceiptSha256:h('c'),predecessorPointerSha256:h('d'),predecessorPolicySha256:{process:h('1'),coding:h('2'),autonomous:h('3'),desktop:h('4'),host:h('5')},preflightSubjectSha256:h('e'),nodeSha256:h('f'),deployScriptSha256:h('0'),hostCommandPins:[],nonce:h('6'),issuedAt:'2026-10-24T00:00:00.000Z',expiresAt:'2026-10-24T00:05:00.000Z'});
8
8
  test('R153 UAC receipt carries exact no-grants narrow migration subject',()=>{
9
- const x=base(),receipt=createUacApproval(x);
9
+ const x={...base(),hostCommandPins:[{command_id:'powershell_script',sha256:h('a')},{command_id:'cmd_script',sha256:h('b')}]},receipt=createUacApproval(x);
10
10
  assert.equal(receipt.schema,'deadbyte.r153-uac-approval.v1');
11
11
  assert.equal(receipt.action,'narrow_legacy_policy_and_activate');
12
12
  assert.deepEqual(receipt.allowed_authority_after,{process:false,coding:false,autonomous:false,desktop:false,host:false});
13
+ assert.deepEqual(receipt.host_command_pins,[{command_id:'cmd_script',sha256:h('b')},{command_id:'powershell_script',sha256:h('a')}]);
13
14
  assert.match(receipt.subject_sha256,/^[0-9a-f]{64}$/);
14
15
  assert.deepEqual(verifyUacApproval(receipt,x,{now:'2026-10-24T00:02:00.000Z'}),receipt);
15
16
  });
@@ -19,6 +20,7 @@ test('R153 UAC receipt rejects drift across every authority/candidate/runtime in
19
20
  assert.throws(()=>verifyUacApproval(receipt,{...x,[key]:value},{now:'2026-10-24T00:02:00.000Z'}),undefined,key);
20
21
  }
21
22
  assert.throws(()=>verifyUacApproval(receipt,{...x,predecessorPolicySha256:{...x.predecessorPolicySha256,host:h('a')}},{now:'2026-10-24T00:02:00.000Z'}));
23
+ assert.throws(()=>verifyUacApproval(receipt,{...x,hostCommandPins:[{command_id:'cmd_script',sha256:h('a')}]},{now:'2026-10-24T00:02:00.000Z'}));
22
24
  });
23
25
  test('R153 UAC receipt fails closed on expiration, malformed, replay-like tamper and grant widening',()=>{
24
26
  const x=base(),receipt=createUacApproval(x);
@@ -31,7 +33,7 @@ test('R153 UAC receipt fails closed on expiration, malformed, replay-like tamper
31
33
  assert.throws(()=>createUacApproval({...x,issuedAt:'not-a-date'}));
32
34
  assert.throws(()=>createUacApproval({...x,nonce:'x'}));
33
35
  });
34
- test('R153 UAC scope only accepts protected root and exact v0.15.59',()=>{
36
+ test('R154 UAC scope only accepts protected root and exact v0.15.61',()=>{
35
37
  assert.throws(()=>createUacApproval({...base(),candidateRoot:'C:\\Users\\DEADBYTE\\npm-cache'}),/protected/i);
36
38
  assert.throws(()=>createUacApproval({...base(),candidateVersion:'0.15.55'}),/candidate/i);
37
39
  assert.throws(()=>validateApprovalWindow('2026-10-24T00:00:00.000Z','2026-10-24T00:00:00.000Z','2026-10-24T00:00:00.000Z'));
@@ -45,7 +45,7 @@ test('R153 RED: mutable npx entrypoint stages exact registry package before priv
45
45
  assert.doesNotMatch(script,/npm-cli\.js|npm install/i);
46
46
  assert.match(script,/Get-FileHash -LiteralPath \$file -Algorithm SHA256/);
47
47
  assert.match(script,/NODE_OPTIONS/);
48
- assert.match(script,/https:\/\/registry\.npmjs\.org\/deadbyte-mcp\/0\.15\.59/);
48
+ assert.match(script,/https:\/\/registry\.npmjs\.org\/deadbyte-mcp\/0\.15\.61/);
49
49
  assert.match(script,/live npm registry tarball SHA-256 mismatch/);
50
50
  assert.match(script,/live npm registry tarball integrity mismatch/);
51
51
  assert.match(script,/DEADBYTE-R153-Stage-/);
@@ -54,6 +54,7 @@ test('R153 RED: mutable npx entrypoint stages exact registry package before priv
54
54
  assert.match(script,/'\/inheritance:r'/);
55
55
  assert.match(script,/verify-protected-stage-r153\.mjs/);
56
56
  assert.match(script,/request-uac-migration-r153\.ps1/);
57
- assert.match(script,/& \$helper -Elevated/);
57
+ assert.match(script,/\$helperArgs\s*=\s*@\('-Elevated'/);
58
+ assert.match(script,/& \$helper @helperArgs/);
58
59
  assert.match(script,/Remove-Item -LiteralPath \$prefix -Recurse -Force/);
59
60
  });
@@ -0,0 +1,45 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {spawnSync} from 'node:child_process';
4
+ import {fileURLToPath} from 'node:url';
5
+ import {
6
+ normalizeHostCommandPins,
7
+ encodeHostCommandPins,
8
+ decodeHostCommandPins
9
+ } from '../src/host-command-pins-r154.mjs';
10
+
11
+ const h=value=>value.repeat(64);
12
+
13
+ test('R154 accepts a bounded set of distinct existing-command repins',()=>{
14
+ const pins=normalizeHostCommandPins([
15
+ `powershell_script=${h('a')}`,
16
+ `cmd_script=${h('b')}`,
17
+ `cmd_inline=${h('b')}`
18
+ ]);
19
+ assert.deepEqual(pins,[
20
+ {command_id:'cmd_inline',sha256:h('b')},
21
+ {command_id:'cmd_script',sha256:h('b')},
22
+ {command_id:'powershell_script',sha256:h('a')}
23
+ ]);
24
+ assert.deepEqual(decodeHostCommandPins(encodeHostCommandPins(pins)),pins);
25
+ });
26
+
27
+ test('R154 rejects duplicate, malformed, oversized, and delimiter-injected repins',()=>{
28
+ assert.throws(()=>normalizeHostCommandPins([`cmd_script=${h('a')}`,`cmd_script=${h('a')}`]),/duplicate/i);
29
+ assert.throws(()=>normalizeHostCommandPins([`unrelated_command=${h('a')}`]),/not repinnable/i);
30
+ assert.throws(()=>normalizeHostCommandPins([`bad/name=${h('a')}`]),/contract/i);
31
+ assert.throws(()=>normalizeHostCommandPins([`cmd_script=${h('A')}`]),/contract/i);
32
+ assert.throws(()=>normalizeHostCommandPins(Array.from({length:17},(_,i)=>`cmd_${i}=${h('a')}`)),/limit/i);
33
+ assert.throws(()=>decodeHostCommandPins('["cmd_script='+h('a')+'","evil"]'),/contract/i);
34
+ });
35
+
36
+ test('R154 CLI no longer rejects the second explicit command repin in parsing',()=>{
37
+ const cli=fileURLToPath(new URL('../src/deadbyte-cli.mjs',import.meta.url));
38
+ const run=spawnSync(process.execPath,[cli,'remote',
39
+ '--host-command-pin',`powershell_script=${h('a')}`,
40
+ '--host-command-pin',`cmd_script=${h('b')}`,
41
+ 'status'],{encoding:'utf8',timeout:8000});
42
+ assert.equal(run.status,1);
43
+ assert.doesNotMatch(run.stderr,/may be specified once|requires powershell_script/);
44
+ assert.match(run.stderr,/presentation flags are valid only for foreground session/);
45
+ });
@@ -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'].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'].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');