38 lines
2.8 KiB
JavaScript
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'});
|
|
});
|