Assessor_2.0/tests/results-evidence-browser-ch...

47 lines
4.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Synthetic browser check of the actual Results window; no datastore mutation.
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { createServer } from 'node:http';
import { pathToFileURL } from 'node:url';
import { build } from 'esbuild';
const { chromium } = await import(pathToFileURL(process.env.PLAYWRIGHT_MODULE).href);
const main = await readFile('src/main.tsx', 'utf8');
const styles = [...main.matchAll(/^import '([^']+\.css)';/gm)].map(([, path]) =>
`import ${JSON.stringify(path.startsWith('.') ? './src/' + path.slice(2) : path)};`).join('\n');
const bundle = await build({ stdin: { resolveDir: process.cwd(), loader: 'tsx', contents: `${styles}
import React from 'react'; import {createRoot} from 'react-dom/client';
import {FloatingResultsWindow} from './src/features/linked-results/FloatingResultsWindow';
import {makeSheet} from './src/importers/sheet-factory';
const finding=makeSheet('Synthetic',[['Title','Status','Source Rule ID','Verwandte Daten'],
['Synthetic SMBv1 finding','Matched','S-SMB-v1','synthetic::rule-details-S-SMB-v1']], '', 'synthetic.html').analysis.records[0];finding.importFileId='synthetic';
const own=makeSheet('PingCastle · Details',[['Domain controller'],['DUMMY-DC']], '', 'synthetic.html',{id:'pingcastle-section-synthetic::rule-details-S-SMB-v1'});
const inventory=makeSheet('PingCastle · Inventory',[['Domain controller','SMB v1'],['DUMMY-OTHER','NO']], '', 'synthetic.html');
const root=createRoot(document.getElementById('root'));
window.renderSynthetic=tool=>root.render(<FloatingResultsWindow id="synthetic" title="Results – Synthetic evidence" finding={finding}
toolId={tool} outcome="fail" sheets={tool==='pingcastle'?[own,inventory]:[]}
sections={tool==='maester'?[{title:'Test result',value:'| Object | Status |\\n| --- | --- |\\n| DUMMY-BAD | ❌ Failed |\\n| DUMMY-GOOD | ✅ Passed |\\n| DUMMY-UNKNOWN | Investigate |'}]:[]}
color="" zIndex={1} offset={0} search="" onActivate={()=>{}} onClose={()=>{}}/>);
window.renderSynthetic('pingcastle');` }, jsx:'automatic',bundle:true,write:false,outdir:'synthetic',format:'iife',
loader:{'.woff2':'dataurl','.woff':'dataurl','.png':'dataurl','.svg':'dataurl'} });
const server=createServer((req,res)=>{const file=bundle.outputFiles.find(file=>req.url==='/'+file.path.split(/[\\/]/).at(-1));
res.setHeader('Content-Type',file?(req.url.endsWith('.css')?'text/css':'text/javascript'):'text/html');
res.end(file?.contents??'<!doctype html><html><head><meta charset="utf-8"><link rel="stylesheet" href="/stdin.css"></head><body><div id="root"></div><script src="/stdin.js"></script></body></html>');});
await new Promise(resolve=>server.listen(0,'127.0.0.1',resolve));let browser;
try { browser=await chromium.launch({headless:true,channel:'chrome'});const page=await browser.newPage({viewport:{width:1280,height:900}});
page.on('pageerror', error=>console.error(error.message));
await page.goto('http://127.0.0.1:'+server.address().port+'/');
for(const theme of ['dark','light'])for(const tool of ['pingcastle','maester']) {
await page.evaluate(({theme,tool})=>{document.documentElement.dataset.theme=theme;window.renderSynthetic(tool);},{theme,tool});
try { await page.waitForFunction(tool=>document.querySelector('.rich-text-table-row--violation')?.textContent?.includes(tool==='pingcastle'?'DUMMY-DC':'DUMMY-BAD'),tool,{timeout:5000}); }
catch(error) { console.error(tool, await page.locator('tbody tr').evaluateAll(rows=>rows.map(row=>({text:row.textContent,cls:row.className})))); throw error; }
const red=await page.locator('.rich-text-table-row--violation td').first().evaluate(cell=>({actual:getComputedStyle(cell).backgroundColor,
token:getComputedStyle(document.documentElement).getPropertyValue('--violation-highlight-bg').trim(),text:cell.textContent}));
const tokenColor=await page.evaluate(token=>{const element=document.createElement('span');element.style.backgroundColor=token;document.body.append(element);const result=getComputedStyle(element).backgroundColor;element.remove();return result;},red.token);
assert.equal(red.actual,tokenColor);
const neutral=await page.locator('tbody tr').filter({hasText:tool==='pingcastle'?'DUMMY-OTHER':'DUMMY-UNKNOWN'}).first().evaluate(row=>row.classList.contains('rich-text-table-row--violation'));
assert.equal(neutral,false);
if(tool==='maester')assert.equal(await page.locator('.rich-text-table-row--match').count(),1);
}
console.log('Actual Results window: red affected evidence, neutral inventory/unknown rows and explicit pass rows verified in both themes.');
} finally {await browser?.close();await new Promise(resolve=>server.close(resolve));}