29 lines
3.7 KiB
JavaScript
29 lines
3.7 KiB
JavaScript
// Finite, isolated administrator workflow proof using actual UI and HTTP routes.
|
|||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import { createRequire } from 'node:module';
|
||
|
|
import { createServer } from 'node:net';
|
||
|
|
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
||
|
|
import { tmpdir } from 'node:os';
|
||
|
|
import { join, resolve, sep, basename } from 'node:path';
|
||
|
|
import { spawn } from 'node:child_process';
|
||
|
|
import { randomBytes } from 'node:crypto';
|
||
|
|
import { digest } from '../apps/server/store.mjs';
|
||
|
|
import { openStore } from '../apps/server/store.mjs';
|
||
|
|
import { createApp } from '../apps/server/app.mjs';
|
||
|
|
import { verifyPolicy } from '../packages/core/policy.mjs';
|
||
|
|
const require=createRequire(import.meta.url),directory=mkdtempSync(join(tmpdir(),'safetynet-profiles-admin-smoke-'));
|
||
|
|
let store,server,child;
|
||
|
|
try{
|
||
|
|
store=openStore(join(directory,'management'));const adminToken=randomBytes(32).toString('base64url'),config={adminToken,publicUrl:'http://127.0.0.1',secure:false,requireIndependentPolicyApproval:process.env.SAFETYNET_PROFILE_REVIEW_PROOF==='1'};
|
||
|
|
for(const id of ['pilot-device','member-device','outside-device'])store.db.prepare('INSERT INTO devices(id,name,platform,user,token_hash,last_seen) VALUES(?,?,?,?,?,?)').run(id,id,'win32','synthetic-user',`synthetic-${id}`,new Date().toISOString());
|
||
|
|
const operatorToken=randomBytes(32).toString('base64url'),reviewerToken=randomBytes(32).toString('base64url');for(const [value,sub,role]of [[operatorToken,'group-operator','operator'],[reviewerToken,'group-reviewer','admin']])store.db.prepare('INSERT INTO sessions VALUES(?,?,?)').run(digest(value),Date.now()+60000,JSON.stringify({sub,role}));
|
||
|
|
server=createApp(store,config).listen(0,'127.0.0.1');await new Promise(r=>server.once('listening',r));config.publicUrl=`http://127.0.0.1:${server.address().port}`;
|
||
|
|
const env={...process.env,SAFETYNET_ADMIN_SMOKE_PROFILE:join(directory,'browser'),SAFETYNET_ADMIN_SMOKE_URL:config.publicUrl,SAFETYNET_ADMIN_SMOKE_TOKEN:adminToken,SAFETYNET_PROFILE_OPERATOR_TOKEN:operatorToken,SAFETYNET_PROFILE_REVIEWER_TOKEN:reviewerToken};delete env.ELECTRON_RUN_AS_NODE;
|
||
|
|
child=spawn(require('electron'),['scripts/profiles-admin-smoke.cjs'],{env,windowsHide:true,stdio:['ignore','pipe','pipe']});child.stdout.on('data',data=>{if(String(data).includes('PROFILE_ADMIN_PROOF_OK'))console.log('Profile administrator interface workflow passed.');});child.stderr.on('data',data=>{const text=String(data);if(text.includes('PROFILE_ADMIN_PROOF_'))console.error(text.trim());});
|
||
|
|
const timer=setTimeout(()=>child.kill(),60000),code=await new Promise(r=>{child.once('exit',code=>r(code??1));child.once('error',()=>r(1));});clearTimeout(timer);assert.equal(code,0,'Profile administrator interface proof failed');
|
||
|
|
const policy=verifyPolicy(store.envelope(),store.publicKey());assert.equal(policy.version,2);
|
||
|
|
const report={actualAdministratorUi:true,explicitDeviceAssignments:true,employeeDeveloperFlags:true,websiteRestrictions:true,noNode:true,cspPreserved:true,...(config.requireIndependentPolicyApproval?{operatorProposalLeftPolicyUnchanged:true,exactProfileReviewed:true,distinctAdministratorApproval:true}:{effectivePreview:true})};mkdirSync('artifacts',{recursive:true});writeFileSync(config.requireIndependentPolicyApproval?'artifacts/profiles-review-admin-proof.json':'artifacts/profiles-admin-proof.json',JSON.stringify(report,null,2));console.log(JSON.stringify(report));
|
||
|
|
}finally{
|
||
|
|
child?.kill();if(server)await new Promise(r=>{server.closeAllConnections?.();server.close(r);});store?.db.close();const target=resolve(directory);if(!target.startsWith(resolve(tmpdir())+sep)||!basename(target).startsWith('safetynet-profiles-admin-smoke-'))throw Error('Unsafe proof cleanup');rmSync(target,{recursive:true,force:true,maxRetries:10,retryDelay:100});
|
||
|
|
}
|
||
|
|
|