deadbyte-mcp 0.15.71 → 0.15.74

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.
Files changed (82) hide show
  1. package/MANIFEST.SHA256 +81 -28
  2. package/PROVENANCE.json +56 -16
  3. package/README.txt +24 -18
  4. package/RELEASE.json +67 -18
  5. package/SBOM.cdx.json +14 -2
  6. package/TEST-MATRIX.json +44 -2
  7. package/bin/deadbyte-owner-token-r193.exe +0 -0
  8. package/bridge/package.json +1 -1
  9. package/controller/deadbyte-process-policy.json +4 -4
  10. package/docs/R184-package-lock.json +2 -2
  11. package/docs/R192-LIVE-LOG-HARDENING.txt +39 -0
  12. package/native/deadbyte-owner-token-r193.cpp +156 -0
  13. package/package.json +2 -2
  14. package/scripts/gate-windows-r193.ps1 +108 -0
  15. package/scripts/gate-windows-r194.ps1 +112 -0
  16. package/scripts/npm-interactive-r194.mjs +13 -0
  17. package/scripts/npm-publication-r65.mjs +64 -4
  18. package/scripts/npm-release-r48.mjs +58 -11
  19. package/scripts/npm-release-readiness-r193.mjs +80 -0
  20. package/scripts/npm-release-readiness-r194.mjs +80 -0
  21. package/scripts/r188-owner-uac-review.ps1 +91 -0
  22. package/scripts/r188-uac-review-preview.mjs +65 -0
  23. package/scripts/r192-focused.mjs +10 -0
  24. package/scripts/r192-release-tests.mjs +8 -0
  25. package/scripts/r193-compile-token.ps1 +22 -0
  26. package/scripts/r193-evidence-relocate.ps1 +12 -0
  27. package/scripts/r193-focused-gate.mjs +20 -0
  28. package/scripts/r193-import-r188-scripts.ps1 +14 -0
  29. package/scripts/r193-limited-subject-probe.ps1 +25 -0
  30. package/scripts/r193-migrate-runtime-limited.ps1 +103 -0
  31. package/scripts/r193-owner-keygen.mjs +43 -0
  32. package/scripts/r193-owner-request-live.mjs +50 -0
  33. package/scripts/r193-owner-uac-approve.ps1 +42 -0
  34. package/scripts/r193-owner-uac-broker.mjs +139 -0
  35. package/scripts/r193-owner-uac-enroll-and-approve.ps1 +62 -0
  36. package/scripts/r193-test-limited-token.ps1 +49 -0
  37. package/scripts/r193-toolchain-inventory.ps1 +7 -0
  38. package/scripts/r193-uac-bridge-focused.mjs +21 -0
  39. package/src/deadbyte-cli.mjs +2 -1
  40. package/src/r188-owner-uac.mjs +105 -0
  41. package/src/r188-uac-boundary.mjs +21 -0
  42. package/src/r193-live-owner-subject.mjs +110 -0
  43. package/src/r193-owner-secret-acl.mjs +67 -0
  44. package/src/r193-owner-uac-broker.mjs +85 -0
  45. package/src/r193-uac-r70-bridge.mjs +54 -0
  46. package/src/remote-live-log.mjs +22 -1
  47. package/src/version.mjs +1 -1
  48. package/test/process-policy-refresh.test.mjs +1 -1
  49. package/test/r130-release-security-contract.test.mjs +8 -8
  50. package/test/r132-release-identity.test.mjs +7 -7
  51. package/test/r153-prepublish-identity.test.mjs +1 -1
  52. package/test/r160-release-contract.test.mjs +3 -3
  53. package/test/r165-live-cli-skew.test.mjs +1 -1
  54. package/test/r167-release-contract.test.mjs +11 -11
  55. package/test/r168-release-contract.test.mjs +4 -2
  56. package/test/r172-release-contract.test.mjs +6 -6
  57. package/test/r173-release-contract.test.mjs +16 -16
  58. package/test/r179-release-contract.test.mjs +11 -11
  59. package/test/r188-owner-uac.test.mjs +48 -0
  60. package/test/r188-uac-boundary.test.mjs +42 -0
  61. package/test/r190-release-contract.test.mjs +10 -10
  62. package/test/r191-release-contract.test.mjs +12 -12
  63. package/test/r192-live-log-hardening.test.mjs +50 -0
  64. package/test/r192-release-identity.test.mjs +40 -0
  65. package/test/r193-limited-migration-contract.test.mjs +26 -0
  66. package/test/r193-live-owner-subject.test.mjs +61 -0
  67. package/test/r193-native-process-observer.test.mjs +36 -0
  68. package/test/r193-native-token.test.mjs +43 -0
  69. package/test/r193-owner-enrollment-entrypoint.test.mjs +38 -0
  70. package/test/r193-owner-secret-acl.test.mjs +23 -0
  71. package/test/r193-owner-uac-broker.test.mjs +82 -0
  72. package/test/r193-owner-uac-entrypoint.test.mjs +36 -0
  73. package/test/r193-release-identity.test.mjs +56 -0
  74. package/test/r193-release-readiness.test.mjs +87 -0
  75. package/test/r193-uac-r70-bridge.test.mjs +88 -0
  76. package/test/r193-windows-gate.test.mjs +30 -0
  77. package/test/r194-npm-auth-recovery.test.mjs +77 -0
  78. package/test/r194-npm-preauth.test.mjs +57 -0
  79. package/test/r194-release-identity.test.mjs +43 -0
  80. package/test/r194-release-readiness.test.mjs +87 -0
  81. package/test/r194-windows-gate.test.mjs +21 -0
  82. package/test/r59-tool-surface-compat.test.mjs +1 -1
