Files
safetynet/tests/broker-runtime-manifest.test.mjs
T

38 lines
2.8 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {mkdtemp,writeFile,rm,symlink} from 'node:fs/promises';
import path from 'node:path';
import os from 'node:os';
import {BROKER_RUNTIME,verifyOfficialChecksums,verifyBrokerRuntime} from '../scripts/provision-broker-runtime.mjs';
const checksums=`${BROKER_RUNTIME.archiveSha256} ${BROKER_RUNTIME.archive}\n${BROKER_RUNTIME.executableSha256} win-x64/node.exe\n`;
async function fixture(t){
const root=await mkdtemp(path.join(os.tmpdir(),'safetynet-node-runtime-'));t.after(()=>rm(root,{force:true,recursive:true}));
const manifest={format:'safetynet-node-broker-runtime-v1',version:BROKER_RUNTIME.version,platform:'win32',arch:'x64',archiveSha256:BROKER_RUNTIME.archiveSha256,files:[{path:'node.exe',bytes:9,sha256:BROKER_RUNTIME.executableSha256},{path:'LICENSE',bytes:7,sha256:BROKER_RUNTIME.licenseSha256}]};
await writeFile(path.join(root,'runtime-manifest.json'),JSON.stringify(manifest));
await writeFile(path.join(root,'node.exe'),'synthetic');await writeFile(path.join(root,'LICENSE'),'license');
return {root,manifest};
}
test('official checksums must match reviewed archive and standalone executable pins',()=>{
assert.doesNotThrow(()=>verifyOfficialChecksums(checksums));
for(const text of [checksums.replace(BROKER_RUNTIME.archiveSha256,'0'.repeat(64)),checksums+checksums,checksums.replace('win-x64/node.exe','win-arm64/node.exe'),'x'.repeat(65537)])assert.throws(()=>verifyOfficialChecksums(text));
});
test('edited manifest cannot relabel wrong runtime version architecture or archive',async t=>{
const {root,manifest}=await fixture(t);
for(const change of [{version:'24.22.0'},{arch:'arm64'},{archiveSha256:'0'.repeat(64)},{files:[manifest.files[0],manifest.files[0]]}]){
await writeFile(path.join(root,'runtime-manifest.json'),JSON.stringify({...manifest,...change}));
await assert.rejects(verifyBrokerRuntime(root),{code:'broker_runtime_manifest_invalid'});
}
});
test('synthetic executable cannot be accepted as official runtime even with shaped manifest',async t=>{
const {root}=await fixture(t);await assert.rejects(verifyBrokerRuntime(root),{code:'broker_runtime_integrity_mismatch'});
});
test('unlisted runtime injection is rejected before payload verification',async t=>{
const {root}=await fixture(t);await writeFile(path.join(root,'injection.dll'),'private');
await assert.rejects(verifyBrokerRuntime(root),{code:'broker_runtime_inventory_mismatch'});
});
test('runtime directory junction is not trusted as an installation path',async t=>{
const {root}=await fixture(t),alias=root+'-alias';t.after(()=>rm(alias,{force:true,recursive:true}));
await symlink(root,alias,process.platform==='win32'?'junction':'dir');
await assert.rejects(verifyBrokerRuntime(alias),{code:'broker_runtime_path_unsafe'});
});