Files
safetynet/scripts/incident-admin-smoke.cjs
2026-10-13 10:34:48 +02:00

23 lines
5.2 KiB
JavaScript

'use strict';
const {app,BrowserWindow}=require('electron'),assert=require('node:assert/strict'),fs=require('node:fs'),path=require('node:path');
app.disableHardwareAcceleration();app.enableSandbox();app.setPath('userData',process.env.SAFETYNET_ADMIN_SMOKE_PROFILE);let window;const deadline=setTimeout(()=>app.exit(1),50000);
const evaluate=source=>window.webContents.executeJavaScript(source,true);
async function waitFor(source){const until=Date.now()+12000;while(Date.now()<until){if(await evaluate(source))return;await new Promise(r=>setTimeout(r,75));}throw Error('Incident UI state missing: '+await evaluate(`document.getElementById('status').textContent`));}
app.whenReady().then(async()=>{
window=new BrowserWindow({show:false,width:1500,height:1100,webPreferences:{nodeIntegration:false,contextIsolation:true,sandbox:true,offscreen:true,backgroundThrottling:false}});await window.loadURL(process.env.SAFETYNET_ADMIN_SMOKE_URL);
assert.deepEqual(await evaluate(`({node:typeof process,require:typeof require})`),{node:'undefined',require:'undefined'});assert.ok((await evaluate(`fetch(location.href).then(r=>r.headers.get('content-security-policy'))`)).includes("script-src 'self'"));
await evaluate(`document.getElementById('token').value=${JSON.stringify(process.env.SAFETYNET_ADMIN_SMOKE_TOKEN)};document.getElementById('connect').click()`);await waitFor(`document.getElementById('status').textContent.includes('Connected')`);
await evaluate(`document.querySelector('[data-incident-create]').click()`);await waitFor(`!document.getElementById('incident-detail').hidden`);assert.equal(await evaluate(`document.getElementById('incident-event').textContent.includes('NEVER_SHOW_DOCUMENT_CONTENT')`),false);
await evaluate(`document.getElementById('incident-state').value='investigating';document.getElementById('incident-severity').value='high';document.getElementById('incident-assignee').value='Synthetic SOC';document.getElementById('incident-comment').value='Synthetic investigation started. <img src=x onerror=alert(1)>';document.getElementById('incident-save').click()`);await waitFor(`document.getElementById('incident-revision').textContent.includes('revision 2')`);
assert.ok(await evaluate(`document.getElementById('incident-history').textContent.includes('Synthetic investigation started. <img src=x onerror=alert(1)>')`));assert.equal(await evaluate(`document.querySelectorAll('#incident-history img').length`),0);
const id=await evaluate(`document.querySelector('#incident-rows tr').dataset.incidentId`);
await evaluate(`fetch('/api/admin/incidents/'+${JSON.stringify(id)},{method:'PATCH',headers:{authorization:'Bearer '+${JSON.stringify(process.env.SAFETYNET_ADMIN_SMOKE_TOKEN)},'content-type':'application/json'},body:JSON.stringify({expectedRevision:2,status:'resolved'})}).then(r=>{if(!r.ok)throw Error('Concurrent synthetic update failed')})`);
await evaluate(`document.getElementById('incident-comment').value='Preserved concurrent edit';document.getElementById('incident-save').click()`);await waitFor(`document.getElementById('incident-detail-status').textContent.includes('revision conflict')`);assert.equal(await evaluate(`document.getElementById('incident-comment').value`),'Preserved concurrent edit');
await evaluate(`document.getElementById('incident-detail-refresh').click()`);await waitFor(`document.getElementById('incident-revision').textContent.includes('revision 3')`);
await evaluate(`document.getElementById('incident-status-filter').value='open';document.getElementById('incident-status-filter').dispatchEvent(new Event('change'))`);await waitFor(`document.querySelectorAll('#incident-rows tr').length===0`);
await evaluate(`document.getElementById('incident-status-filter').value='resolved';document.getElementById('incident-status-filter').dispatchEvent(new Event('change'))`);await waitFor(`document.querySelectorAll('#incident-rows tr').length===1`);
await window.webContents.session.cookies.set({url:process.env.SAFETYNET_ADMIN_SMOKE_URL,name:'sn_session',value:process.env.SAFETYNET_INCIDENT_AUDITOR_TOKEN,httpOnly:true,sameSite:'lax'});await window.reload();await waitFor(`document.getElementById('status').textContent.includes('Connected')`);await evaluate(`document.querySelector('#incident-rows button').click()`);await waitFor(`!document.getElementById('incident-detail').hidden`);assert.equal(await evaluate(`document.getElementById('incident-save').disabled`),true);assert.equal(await evaluate(`document.querySelector('[data-incident-create]').disabled`),true);
const forbidden=await evaluate(`fetch('/api/admin/incidents/'+${JSON.stringify(id)},{method:'PATCH',headers:{'content-type':'application/json'},body:JSON.stringify({expectedRevision:3,status:'open'})}).then(r=>r.status)`);assert.equal(forbidden,403);
await evaluate(`document.getElementById('incidents').scrollIntoView()`);await new Promise(r=>setTimeout(r,250));fs.mkdirSync('artifacts',{recursive:true});fs.writeFileSync(path.resolve('artifacts/incident-admin.png'),(await window.webContents.capturePage()).toPNG());console.log('INCIDENT_ADMIN_PROOF_OK');clearTimeout(deadline);window.destroy();app.exit(0);
}).catch(error=>{console.error('INCIDENT_ADMIN_PROOF_FAILED',error.stack);clearTimeout(deadline);window?.destroy();app.exit(1);});