#!/usr/bin/env node import { mkdir, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { chromium } from 'playwright'; import { authenticateFrontdoor, createAuthenticatedContext } from './live-frontdoor-auth.mjs'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const webRoot = path.resolve(__dirname, '..'); const outputDir = path.join(webRoot, 'output', 'playwright'); const resultPath = path.join(outputDir, 'live-mirror-operator-journey.json'); const authStatePath = path.join(outputDir, 'live-mirror-operator-journey.state.json'); const authReportPath = path.join(outputDir, 'live-mirror-operator-journey.auth.json'); const screenshotDir = path.join(outputDir, 'mirror-operator-journey'); const baseUrl = process.env.STELLAOPS_FRONTDOOR_BASE_URL?.trim() || 'https://stella-ops.local'; const tenantId = 'demo-prod'; const scopeQuery = `tenant=${tenantId}®ions=us-east&environments=stage&timeWindow=7d`; const sourceApiBasePath = '/api/v1/advisory-sources'; const mirrorApiBasePath = '/api/v1/advisory-sources/mirror'; const setupCatalogRoute = '/setup/integrations/advisory-vex-sources'; const opsCatalogRoute = '/ops/integrations/advisory-vex-sources'; const setupMirrorRoute = '/setup/integrations/advisory-vex-sources/mirror'; const opsMirrorRoute = '/ops/integrations/advisory-vex-sources/mirror'; const setupMirrorNewRoute = '/setup/integrations/advisory-vex-sources/mirror/new'; const opsMirrorNewRoute = '/ops/integrations/advisory-vex-sources/mirror/new'; const setupMirrorClientRoute = '/setup/integrations/advisory-vex-sources/mirror/client-setup'; const opsMirrorClientRoute = '/ops/integrations/advisory-vex-sources/mirror/client-setup'; const mirrorJourneySuffix = Date.now().toString(36); const mirrorJourneyDomainId = `qa-mirror-${mirrorJourneySuffix}`; const mirrorJourneyDisplayName = `QA Mirror ${mirrorJourneySuffix}`; function buildUrl(route) { const separator = route.includes('?') ? '&' : '?'; return `${baseUrl}${route}${separator}${scopeQuery}`; } function cleanText(value) { return typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : ''; } function isStaticAsset(url) { return /\.(?:css|js|map|png|jpg|jpeg|svg|woff2?|ico)(?:$|\?)/i.test(url); } function isIgnorableFailure(request) { const url = request.url(); const error = request.failure()?.errorText ?? ''; return isStaticAsset(url) || /net::ERR_ABORTED|aborted/i.test(error); } function attachRuntime(page, runtime) { page.on('console', (message) => { if (message.type() === 'error') { runtime.consoleErrors.push(cleanText(message.text())); } }); page.on('pageerror', (error) => { runtime.pageErrors.push(cleanText(error instanceof Error ? error.message : String(error))); }); page.on('requestfailed', (request) => { if (isIgnorableFailure(request)) { return; } runtime.requestFailures.push({ method: request.method(), url: request.url(), error: request.failure()?.errorText ?? 'request failed', page: page.url(), }); }); page.on('response', (response) => { if (isStaticAsset(response.url())) { return; } if (response.status() >= 400) { runtime.responseErrors.push({ status: response.status(), method: response.request().method(), url: response.url(), page: page.url(), }); } }); } async function settle(page, ms = 1200) { await page.waitForLoadState('domcontentloaded', { timeout: 20_000 }).catch(() => {}); await page.waitForFunction(() => { const nodes = Array.from(document.querySelectorAll('[role="alert"], .banner, .banner--error')); return !nodes.some((node) => ((node.textContent || '').replace(/\s+/g, ' ').trim().toLowerCase().startsWith('loading '))); }, { timeout: 10_000 }).catch(() => {}); await page.waitForTimeout(ms); } async function navigate(page, route, ms = 1400) { await page.goto(buildUrl(route), { waitUntil: 'domcontentloaded', timeout: 30_000 }); await settle(page, ms); } async function heading(page) { const selectors = [ '.source-catalog h1', '.mirror-dashboard h1', '.wizard h1', '[data-testid="page-title"]', 'main h1', 'h1', ]; for (const selector of selectors) { const locator = page.locator(selector).first(); const text = cleanText(await locator.textContent().catch(() => '')); if (text) { return text; } } return ''; } async function bannerTexts(page) { return page.locator('[role="alert"], .banner, .banner--error, .error-banner, .toast') .evaluateAll((nodes) => nodes.map((node) => (node.textContent || '').replace(/\s+/g, ' ').trim()).filter(Boolean)) .catch(() => []); } async function bodyText(page) { return cleanText(await page.locator('body').textContent().catch(() => '')); } async function capture(page, key, extra = {}) { const screenshotPath = path.join(screenshotDir, `${key}.png`); await page.screenshot({ path: screenshotPath, fullPage: true }).catch(() => {}); return { key, url: page.url(), heading: await heading(page), banners: await bannerTexts(page), screenshotPath, ...extra, }; } function pathPresent(url, expectedPath) { return typeof url === 'string' && url.includes(expectedPath); } async function attemptClick(page, locator, label, waitMs = 1400) { const visible = await locator.isVisible().catch(() => false); if (!visible) { return { clicked: false, reason: `${label} not visible` }; } try { await locator.click({ timeout: 15_000 }); await settle(page, waitMs); return { clicked: true }; } catch (error) { return { clicked: false, reason: cleanText(error instanceof Error ? error.message : String(error)), }; } } async function invokeApi(page, endpoint, init = {}) { return page.evaluate(async ({ endpointPath, tenant, method, requestBody }) => { try { // Extract access token from Angular session storage let authHeader = {}; try { const raw = sessionStorage.getItem('stellaops.auth.session.full'); if (raw) { const session = JSON.parse(raw); const token = session?.tokens?.accessToken; if (token) { authHeader = { 'Authorization': `Bearer ${token}` }; } } } catch { /* token extraction failed; proceed without auth */ } const response = await fetch(endpointPath, { method, credentials: 'include', headers: { 'X-Stella-Ops-Tenant': tenant, ...authHeader, ...(requestBody ? { 'Content-Type': 'application/json' } : {}), }, body: requestBody ? JSON.stringify(requestBody) : undefined, }); const bodyText = await response.text(); let responseBody; try { responseBody = JSON.parse(bodyText); } catch { responseBody = bodyText; } return { ok: response.ok, status: response.status, body: responseBody, }; } catch (error) { return { ok: false, status: 0, body: error instanceof Error ? error.message : String(error), }; } }, { endpointPath: endpoint, tenant: tenantId, method: init.method ?? 'GET', requestBody: init.body ?? null, }); } async function main() { await mkdir(outputDir, { recursive: true }); await mkdir(screenshotDir, { recursive: true }); const runtime = { consoleErrors: [], pageErrors: [], requestFailures: [], responseErrors: [], }; const browser = await chromium.launch({ headless: process.env.PLAYWRIGHT_HEADLESS !== 'false' }); const auth = await authenticateFrontdoor({ statePath: authStatePath, reportPath: authReportPath }); const context = await createAuthenticatedContext(browser, auth, { statePath: auth.statePath }); const page = await context.newPage(); page.setDefaultTimeout(20_000); page.setDefaultNavigationTimeout(30_000); attachRuntime(page, runtime); const results = []; const failures = []; try { await navigate(page, setupCatalogRoute); const mirrorConfigApi = await invokeApi(page, `${mirrorApiBasePath}/config`); const mirrorHealthApi = await invokeApi(page, `${mirrorApiBasePath}/health`); const mirrorDomainsApi = await invokeApi(page, `${mirrorApiBasePath}/domains`); results.push(await capture(page, 'catalog-direct', { hasConfigureMirrorLink: await page.getByRole('link', { name: 'Configure Mirror', exact: true }).isVisible().catch(() => false), hasConnectMirrorLink: await page.getByRole('link', { name: 'Connect to Mirror', exact: true }).isVisible().catch(() => false), hasCreateMirrorDomainButton: await page.getByRole('button', { name: 'Create Mirror Domain', exact: true }).isVisible().catch(() => false), mirrorConfigApi, mirrorHealthApi, mirrorDomainsApi, })); await navigate(page, opsCatalogRoute); results.push(await capture(page, 'ops-catalog-direct', { hasConfigureMirrorLink: await page.getByRole('link', { name: 'Configure Mirror', exact: true }).isVisible().catch(() => false), hasConnectMirrorLink: await page.getByRole('link', { name: 'Connect to Mirror', exact: true }).isVisible().catch(() => false), hasCreateMirrorDomainButton: await page.getByRole('button', { name: 'Create Mirror Domain', exact: true }).isVisible().catch(() => false), })); await navigate(page, setupCatalogRoute); const catalogConfigureResult = await attemptClick( page, page.getByRole('link', { name: 'Configure Mirror', exact: true }), 'Catalog Configure Mirror', ); results.push(await capture(page, 'catalog-configure-mirror-handoff', { clickResult: catalogConfigureResult })); await navigate(page, setupCatalogRoute); const catalogCreateResult = await attemptClick( page, page.getByRole('button', { name: 'Create Mirror Domain', exact: true }), 'Catalog Create Mirror Domain', ); results.push(await capture(page, 'catalog-create-domain-handoff', { clickResult: catalogCreateResult })); await navigate(page, setupMirrorRoute); const mirrorDashboardConfigApi = await invokeApi(page, `${mirrorApiBasePath}/config`); results.push(await capture(page, 'dashboard-direct', { hasCreateDomainButton: await page.getByRole('button', { name: 'Create Domain', exact: true }).isVisible().catch(() => false), hasSetupMirrorButton: await page.getByRole('button', { name: /Set Up Mirror Connection|Configure/i }).first().isVisible().catch(() => false), mirrorConfigApi: mirrorDashboardConfigApi, })); await navigate(page, opsMirrorRoute); results.push(await capture(page, 'ops-dashboard-direct', { hasCreateDomainButton: await page.getByRole('button', { name: 'Create Domain', exact: true }).isVisible().catch(() => false), hasSetupMirrorButton: await page.getByRole('button', { name: /Set Up Mirror Connection|Configure/i }).first().isVisible().catch(() => false), })); await navigate(page, setupMirrorRoute); const dashboardCreateResult = await attemptClick( page, page.getByRole('button', { name: 'Create Domain', exact: true }), 'Dashboard Create Domain', ); results.push(await capture(page, 'dashboard-create-domain-handoff', { clickResult: dashboardCreateResult })); await navigate(page, setupMirrorRoute); const setupButton = page.getByRole('button', { name: /Set Up Mirror Connection|Configure/i }).first(); const dashboardConsumerResult = await attemptClick( page, setupButton, 'Dashboard Configure Consumer', ); results.push(await capture(page, 'dashboard-configure-consumer-handoff', { clickResult: dashboardConsumerResult })); await navigate(page, setupMirrorNewRoute); const sourceCheckboxes = page.locator('.source-row-label input[type="checkbox"]'); const sourceCount = await sourceCheckboxes.count().catch(() => 0); if (sourceCount >= 2) { await sourceCheckboxes.nth(0).check({ force: true }); await sourceCheckboxes.nth(1).check({ force: true }); } const builderNextToConfig = await attemptClick( page, page.getByRole('button', { name: 'Next: Configure Domain', exact: true }), 'Builder next to config', 800, ); if (builderNextToConfig.clicked) { await page.locator('#domainId').fill(mirrorJourneyDomainId).catch(() => {}); await page.locator('#displayName').fill(mirrorJourneyDisplayName).catch(() => {}); const signingKeyInput = page.locator('#signingKeyId'); if (await signingKeyInput.isVisible().catch(() => false)) { await signingKeyInput.fill('operator-mirror-signing-key').catch(() => {}); } } const builderNextToReview = await attemptClick( page, page.getByRole('button', { name: 'Next: Review', exact: true }), 'Builder next to review', 800, ); const generateToggle = page.getByLabel('Generate mirror output immediately after creation'); if (await generateToggle.isVisible().catch(() => false)) { await generateToggle.check({ force: true }).catch(() => {}); } const builderCreateResult = await attemptClick( page, page.getByRole('button', { name: 'Create Domain', exact: true }), 'Builder create domain', 2400, ); const createdDomainConfigApi = await invokeApi(page, `${mirrorApiBasePath}/domains/${encodeURIComponent(mirrorJourneyDomainId)}/config`); const createdDomainEndpointsApi = await invokeApi(page, `${mirrorApiBasePath}/domains/${encodeURIComponent(mirrorJourneyDomainId)}/endpoints`); const createdDomainStatusApi = await invokeApi(page, `${mirrorApiBasePath}/domains/${encodeURIComponent(mirrorJourneyDomainId)}/status`); const publicMirrorIndexApi = await invokeApi(page, '/concelier/exports/index.json'); const publicDomainManifestApi = await invokeApi(page, `/concelier/exports/mirror/${mirrorJourneyDomainId}/manifest.json`); const publicDomainBundleApi = await invokeApi(page, `/concelier/exports/mirror/${mirrorJourneyDomainId}/bundle.json`); results.push(await capture(page, 'builder-create-attempt', { sourceCount, nextToConfig: builderNextToConfig, nextToReview: builderNextToReview, createClick: builderCreateResult, createErrorBanner: cleanText(await page.locator('.banner--error').first().textContent().catch(() => '')), domainConfigApi: createdDomainConfigApi, domainEndpointsApi: createdDomainEndpointsApi, domainStatusApi: createdDomainStatusApi, publicMirrorIndexApi, publicDomainManifestApi, publicDomainBundleApi, })); await navigate(page, opsMirrorNewRoute); results.push(await capture(page, 'ops-builder-direct', { sourceCount: await page.locator('.source-row-label input[type="checkbox"]').count().catch(() => 0), })); await navigate(page, setupMirrorRoute); const viewEndpointsResult = await attemptClick( page, page.getByRole('button', { name: 'View Endpoints', exact: true }).first(), 'Dashboard view endpoints', 1200, ); const viewConfigResult = await attemptClick( page, page.getByRole('button', { name: 'View Config', exact: true }).first(), 'Dashboard view config', 1200, ); results.push(await capture(page, 'dashboard-domain-panels', { viewEndpointsResult, viewConfigResult, endpointsPanelText: cleanText(await page.locator('.card-endpoints').first().textContent().catch(() => '')), configPanelText: cleanText(await page.locator('.card-config').first().textContent().catch(() => '')), })); await navigate(page, setupMirrorClientRoute); const clientConfigApi = await invokeApi(page, `${mirrorApiBasePath}/config`); const clientDomainsApi = await invokeApi(page, `${mirrorApiBasePath}/domains`); await page.locator('#mirrorAddress').fill(baseUrl).catch(() => {}); const clientTestConnection = await attemptClick( page, page.getByRole('button', { name: 'Test Connection', exact: true }), 'Mirror client test connection', 2200, ); const discoveredDomainOptions = await page.locator('#domainSelect option').count().catch(() => 0); const nextToSignatureVisible = await page.getByRole('button', { name: 'Next: Signature Verification', exact: true }).isVisible().catch(() => false); const nextToSignatureEnabled = nextToSignatureVisible ? await page.getByRole('button', { name: 'Next: Signature Verification', exact: true }).isEnabled().catch(() => false) : false; results.push(await capture(page, 'client-setup-direct', { mirrorConfigApi: clientConfigApi, mirrorDomainsApi: clientDomainsApi, testConnection: clientTestConnection, connectedBanner: cleanText(await page.locator('.result-banner--success').first().textContent().catch(() => '')), connectionErrorBanner: cleanText(await page.locator('.result-banner--error').first().textContent().catch(() => '')), discoveredDomainOptions, nextToSignatureVisible, nextToSignatureEnabled, })); await navigate(page, opsMirrorClientRoute); results.push(await capture(page, 'ops-client-setup-direct', { hasMirrorAddress: await page.locator('#mirrorAddress').isVisible().catch(() => false), hasTestConnectionButton: await page.getByRole('button', { name: 'Test Connection', exact: true }).isVisible().catch(() => false), })); await navigate(page, '/ops/operations/feeds-airgap'); const feedsConfigureResult = await attemptClick( page, page.getByRole('link', { name: 'Configure Sources', exact: true }), 'Feeds & Airgap Configure Sources', 1000, ); results.push(await capture(page, 'feeds-airgap-configure-sources-handoff', { clickResult: feedsConfigureResult })); await navigate(page, '/security'); const securityConfigureResult = await attemptClick( page, page.getByRole('link', { name: /Configure sources|Configure advisory feeds|Configure VEX sources/i }).first(), 'Security Configure sources', 1000, ); results.push(await capture(page, 'security-configure-sources-handoff', { clickResult: securityConfigureResult })); } finally { await invokeApi(page, `${mirrorApiBasePath}/domains/${encodeURIComponent(mirrorJourneyDomainId)}`, { method: 'DELETE', }).catch(() => {}); await page.close().catch(() => {}); await context.close().catch(() => {}); await browser.close().catch(() => {}); } const catalogDirect = results.find((entry) => entry.key === 'catalog-direct'); if (catalogDirect?.heading !== 'Advisory & VEX Source Catalog') { failures.push(`Catalog direct route heading mismatch: ${catalogDirect?.heading || ''}`); } if (!catalogDirect?.hasConfigureMirrorLink || !catalogDirect?.hasCreateMirrorDomainButton) { failures.push('Catalog direct route is missing primary mirror actions.'); } if (!catalogDirect?.mirrorConfigApi?.ok) { failures.push(`Mirror config API is not healthy for catalog context: status=${catalogDirect?.mirrorConfigApi?.status ?? ''}`); } if (!catalogDirect?.mirrorDomainsApi?.ok) { failures.push(`Mirror domains API is not healthy for catalog context: status=${catalogDirect?.mirrorDomainsApi?.status ?? ''}`); } const opsCatalogDirect = results.find((entry) => entry.key === 'ops-catalog-direct'); if (opsCatalogDirect?.heading !== 'Advisory & VEX Source Catalog') { failures.push(`Ops catalog direct route heading mismatch: ${opsCatalogDirect?.heading || ''}`); } if (!opsCatalogDirect?.hasConfigureMirrorLink || !opsCatalogDirect?.hasCreateMirrorDomainButton) { failures.push('Ops catalog direct route is missing primary mirror actions.'); } const configureHandoff = results.find((entry) => entry.key === 'catalog-configure-mirror-handoff'); if (configureHandoff?.clickResult && !configureHandoff.clickResult.clicked) { failures.push(`Catalog Configure Mirror action failed before navigation: ${configureHandoff.clickResult.reason}`); } if (!pathPresent(configureHandoff?.url, '/advisory-vex-sources/mirror')) { failures.push(`Catalog Configure Mirror did not land on mirror dashboard: ${configureHandoff?.url || ''}`); } const catalogCreate = results.find((entry) => entry.key === 'catalog-create-domain-handoff'); if (catalogCreate?.clickResult && !catalogCreate.clickResult.clicked) { failures.push(`Catalog Create Mirror Domain action failed before navigation: ${catalogCreate.clickResult.reason}`); } if (!pathPresent(catalogCreate?.url, '/advisory-vex-sources/mirror/new')) { failures.push(`Catalog Create Mirror Domain did not land on /mirror/new: ${catalogCreate?.url || ''}`); } const dashboardDirect = results.find((entry) => entry.key === 'dashboard-direct'); if (dashboardDirect?.heading !== 'Mirror Dashboard') { failures.push(`Mirror dashboard direct route heading mismatch: ${dashboardDirect?.heading || ''}`); } if (!dashboardDirect?.mirrorConfigApi?.ok) { failures.push(`Mirror config API is not healthy for dashboard context: status=${dashboardDirect?.mirrorConfigApi?.status ?? ''}`); } const opsDashboard = results.find((entry) => entry.key === 'ops-dashboard-direct'); if (opsDashboard?.heading !== 'Mirror Dashboard') { failures.push(`Ops mirror dashboard direct route heading mismatch: ${opsDashboard?.heading || ''}`); } if (!opsDashboard?.hasCreateDomainButton || !opsDashboard?.hasSetupMirrorButton) { failures.push('Ops mirror dashboard is missing primary actions.'); } const dashboardCreate = results.find((entry) => entry.key === 'dashboard-create-domain-handoff'); if (dashboardCreate?.clickResult && !dashboardCreate.clickResult.clicked) { failures.push(`Dashboard Create Domain action failed before navigation: ${dashboardCreate.clickResult.reason}`); } if (!pathPresent(dashboardCreate?.url, '/advisory-vex-sources/mirror/new')) { failures.push(`Dashboard Create Domain did not land on /mirror/new: ${dashboardCreate?.url || ''}`); } const dashboardConsumer = results.find((entry) => entry.key === 'dashboard-configure-consumer-handoff'); if (dashboardConsumer?.clickResult && !dashboardConsumer.clickResult.clicked) { failures.push(`Dashboard Configure Consumer action failed before navigation: ${dashboardConsumer.clickResult.reason}`); } if (!pathPresent(dashboardConsumer?.url, '/advisory-vex-sources/mirror/client-setup')) { failures.push(`Dashboard Configure Consumer did not land on /mirror/client-setup: ${dashboardConsumer?.url || ''}`); } const builderAttempt = results.find((entry) => entry.key === 'builder-create-attempt'); const builderText = cleanText(builderAttempt?.createErrorBanner || ''); if (!builderAttempt?.nextToConfig?.clicked || !builderAttempt?.nextToReview?.clicked || !builderAttempt?.createClick?.clicked) { failures.push(`Mirror domain builder flow was blocked before submit. nextToConfig=${builderAttempt?.nextToConfig?.reason || 'ok'} nextToReview=${builderAttempt?.nextToReview?.reason || 'ok'} create=${builderAttempt?.createClick?.reason || 'ok'}`); } if (builderText || builderAttempt?.heading !== 'Mirror Domain Created') { failures.push(`Mirror domain create journey did not complete successfully. Banner="${builderText || ''}" finalUrl="${builderAttempt?.url || ''}"`); } if (!builderAttempt?.domainConfigApi?.ok) { failures.push(`Created mirror domain config API failed: status=${builderAttempt?.domainConfigApi?.status ?? ''}`); } if (!builderAttempt?.domainEndpointsApi?.ok) { failures.push(`Created mirror domain endpoints API failed: status=${builderAttempt?.domainEndpointsApi?.status ?? ''}`); } if (!builderAttempt?.domainStatusApi?.ok) { failures.push(`Created mirror domain status API failed: status=${builderAttempt?.domainStatusApi?.status ?? ''}`); } if (!builderAttempt?.publicMirrorIndexApi?.ok) { failures.push(`Public mirror index was not reachable through the frontdoor: status=${builderAttempt?.publicMirrorIndexApi?.status ?? ''}`); } if (!builderAttempt?.publicDomainManifestApi?.ok) { failures.push(`Public mirror manifest was not reachable for ${mirrorJourneyDomainId}: status=${builderAttempt?.publicDomainManifestApi?.status ?? ''}`); } if (!builderAttempt?.publicDomainBundleApi?.ok) { failures.push(`Public mirror bundle was not reachable for ${mirrorJourneyDomainId}: status=${builderAttempt?.publicDomainBundleApi?.status ?? ''}`); } const opsBuilderDirect = results.find((entry) => entry.key === 'ops-builder-direct'); if (opsBuilderDirect?.heading !== 'Create Mirror Domain') { failures.push(`Ops mirror builder direct route heading mismatch: ${opsBuilderDirect?.heading || ''}`); } const dashboardPanels = results.find((entry) => entry.key === 'dashboard-domain-panels'); if (dashboardPanels?.viewEndpointsResult && !dashboardPanels.viewEndpointsResult.clicked) { failures.push(`Mirror dashboard View Endpoints action failed: ${dashboardPanels.viewEndpointsResult.reason}`); } if (dashboardPanels?.viewConfigResult && !dashboardPanels.viewConfigResult.clicked) { failures.push(`Mirror dashboard View Config action failed: ${dashboardPanels.viewConfigResult.reason}`); } if (!dashboardPanels?.endpointsPanelText?.includes('/concelier/exports')) { failures.push('Mirror dashboard endpoints panel did not render public mirror paths.'); } if (!dashboardPanels?.configPanelText?.includes('Index limit')) { failures.push('Mirror dashboard config panel did not render resolved domain configuration.'); } const clientSetup = results.find((entry) => entry.key === 'client-setup-direct'); if (clientSetup?.heading !== 'Mirror Client Setup') { failures.push(`Mirror client setup direct route heading mismatch: ${clientSetup?.heading || ''}`); } if (!clientSetup?.mirrorConfigApi?.ok) { failures.push(`Mirror config API is not healthy for client setup context: status=${clientSetup?.mirrorConfigApi?.status ?? ''}`); } if (!clientSetup?.mirrorDomainsApi?.ok) { failures.push(`Mirror domains API is not healthy for client setup context: status=${clientSetup?.mirrorDomainsApi?.status ?? ''}`); } if (clientSetup?.testConnection && !clientSetup.testConnection.clicked) { failures.push(`Mirror client Test Connection action failed before request completed: ${clientSetup.testConnection.reason}`); } if (clientSetup?.connectionErrorBanner) { failures.push(`Mirror client connection preflight failed: ${clientSetup.connectionErrorBanner}`); } if (!clientSetup?.nextToSignatureEnabled) { failures.push('Mirror client setup cannot proceed to signature verification after test connection.'); } const opsClientSetup = results.find((entry) => entry.key === 'ops-client-setup-direct'); if (opsClientSetup?.heading !== 'Mirror Client Setup') { failures.push(`Ops mirror client setup direct route heading mismatch: ${opsClientSetup?.heading || ''}`); } if (!opsClientSetup?.hasMirrorAddress || !opsClientSetup?.hasTestConnectionButton) { failures.push('Ops mirror client setup is missing connection controls.'); } const feedsHandoff = results.find((entry) => entry.key === 'feeds-airgap-configure-sources-handoff'); if (feedsHandoff?.clickResult && !feedsHandoff.clickResult.clicked) { failures.push(`Feeds & Airgap Configure Sources action failed before navigation: ${feedsHandoff.clickResult.reason}`); } if (!pathPresent(feedsHandoff?.url, '/integrations/advisory-vex-sources')) { failures.push(`Feeds & Airgap Configure Sources did not land on advisory source catalog: ${feedsHandoff?.url || ''}`); } const securityHandoff = results.find((entry) => entry.key === 'security-configure-sources-handoff'); if (securityHandoff?.clickResult && !securityHandoff.clickResult.clicked) { failures.push(`Security Configure sources action failed before navigation: ${securityHandoff.clickResult.reason}`); } if (!pathPresent(securityHandoff?.url, '/integrations/advisory-vex-sources')) { failures.push(`Security Configure sources did not land on advisory source catalog: ${securityHandoff?.url || ''}`); } const report = { generatedAtUtc: new Date().toISOString(), baseUrl, failedCheckCount: failures.length, runtimeIssueCount: runtime.consoleErrors.length + runtime.pageErrors.length + runtime.requestFailures.length + runtime.responseErrors.length, results, failures, runtime, }; await writeFile(resultPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8'); process.stdout.write(`${JSON.stringify(report, null, 2)}\n`); process.exit(failures.length === 0 ? 0 : 1); } main().catch(async (error) => { const report = { generatedAtUtc: new Date().toISOString(), baseUrl, failedCheckCount: 1, runtimeIssueCount: 1, failures: [error instanceof Error ? error.message : String(error)], }; await mkdir(outputDir, { recursive: true }); await writeFile(resultPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8'); process.stderr.write(`${report.failures[0]}\n`); process.exit(1); });