2026-10-13 16:58:15 +02:00
'use strict' ;
const { app , BrowserWindow } = require ( 'electron' );
const fs = require ( 'node:fs' ), path = require ( 'node:path' ), assert = require ( 'node:assert/strict' );
app . setPath ( 'userData' , process . env . SAFETYNET_SMOKE_USERDATA ); app . disableHardwareAcceleration (); require ( '../apps/browser/main.cjs' );
const wait = ms => new Promise ( r => setTimeout ( r , ms )), headers = { authorization : `Bearer ${ process . env . SAFETYNET_SMOKE_ADMIN } ` , 'content-type' : 'application/json' };
2026-10-13 18:04:02 +02:00
const startupAt = Date . now ();
function safeSnapshot ( stage ){ return { stage , elapsedMs : Date . now () - startupAt , phase : process . env . SAFETYNET_SMOKE_PHASE , windows : BrowserWindow . getAllWindows (). map ( w =>({ destroyed : w . isDestroyed (), loading : w . webContents . isLoading (), urlKind : w . webContents . getURL (). endsWith ( 'index.html' ) ? 'shell' : w . webContents . getURL () === '' ? 'empty' : 'other' , children : w . contentView . children . length })), metrics : app . getAppMetrics (). map ( m =>({ type : m . type , cpu : m . cpu . percentCPUUsage , idleWakeupsPerSecond : m . cpu . idleWakeupsPerSecond , memoryWorkingSetSize : m . memory . workingSetSize }))};}
async function until ( fn , stage = 'native-wait' ){ const started = Date . now (); for ( let n = 0 ; n < 200 ; n ++ ){ const result = await fn (); if ( result ) return result ; await wait ( 100 );} fs . writeFileSync ( path . join ( process . env . SAFETYNET_SMOKE_ARTIFACTS , 'individual-agent-timeout-' + process . env . SAFETYNET_SMOKE_PHASE + '.json' ), JSON . stringify ({... safeSnapshot ( stage ), waitElapsedMs : Date . now () - started }, null , 2 )); throw Error ( 'Individual native fixture timed out: ' + stage );}
2026-10-13 16:58:15 +02:00
const overview = async ()=> ( await fetch ( process . env . SAFETYNET_SMOKE_SERVER + '/api/admin/overview' ,{ headers })). json ();
app . whenReady (). then ( async ()=>{ let page ; try {
2026-10-13 18:04:02 +02:00
const win = await until (()=>{ const w = BrowserWindow . getAllWindows ()[ 0 ]; return w &&! w . webContents . isLoading () && w . webContents . getURL (). endsWith ( 'index.html' ) && w ;}, 'initial-shell-load' );
fs . writeFileSync ( path . join ( process . env . SAFETYNET_SMOKE_ARTIFACTS , 'individual-agent-startup-' + process . env . SAFETYNET_SMOKE_PHASE + '.json' ), JSON . stringify ( safeSnapshot ( 'shell-ready' ), null , 2 ));
2026-10-13 16:58:15 +02:00
if ( process . env . SAFETYNET_SMOKE_PHASE === 'restart' ){
await until ( async ()=> ( await win . webContents . executeJavaScript ( 'window.safetynet.state()' )). data . ready );
page = win . contentView . children . find ( v => v . webContents !== win . webContents ). webContents ;
assert . equal (( await win . webContents . executeJavaScript ( 'window.safetynet.agentConnection("reader-a")' )). ok , false , 'Restart accepted restored generation below durable floor' );
const state = ( await win . webContents . executeJavaScript ( 'window.safetynet.state()' )). data ; assert . ok ( Array . isArray ( state . agentGrants )); assert . ok ( ! state . agentGrants . some ( g => g . id === 'reader-a' ), 'Restored old generation visible after restart' ); assert . ok ( state . agentGrants . some ( g => g . id === 'state-b' ), 'Unaffected actor missing after restart' );
const oldFile = path . join ( app . getPath ( 'userData' ), 'old-generation-fixture.json' ), requestFile = path . join ( app . getPath ( 'userData' ), 'restart-request.json' ); fs . writeFileSync ( requestFile , JSON . stringify ({ action : 'sessions' , args : {}}));
const child = require ( 'node:child_process' ). spawn ( process . execPath ,[ 'scripts/agent-client.cjs' , '--connection' , oldFile , '--request' , requestFile ],{ windowsHide : true , stdio : [ 'ignore' , 'ignore' , 'ignore' ]}); assert . equal ( await new Promise ( r => child . once ( 'exit' , r )), 1 , 'Old descriptor reached restarted listener' );
const proofFile = path . join ( process . env . SAFETYNET_SMOKE_ARTIFACTS , 'individual-agent-native-proof.json' ), proof = JSON . parse ( fs . readFileSync ( proofFile , 'utf8' )); proof . durableGenerationFloorAfterRestart = true ; proof . oldDescriptorRejectedAfterRestart = true ; fs . writeFileSync ( proofFile , JSON . stringify ( proof , null , 2 ));
require ( '../apps/browser/page-clipboard-guard.cjs' ). disposePageClipboardGuard ( page ); console . log ( 'Individual generation floor restart proof passed' ); app . exit ( 0 ); return ;
}
2026-10-13 18:04:02 +02:00
page = win . contentView . children . find ( v => v . webContents !== win . webContents ) ? . webContents ;
2026-10-13 16:58:15 +02:00
const enroll = await win . webContents . executeJavaScript ( `window.safetynet.enroll( ${ JSON . stringify ({ server : process . env . SAFETYNET_SMOKE_SERVER , code : process . env . SAFETYNET_SMOKE_CODE } )})` ); assert . equal ( enroll . ok , true );
page = win . contentView . children . find ( v => v . webContents !== win . webContents ). webContents ; await until (()=> ! page . isLoading ());
assert . equal (( await win . webContents . executeJavaScript ( 'window.safetynet.agentConnection()' )). ok , false );
await win . webContents . executeJavaScript ( 'document.getElementById("agents").click()' ); await until (()=> win . webContents . executeJavaScript ( 'document.getElementById("agent-pairing")?.open' ));
assert . deepEqual ( await win . webContents . executeJavaScript ( 'Array.from(document.querySelectorAll(".agent-grant-choice strong"),e=>e.textContent)' ),[ 'Reader A' , 'State B' ]);
fs . writeFileSync ( path . join ( process . env . SAFETYNET_SMOKE_ARTIFACTS , 'individual-agent-pairing-ui.png' ),( await win . webContents . capturePage ()). toPNG ());
for ( const index of [ 0 , 1 ]){ await win . webContents . executeJavaScript ( `document.querySelectorAll('.agent-grant-choice')[ ${ index } ].click()` ); await until (()=> win . webContents . executeJavaScript ( `document.getElementById('agent-pairing-result').textContent.startsWith( ${ JSON . stringify ( 'Identity: ' + ( index === 0 ? 'Reader A' : 'State B' )) } )` ));}
await win . webContents . executeJavaScript ( 'document.getElementById("agent-pairing").close()' );
const pair = async id =>{ const r = await win . webContents . executeJavaScript ( `window.safetynet.agentConnection( ${ JSON . stringify ( id ) } )` ); assert . equal ( r . ok , true ); return r . data ;};
const a = await pair ( 'reader-a' ), b = await pair ( 'state-b' ); assert . notEqual ( a . credentialPath , b . credentialPath ); assert . equal ( fs . existsSync ( path . join ( app . getPath ( 'userData' ), 'agent-connection.json' )), false );
fs . copyFileSync ( a . credentialPath , path . join ( app . getPath ( 'userData' ), 'old-generation-fixture.json' ));
for ( const c of [ a , b ]){ const descriptor = JSON . parse ( fs . readFileSync ( c . credentialPath , 'utf8' )); assert . equal ( descriptor . format , 'windows-dpapi-v1' ); assert . equal ( Object . hasOwn ( descriptor , 'token' ), false );}
const requestFile = path . join ( app . getPath ( 'userData' ), 'individual-fixture-request.json' );
async function call ( connection , action , args = {}){ fs . writeFileSync ( requestFile , JSON . stringify ({ action , args })); const child = require ( 'node:child_process' ). spawn ( process . execPath ,[ 'scripts/agent-client.cjs' , '--connection' , connection . credentialPath , '--request' , requestFile ],{ windowsHide : true , stdio : [ 'ignore' , 'pipe' , 'pipe' ]}); let output = '' ; child . stdout . on ( 'data' , v => output += v ); child . stderr . on ( 'data' ,()=>{}); const exit = await new Promise ( r =>{ child . once ( 'exit' , r ); child . once ( 'error' ,()=> r ( 1 ));}); return { exit , result : exit === 0 ? JSON . parse ( output ). result : undefined };}
const sessions = await call ( a , 'sessions' ); assert . equal ( sessions . exit , 0 ); const sessionId = sessions . result [ 0 ]. id ;
2026-10-13 18:04:02 +02:00
assert . equal (( await call ( a , 'navigate' ,{ sessionId , url : process . env . SAFETYNET_SMOKE_SINK + '/protected-title' })). exit , 0 );
await until (()=> page . getTitle () === 'Synthetic confidential inventory title' , 'protected-title-load' );
const protectedInventory = await call ( a , 'sessions' ); assert . equal ( protectedInventory . exit , 0 ); assert . equal ( protectedInventory . result . find ( row => row . id === sessionId ) ? . title , 'Protected page' , 'Page-controlled confidential title escaped inventory classification' );
assert . equal (( await call ( a , 'navigate' ,{ sessionId , url : process . env . SAFETYNET_SMOKE_SINK + '/allowed' })). exit , 0 );
2026-10-13 16:58:15 +02:00
assert . equal (( await call ( a , 'read' ,{ sessionId })). exit , 0 ); assert . equal (( await call ( a , 'application:state' )). exit , 1 ); assert . equal (( await call ( b , 'application:state' )). exit , 0 ); assert . equal (( await call ( b , 'read' ,{ sessionId })). exit , 1 );
assert . equal (( await call ( a , 'navigate' ,{ sessionId , url : process . env . SAFETYNET_SMOKE_SINK + '/allowed' })). exit , 0 , 'Approved host navigation failed' );
assert . equal (( await call ( a , 'navigate' ,{ sessionId , url : process . env . SAFETYNET_SMOKE_FORBIDDEN })). exit , 1 , 'Actor reached forbidden host' );
assert . equal (( await call ( a , 'navigate' ,{ sessionId , url : process . env . SAFETYNET_SMOKE_SINK + '/redirect' })). exit , 1 , 'Actor followed forbidden redirect' );
assert . equal (( await ( await fetch ( process . env . SAFETYNET_SMOKE_SINK + '/count' )). json ()). forbiddenRequests , 0 , 'Forbidden receiver received actual network request' );
const humanNavigation = await win . webContents . executeJavaScript ( `window.safetynet.navigate( ${ JSON . stringify ( process . env . SAFETYNET_SMOKE_SINK + '/human' ) } )` ); assert . equal ( humanNavigation . ok , true , 'Human navigation failed' ); await until (()=> ! page . isLoading ());
assert . equal ( await page . executeJavaScript ( `fetch( ${ JSON . stringify ( process . env . SAFETYNET_SMOKE_SINK + '/count' ) } ).then(r=>r.ok)` ), true , 'Owned tab request failed after human navigation' );
const managedSession = require ( 'electron' ). session . fromPartition ( 'persist:safetynet-managed' ); let ownerlessRejected = false ; try { await managedSession . fetch ( process . env . SAFETYNET_SMOKE_SINK + '/ownerless' );} catch { ownerlessRejected = true ;} assert . equal ( ownerlessRejected , true , 'Ownerless session request escaped individual-mode ownership guard' );
assert . equal (( await ( await fetch ( process . env . SAFETYNET_SMOKE_SINK + '/count' )). json ()). ownerlessRequests , 0 , 'Ownerless request reached receiver' );
const change = async modify =>{ const policy = ( await overview ()). policy ; modify ( policy ); policy . version ++ ; const r = await fetch ( process . env . SAFETYNET_SMOKE_SERVER + '/api/admin/policy' ,{ method : 'PUT' , headers , body : JSON . stringify ( policy )}); assert . equal ( r . status , 200 ); await until ( async ()=>{ const s = await win . webContents . executeJavaScript ( 'window.safetynet.state()' ); return s . data . ready && s . data . policyVersion === policy . version ;});};
await change ( p =>{ p . agents . grants . find ( g => g . id === 'reader-a' ). enabled = false ;}); assert . equal (( await call ( a , 'sessions' )). exit , 1 ); assert . equal (( await call ( b , 'application:state' )). exit , 0 );
await change ( p =>{ const g = p . agents . grants . find ( g => g . id === 'reader-a' ); g . enabled = true ; g . generation = 2 ;}); const generationTwo = await pair ( 'reader-a' ); assert . equal ( generationTwo . generation , 2 ); assert . equal (( await call ( generationTwo , 'sessions' )). exit , 0 );
await change ( p =>{ p . agents . grants . find ( g => g . id === 'reader-a' ). generation = 1 ;}); assert . equal (( await win . webContents . executeJavaScript ( 'window.safetynet.agentConnection("reader-a")' )). ok , false , 'Live rollback bypassed generation floor' );
const events = await until ( async ()=>{ const e = ( await overview ()). events . filter ( e => e . metadata . agent ? . principalId ); return e . some ( e => e . metadata . agent . principalId === 'reader-a' && e . kind === 'agent.action' ) && e . some ( e => e . metadata . agent . principalId === 'state-b' && e . kind === 'agent.action' ) && e ;});
await wait ( 1500 ); let traceProof ;
for ( const event of events . filter ( e => e . kind === 'agent.action' && e . metadata . traceId )){ const r = await fetch ( 'http://127.0.0.1:4318/api/trace/' + event . metadata . traceId ); if ( ! r . ok ) continue ; const trace = await r . json (); const spans = trace . spans || trace ; if ( Array . isArray ( spans ) && spans . some ( s => s . name === 'browser.agent' && s . operation === 'agent.request' )){ traceProof = { traceId : event . metadata . traceId , principalId : event . metadata . agent . principalId , stages : spans . map ( s =>({ name : s . name , operation : s . operation , parentSpanId : s . parentSpanId , spanId : s . spanId , durationMs : s . durationMs }))}; break ;}}
assert . ok ( traceProof , 'Actual agent request trace missing' );
const root = traceProof . stages . find ( s => s . operation === 'agent.request' ); assert . equal ( root . parentSpanId , null );
for ( const operation of [ 'agent.decrypt' , 'agent.authorize' , 'agent.dispatch' , 'agent.project' , 'agent.audit' , 'agent.encrypt' ]) assert . ok ( traceProof . stages . some ( s => s . operation === operation && s . parentSpanId === root . spanId && Number . isFinite ( s . durationMs ) && s . durationMs >= 0 ), 'Missing correlated stage ' + operation );
2026-10-13 18:04:02 +02:00
fs . writeFileSync ( path . join ( process . env . SAFETYNET_SMOKE_ARTIFACTS , 'individual-agent-native-proof.json' ), JSON . stringify ({ actualElectron : true , classifiedInventoryRedactsTitlePreservesId : true , explicitGrantSelection : true , renderedGrantChoices : true , uiPairingBothActors : true , separateDPAPIDescriptors : true , noLegacyDescriptor : true , twoActors : true , scopeIntersection : true , approvedHostNavigation : true , forbiddenHostDeniedBeforeTransmission : true , forbiddenRedirectDeniedBeforeTransmission : true , forbiddenReceiverRequests : 0 , humanNavigationPreserved : true , ownedTabFetchAfterHumanNavigation : true , ownerlessSessionFetchBlockedBeforeTransmission : true , ownerlessReceiverRequests : 0 , targetedRevocation : true , unaffectedPeer : true , liveGenerationRollbackDenied : true , attributedAudit : true , traceProof }, null , 2 )); console . log ( 'Individual agent native proof passed' );
2026-10-13 16:58:15 +02:00
require ( '../apps/browser/page-clipboard-guard.cjs' ). disposePageClipboardGuard ( page ); app . exit ( 0 );
} catch ( error ){ console . error ( error . stack ); if ( page ) require ( '../apps/browser/page-clipboard-guard.cjs' ). disposePageClipboardGuard ( page ); app . exit ( 1 );}});