@@ -0,0 +1,105 @@
1
+ // R188 - no Windows Hello, no PEM owner key, no grant issuance.
2
+ // Unprivileged challenge creation and read-only owner-review validation.
3
+ // Only an independently launched, R89-protected native elevated broker
4
+ // may record an actual approval. Do not turn this into a grant primitive.
5
+ import {createHash,randomBytes} from 'node:crypto';
6
+ import path from 'node:path';
7
+ import {canonicalJson} from './canonical-json.mjs';
8
+ const SHA=/^[a-f0-9]{64}$/;
9
+ const CHALLENGE=/^[A-Za-z0-9_-]{43}$/;
10
+ const ID=/^[A-Za-z0-9._-]{1,64}$/;
11
+ const digest=x=>createHash('sha256').update(Buffer.from(canonicalJson(x),'utf8')).digest('hex');
12
+ function invalid(msg){throw Error('R188 '+msg);}
13
+ function exact(value,fields,label){
14
+ if(!value||typeof value!=='object'||Array.isArray(value)||
15
+ Object.keys(value).length!==fields.length||
16
+ fields.some(f=>!Object.hasOwn(value,f)))invalid(label+' schema mismatch');
17
+ }
18
+ function project(p){
19
+ if(typeof p!=='string'||!path.win32.isAbsolute(p)||p.startsWith('\\\\')||
20
+ path.win32.normalize(p).toLowerCase()===path.win32.parse(p).root.toLowerCase())
21
+ invalid('project root must be a bounded local Windows path');
22
+ return path.win32.normalize(p);
23
+ }
24
+ function fields(o){
25
+ for(const k of ['machineEpoch','releaseManifestSha256','codingPolicySha256','autonomousPolicySha256']){
26
+ if(typeof o?.[k]!=='string'||!SHA.test(o[k]))invalid('invalid '+k);
27
+ }
28
+ if(o.rootId!=='core'||!ID.test(o.rootId))invalid('root scope must be core');
29
+ const root=project(o.projectRoot);
30
+ if(!Number.isSafeInteger(o.maxSeconds)||o.maxSeconds<1||o.maxSeconds>3600)
31
+ invalid('maxSeconds outside owner-reviewed window');
32
+ return root;
33
+ }
34
+ const scopeKeys=['schema','machine_epoch','release_manifest_sha256',
35
+ 'coding_policy_sha256','autonomous_policy_sha256','root_id','project_root',
36
+ 'operation','max_seconds','issued_at_utc','expires_at_utc'];
37
+ const requestKeys=['schema','challenge','subject','request_sha256','review_phrase',
38
+ 'owner_approved','authority_granted','require_interactive_uac'];
39
+ function iso(v){
40
+ if(typeof v!=='string'||!/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(v)||
41
+ !Number.isFinite(Date.parse(v))||new Date(v).toISOString()!==v)
42
+ invalid('UTC time not canonical');
43
+ return Date.parse(v);
44
+ }
45
+ function hashFor(challenge,subject){return digest({schema:'deadbyte.r188-owner-uac-request.v1',challenge,subject});}
46
+ function phrase(hash){return 'APPROVE-'+hash.slice(0,12).toUpperCase();}
47
+ export function createR188OwnerUacRequest({
48
+ machineEpoch,releaseManifestSha256,codingPolicySha256,autonomousPolicySha256,
49
+ rootId,projectRoot,maxSeconds,now=new Date(),expiresInMs=120000
50
+ }={}){
51
+ const input={machineEpoch,releaseManifestSha256,codingPolicySha256,
52
+ autonomousPolicySha256,rootId,projectRoot,maxSeconds};
53
+ const normalized=fields(input);
54
+ if(!(now instanceof Date)||!Number.isFinite(now.getTime())||
55
+ !Number.isSafeInteger(expiresInMs)||expiresInMs<1000||expiresInMs>300000)
56
+ invalid('request lifetime invalid');
57
+ const subject=Object.freeze({
58
+ schema:'deadbyte.r188-owner-uac-subject.v1',machine_epoch:machineEpoch,
59
+ release_manifest_sha256:releaseManifestSha256,
60
+ coding_policy_sha256:codingPolicySha256,
61
+ autonomous_policy_sha256:autonomousPolicySha256,
62
+ root_id:rootId,project_root:normalized,
63
+ operation:'autonomous_goal_run',max_seconds:maxSeconds,
64
+ issued_at_utc:now.toISOString(),
65
+ expires_at_utc:new Date(now.getTime()+expiresInMs).toISOString()
66
+ });
67
+ const challenge=randomBytes(32).toString('base64url');
68
+ const request_sha256=hashFor(challenge,subject);
69
+ return Object.freeze({schema:'deadbyte.r188-owner-uac-request.v1',
70
+ challenge,subject,request_sha256,review_phrase:phrase(request_sha256),
71
+ owner_approved:false,authority_granted:false,require_interactive_uac:true});
72
+ }
73
+ export function verifyR188OwnerUacRequest({request,expected,now=new Date()}={}){
74
+ exact(request,requestKeys,'request');exact(request.subject,scopeKeys,'subject');
75
+ const subject=request.subject;
76
+ const root=fields(expected);
77
+ if(request.schema!=='deadbyte.r188-owner-uac-request.v1'||
78
+ subject.schema!=='deadbyte.r188-owner-uac-subject.v1'||
79
+ request.owner_approved!==false||request.authority_granted!==false||
80
+ request.require_interactive_uac!==true||
81
+ typeof request.challenge!=='string'||!CHALLENGE.test(request.challenge)||
82
+ Buffer.from(request.challenge,'base64url').length!==32||
83
+ Buffer.from(request.challenge,'base64url').toString('base64url')!==request.challenge)
84
+ invalid('request shape or challenge invalid');
85
+ const expectedBindings={
86
+ machine_epoch:expected.machineEpoch,release_manifest_sha256:expected.releaseManifestSha256,
87
+ coding_policy_sha256:expected.codingPolicySha256,
88
+ autonomous_policy_sha256:expected.autonomousPolicySha256,root_id:expected.rootId,
89
+ project_root:root,operation:'autonomous_goal_run',max_seconds:expected.maxSeconds
90
+ };
91
+ for(const [k,v] of Object.entries(expectedBindings)){
92
+ if(subject[k]!==v)invalid('request scope mismatch: '+k);
93
+ }
94
+ if(!(now instanceof Date)||!Number.isFinite(now.getTime()))invalid('current time invalid');
95
+ const issued=iso(subject.issued_at_utc),expires=iso(subject.expires_at_utc);
96
+ if(expires<=issued||expires-issued>300000||
97
+ now.getTime()<issued||now.getTime()>=expires)invalid('request expired or not yet valid');
98
+ if(typeof request.request_sha256!=='string'||!SHA.test(request.request_sha256)||
99
+ request.request_sha256!==hashFor(request.challenge,subject)||
100
+ request.review_phrase!==phrase(request.request_sha256))
101
+ invalid('request digest or owner phrase altered');
102
+ return Object.freeze({status:'VERIFIED_FOR_REVIEW_ONLY',request_sha256:request.request_sha256,
103
+ review_phrase:request.review_phrase,authority_granted:false,owner_approved:false,
104
+ next_gate:'PROTECTED_INTERACTIVE_UAC_WITH_EXACT_REQUEST_AND_EPOCH'});
105
+ }
@@ -0,0 +1,21 @@
1
+ // R188: pure fail-closed decision gate, NOT proof of a Windows UAC action.
2
+ // A privileged native broker MUST determine these facts independently using
3
+ // token and ACL inspection. Never accept a caller's self-reported booleans.
4
+ export function assessR188UacBoundary(e={}){
5
+ const finish=(reason)=>Object.freeze({schema:'deadbyte.r188-uac-boundary.v1',
6
+ status:'BLOCKED',reason,authority_granted:false,grant_issued:false});
7
+ if(e.codingElevation!=='standard')return finish('CODING_ALREADY_ELEVATED');
8
+ if(e.privilegedParentReachable!==false)return finish('ELEVATED_PARENT_STILL_REACHABLE');
9
+ if(e.ownerElevation!=='elevated')return finish('OWNER_NOT_ELEVATED');
10
+ if(e.protectedBroker!==true)return finish('BROKER_NOT_PROTECTED');
11
+ if(e.enableUac!==true||e.secureDesktop!==true||
12
+ e.promptMode!=='explicit_secure_desktop')
13
+ return finish('UAC_NOT_INTERACTIVE_AND_SECURE');
14
+ if(e.nativeEpochPinned!==true||e.releaseAndPoliciesPinned!==true)
15
+ return finish('AUTHORITY_EPOCH_OR_POLICY_NOT_PINNED');
16
+ if(e.ownerGesture!=='approved')return finish('OWNER_NOT_APPROVED');
17
+ return Object.freeze({schema:'deadbyte.r188-uac-boundary.v1',
18
+ status:'ELIGIBLE_FOR_PROTECTED_OWNER_REVIEW',reason:null,
19
+ authority_granted:false,grant_issued:false,
20
+ next_gate:'SIGNED_EPOCH_ONE_TIME_GRANT_TRANSACTION'});
21
+ }
@@ -0,0 +1,110 @@
1
+ // Build the R193 owner-signing subject from independently observed live state.
2
+ // No caller-supplied digest is trusted until it matches these exact bytes.
3
+ import {createHash} from 'node:crypto';
4
+ import {canonicalJson} from './canonical-json.mjs';
5
+ import {verifyR188OwnerUacRequest} from './r188-owner-uac.mjs';
6
+
7
+ const SHA=/^[a-f0-9]{64}$/;
8
+ const FILETIME=/^[a-f0-9]{16}$/;
9
+ const COMPONENTS=Object.freeze(['bridge','cloud','core','supervisor']);
10
+ const PLANES=Object.freeze(['process','coding','autonomous','desktop','host']);
11
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
12
+ function block(reason){throw new Error('R193 live owner subject blocked: '+reason);}
13
+ function record(value,label){if(!value||typeof value!=='object'||Array.isArray(value))block(label+' invalid');return value;}
14
+ function digest(value,label){if(typeof value!=='string'||!SHA.test(value))block(label+' invalid');return value;}
15
+ function samePath(a,b){return typeof a==='string'&&typeof b==='string'&&
16
+ a.replaceAll('/','\\').toLowerCase()===b.replaceAll('/','\\').toLowerCase();}
17
+ function isoFiletime(value){
18
+ const match=/^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d)\.(\d{1,7})Z$/.exec(value??'');
19
+ if(!match)block('process creation UTC invalid');
20
+ const base=Date.parse(match[1]+'.000Z');
21
+ if(!Number.isFinite(base))block('process creation UTC invalid');
22
+ return (BigInt(base+11644473600000)*10000n+
23
+ BigInt(match[2].padEnd(7,'0'))).toString(16).padStart(16,'0');
24
+ }
25
+ function authorityVector(observation){
26
+ const authority=record(observation.authority,'authority observation');
27
+ const out={};
28
+ for(const plane of PLANES){
29
+ const item=record(authority[plane],plane+' authority');
30
+ if(typeof item.configured!=='boolean'||typeof item.armed!=='boolean'||
31
+ typeof item.reason!=='string'||item.reason.length<1||item.reason.length>64)
32
+ block(plane+' authority fields invalid');
33
+ const seq=item.epoch_seq??null,head=item.epoch_sha256??null;
34
+ if((seq!==null&&(!Number.isSafeInteger(seq)||seq<0))||
35
+ (head!==null&&!SHA.test(head)))block(plane+' epoch identity invalid');
36
+ if(item.armed===true&&(seq===null||head===null))block(plane+' armed epoch missing');
37
+ out[plane]={configured:item.configured,armed:item.armed,reason:item.reason,
38
+ epoch_seq:seq,epoch_sha256:head};
39
+ }
40
+ return out;
41
+ }
42
+
43
+ export function createR193LiveMachineEpoch({activePointer,controllerObservation}={}){
44
+ const pointer=record(activePointer,'active pointer');
45
+ const observation=record(controllerObservation,'controller observation');
46
+ for(const field of ['release_id','version','manifest_sha256','generation_manifest_sha256'])
47
+ if(typeof pointer[field]!=='string'||!pointer[field])block('active pointer '+field+' invalid');
48
+ digest(pointer.manifest_sha256,'release manifest SHA-256');
49
+ digest(pointer.generation_manifest_sha256,'generation manifest SHA-256');
50
+ if(observation.schema!=='deadbyte.controller-observation.v1'||
51
+ !samePath(observation.core_root,pointer.release_root))
52
+ block('controller does not match active release');
53
+ return sha(Buffer.from(canonicalJson({
54
+ schema:'deadbyte.r193-live-machine-epoch.v1',
55
+ release_id:pointer.release_id,version:pointer.version,
56
+ manifest_sha256:pointer.manifest_sha256,
57
+ generation_manifest_sha256:pointer.generation_manifest_sha256,
58
+ authority:authorityVector(observation)
59
+ }),'utf8'));
60
+ }
61
+
62
+ export function buildR193LiveOwnerBoundary({request,activePointer,installedManifestBytes,
63
+ codingPolicyBytes,autonomousPolicyBytes,controllerObservation,supervisorLedger,
64
+ processReports,brokerR89Trusted,keyAclTrusted,uac,ownerGesture,now=new Date()}={}){
65
+ if(!Buffer.isBuffer(installedManifestBytes)||installedManifestBytes.length<1)block('manifest bytes missing');
66
+ if(!Buffer.isBuffer(codingPolicyBytes)||codingPolicyBytes.length<1)block('Coding policy bytes missing');
67
+ if(!Buffer.isBuffer(autonomousPolicyBytes)||autonomousPolicyBytes.length<1)block('Autonomous policy bytes missing');
68
+ const pointer=record(activePointer,'active pointer');
69
+ const observation=record(controllerObservation,'controller observation');
70
+ const manifestSha=sha(installedManifestBytes),codingSha=sha(codingPolicyBytes),autonomousSha=sha(autonomousPolicyBytes);
71
+ if(pointer.manifest_sha256!==manifestSha)block('active release manifest drift');
72
+ if(request?.subject?.release_manifest_sha256!==manifestSha||
73
+ request?.subject?.coding_policy_sha256!==codingSha||
74
+ request?.subject?.autonomous_policy_sha256!==autonomousSha)
75
+ block('request release or policy drift');
76
+ const machineEpoch=createR193LiveMachineEpoch({activePointer:pointer,controllerObservation:observation});
77
+ const expected={machineEpoch,releaseManifestSha256:manifestSha,codingPolicySha256:codingSha,
78
+ autonomousPolicySha256:autonomousSha,rootId:request?.subject?.root_id,
79
+ projectRoot:request?.subject?.project_root,maxSeconds:request?.subject?.max_seconds};
80
+ verifyR188OwnerUacRequest({request,expected,now});
81
+ const supervisor=record(supervisorLedger,'supervisor ledger');
82
+ const sources={bridge:observation.bridge,core:observation.core,cloud:observation.cloud,supervisor};
83
+ const reports=record(processReports,'native process reports');
84
+ const agent_processes=[];
85
+ for(const component of COMPONENTS){
86
+ const source=record(sources[component],component+' identity');
87
+ const report=record(reports[component],component+' token report');
88
+ if(source.alive!==true&&component!=='supervisor')block(component+' is not alive');
89
+ if(component==='supervisor'&&observation.supervisor?.running!==true)block('supervisor is not running');
90
+ if(report.schema!=='deadbyte.r193-native-process-token.v1'||report.alive!==true||
91
+ report.identity_verified!==true||report.pid!==source.pid||
92
+ !FILETIME.test(report.creation_filetime_hex)||
93
+ report.creation_filetime_hex!==isoFiletime(source.creation_time_utc))
94
+ block(component+' native process identity mismatch');
95
+ agent_processes.push({component,pid:report.pid,
96
+ creation_time_utc:new Date(Date.parse(source.creation_time_utc)).toISOString(),
97
+ alive:true,identity_verified:true,elevated:report.elevated,
98
+ admin_enabled:report.admin_enabled,integrity_rid:report.integrity_rid,
99
+ token_type:report.token_type});
100
+ }
101
+ const u=record(uac,'UAC policy');
102
+ return Object.freeze({expected:Object.freeze(expected),boundary:Object.freeze({
103
+ schema:'deadbyte.r193-owner-runtime-boundary.v1',
104
+ broker_r89_trusted:brokerR89Trusted===true,key_acl_trusted:keyAclTrusted===true,
105
+ enable_uac:u.enable_uac===true,secure_desktop:u.secure_desktop===true,
106
+ prompt_mode:u.prompt_mode,owner_gesture:ownerGesture,
107
+ live_epoch_verified:true,live_policies_verified:true,live_release_verified:true,
108
+ agent_processes:Object.freeze(agent_processes)
109
+ })});
110
+ }
@@ -0,0 +1,67 @@
1
+ import {execFile} from 'node:child_process';
2
+ import {promisify} from 'node:util';
3
+ import path from 'node:path';
4
+
5
+ const execFileAsync=promisify(execFile);
6
+ const TRUSTED=new Set(['S-1-5-18','S-1-5-32-544',
7
+ 'S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464']);
8
+ function blocked(reason,pathValue=null){return Object.freeze({trusted:false,reason,path:pathValue});}
9
+ export function evaluateR193OwnerSecretAcl(records,files){
10
+ if(!Array.isArray(files)||files.length!==2||!Array.isArray(records)||records.length!==2)
11
+ return blocked('INCOMPLETE_OWNER_SECRET_ACL');
12
+ const expected=new Set(files.map(file=>path.win32.normalize(file).toLowerCase()));
13
+ const seen=new Set();
14
+ for(const record of records){
15
+ const key=typeof record?.path==='string'?path.win32.normalize(record.path).toLowerCase():'';
16
+ if(!expected.has(key)||seen.has(key))return blocked('OWNER_SECRET_ACL_PATH_MISMATCH',key);
17
+ seen.add(key);
18
+ if(record.reparse!==false||record.protected!==true||!TRUSTED.has(record.owner)||
19
+ typeof record.directory!=='boolean'||!Array.isArray(record.aces))
20
+ return blocked('OWNER_SECRET_ACL_UNTRUSTED',key);
21
+ for(const ace of record.aces){
22
+ if(!ace||!['Allow','Deny'].includes(ace.type)||typeof ace.sid!=='string'||
23
+ typeof ace.inherited!=='boolean'||!Number.isSafeInteger(ace.mask))
24
+ return blocked('OWNER_SECRET_ACL_UNKNOWN_RULE',key);
25
+ if(ace.inherited===true)return blocked('OWNER_SECRET_ACL_INHERITED_RULE',key);
26
+ if(ace.type==='Allow'&&!TRUSTED.has(ace.sid))
27
+ return blocked('OWNER_SECRET_READABLE_BY_AGENT_PRINCIPAL',key);
28
+ }
29
+ }
30
+ return Object.freeze({trusted:true,reason:'OWNER_SECRET_ADMIN_SYSTEM_ONLY'});
31
+ }
32
+
33
+ const probe=String.raw`
34
+ $ErrorActionPreference='Stop';Set-StrictMode -Version Latest
35
+ try{
36
+ $files=ConvertFrom-Json ([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('__FILES__')))
37
+ $out=@()
38
+ foreach($p in @($files)){
39
+ $item=Get-Item -LiteralPath $p -Force -ErrorAction Stop
40
+ $acl=Get-Acl -LiteralPath $p -ErrorAction Stop
41
+ $rules=@()
42
+ foreach($entry in $acl.GetAccessRules($true,$true,[Security.Principal.SecurityIdentifier])){
43
+ $rules+=@{sid=$entry.IdentityReference.Value;type=$entry.AccessControlType.ToString();
44
+ mask=([int64]$entry.FileSystemRights -band [int64]4294967295);inherited=[bool]$entry.IsInherited}
45
+ }
46
+ $out+=@{path=$item.FullName;owner=$acl.GetOwner([Security.Principal.SecurityIdentifier]).Value;
47
+ reparse=[bool]($item.Attributes -band [IO.FileAttributes]::ReparsePoint);
48
+ protected=[bool]$acl.AreAccessRulesProtected;directory=[bool]$item.PSIsContainer;aces=$rules}
49
+ }
50
+ ConvertTo-Json @($out) -Depth 7 -Compress
51
+ }catch{[Console]::Error.WriteLine('R193_OWNER_SECRET_ACL_PROBE_FAILED');exit 12}
52
+ `;
53
+ export async function inspectR193OwnerSecretAcl(files){
54
+ if(process.platform!=='win32'||process.arch!=='x64')
55
+ throw new Error('R193 owner secret ACL requires Windows x64');
56
+ const ps='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
57
+ const encodedFiles=Buffer.from(JSON.stringify(files),'utf8').toString('base64');
58
+ const encoded=Buffer.from(probe.replace('__FILES__',encodedFiles),'utf16le').toString('base64');
59
+ let stdout;
60
+ try{({stdout}=await execFileAsync(ps,['-NoLogo','-NoProfile','-NonInteractive','-EncodedCommand',encoded],
61
+ {windowsHide:true,timeout:12000,maxBuffer:128*1024,encoding:'utf8'}));}
62
+ catch{throw new Error('R193 owner secret ACL inspection failed closed');}
63
+ let records;try{records=JSON.parse(stdout);}catch{throw new Error('R193 owner secret ACL response invalid');}
64
+ const decision=evaluateR193OwnerSecretAcl(records,files);
65
+ if(!decision.trusted)throw new Error('R193 owner secret ACL untrusted: '+decision.reason);
66
+ return decision;
67
+ }
@@ -0,0 +1,85 @@
1
+ // R193 protected owner decision boundary.
2
+ //
3
+ // This module is deliberately pure. It cannot launch UAC, enroll a key, write
4
+ // an approval, issue a grant, or mutate an epoch. A protected interactive host
5
+ // must independently observe the Windows token/process vector and R89/key ACLs
6
+ // before calling it. The returned R70 approval remains single-use input to the
7
+ // existing R186 transaction; it is not authority by itself.
8
+ import {createPublicKey} from 'node:crypto';
9
+ import {signR193R70ApprovalFromOwnerReview} from './r193-uac-r70-bridge.mjs';
10
+
11
+ const COMPONENTS=Object.freeze(['bridge','cloud','core','supervisor']);
12
+ const BOUNDARY_FIELDS=Object.freeze([
13
+ 'schema','broker_r89_trusted','key_acl_trusted','enable_uac','secure_desktop',
14
+ 'prompt_mode','owner_gesture','live_epoch_verified','live_policies_verified',
15
+ 'live_release_verified','agent_processes'
16
+ ]);
17
+ const PROCESS_FIELDS=Object.freeze([
18
+ 'component','pid','creation_time_utc','alive','identity_verified','elevated',
19
+ 'admin_enabled','integrity_rid','token_type'
20
+ ]);
21
+
22
+ function block(reason){throw new Error(`R193 owner UAC broker blocked: ${reason}`);}
23
+ function exact(value,fields,label){
24
+ if(!value||typeof value!=='object'||Array.isArray(value)||
25
+ Object.keys(value).length!==fields.length||
26
+ fields.some(field=>!Object.hasOwn(value,field)))block(`${label} schema mismatch`);
27
+ }
28
+ function canonicalUtc(value,label){
29
+ if(typeof value!=='string'||
30
+ !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(value)||
31
+ !Number.isFinite(Date.parse(value))||new Date(value).toISOString()!==value)
32
+ block(`${label} creation identity invalid`);
33
+ }
34
+ function verifyProcesses(processes){
35
+ if(!Array.isArray(processes)||processes.length!==COMPONENTS.length)
36
+ block('complete agent process vector required');
37
+ const observed=[];
38
+ for(const process of processes){
39
+ exact(process,PROCESS_FIELDS,'agent process');
40
+ if(!COMPONENTS.includes(process.component)||observed.includes(process.component))
41
+ block('agent process component missing or duplicated');
42
+ observed.push(process.component);
43
+ if(!Number.isSafeInteger(process.pid)||process.pid<1||process.pid>0x7fffffff)
44
+ block('agent process PID invalid');
45
+ canonicalUtc(process.creation_time_utc,process.component);
46
+ if(process.alive!==true||process.identity_verified!==true)
47
+ block(`${process.component} process identity unverified`);
48
+ if(process.elevated!==false||process.admin_enabled!==false||
49
+ process.integrity_rid<8192||process.integrity_rid>=12288||
50
+ process.token_type!=='primary')
51
+ block(`${process.component} process is not a verified Limited primary token`);
52
+ }
53
+ if(COMPONENTS.some(component=>!observed.includes(component)))
54
+ block('complete agent process vector required');
55
+ }
56
+
57
+ export function approveR193OwnerRequest({request,expected,privateKeyDer,boundary,now=new Date()}={}){
58
+ exact(boundary,BOUNDARY_FIELDS,'runtime boundary');
59
+ if(boundary.schema!=='deadbyte.r193-owner-runtime-boundary.v1')
60
+ block('runtime boundary schema invalid');
61
+ if(boundary.broker_r89_trusted!==true)block('R89 protected broker not verified');
62
+ if(boundary.key_acl_trusted!==true)block('owner signing key ACL not verified');
63
+ if(boundary.enable_uac!==true||boundary.secure_desktop!==true||
64
+ boundary.prompt_mode!=='explicit_secure_desktop')
65
+ block('secure interactive UAC policy not verified');
66
+ if(boundary.owner_gesture!=='approved')block('owner gesture absent or rejected');
67
+ if(boundary.live_epoch_verified!==true)block('live authority epoch not verified');
68
+ if(boundary.live_policies_verified!==true)block('live policy identities not verified');
69
+ if(boundary.live_release_verified!==true)block('live release identity not verified');
70
+ verifyProcesses(boundary.agent_processes);
71
+ const signed=signR193R70ApprovalFromOwnerReview({request,expected,privateKeyDer,now});
72
+ const publicPem=createPublicKey({key:signed.owner_public_key_spki_der,
73
+ format:'der',type:'spki'}).export({format:'pem',type:'spki'}).toString();
74
+ return Object.freeze({
75
+ status:'OWNER_APPROVED_FOR_SINGLE_USE_GRANT',
76
+ request_sha256:signed.request_sha256,
77
+ owner_key_id:signed.approval.owner_key_id,
78
+ owner_public_key_pem:publicPem,
79
+ approval:signed.approval,
80
+ owner_approved:true,
81
+ authority_granted:false,
82
+ private_key_material_returned:false,
83
+ next_gate:'R186_PROTECTED_SINGLE_USE_GRANT_TRANSACTION'
84
+ });
85
+ }
@@ -0,0 +1,54 @@
1
+ // R193 bridge: translate a short-lived, exact R188 scope review into the
2
+ // already-supported R70 signed approval format. This function is NOT consent,
3
+ // UAC evidence, protected-key enrollment, epoch issuance or a grant. Its caller
4
+ // must be an independently elevated, R89-protected owner broker and must never
5
+ // expose the owner's private DER or the signing operation to an agent process.
6
+ import {createHash,createPrivateKey,createPublicKey,sign} from 'node:crypto';
7
+ import {canonicalJson} from './canonical-json.mjs';
8
+ import {verifyR188OwnerUacRequest} from './r188-owner-uac.mjs';
9
+
10
+ const sha=b=>createHash('sha256').update(b).digest('hex');
11
+ const encode=x=>Buffer.from(canonicalJson(x),'utf8');
12
+ const DOMAIN=Buffer.from('DEADBYTE-R70-PROJECT-OWNER-APPROVAL\0','utf8');
13
+
14
+ export function signR193R70ApprovalFromOwnerReview({
15
+ request,expected,privateKeyDer,now=new Date()
16
+ }={}){
17
+ // The supplied private key is data for an already-trusted protected caller.
18
+ // Never read it from an agent-accessible path inside this module.
19
+ if(!Buffer.isBuffer(privateKeyDer)||privateKeyDer.length<32||privateKeyDer.length>8192)
20
+ throw Error('R193 protected owner signing material missing');
21
+ if(!(now instanceof Date)||!Number.isFinite(now.getTime()))
22
+ throw Error('R193 invalid review time');
23
+ const verified=verifyR188OwnerUacRequest({request,expected,now});
24
+ if(verified.status!=='VERIFIED_FOR_REVIEW_ONLY'||verified.authority_granted!==false)
25
+ throw Error('R193 unexpected owner-review contract');
26
+ let privateKey;
27
+ try{privateKey=createPrivateKey({key:privateKeyDer,format:'der',type:'pkcs8'});}
28
+ catch{throw Error('R193 protected Ed25519 key invalid');}
29
+ if(privateKey.asymmetricKeyType!=='ed25519')
30
+ throw Error('R193 protected signing key must be Ed25519');
31
+ const publicKey=createPublicKey(privateKey);
32
+ const ownerKeyId=sha(publicKey.export({format:'der',type:'spki'}));
33
+ const s=request.subject;
34
+ // Preserve the exact request expiry: signing does not extend authority.
35
+ const subject=Object.freeze({
36
+ schema:'deadbyte.project-authority-subject.r70.v1',
37
+ scope:'coding_autonomous_native_diff',
38
+ root_id:s.root_id,project_root:s.project_root,
39
+ coding_policy_sha256:s.coding_policy_sha256,
40
+ autonomous_policy_sha256:s.autonomous_policy_sha256,
41
+ reviewed_artifact_sha256:s.release_manifest_sha256,
42
+ issued_at_utc:s.issued_at_utc,expires_at_utc:s.expires_at_utc
43
+ });
44
+ const digest=sha(encode(subject));
45
+ const signed=Object.freeze({schema:'deadbyte.project-owner-approval.r70.v1',
46
+ subject_sha256:digest,owner_key_id:ownerKeyId});
47
+ const signature=sign(null,Buffer.concat([DOMAIN,encode(signed)]),privateKey);
48
+ return Object.freeze({
49
+ status:'PROTECTED_SIGNATURE_FORMAT_ONLY',authority_granted:false,owner_approved:false,
50
+ request_sha256:verified.request_sha256,
51
+ owner_public_key_spki_der:publicKey.export({format:'der',type:'spki'}),
52
+ approval:Object.freeze({...signed,subject,signature_base64:signature.toString('base64')})
53
+ });
54
+ }
@@ -62,6 +62,19 @@ export function formatRemoteLogResetNotice(file,reason){
62
62
  return '[LIVELOG] RUNTIME_LOG_REOPENED '+name+' — '+detail+'; console diagnostic continuity may have gaps; audit verification is separate';
63
63
  }
