import {createServer} from 'node:http'; import {createRequire} from 'node:module'; import {mkdtempSync,mkdirSync,rmSync} from 'node:fs'; import {tmpdir} from 'node:os'; import {join,resolve} from 'node:path'; import {spawn} from 'node:child_process'; import {randomBytes} from 'node:crypto'; import {createApp} from '../apps/server/app.mjs'; import {openStore,digest} from '../apps/server/store.mjs'; import {startTelemetry} from '../apps/server/telemetry.mjs'; const collector='http://127.0.0.1:4318'; if(!(await fetch(collector+'/health')).ok)throw Error('Protected collector unavailable'); process.env.OTEL_EXPORTER_OTLP_ENDPOINT=collector;const telemetry=startTelemetry(); const temporary=mkdtempSync(join(tmpdir(),'safetynet-individual-'));mkdirSync('artifacts',{recursive:true}); if(!resolve(temporary).startsWith(resolve(tmpdir())+requireSeparator())||!temporary.split(/[\\/]/).at(-1).startsWith('safetynet-individual-'))throw Error('Unsafe temporary fixture path'); function requireSeparator(){return process.platform==='win32'?'\\':'/';} const store=openStore(join(temporary,'db')),code=randomBytes(32).toString('base64url'),adminToken=randomBytes(32).toString('base64url'); let forbiddenRequests=0,ownerlessRequests=0;const forbidden=createServer((_req,res)=>{forbiddenRequests++;res.end('Forbidden receiver');}).listen(0,'127.0.0.2');await new Promise(r=>forbidden.once('listening',r)); const forbiddenUrl=`http://127.0.0.2:${forbidden.address().port}/forbidden`; const sink=createServer((req,res)=>{if(req.url==='/count'){res.setHeader('content-type','application/json');res.end(JSON.stringify({forbiddenRequests,ownerlessRequests}));return;}if(req.url==='/ownerless')ownerlessRequests++;if(req.url==='/redirect'){res.writeHead(302,{location:forbiddenUrl});res.end();return;}res.setHeader('content-type','text/html');res.end(req.url==='/protected-title'?'Synthetic confidential inventory title

Public actor fixture

':'Individual actor fixture

Public actor fixture

');}).listen(0,'127.0.0.1');await new Promise(r=>sink.once('listening',r)); const p=store.get('policy');p.browser.homeUrl=`http://127.0.0.1:${sink.address().port}`; p.agents={...p.agents,enabled:true,identityMode:'individual',scopes:['sessions','navigate','read','application:state','settings:get'],allowedHosts:['127.0.0.1','127.0.0.2'],grants:[{id:'reader-a',name:'Reader A',enabled:true,expiresAt:new Date(Date.now()+3600000).toISOString(),scopes:['sessions','navigate','read'],allowedHosts:['127.0.0.1'],generation:1},{id:'state-b',name:'State B',enabled:true,expiresAt:new Date(Date.now()+3600000).toISOString(),scopes:['application:state'],allowedHosts:['127.0.0.1'],generation:1}]}; p.dlp.rules.push({id:'inventory-confidential-fixture',label:'Synthetic inventory fixture',action:'block',kind:'literal',value:'Synthetic confidential inventory title'}); p.diagnostics={...p.diagnostics,enabled:true,mode:'debug',endpoint:collector,sampleRate:1,debugSampleRate:1,flushIntervalMs:250};store.put('policy',p);store.db.prepare('INSERT INTO enrollments VALUES(?,?,?)').run(digest(code),Date.now()+600000,'individual-fixture'); const config={secure:false,publicUrl:'http://127.0.0.1',adminToken,requirePQManagement:true}; const management=createApp(store,config).listen(0,'127.0.0.1');await new Promise(r=>management.once('listening',r));config.publicUrl=`http://127.0.0.1:${management.address().port}`; const electron=createRequire(import.meta.url)('electron'); async function run(phase){const child=spawn(electron,['scripts/individual-agent-electron.cjs'],{windowsHide:true,stdio:'inherit',env:{...process.env,SAFETYNET_SMOKE_SERVER:config.publicUrl,SAFETYNET_SMOKE_CODE:code,SAFETYNET_SMOKE_ADMIN:adminToken,SAFETYNET_SMOKE_USERDATA:join(temporary,'browser'),SAFETYNET_SMOKE_ARTIFACTS:resolve('artifacts'),SAFETYNET_SMOKE_PHASE:phase,SAFETYNET_SMOKE_SINK:p.browser.homeUrl,SAFETYNET_SMOKE_FORBIDDEN:forbiddenUrl}});const deadline=setTimeout(()=>child.kill(),180000);const exit=await new Promise(r=>{child.once('exit',v=>r(v??1));child.once('error',()=>r(1));});clearTimeout(deadline);return exit;} let exit=await run('initial');if(exit===0)exit=await run('restart'); for(const server of [management,sink,forbidden])server.closeAllConnections();await Promise.all([new Promise(r=>management.close(r)),new Promise(r=>sink.close(r)),new Promise(r=>forbidden.close(r))]);store.db.close();await telemetry?.shutdown();rmSync(temporary,{recursive:true,force:true});process.exit(exit);