deadbyte-mcp 0.15.72 → 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.
- package/MANIFEST.SHA256 +75 -27
- package/PROVENANCE.json +42 -14
- package/README.txt +24 -18
- package/RELEASE.json +52 -18
- package/SBOM.cdx.json +14 -2
- package/TEST-MATRIX.json +30 -2
- package/bin/deadbyte-owner-token-r193.exe +0 -0
- package/bridge/package.json +1 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R184-package-lock.json +2 -2
- package/native/deadbyte-owner-token-r193.cpp +156 -0
- package/package.json +2 -2
- package/scripts/gate-windows-r193.ps1 +108 -0
- package/scripts/gate-windows-r194.ps1 +112 -0
- package/scripts/npm-interactive-r194.mjs +13 -0
- package/scripts/npm-publication-r65.mjs +64 -4
- package/scripts/npm-release-r48.mjs +58 -11
- package/scripts/npm-release-readiness-r193.mjs +80 -0
- package/scripts/npm-release-readiness-r194.mjs +80 -0
- package/scripts/r188-owner-uac-review.ps1 +91 -0
- package/scripts/r188-uac-review-preview.mjs +65 -0
- package/scripts/r193-compile-token.ps1 +22 -0
- package/scripts/r193-evidence-relocate.ps1 +12 -0
- package/scripts/r193-focused-gate.mjs +20 -0
- package/scripts/r193-import-r188-scripts.ps1 +14 -0
- package/scripts/r193-limited-subject-probe.ps1 +25 -0
- package/scripts/r193-migrate-runtime-limited.ps1 +103 -0
- package/scripts/r193-owner-keygen.mjs +43 -0
- package/scripts/r193-owner-request-live.mjs +50 -0
- package/scripts/r193-owner-uac-approve.ps1 +42 -0
- package/scripts/r193-owner-uac-broker.mjs +139 -0
- package/scripts/r193-owner-uac-enroll-and-approve.ps1 +62 -0
- package/scripts/r193-test-limited-token.ps1 +49 -0
- package/scripts/r193-toolchain-inventory.ps1 +7 -0
- package/scripts/r193-uac-bridge-focused.mjs +21 -0
- package/src/r188-owner-uac.mjs +105 -0
- package/src/r188-uac-boundary.mjs +21 -0
- package/src/r193-live-owner-subject.mjs +110 -0
- package/src/r193-owner-secret-acl.mjs +67 -0
- package/src/r193-owner-uac-broker.mjs +85 -0
- package/src/r193-uac-r70-bridge.mjs +54 -0
- package/src/version.mjs +1 -1
- package/test/process-policy-refresh.test.mjs +1 -1
- package/test/r130-release-security-contract.test.mjs +8 -8
- package/test/r132-release-identity.test.mjs +7 -7
- package/test/r153-prepublish-identity.test.mjs +1 -1
- package/test/r160-release-contract.test.mjs +3 -3
- package/test/r165-live-cli-skew.test.mjs +1 -1
- package/test/r167-release-contract.test.mjs +11 -11
- package/test/r168-release-contract.test.mjs +4 -4
- package/test/r172-release-contract.test.mjs +6 -6
- package/test/r173-release-contract.test.mjs +16 -16
- package/test/r179-release-contract.test.mjs +11 -11
- package/test/r188-owner-uac.test.mjs +48 -0
- package/test/r188-uac-boundary.test.mjs +42 -0
- package/test/r190-release-contract.test.mjs +10 -10
- package/test/r191-release-contract.test.mjs +12 -12
- package/test/r192-release-identity.test.mjs +10 -10
- package/test/r193-limited-migration-contract.test.mjs +26 -0
- package/test/r193-live-owner-subject.test.mjs +61 -0
- package/test/r193-native-process-observer.test.mjs +36 -0
- package/test/r193-native-token.test.mjs +43 -0
- package/test/r193-owner-enrollment-entrypoint.test.mjs +38 -0
- package/test/r193-owner-secret-acl.test.mjs +23 -0
- package/test/r193-owner-uac-broker.test.mjs +82 -0
- package/test/r193-owner-uac-entrypoint.test.mjs +36 -0
- package/test/r193-release-identity.test.mjs +56 -0
- package/test/r193-release-readiness.test.mjs +87 -0
- package/test/r193-uac-r70-bridge.test.mjs +88 -0
- package/test/r193-windows-gate.test.mjs +30 -0
- package/test/r194-npm-auth-recovery.test.mjs +77 -0
- package/test/r194-npm-preauth.test.mjs +57 -0
- package/test/r194-release-identity.test.mjs +43 -0
- package/test/r194-release-readiness.test.mjs +87 -0
- package/test/r194-windows-gate.test.mjs +21 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {createR188OwnerUacRequest,verifyR188OwnerUacRequest} from '../src/r188-owner-uac.mjs';
|
|
4
|
+
const h=c=>c.repeat(64);
|
|
5
|
+
const issued=new Date('2026-10-28T06:00:00.000Z');
|
|
6
|
+
const fixture={
|
|
7
|
+
machineEpoch:h('e'),releaseManifestSha256:h('a'),
|
|
8
|
+
codingPolicySha256:h('b'),autonomousPolicySha256:h('c'),
|
|
9
|
+
rootId:'core',projectRoot:'D:\\Projects\\deadbyte-mcp',
|
|
10
|
+
maxSeconds:600,now:issued,expiresInMs:120000
|
|
11
|
+
};
|
|
12
|
+
test('R188 no-Windows-Hello UAC review is project-scoped, short lived and not a grant',()=>{
|
|
13
|
+
const a=createR188OwnerUacRequest(fixture),b=createR188OwnerUacRequest(fixture);
|
|
14
|
+
assert.equal(a.schema,'deadbyte.r188-owner-uac-request.v1');
|
|
15
|
+
assert.equal(a.subject.root_id,'core');
|
|
16
|
+
assert.equal(a.subject.operation,'autonomous_goal_run');
|
|
17
|
+
assert.equal(a.subject.max_seconds,600);
|
|
18
|
+
assert.equal(a.subject.expires_at_utc,'2026-10-28T06:02:00.000Z');
|
|
19
|
+
assert.notEqual(a.challenge,b.challenge);
|
|
20
|
+
assert.equal(a.authority_granted,false);
|
|
21
|
+
assert.equal(a.owner_approved,false);
|
|
22
|
+
assert.equal(a.require_interactive_uac,true);
|
|
23
|
+
assert.match(a.review_phrase,/^APPROVE-[A-F0-9]{12}$/);
|
|
24
|
+
assert.match(a.request_sha256,/^[a-f0-9]{64}$/);
|
|
25
|
+
const r=verifyR188OwnerUacRequest({request:a,expected:fixture,now:new Date(issued.getTime()+1000)});
|
|
26
|
+
assert.equal(r.status,'VERIFIED_FOR_REVIEW_ONLY');
|
|
27
|
+
assert.equal(r.authority_granted,false);
|
|
28
|
+
assert.equal(r.request_sha256,a.request_sha256);
|
|
29
|
+
});
|
|
30
|
+
test('R188 disallows broad scopes and unsafe timestamps before preparing a review',()=>{
|
|
31
|
+
for(const change of [
|
|
32
|
+
{rootId:'all'}, {maxSeconds:3601}, {maxSeconds:0},
|
|
33
|
+
{machineEpoch:'a'}, {codingPolicySha256:h('g')},
|
|
34
|
+
{projectRoot:'D:\\'},{projectRoot:'relative'},
|
|
35
|
+
{expiresInMs:300001},{expiresInMs:-1}
|
|
36
|
+
])assert.throws(()=>createR188OwnerUacRequest({...fixture,...change}),/R188/);
|
|
37
|
+
});
|
|
38
|
+
test('R188 rejects changed release, policy, epoch, path, signature-like receipt or expired request',()=>{
|
|
39
|
+
const request=createR188OwnerUacRequest(fixture);
|
|
40
|
+
for(const change of [
|
|
41
|
+
{releaseManifestSha256:h('f')},{codingPolicySha256:h('d')},
|
|
42
|
+
{autonomousPolicySha256:h('0')},{machineEpoch:h('1')},
|
|
43
|
+
{projectRoot:'D:\\Other'}
|
|
44
|
+
])assert.throws(()=>verifyR188OwnerUacRequest({request,expected:{...fixture,...change},now:issued}),/R188/);
|
|
45
|
+
assert.throws(()=>verifyR188OwnerUacRequest({request:{...request,owner_approved:true},expected:fixture,now:issued}),/R188/);
|
|
46
|
+
assert.throws(()=>verifyR188OwnerUacRequest({request:{...request,challenge:'A'.repeat(43)},expected:fixture,now:issued}),/R188/);
|
|
47
|
+
assert.throws(()=>verifyR188OwnerUacRequest({request,expected:fixture,now:new Date(issued.getTime()+120000)}),/R188/);
|
|
48
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import {spawnSync} from 'node:child_process';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {inspectTrustedInstallation,privilegedEpochInstallFiles} from '../src/privileged-install-trust-r89.mjs';
|
|
8
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
9
|
+
test('R188 owner review is explicitly manual, protected, with UAC secure desktop and expiry review',async()=>{
|
|
10
|
+
const script=await readFile(path.join(root,'scripts','r188-owner-uac-review.ps1'),'utf8');
|
|
11
|
+
assert.match(script,/#requires -RunAsAdministrator/);
|
|
12
|
+
assert.match(script,/EnableLUA/);
|
|
13
|
+
assert.match(script,/PromptOnSecureDesktop/);
|
|
14
|
+
assert.match(script,/ConsentPromptBehaviorAdmin/);
|
|
15
|
+
assert.match(script,/Read-Host/);
|
|
16
|
+
assert.match(script,/REVIEWED_NO_GRANT/);
|
|
17
|
+
assert.match(script,/authority_granted=\$false/);
|
|
18
|
+
assert.match(script,/grant_issued=\$false/);
|
|
19
|
+
assert.match(script,/FileMode\]::CreateNew/);
|
|
20
|
+
assert.doesNotMatch(script,/Start-Process\s+.*-Verb\s+RunAs/i);
|
|
21
|
+
assert.doesNotMatch(script,/Arm-Autonomous|transaction_revoke|autonomous-grant\.json/);
|
|
22
|
+
});
|
|
23
|
+
test('R188 UAC preflight fails closed at the applicable trust or request boundary',async()=>{
|
|
24
|
+
let trusted=false;
|
|
25
|
+
try{
|
|
26
|
+
trusted=(await inspectTrustedInstallation(privilegedEpochInstallFiles(root,process.execPath))).trusted===true;
|
|
27
|
+
}catch{}
|
|
28
|
+
const script=path.join(root,'scripts','r188-uac-review-preview.mjs');
|
|
29
|
+
const r=spawnSync(process.execPath,[script,'D:\\bad-request.json'],{
|
|
30
|
+
encoding:'utf8',cwd:root,windowsHide:true,timeout:12000,maxBuffer:512*1024});
|
|
31
|
+
assert.equal(r.status,2);
|
|
32
|
+
if(trusted)assert.match(r.stderr,/ENOENT.*bad-request\.json/i);
|
|
33
|
+
else assert.match(r.stderr,/R188_UAC_REVIEW_BLOCKED|R89_PROTECTED_INSTALLATION_REQUIRED|R89 privileged installation not protected: UNTRUSTED_WRITE_ACE/);
|
|
34
|
+
assert.doesNotMatch(r.stdout,/authority_granted":true/);
|
|
35
|
+
});
|
|
36
|
+
test('R188 broker cannot pretend owner-reviewed data is a current epoch or signed grant',async()=>{
|
|
37
|
+
const script=await readFile(path.join(root,'scripts','r188-uac-review-preview.mjs'),'utf8');
|
|
38
|
+
assert.match(script,/live_epoch_verified:false/);
|
|
39
|
+
assert.match(script,/live_policies_verified:false/);
|
|
40
|
+
assert.match(script,/authority_granted:false/);
|
|
41
|
+
assert.match(script,/R89_PROTECTED_INSTALLATION_REQUIRED/);
|
|
42
|
+
});
|
|
@@ -8,17 +8,17 @@ test('R190 candidate identity separates published source 0.15.69 from active run
|
|
|
8
8
|
json('package.json'),json('bridge/package.json'),json('RELEASE.json'),json('PROVENANCE.json'),
|
|
9
9
|
json('TEST-MATRIX.json'),json('SBOM.cdx.json'),readFile(new URL('../src/version.mjs',import.meta.url),'utf8')]);
|
|
10
10
|
for(const value of [pkg.version,bridge.version,release.version,provenance.version,matrix.version,
|
|
11
|
-
sbom.metadata.component.version])assert.equal(value,'0.15.
|
|
12
|
-
assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.
|
|
13
|
-
assert.equal(release.train,'
|
|
14
|
-
assert.equal(release.source_predecessor.version,'0.15.
|
|
15
|
-
assert.equal(release.source_predecessor.tarball_sha256,'
|
|
16
|
-
assert.equal(release.source_predecessor.manifest_sha256,'
|
|
17
|
-
assert.equal(release.runtime_predecessor.version,'0.15.
|
|
18
|
-
assert.equal(release.runtime_predecessor.release_id,'v0.15.
|
|
19
|
-
assert.equal(provenance.source_predecessor_version,'0.15.
|
|
11
|
+
sbom.metadata.component.version])assert.equal(value,'0.15.74');
|
|
12
|
+
assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.74'/);
|
|
13
|
+
assert.equal(release.train,'R194');assert.equal(matrix.train,'R194');
|
|
14
|
+
assert.equal(release.source_predecessor.version,'0.15.73');
|
|
15
|
+
assert.equal(release.source_predecessor.tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
|
|
16
|
+
assert.equal(release.source_predecessor.manifest_sha256,'e0b3f8b333f1c1260a97b178d1a8beff5742355296a9fe7daba378612604a3bd');
|
|
17
|
+
assert.equal(release.runtime_predecessor.version,'0.15.72');
|
|
18
|
+
assert.equal(release.runtime_predecessor.release_id,'v0.15.72-0a5d9436e06e2d9e');
|
|
19
|
+
assert.equal(provenance.source_predecessor_version,'0.15.73');
|
|
20
20
|
assert.equal(provenance.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
|
|
21
|
-
assert.match(sbom.serialNumber,/
|
|
21
|
+
assert.match(sbom.serialNumber,/r194:0\.15\.74$/);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
test('R190 release metadata records verified recovery without claiming publication or activation',async()=>{
|
|
@@ -6,23 +6,23 @@ import path from 'node:path';
|
|
|
6
6
|
import {DEADBYTE_VERSION} from '../src/version.mjs';
|
|
7
7
|
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
8
8
|
const json=async f=>JSON.parse(await readFile(path.join(root,f),'utf8'));
|
|
9
|
-
const predecessor='v0.15.
|
|
10
|
-
const publishedManifest='
|
|
11
|
-
const publishedTarball='
|
|
9
|
+
const predecessor='v0.15.72-0a5d9436e06e2d9e';
|
|
10
|
+
const publishedManifest='0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90';
|
|
11
|
+
const publishedTarball='15ab5d9808cbca342aee3f64c6d1123e8fbb72964674eab460e355c8675bf84d';
|
|
12
12
|
test('R191 exact version identity includes bundled bridge, lock snapshot, SBOM, provenance and matrix',async()=>{
|
|
13
13
|
const [pkg,bridge,lock,release,provenance,matrix,bom]=await Promise.all(['package.json','bridge/package.json','docs/R184-package-lock.json','RELEASE.json','PROVENANCE.json','TEST-MATRIX.json','SBOM.cdx.json'].map(json));
|
|
14
|
-
for(const ver of [pkg.version,bridge.version,lock.version,lock.packages[''].version,release.version,provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION])assert.equal(ver,'0.15.
|
|
15
|
-
for(const train of [release.train,matrix.train])assert.equal(train,'
|
|
16
|
-
assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:
|
|
14
|
+
for(const ver of [pkg.version,bridge.version,lock.version,lock.packages[''].version,release.version,provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION])assert.equal(ver,'0.15.74');
|
|
15
|
+
for(const train of [release.train,matrix.train])assert.equal(train,'R194');
|
|
16
|
+
assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r194:0.15.74');
|
|
17
17
|
assert.equal(release.parent.release_id,predecessor);
|
|
18
18
|
assert.equal(provenance.parent_release_id,predecessor);
|
|
19
|
-
assert.equal(release.source_predecessor.version,'0.15.
|
|
20
|
-
assert.equal(release.source_predecessor.manifest_sha256,
|
|
21
|
-
assert.equal(release.source_predecessor.tarball_sha256,
|
|
22
|
-
assert.equal(provenance.source_predecessor_version,'0.15.
|
|
19
|
+
assert.equal(release.source_predecessor.version,'0.15.73');
|
|
20
|
+
assert.equal(release.source_predecessor.manifest_sha256,'e0b3f8b333f1c1260a97b178d1a8beff5742355296a9fe7daba378612604a3bd');
|
|
21
|
+
assert.equal(release.source_predecessor.tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
|
|
22
|
+
assert.equal(provenance.source_predecessor_version,'0.15.73');
|
|
23
23
|
assert.equal(provenance.parent_tarball_sha256,publishedTarball);
|
|
24
|
-
assert.equal(provenance.source_predecessor_tarball_sha256,
|
|
25
|
-
assert.equal(provenance.source_predecessor_manifest_file_sha256,
|
|
24
|
+
assert.equal(provenance.source_predecessor_tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
|
|
25
|
+
assert.equal(provenance.source_predecessor_manifest_file_sha256,'e0b3f8b333f1c1260a97b178d1a8beff5742355296a9fe7daba378612604a3bd');
|
|
26
26
|
assert.equal(release.r191_activation_repair.npm_publish,'NOT_RUN');
|
|
27
27
|
assert.equal(release.r191_activation_repair.production_activation,'NOT_RUN');
|
|
28
28
|
assert.equal(release.r190_foreground_recovery.status,'PREPUBLISH_VERIFIED');
|
|
@@ -3,21 +3,21 @@ import {readFile} from 'node:fs/promises';import {createHash} from 'node:crypto'
|
|
|
3
3
|
import {DEADBYTE_VERSION} from '../src/version.mjs';
|
|
4
4
|
const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
|
|
5
5
|
const read=async name=>JSON.parse(await readFile(path.join(root,name),'utf8'));
|
|
6
|
-
const prevHash='
|
|
7
|
-
const prevTar='
|
|
8
|
-
test('
|
|
6
|
+
const prevHash='0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90';
|
|
7
|
+
const prevTar='15ab5d9808cbca342aee3f64c6d1123e8fbb72964674eab460e355c8675bf84d';
|
|
8
|
+
test('R193 current identity retains exact published R192 predecessor evidence',async()=>{
|
|
9
9
|
const [pkg,bridge,lock,release,prov,matrix,bom]=await Promise.all([
|
|
10
10
|
read('package.json'),read('bridge/package.json'),read('docs/R184-package-lock.json'),
|
|
11
11
|
read('RELEASE.json'),read('PROVENANCE.json'),read('TEST-MATRIX.json'),read('SBOM.cdx.json')]);
|
|
12
12
|
for(const actual of [pkg.version,bridge.version,lock.version,lock.packages[''].version,
|
|
13
13
|
release.version,prov.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION])
|
|
14
|
-
assert.equal(actual,'0.15.
|
|
15
|
-
assert.equal(release.train,'
|
|
16
|
-
assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:
|
|
17
|
-
assert.equal(release.parent.release_id,'v0.15.
|
|
14
|
+
assert.equal(actual,'0.15.74');
|
|
15
|
+
assert.equal(release.train,'R194');assert.equal(matrix.train,'R194');
|
|
16
|
+
assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r194:0.15.74');
|
|
17
|
+
assert.equal(release.parent.release_id,'v0.15.72-0a5d9436e06e2d9e');
|
|
18
18
|
assert.equal(release.parent.manifest_sha256,prevHash);
|
|
19
|
-
assert.equal(release.source_predecessor.tarball_sha256,
|
|
20
|
-
assert.equal(release.source_predecessor.manifest_sha256,
|
|
19
|
+
assert.equal(release.source_predecessor.tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
|
|
20
|
+
assert.equal(release.source_predecessor.manifest_sha256,'e0b3f8b333f1c1260a97b178d1a8beff5742355296a9fe7daba378612604a3bd');
|
|
21
21
|
assert.equal(prov.parent_tarball_sha256,prevTar);
|
|
22
22
|
assert.equal(prov.parent_manifest_sha256,prevHash);
|
|
23
23
|
assert.equal(release.r192.production_activation,'NOT_RUN');
|
|
@@ -33,7 +33,7 @@ test('R192 foreground reader enforces caller-safe telemetry rather than changing
|
|
|
33
33
|
assert.match(log,/sanitizeAuditArgs\(compact\[6\]\)/);
|
|
34
34
|
const [policy,release]=await Promise.all([
|
|
35
35
|
read('controller/deadbyte-process-policy.json'),read('RELEASE.json')]);
|
|
36
|
-
const approved=release.
|
|
36
|
+
const approved=release.r194.development_policy_root;
|
|
37
37
|
assert.equal(typeof approved,'string');
|
|
38
38
|
assert.ok(path.isAbsolute(approved));
|
|
39
39
|
assert.equal(path.resolve(policy.roots.core.path),path.resolve(approved));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
7
|
+
test('R193 Limited migration uses supported lifecycle, Limited tasks and never silently rearms',async()=>{
|
|
8
|
+
const source=await readFile(path.join(root,'scripts','r193-migrate-runtime-limited.ps1'),'utf8');
|
|
9
|
+
assert.match(source,/#requires -RunAsAdministrator/);
|
|
10
|
+
assert.match(source,/Invoke-Controller supervisorstop/);
|
|
11
|
+
assert.match(source,/Invoke-Controller stop/);
|
|
12
|
+
assert.match(source,/DEADBYTE-MCP-Runtime-Logon/);
|
|
13
|
+
assert.match(source,/RunLevel Limited/);
|
|
14
|
+
assert.match(source,/desktop_reapproval_required=\$true/);
|
|
15
|
+
assert.doesNotMatch(source,/armdesktop|armprocess|armcoding|armhost|armautonomous/i);
|
|
16
|
+
assert.doesNotMatch(source,/Stop-Process|taskkill|TerminateProcess/i);
|
|
17
|
+
});
|
|
18
|
+
test('R193 owner request is generated only from fixed protected live state after migration',async()=>{
|
|
19
|
+
const source=await readFile(path.join(root,'scripts','r193-owner-request-live.mjs'),'utf8');
|
|
20
|
+
assert.match(source,/process\.argv\.length!==2/);
|
|
21
|
+
assert.match(source,/createR193LiveMachineEpoch/);
|
|
22
|
+
assert.match(source,/verifyManifestTreeExact/);
|
|
23
|
+
assert.match(source,/observation\.state!=='ONLINE'/);
|
|
24
|
+
assert.match(source,/authority_granted:false/);
|
|
25
|
+
assert.doesNotMatch(source,/createPrivateKey|issueR186AutonomousGrant|createAuthorityEpochStore|armautonomous/i);
|
|
26
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import {createR188OwnerUacRequest} from '../src/r188-owner-uac.mjs';
|
|
5
|
+
import {buildR193LiveOwnerBoundary,createR193LiveMachineEpoch} from '../src/r193-live-owner-subject.mjs';
|
|
6
|
+
|
|
7
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
8
|
+
const filetime=iso=>{
|
|
9
|
+
const m=/^(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d)\.(\d{1,7})Z$/.exec(iso);
|
|
10
|
+
return (BigInt(Date.parse(m[1]+'.000Z')+11644473600000)*10000n+BigInt(m[2].padEnd(7,'0'))).toString(16).padStart(16,'0');
|
|
11
|
+
};
|
|
12
|
+
function fixture(){
|
|
13
|
+
const manifest=Buffer.from('manifest'),coding=Buffer.from('coding'),autonomous=Buffer.from('autonomous');
|
|
14
|
+
const pointer={release_id:'v0.15.72-test',version:'0.15.72',manifest_sha256:sha(manifest),
|
|
15
|
+
generation_manifest_sha256:'d'.repeat(64),release_root:'C:\\Program Files\\DEADBYTE-Test'};
|
|
16
|
+
const authority={process:{configured:true,armed:true,reason:'standing-grant',epoch_seq:1,epoch_sha256:'1'.repeat(64)},
|
|
17
|
+
coding:{configured:true,armed:true,reason:'standing-grant',epoch_seq:2,epoch_sha256:'2'.repeat(64)},
|
|
18
|
+
autonomous:{configured:true,armed:false,reason:'disarmed'},
|
|
19
|
+
desktop:{configured:true,armed:true,reason:'standing-grant',epoch_seq:3,epoch_sha256:'3'.repeat(64)},
|
|
20
|
+
host:{configured:true,armed:true,reason:'standing-grant',epoch_seq:4,epoch_sha256:'4'.repeat(64)}};
|
|
21
|
+
const times={bridge:'2026-10-29T08:00:00.1234567Z',core:'2026-10-29T08:00:01.0000000Z',
|
|
22
|
+
cloud:'2026-10-29T08:00:02.7654321Z',supervisor:'2026-10-29T08:00:03.1000000Z'};
|
|
23
|
+
const observation={schema:'deadbyte.controller-observation.v1',core_root:pointer.release_root,
|
|
24
|
+
bridge:{alive:true,pid:101,creation_time_utc:times.bridge},core:{alive:true,pid:102,creation_time_utc:times.core},
|
|
25
|
+
cloud:{alive:true,pid:103,creation_time_utc:times.cloud},supervisor:{running:true},authority};
|
|
26
|
+
const supervisor={pid:104,creation_time_utc:times.supervisor};
|
|
27
|
+
const reports=Object.fromEntries(['bridge','core','cloud','supervisor'].map((component,index)=>[component,{
|
|
28
|
+
schema:'deadbyte.r193-native-process-token.v1',pid:101+index,creation_filetime_hex:filetime(times[component]),
|
|
29
|
+
alive:true,identity_verified:true,elevated:false,admin_enabled:false,integrity_rid:8192,token_type:'primary'}]));
|
|
30
|
+
const machineEpoch=createR193LiveMachineEpoch({activePointer:pointer,controllerObservation:observation});
|
|
31
|
+
const now=new Date('2026-10-29T08:01:00.000Z');
|
|
32
|
+
const request=createR188OwnerUacRequest({machineEpoch,releaseManifestSha256:sha(manifest),
|
|
33
|
+
codingPolicySha256:sha(coding),autonomousPolicySha256:sha(autonomous),rootId:'core',
|
|
34
|
+
projectRoot:'D:\\Projects\\deadbyte-mcp',maxSeconds:600,now,expiresInMs:120000});
|
|
35
|
+
return {manifest,coding,autonomous,pointer,observation,supervisor,reports,request,now};
|
|
36
|
+
}
|
|
37
|
+
const build=(f,changes={})=>buildR193LiveOwnerBoundary({request:f.request,activePointer:f.pointer,
|
|
38
|
+
installedManifestBytes:f.manifest,codingPolicyBytes:f.coding,autonomousPolicyBytes:f.autonomous,
|
|
39
|
+
controllerObservation:f.observation,supervisorLedger:f.supervisor,processReports:f.reports,
|
|
40
|
+
brokerR89Trusted:true,keyAclTrusted:true,uac:{enable_uac:true,secure_desktop:true,prompt_mode:'explicit_secure_desktop'},
|
|
41
|
+
ownerGesture:'approved',now:new Date(f.now.getTime()+1000),...changes});
|
|
42
|
+
|
|
43
|
+
test('R193 derives exact owner boundary from live release, policies, epoch and kernel process identities',()=>{
|
|
44
|
+
const f=fixture(),out=build(f);
|
|
45
|
+
assert.equal(out.expected.machineEpoch,f.request.subject.machine_epoch);
|
|
46
|
+
assert.equal(out.boundary.agent_processes.length,4);
|
|
47
|
+
assert.equal(out.boundary.agent_processes.every(x=>x.identity_verified&&!x.elevated),true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('R193 live subject rejects release, policy, authority and process identity drift',()=>{
|
|
51
|
+
const f=fixture();
|
|
52
|
+
for(const changes of [
|
|
53
|
+
{installedManifestBytes:Buffer.from('changed')},
|
|
54
|
+
{codingPolicyBytes:Buffer.from('changed')},
|
|
55
|
+
{autonomousPolicyBytes:Buffer.from('changed')},
|
|
56
|
+
{activePointer:{...f.pointer,generation_manifest_sha256:'e'.repeat(64)}},
|
|
57
|
+
{processReports:{...f.reports,core:{...f.reports.core,pid:999}}},
|
|
58
|
+
{processReports:{...f.reports,cloud:{...f.reports.cloud,creation_filetime_hex:'0'.repeat(16)}}},
|
|
59
|
+
{controllerObservation:{...f.observation,authority:{...f.observation.authority,host:{...f.observation.authority.host,epoch_seq:5}}}}
|
|
60
|
+
])assert.throws(()=>build(f,changes),/R193|R188/);
|
|
61
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
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 path from 'node:path';
|
|
6
|
+
|
|
7
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
8
|
+
const binary=path.join(root,'bin','deadbyte-owner-token-r193.exe');
|
|
9
|
+
|
|
10
|
+
test('R193 native observer reports target process token and kernel creation identity',()=>{
|
|
11
|
+
const result=spawnSync(binary,['--inspect-pid',String(process.pid)],{
|
|
12
|
+
cwd:root,encoding:'utf8',windowsHide:true,timeout:10000,maxBuffer:256*1024});
|
|
13
|
+
assert.equal(result.status,0,result.stderr);
|
|
14
|
+
const report=JSON.parse(result.stdout);
|
|
15
|
+
assert.equal(report.schema,'deadbyte.r193-native-process-token.v1');
|
|
16
|
+
assert.equal(report.pid,process.pid);
|
|
17
|
+
assert.equal(report.alive,true);
|
|
18
|
+
assert.equal(report.identity_verified,true);
|
|
19
|
+
assert.match(report.creation_filetime_hex,/^[0-9a-f]{16}$/);
|
|
20
|
+
assert.equal(typeof report.elevated,'boolean');
|
|
21
|
+
assert.equal(typeof report.admin_enabled,'boolean');
|
|
22
|
+
assert.ok(Number.isSafeInteger(report.integrity_rid));
|
|
23
|
+
assert.equal(report.token_type,'primary');
|
|
24
|
+
assert.equal(report.owner_approved,false);
|
|
25
|
+
assert.equal(report.authority_granted,false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('R193 native observer rejects missing, malformed and nonexistent target PIDs',()=>{
|
|
29
|
+
for(const args of [['--inspect-pid'],['--inspect-pid','0'],['--inspect-pid','x'],
|
|
30
|
+
['--inspect-pid','2147483647']]){
|
|
31
|
+
const result=spawnSync(binary,args,{cwd:root,encoding:'utf8',windowsHide:true,
|
|
32
|
+
timeout:10000,maxBuffer:256*1024});
|
|
33
|
+
assert.notEqual(result.status,0);
|
|
34
|
+
assert.doesNotMatch(result.stdout,/"identity_verified":true/);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {spawnSync} from 'node:child_process';
|
|
4
|
+
import {existsSync,readFileSync} from 'node:fs';
|
|
5
|
+
import {createHash} from 'node:crypto';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {fileURLToPath} from 'node:url';
|
|
8
|
+
|
|
9
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
10
|
+
const file=path.join(root,'bin','deadbyte-owner-token-r193.exe');
|
|
11
|
+
const binarySha='d554d732872f3d671fd2fb63c11fc0dac1f8cae377259c6d64dd0c5b3762f2b8';
|
|
12
|
+
const sha=x=>createHash('sha256').update(x).digest('hex');
|
|
13
|
+
const onlyWindows={skip:process.platform!=='win32'?'Windows token ABI required':false};
|
|
14
|
+
|
|
15
|
+
test('R193 native token inspection reports observed privilege, but never owner consent',onlyWindows,()=>{
|
|
16
|
+
assert.ok(existsSync(file),'compile R193 native Windows token gate before testing');
|
|
17
|
+
assert.equal(sha(readFileSync(file)),binarySha);
|
|
18
|
+
const result=spawnSync(file,['--report'],{encoding:'utf8',shell:false,timeout:10000});
|
|
19
|
+
assert.equal(result.status,0,result.stderr);
|
|
20
|
+
const v=JSON.parse(result.stdout);
|
|
21
|
+
assert.equal(v.schema,'deadbyte.r193-native-token.v1');
|
|
22
|
+
assert.equal(v.parent_independence_verified,false);
|
|
23
|
+
assert.equal(v.owner_approved,false);
|
|
24
|
+
assert.equal(v.authority_granted,false);
|
|
25
|
+
assert.equal(v.token_type,1);
|
|
26
|
+
const elevated=v.elevated||v.admin_enabled||v.integrity_rid>=12288;
|
|
27
|
+
assert.equal(v.status,elevated?'BLOCKED':'STANDARD_TOKEN_OBSERVED');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('R193 native --require-standard denies elevated processes and honors limited tokens',onlyWindows,()=>{
|
|
31
|
+
const raw=spawnSync(file,['--require-standard'],{encoding:'utf8',shell:false,timeout:10000});
|
|
32
|
+
const v=JSON.parse(raw.stdout);
|
|
33
|
+
assert.equal(raw.status,v.status==='STANDARD_TOKEN_OBSERVED'?0:3,raw.stderr);
|
|
34
|
+
assert.equal(v.owner_approved,false);
|
|
35
|
+
assert.equal(v.authority_granted,false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('R193 native gate does not expose any grant subcommand',onlyWindows,()=>{
|
|
39
|
+
const raw=spawnSync(file,['--grant'],{encoding:'utf8',shell:false,timeout:10000});
|
|
40
|
+
assert.equal(raw.status,64);
|
|
41
|
+
assert.match(raw.stderr,/usage:/i);
|
|
42
|
+
assert.equal(raw.stdout,'');
|
|
43
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import {spawnSync} from 'node:child_process';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {inspectTrustedInstallation,privilegedEpochInstallFiles} from '../src/privileged-install-trust-r89.mjs';
|
|
8
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
9
|
+
test('R193 one-time enrollment has fixed owner path, no key export and no grant operation',async()=>{
|
|
10
|
+
const keygen=await readFile(path.join(root,'scripts','r193-owner-keygen.mjs'),'utf8');
|
|
11
|
+
const installer=await readFile(path.join(root,'scripts','r193-owner-uac-enroll-and-approve.ps1'),'utf8');
|
|
12
|
+
assert.match(keygen,/const OWNER='C:\\\\Program Files\\\\DEADBYTE-OwnerAuthority'/);
|
|
13
|
+
assert.match(keygen,/process\.argv\.length!==2/);
|
|
14
|
+
assert.match(keygen,/private_key_exported:false/);
|
|
15
|
+
assert.doesNotMatch(keygen,/issueR186AutonomousGrant|createAuthorityEpochStore|Arm-Autonomous|armautonomous/i);
|
|
16
|
+
assert.match(installer,/#requires -RunAsAdministrator/);
|
|
17
|
+
assert.match(installer,/SetAccessRuleProtection\(\$true,\$false\)/);
|
|
18
|
+
assert.doesNotMatch(installer,/BuiltinUsers|S-1-5-32-545|Users.*Read/i);
|
|
19
|
+
assert.match(installer,/FileMode\]::CreateNew/);
|
|
20
|
+
assert.match(installer,/Read-Host/);
|
|
21
|
+
assert.doesNotMatch(installer,/Start-Process.*-Verb\s+RunAs/i);
|
|
22
|
+
});
|
|
23
|
+
test('R193 keygen refuses mutable development bytes before creating owner material',async t=>{
|
|
24
|
+
let trusted=false;
|
|
25
|
+
try{
|
|
26
|
+
trusted=(await inspectTrustedInstallation(privilegedEpochInstallFiles(root,process.execPath))).trusted===true;
|
|
27
|
+
}catch{}
|
|
28
|
+
if(trusted){
|
|
29
|
+
t.skip('protected installation: executing keygen would cross the owner-enrollment boundary');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const cli=path.join(root,'scripts','r193-owner-keygen.mjs');
|
|
33
|
+
const result=spawnSync(process.execPath,[cli],{cwd:root,encoding:'utf8',windowsHide:true,
|
|
34
|
+
timeout:20000,maxBuffer:256*1024});
|
|
35
|
+
assert.equal(result.status,2);
|
|
36
|
+
assert.match(result.stderr,/R89 privileged installation not protected|R193/i);
|
|
37
|
+
assert.equal(result.stdout,'');
|
|
38
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {evaluateR193OwnerSecretAcl} from '../src/r193-owner-secret-acl.mjs';
|
|
4
|
+
const admin='S-1-5-32-544',system='S-1-5-18',users='S-1-5-32-545';
|
|
5
|
+
const files=['C:\\Program Files\\DEADBYTE-OwnerAuthority','C:\\Program Files\\DEADBYTE-OwnerAuthority\\owner-private.der'];
|
|
6
|
+
const records=()=>[
|
|
7
|
+
{path:files[0],owner:admin,reparse:false,protected:true,directory:true,
|
|
8
|
+
aces:[{sid:admin,type:'Allow',mask:0x1f01ff,inherited:false},{sid:system,type:'Allow',mask:0x1f01ff,inherited:false}]},
|
|
9
|
+
{path:files[1],owner:admin,reparse:false,protected:true,directory:false,
|
|
10
|
+
aces:[{sid:admin,type:'Allow',mask:0x1f01ff,inherited:false},{sid:system,type:'Allow',mask:0x1f01ff,inherited:false}]}
|
|
11
|
+
];
|
|
12
|
+
test('R193 owner secret ACL accepts only protected Administrator and SYSTEM access',()=>{
|
|
13
|
+
assert.deepEqual(evaluateR193OwnerSecretAcl(records(),files),
|
|
14
|
+
{trusted:true,reason:'OWNER_SECRET_ADMIN_SYSTEM_ONLY'});
|
|
15
|
+
});
|
|
16
|
+
test('R193 owner secret ACL rejects Users read, inheritance, reparse and wrong owner',()=>{
|
|
17
|
+
const cases=[
|
|
18
|
+
x=>x[1].aces.push({sid:users,type:'Allow',mask:0x120089,inherited:false}),
|
|
19
|
+
x=>x[1].aces[0].inherited=true,x=>x[0].reparse=true,x=>x[0].owner=users
|
|
20
|
+
];
|
|
21
|
+
for(const mutate of cases){const value=records();mutate(value);
|
|
22
|
+
assert.equal(evaluateR193OwnerSecretAcl(value,files).trusted,false);}
|
|
23
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {generateKeyPairSync} from 'node:crypto';
|
|
4
|
+
import {mkdtemp,rm} from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {createR188OwnerUacRequest} from '../src/r188-owner-uac.mjs';
|
|
8
|
+
import {verifyProjectOwnerApproval} from '../src/r70-owner-approval.mjs';
|
|
9
|
+
import {approveR193OwnerRequest} from '../src/r193-owner-uac-broker.mjs';
|
|
10
|
+
|
|
11
|
+
const h=c=>c.repeat(64);
|
|
12
|
+
async function fixture(){
|
|
13
|
+
const projectRoot=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r193-broker-'));
|
|
14
|
+
const now=new Date('2026-10-29T08:00:00.000Z');
|
|
15
|
+
const expected={machineEpoch:h('e'),releaseManifestSha256:h('a'),
|
|
16
|
+
codingPolicySha256:h('b'),autonomousPolicySha256:h('c'),
|
|
17
|
+
rootId:'core',projectRoot,maxSeconds:600};
|
|
18
|
+
const request=createR188OwnerUacRequest({...expected,now,expiresInMs:120000});
|
|
19
|
+
const pair=generateKeyPairSync('ed25519');
|
|
20
|
+
const privateKeyDer=pair.privateKey.export({format:'der',type:'pkcs8'});
|
|
21
|
+
const processes=['bridge','core','cloud','supervisor'].map((component,index)=>({
|
|
22
|
+
component,pid:1000+index,creation_time_utc:`2026-10-29T07:5${index}:00.000Z`,
|
|
23
|
+
alive:true,identity_verified:true,elevated:false,admin_enabled:false,
|
|
24
|
+
integrity_rid:8192,token_type:'primary'
|
|
25
|
+
}));
|
|
26
|
+
const boundary={schema:'deadbyte.r193-owner-runtime-boundary.v1',
|
|
27
|
+
broker_r89_trusted:true,key_acl_trusted:true,enable_uac:true,
|
|
28
|
+
secure_desktop:true,prompt_mode:'explicit_secure_desktop',
|
|
29
|
+
owner_gesture:'approved',live_epoch_verified:true,live_policies_verified:true,
|
|
30
|
+
live_release_verified:true,agent_processes:processes};
|
|
31
|
+
return {projectRoot,now,expected,request,pair,privateKeyDer,boundary};
|
|
32
|
+
}
|
|
33
|
+
const cleanup=f=>rm(f.projectRoot,{recursive:true,force:true});
|
|
34
|
+
const approve=(f,patch={})=>approveR193OwnerRequest({request:f.request,
|
|
35
|
+
expected:f.expected,privateKeyDer:f.privateKeyDer,
|
|
36
|
+
boundary:{...f.boundary,...patch},now:new Date(f.now.getTime()+1000)});
|
|
37
|
+
|
|
38
|
+
test('R193 protected UAC broker signs exact R70 approval only after a fully Limited live boundary',async()=>{
|
|
39
|
+
const f=await fixture();
|
|
40
|
+
try{
|
|
41
|
+
const out=approve(f);
|
|
42
|
+
assert.equal(out.status,'OWNER_APPROVED_FOR_SINGLE_USE_GRANT');
|
|
43
|
+
assert.equal(out.authority_granted,false);
|
|
44
|
+
assert.equal(out.owner_approved,true);
|
|
45
|
+
assert.equal(out.private_key_material_returned,false);
|
|
46
|
+
assert.equal(Object.hasOwn(out,'privateKeyDer'),false);
|
|
47
|
+
assert.equal(out.request_sha256,f.request.request_sha256);
|
|
48
|
+
const verified=await verifyProjectOwnerApproval({approval:out.approval,
|
|
49
|
+
ownerPublicKey:out.owner_public_key_pem,expected:{rootId:'core',
|
|
50
|
+
projectRoot:f.projectRoot,codingPolicySha256:h('b'),
|
|
51
|
+
autonomousPolicySha256:h('c'),reviewedArtifactSha256:h('a')},
|
|
52
|
+
now:new Date(f.now.getTime()+1000)});
|
|
53
|
+
assert.equal(verified.approved,true);
|
|
54
|
+
}finally{await cleanup(f);}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('R193 broker refuses any elevated, unverified, missing, duplicate or dead agent process',async()=>{
|
|
58
|
+
const f=await fixture();
|
|
59
|
+
try{
|
|
60
|
+
for(const agent_processes of [
|
|
61
|
+
f.boundary.agent_processes.map((x,i)=>i?x:{...x,elevated:true,integrity_rid:12288}),
|
|
62
|
+
f.boundary.agent_processes.map((x,i)=>i?x:{...x,identity_verified:false}),
|
|
63
|
+
f.boundary.agent_processes.map((x,i)=>i?x:{...x,alive:false}),
|
|
64
|
+
f.boundary.agent_processes.slice(0,3),
|
|
65
|
+
[...f.boundary.agent_processes,f.boundary.agent_processes[0]]
|
|
66
|
+
])assert.throws(()=>approve(f,{agent_processes}),/R193.*process|Limited|identity/i);
|
|
67
|
+
}finally{await cleanup(f);}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('R193 broker refuses untrusted key/package, insecure UAC, absent gesture and live identity drift',async()=>{
|
|
71
|
+
const f=await fixture();
|
|
72
|
+
try{
|
|
73
|
+
for(const patch of [
|
|
74
|
+
{broker_r89_trusted:false},{key_acl_trusted:false},{enable_uac:false},
|
|
75
|
+
{secure_desktop:false},{prompt_mode:'silent'},{owner_gesture:'rejected'},
|
|
76
|
+
{live_epoch_verified:false},{live_policies_verified:false},{live_release_verified:false}
|
|
77
|
+
])assert.throws(()=>approve(f,patch),/R193/);
|
|
78
|
+
assert.throws(()=>approveR193OwnerRequest({request:f.request,
|
|
79
|
+
expected:{...f.expected,machineEpoch:h('0')},privateKeyDer:f.privateKeyDer,
|
|
80
|
+
boundary:f.boundary,now:f.now}),/R188|R193/);
|
|
81
|
+
}finally{await cleanup(f);}
|
|
82
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import {spawnSync} from 'node:child_process';
|
|
5
|
+
import {fileURLToPath} from 'node:url';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import {inspectTrustedInstallation,privilegedEpochInstallFiles} from '../src/privileged-install-trust-r89.mjs';
|
|
8
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
9
|
+
test('R193 owner entrypoint is fixed-scope, protected and exposes no caller-selected key or state root',async()=>{
|
|
10
|
+
const cli=await readFile(path.join(root,'scripts','r193-owner-uac-broker.mjs'),'utf8');
|
|
11
|
+
const ps=await readFile(path.join(root,'scripts','r193-owner-uac-approve.ps1'),'utf8');
|
|
12
|
+
assert.match(cli,/const STATE='C:\\\\Users\\\\DEADBYTE\\\\\.deadbyte-mcp'/);
|
|
13
|
+
assert.match(cli,/const OWNER='C:\\\\Program Files\\\\DEADBYTE-OwnerAuthority'/);
|
|
14
|
+
assert.match(cli,/inspectTrustedInstallation/);
|
|
15
|
+
assert.match(cli,/verifyManifestTreeExact/);
|
|
16
|
+
assert.match(cli,/inspectR193OwnerSecretAcl/);
|
|
17
|
+
assert.match(cli,/exactOrWrite/);
|
|
18
|
+
assert.doesNotMatch(cli,/private-key|owner-dir|state-root/);
|
|
19
|
+
assert.match(ps,/#requires -RunAsAdministrator/);
|
|
20
|
+
assert.match(ps,/Read-Host/);
|
|
21
|
+
assert.doesNotMatch(ps,/Start-Process.*-Verb\s+RunAs/i);
|
|
22
|
+
assert.doesNotMatch(ps,/armautonomous|authority_granted\s*=\s*\$true/i);
|
|
23
|
+
});
|
|
24
|
+
test('R193 owner entrypoint fails closed before approval when its request is absent',async()=>{
|
|
25
|
+
let trusted=false;
|
|
26
|
+
try{
|
|
27
|
+
trusted=(await inspectTrustedInstallation(privilegedEpochInstallFiles(root,process.execPath))).trusted===true;
|
|
28
|
+
}catch{}
|
|
29
|
+
const cli=path.join(root,'scripts','r193-owner-uac-broker.mjs');
|
|
30
|
+
const result=spawnSync(process.execPath,[cli,'preflight','D:\\missing-request.json'],{
|
|
31
|
+
cwd:root,encoding:'utf8',windowsHide:true,timeout:20000,maxBuffer:512*1024});
|
|
32
|
+
assert.equal(result.status,2);
|
|
33
|
+
if(trusted)assert.match(result.stderr,/ENOENT.*missing-request\.json/i);
|
|
34
|
+
else assert.match(result.stderr,/R193_OWNER_UAC_BROKER_BLOCKED|R89 privileged installation not protected/i);
|
|
35
|
+
assert.equal(result.stdout,'');
|
|
36
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {readFile} from 'node:fs/promises';
|
|
4
|
+
import {fileURLToPath} from 'node:url';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
|
|
7
|
+
const root=fileURLToPath(new URL('..',import.meta.url));
|
|
8
|
+
const json=async file=>JSON.parse(await readFile(path.join(root,file),'utf8'));
|
|
9
|
+
const parent={
|
|
10
|
+
version:'0.15.72',
|
|
11
|
+
release_id:'v0.15.72-0a5d9436e06e2d9e',
|
|
12
|
+
manifest_sha256:'0a5d9436e06e2d9e7cf9179417465955d8ca5ba88655b13dd019190243c1cc90',
|
|
13
|
+
generation_manifest_sha256:'aec7b998306a3bbbcc59088648e7bc46ca7e203d749d4550b5b5f372032f92b0'
|
|
14
|
+
};
|
|
15
|
+
const parentTarball='15ab5d9808cbca342aee3f64c6d1123e8fbb72964674eab460e355c8675bf84d';
|
|
16
|
+
|
|
17
|
+
test('R193 package identity binds exact active and published 0.15.72 predecessor',async()=>{
|
|
18
|
+
const [pkg,bridge,release,provenance,matrix,sbom,versionSource]=await Promise.all([
|
|
19
|
+
json('package.json'),json('bridge/package.json'),json('RELEASE.json'),json('PROVENANCE.json'),
|
|
20
|
+
json('TEST-MATRIX.json'),json('SBOM.cdx.json'),readFile(path.join(root,'src','version.mjs'),'utf8')]);
|
|
21
|
+
assert.equal(pkg.version,'0.15.74');
|
|
22
|
+
assert.equal(bridge.version,'0.15.74');
|
|
23
|
+
assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.74'/);
|
|
24
|
+
assert.equal(release.version,'0.15.74');
|
|
25
|
+
assert.equal(release.train,'R194');
|
|
26
|
+
for(const key of Object.keys(parent)){
|
|
27
|
+
assert.equal(release.parent[key],parent[key]);
|
|
28
|
+
assert.equal(release.runtime_predecessor[key],parent[key]);
|
|
29
|
+
}
|
|
30
|
+
assert.equal(release.source_predecessor.version,'0.15.73');
|
|
31
|
+
assert.equal(release.source_predecessor.train,'R193');
|
|
32
|
+
assert.equal(release.source_predecessor.manifest_sha256,'e0b3f8b333f1c1260a97b178d1a8beff5742355296a9fe7daba378612604a3bd');
|
|
33
|
+
assert.equal(release.source_predecessor.tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
|
|
34
|
+
assert.equal(provenance.version,'0.15.74');
|
|
35
|
+
assert.equal(provenance.parent_release_id,parent.release_id);
|
|
36
|
+
assert.equal(provenance.parent_manifest_sha256,parent.manifest_sha256);
|
|
37
|
+
assert.equal(provenance.parent_generation_manifest_sha256,parent.generation_manifest_sha256);
|
|
38
|
+
assert.equal(provenance.source_predecessor_version,'0.15.73');
|
|
39
|
+
assert.equal(provenance.source_predecessor_tarball_sha256,'13c3dd23a535609aa53173b328c7d9299d5dcada684f3253a88af6a4b300c534');
|
|
40
|
+
assert.equal(matrix.version,'0.15.74');
|
|
41
|
+
assert.equal(matrix.train,'R194');
|
|
42
|
+
assert.equal(sbom.metadata.component.version,'0.15.74');
|
|
43
|
+
assert.match(sbom.serialNumber,/r194:0\.15\.74$/);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('R193 manifest binds every protected owner-boundary implementation file',async()=>{
|
|
47
|
+
const manifest=await readFile(path.join(root,'MANIFEST.SHA256'),'utf8');
|
|
48
|
+
for(const file of [
|
|
49
|
+
'bin/deadbyte-owner-token-r193.exe','native/deadbyte-owner-token-r193.cpp',
|
|
50
|
+
'scripts/r193-migrate-runtime-limited.ps1','scripts/r193-owner-keygen.mjs',
|
|
51
|
+
'scripts/r193-owner-request-live.mjs','scripts/r193-owner-uac-approve.ps1',
|
|
52
|
+
'scripts/r193-owner-uac-broker.mjs','scripts/r193-owner-uac-enroll-and-approve.ps1',
|
|
53
|
+
'src/r193-live-owner-subject.mjs','src/r193-owner-secret-acl.mjs',
|
|
54
|
+
'src/r193-owner-uac-broker.mjs','test/r193-release-identity.test.mjs'
|
|
55
|
+
]) assert.match(manifest,new RegExp(' '+file.replaceAll('.','\\.')+'(?:\\r?\\n|$)'));
|
|
56
|
+
});
|