64
64
 
65
+ // Bound the foreground reader state to the current discovery snapshot.
66
+ // Audit continuity is still enforced by the signed journal, not this cache.
67
+ export function pruneLiveLogReaders(offsets,partialLines,liveFiles){
68
+ if(!(offsets instanceof Map)||!(partialLines instanceof Map)||
69
+ !Array.isArray(liveFiles)||liveFiles.some(file=>typeof file!=='string'||!file))
70
+ throw new Error('live log reader state invalid');
71
+ const keep=new Set(liveFiles);
72
+ let cursorsRemoved=0,fragmentsRemoved=0;
73
+ for(const file of offsets.keys())if(!keep.has(file)){offsets.delete(file);cursorsRemoved++;}
74
+ for(const file of partialLines.keys())if(!keep.has(file)){partialLines.delete(file);fragmentsRemoved++;}
75
+ return {cursors_removed:cursorsRemoved,fragments_removed:fragmentsRemoved};
76
+ }
77
+
65
78
  export function selectLiveLogNames({auditNames=[],runtimeNames=[]}={}){
66
79
  if(!Array.isArray(auditNames)||!Array.isArray(runtimeNames)) throw new Error('live log names must be arrays');
67
80
  const audit=[...new Set(auditNames.filter(name=>typeof name==='string'&&/^segment-\d{8}\.jsonl$/.test(name)))].sort().slice(-2);
@@ -713,6 +726,14 @@ export function formatRuntimeDiagnosticLine(file,line,{verbose=false,displayMode
713
726
  return remoteDisplayText('['+label+'.DEBUG] OUT '+output[1],displayMode);
714
727
  }
715
728
  const compact=line.match(/^\[TOOL\]\s+(\S+)\s+#(\d+)\s+(✓|✗|OK|ERR)\s+([A-Za-z0-9_.-]+)\s+([^\s]+)(?:\s+—\s+(.+))?$/u);
716
- if(compact) return verbose?remoteDisplayText('['+label+'.DEBUG] #'+compact[2]+' '+compact[3]+' '+compact[4]+' '+compact[5]+(compact[6]?' — '+compact[6]:''),displayMode):null;
729
+ if(compact){
730
+ if(!verbose)return null;
731
+ // Runtime logs are lower-trust diagnostics than signed audit records.
732
+ // Never echo a donor/transport error reason before screening and bounding it.
733
+ const screened=compact[6]?sanitizeAuditArgs(compact[6]):null;
734
+ const reason=typeof screened==='string'?clipped(screened,180):screened?'[REDACTED]':'';
735
+ return remoteDisplayText('['+label+'.DEBUG] #'+compact[2]+' '+compact[3]+' '+compact[4]+' '+compact[5]+
736
+ (reason?' — '+reason:''),displayMode);
737
+ }
717
738
  return null;
718
739
  }
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.15.71';
1
+ export const DEADBYTE_VERSION = '0.15.74';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';
@@ -70,7 +70,7 @@ test('R167 process policy binds coherently to the explicit development root', as
70
70
  // The distributed policy is pinned to its explicit development provenance,
71
71
  // not to the physical extraction path of the exact immutable npm tarball.
72
72
  const release = JSON.parse(await readFile(path.join(repoRoot, 'RELEASE.json'), 'utf8'));
73
- const approvedRoot = release.r191_activation_repair?.development_policy_root;
73
+ const approvedRoot = release.r194?.development_policy_root;
74
74
  assert.equal(typeof approvedRoot, 'string', 'R191 development policy root must be explicit in release metadata');
75
75
  assert.ok(path.isAbsolute(approvedRoot), 'R191 development policy root must be absolute');
76
76
  const expectedRoot = path.resolve(approvedRoot);
@@ -14,14 +14,14 @@ test('current successor retains the R130 security baseline with truthful R190 id
14
14
  read('SBOM.cdx.json'),readReleaseLock(root),read('TEST-MATRIX.json')]);
15
15
  assert.equal(pkg.name,'deadbyte-mcp');
16
16
  for(const actual of [pkg.version,release.version,provenance.version,matrix.version,bom.metadata.component.version,lock.version,lock.packages[''].version,DEADBYTE_VERSION])
17
- assert.equal(actual,'0.15.71');
18
- assert.equal(release.train,'R191');
19
- assert.equal(matrix.train,'R191');
20
- assert.equal(release.source_predecessor.version,'0.15.70');
21
- assert.equal(release.source_predecessor.train,'R190');
22
- assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.70\.tgz/i);
23
- assert.equal(release.source_predecessor.manifest_status,'PUBLISHED_EXACT_MANIFEST_VERIFIED_NOT_ACTIVE');
24
- assert.equal(release.runtime_predecessor.version,'0.15.68');
17
+ assert.equal(actual,'0.15.74');
18
+ assert.equal(release.train,'R194');
19
+ assert.equal(matrix.train,'R194');
20
+ assert.equal(release.source_predecessor.version,'0.15.73');
21
+ assert.equal(release.source_predecessor.train,'R193');
22
+ assert.match(release.source_predecessor.source_path,/r193-final-closure/i);
23
+ assert.equal(release.source_predecessor.manifest_status,'FROZEN_R193_CLOSURE_VERIFIED');
24
+ assert.equal(release.runtime_predecessor.version,'0.15.72');
25
25
  assert.equal(provenance.r160.source_predecessor_manifest_status,'STALE_REJECTED');
26
26
  assert.equal(pkg.dependencies['@modelcontextprotocol/client'],'2.3.1');
27
27
  assert.equal(pkg.dependencies['@modelcontextprotocol/server'],'2.3.1');
@@ -16,17 +16,17 @@ test('R190 package identity preserves R132 evidence and published R179 source pr
16
16
  for(const value of [pkg.version,lock.version,lock.packages[''].version,release.version,prov.version,bom.metadata.component.version,matrix.version,DEADBYTE_VERSION]){
17
17
  assert.equal(value,pkg.version);
18
18
  }
19
- assert.equal(release.train,'R191');
20
- assert.equal(matrix.train,'R191');
21
- assert.equal(release.source_predecessor.version,'0.15.70');
22
- assert.equal(release.source_predecessor.train,'R190');
23
- assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.70\.tgz/i);
19
+ assert.equal(release.train,'R194');
20
+ assert.equal(matrix.train,'R194');
21
+ assert.equal(release.source_predecessor.version,'0.15.73');
22
+ assert.equal(release.source_predecessor.train,'R193');
23
+ assert.match(release.source_predecessor.source_path,/r193-final-closure/i);
24
24
  assert.equal(prov.r160.source_predecessor_manifest_status,'STALE_REJECTED');
25
25
  assert.equal(release.r165.published_source_manifest_sha256,'4adf7d94682fbb71c4a91eb3147ecc48076bbc5d79cb67fcb875cde6a1bb4805');
26
26
  assert.equal(release.r165.published_source_tarball_sha256,'812e97609b7c51353ed25f2202129737e43bb4fbe0778c3adec43ec065352641');
27
- assert.equal(release.source_predecessor.tarball_sha256,'1a5f5f30bf4781ed951d6d201b8a972d088b2091555d7f4cc2e2bb899ed5707e');
27
+ assert.equal(release.source_predecessor.tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
28
28
  assert.notEqual(release.r179.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
29
- assert.equal(release.runtime_predecessor.version,'0.15.68');
29
+ assert.equal(release.runtime_predecessor.version,'0.15.72');
30
30
  assert.equal(prov.runtime_predecessor.release_id,release.runtime_predecessor.release_id);
31
31
  assert.equal(prov.runtime_predecessor.manifest_sha256,release.runtime_predecessor.manifest_sha256);
32
32
  assert.equal(prov.runtime_predecessor.generation_manifest_sha256,release.runtime_predecessor.generation_manifest_sha256);
@@ -26,7 +26,7 @@ test('R153 historical verifier refuses current successor package identity',async
26
26
  const state={pkg:JSON.parse(await readFile(path.join(root,'package.json'),'utf8')),
27
27
  release:JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8')),
28
28
  bridge:JSON.parse(await readFile(path.join(root,'bridge/package.json'),'utf8'))};
29
- assert.equal(state.pkg.version,'0.15.71');
29
+ assert.equal(state.pkg.version,'0.15.74');
30
30
  assert.throws(()=>verifyR153Lineage(state),/package version/);
31
31
  await assert.rejects(verifyR153IdentityTree(root),/package version/);
32
32
  });
@@ -8,9 +8,9 @@ const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
8
8
 
9
9
  test('R160 historical contract remains distinct from the current package identity',async()=>{
10
10
  const [release,provenance]=await Promise.all([read('RELEASE.json'),read('PROVENANCE.json')]);
11
- assert.equal(release.runtime_predecessor.version,'0.15.68');
12
- assert.equal(release.runtime_predecessor.release_id,'v0.15.68-ff29dbb2fbb89862');
13
- assert.equal(release.runtime_predecessor.manifest_sha256,'ff29dbb2fbb898625592afb47835a4a62ef289429f1e0a89a83242398cd98885');
11
+ assert.equal(release.runtime_predecessor.version,'0.15.72');
12
+ assert.equal(release.runtime_predecessor.release_id,'v0.15.72-0a5d9436e06e2d9e');
13
+ assert.equal(release.runtime_predecessor.manifest_sha256,'0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90');
14
14
  assert.equal(release.r160.runtime_predecessor_version,'0.15.61');
15
15
  assert.equal(release.r160.source_predecessor_train,'R159');
16
16
  assert.equal(release.r160.public_tool_delta,0);
@@ -17,7 +17,7 @@ const hashMarker=c=>c.repeat(64);
17
17
  async function fixture(t,kind){
18
18
  assert.equal(typeof envRoot,'string'); assert.ok(path.isAbsolute(envRoot));
19
19
  assert.match(sha(await readFile(path.join(envRoot,'MANIFEST.SHA256'))),/^[0-9a-f]{64}$/);
20
- assert.equal(JSON.parse(await readFile(path.join(envRoot,'package.json'),'utf8')).version,'0.15.71');
20
+ assert.equal(JSON.parse(await readFile(path.join(envRoot,'package.json'),'utf8')).version,'0.15.74');
21
21
  const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r164-skew-e2e-'));
22
22
  t.after(async()=>{await rm(dir,{recursive:true,force:true,maxRetries:10,retryDelay:150});});
23
23
  const state=path.join(dir,'state'),bin=path.join(state,'bin');
@@ -8,7 +8,7 @@ import {DEADBYTE_VERSION} from '../src/version.mjs';
8
8
  const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
9
9
  const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
10
10
  const readOptional=async rel=>{try{return await read(rel);}catch(error){if(error?.code==='ENOENT')return null;throw error;}};
11
- const VERSION='0.15.71';
11
+ const VERSION='0.15.74';
12
12
  const R166_MANIFEST='ad3c091fbbe2bac6d234548724008b67305fd483ad6542f92d5aeb1aa84f5849';
13
13
  const R166_TARBALL='3d22412c3cebabd66bfa92ca4dbaaf3ef49acba7f92436a16485d7e4cb18c653';
14
14
 
@@ -20,20 +20,20 @@ test('current package identity retains the immutable R167/R173 activation lineag
20
20
  provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION];
21
21
  if(lock)versions.push(lock.version,lock.packages[''].version);
22
22
  for(const version of versions)assert.equal(version,VERSION);
23
- assert.equal(release.train,'R191');
24
- assert.equal(matrix.train,'R191');
25
- assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r191:0.15.71');
23
+ assert.equal(release.train,'R194');
24
+ assert.equal(matrix.train,'R194');
25
+ assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r194:0.15.74');
26
26
  assert.deepEqual(release.runtime_predecessor,{
27
- version:'0.15.68',release_id:'v0.15.68-ff29dbb2fbb89862',
28
- manifest_sha256:'ff29dbb2fbb898625592afb47835a4a62ef289429f1e0a89a83242398cd98885',
29
- generation_manifest_sha256:'2887d4a8d54ea6fc6b28869072f72491c892dfe28178b3537936dce958147bd2'
27
+ version:'0.15.72',release_id:'v0.15.72-0a5d9436e06e2d9e',
28
+ manifest_sha256:'0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90',
29
+ generation_manifest_sha256:'aec7b998306a3bbbcc59088648e7bc46ca7e203d749d4550b5b5f372032f92b0'
30
30
  });
31
- assert.equal(release.source_predecessor.version,'0.15.70');
32
- assert.equal(release.source_predecessor.train,'R190');
33
- assert.equal(release.source_predecessor.tarball_sha256,'1a5f5f30bf4781ed951d6d201b8a972d088b2091555d7f4cc2e2bb899ed5707e');
31
+ assert.equal(release.source_predecessor.version,'0.15.73');
32
+ assert.equal(release.source_predecessor.train,'R193');
33
+ assert.equal(release.source_predecessor.tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
34
34
  assert.equal(release.r173.source_predecessor_version,'0.15.67');
35
35
  assert.equal(release.r167.source_predecessor_manifest_sha256,R166_MANIFEST);
36
- assert.equal(provenance.source_predecessor_manifest_file_sha256,'df15db35c7ddddd769650f5c86557159d10d99e9eef4dd232cae67faeb8ad6e3');
36
+ assert.equal(provenance.source_predecessor_manifest_file_sha256,'e0b3f8b333f1c1260a97b178d1a8beff5742355296a9fe7daba378612604a3bd');
37
37
  assert.equal(provenance.r173.source_predecessor_manifest_sha256,'4fd7bfc76b1de6401c142b607cc84e847434b28c888bc99ceb09c9e8e5adc8f8');
38
38
  assert.equal(release.r172.source_predecessor_manifest_sha256,'962e227dace247d59aa860211388fbde461c5f9c8a7e8a878e34a14a27d355f8');
39
39
  assert.equal(release.r172.source_predecessor_tarball_sha256,'31b194a4fbff7dbdb9f4f275b4ea49c5115f7b0bb2241c0c72d72ef690311a5d');