main
mjs 122 lines 4.61 KB
Raw
1 import fs from 'node:fs/promises';
2 import path from 'node:path';
3 import {chromium} from 'playwright';
4
5 const BASE_URL = process.env.COPILOT_BASE_URL || 'https://copilot-lab.socfortressmdr.us';
6 const USERNAME = process.env.COPILOT_USERNAME;
7 const PASSWORD = process.env.COPILOT_PASSWORD;
8
9 if (!USERNAME || !PASSWORD) {
10 console.error('Missing COPILOT_USERNAME or COPILOT_PASSWORD in environment.');
11 process.exit(1);
12 }
13
14 const OUT_DIR = path.resolve(process.cwd(), '..', '..', 'docs', 'assets', 'ui');
15
16 const routes = [
17 {key: 'overview', path: '/overview'},
18 {key: 'incident-sources', path: '/incident-management/sources'},
19 {key: 'incident-alerts', path: '/incident-management/alerts'},
20 {key: 'incident-cases', path: '/incident-management/cases'},
21 {key: 'alerts-siem', path: '/alerts/siem'},
22 {key: 'alerts-mitre', path: '/alerts/mitre'},
23 {key: 'alerts-atomic-red-team', path: '/alerts/atomic-red-team'},
24 {key: 'artifacts', path: '/artifacts'},
25 {key: 'customers', path: '/customers'},
26 {key: 'agents', path: '/agents'},
27 {key: 'agents-groups', path: '/agents/groups'},
28 {key: 'agents-sysmon-config', path: '/agents/sysmon-config'},
29 {key: 'agents-detection-rules', path: '/agents/detection-rules'},
30 {key: 'agents-copilot-actions', path: '/agents/copilot-actions'},
31 {key: 'agents-vulnerability-overview', path: '/agents/vulnerability-overview'},
32 {key: 'agents-sca-overview', path: '/agents/sca-overview'},
33 {key: 'patch-tuesday', path: '/patch-tuesday'},
34 {key: 'report-general', path: '/report-creation/general'},
35 {key: 'report-vulnerability', path: '/report-creation/vulnerability-reports'},
36 {key: 'report-sca', path: '/report-creation/sca-reports'},
37 {key: 'healthcheck', path: '/healthcheck'},
38 {key: 'indices-management', path: '/indices/management'},
39 {key: 'indices-snapshots', path: '/indices/snapshots'},
40 {key: 'graylog-management', path: '/graylog/management'},
41 {key: 'graylog-metrics', path: '/graylog/metrics'},
42 {key: 'graylog-pipelines', path: '/graylog/pipelines'},
43 {key: 'connectors', path: '/connectors'},
44 {key: 'external-third-party-integrations', path: '/external-services/third-party-integrations'},
45 {key: 'external-network-connectors', path: '/external-services/network-connectors'},
46 {key: 'external-singul-app-auth', path: '/external-services/singul-app-auth'},
47 {key: 'scheduler', path: '/scheduler'},
48 {key: 'customer-portal', path: '/customer-portal'}
49 ];
50
51 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
52
53 async function ensureDir(p) {
54 await fs.mkdir(p, {recursive: true});
55 }
56
57 async function main() {
58 await ensureDir(OUT_DIR);
59
60 const browser = await chromium.launch({headless: true});
61 const context = await browser.newContext({
62 viewport: {width: 1440, height: 900},
63 deviceScaleFactor: 2,
64 });
65 const page = await context.newPage();
66
67 // Login
68 await page.goto(`${BASE_URL}/login`, {waitUntil: 'domcontentloaded'});
69 await page.waitForTimeout(500);
70
71 // Try a few common selectors for the login form
72 const userInput = page.getByRole('textbox', {name: /username/i}).first()
73 .or(page.getByPlaceholder(/username/i).first())
74 .or(page.locator('input[type="text"], input[type="email"]').first());
75
76 const passInput = page.getByRole('textbox', {name: /password/i}).first()
77 .or(page.getByPlaceholder(/password/i).first())
78 .or(page.locator('input[type="password"]').first());
79
80 await userInput.fill(USERNAME);
81 await passInput.fill(PASSWORD);
82
83 const signIn = page.getByRole('button', {name: /sign in/i}).first()
84 .or(page.locator('button[type="submit"]').first());
85
86 await Promise.all([
87 page.waitForLoadState('networkidle').catch(() => undefined),
88 signIn.click()
89 ]);
90
91 // Give SPA time to hydrate
92 await sleep(1500);
93
94 // If still on /login, fail early
95 if (page.url().includes('/login')) {
96 const shot = path.join(OUT_DIR, '_login-failed.png');
97 await page.screenshot({path: shot, fullPage: true});
98 throw new Error(`Login appears to have failed; screenshot saved to ${shot}`);
99 }
100
101 // Screenshot sweep
102 for (const r of routes) {
103 const url = `${BASE_URL}${r.path}`;
104 console.log(`SHOT ${r.key} -> ${url}`);
105 await page.goto(url, {waitUntil: 'domcontentloaded'});
106 await page.waitForTimeout(1200);
107
108 // Attempt to close any toast/overlay by pressing Escape (best-effort)
109 await page.keyboard.press('Escape').catch(() => undefined);
110
111 const outPath = path.join(OUT_DIR, `${r.key}.png`);
112 await page.screenshot({path: outPath, fullPage: true});
113 }
114
115 await browser.close();
116 console.log(`Done. Wrote ${routes.length} screenshots to ${OUT_DIR}`);
117 }
118
119 main().catch((err) => {
120 console.error(err?.stack || String(err));
121 process.exit(1);
122 });