import { chromium } from '@playwright/test'; import { createServer as createHttpServer } from 'node:http'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { createServer as createViteServer } from 'vite'; const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const probeHits = []; function listen(server) { return new Promise((resolveListen, reject) => { server.once('error', reject); server.listen(0, '127.0.0.1', () => { server.off('error', reject); const address = server.address(); if (!address || typeof address === 'string') { reject(new Error('Local probe did not expose a TCP port')); return; } resolveListen(address.port); }); }); } function close(server) { return new Promise((resolveClose, reject) => { server.close((error) => error ? reject(error) : resolveClose()); }); } const probe = createHttpServer((request, response) => { probeHits.push(request.url ?? '/'); response.writeHead(204, { 'Access-Control-Allow-Origin': '*' }); response.end(); }); let browser; let vite; try { const probePort = await listen(probe); const probeBaseUrl = `http://127.0.0.1:${probePort}`; vite = await createViteServer({ root, logLevel: 'error', server: { host: '127.0.0.1', port: 0 }, plugins: [{ name: 'artifact-csp-probe-page', configureServer(server) { server.middlewares.use('/artifact-csp-probe.html', (_request, response) => { response.setHeader('Content-Type', 'text/html; charset=utf-8'); response.end('Artifact CSP probe'); }); }, }], }); await vite.listen(); const viteAddress = vite.httpServer?.address(); if (!viteAddress || typeof viteAddress === 'string') throw new Error('Vite probe page did not expose a TCP port'); const controlResponse = await fetch(`${probeBaseUrl}/control`); if (!controlResponse.ok || probeHits.length !== 1) throw new Error('Local probe control request failed'); probeHits.length = 0; browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto(`http://127.0.0.1:${viteAddress.port}/artifact-csp-probe.html`); const payloads = [ { id: 'comment-head', html: `` }, { id: 'before-head', html: `late head` }, { id: 'inline-script', html: `` }, { id: 'meta-refresh', html: `` }, ]; for (const payload of payloads) { await page.evaluate(async ({ artifactId, sourceHtml }) => { const { prepareHtmlArtifact } = await import('/src/lib/agent-tools.ts'); const artifact = prepareHtmlArtifact(sourceHtml, 'CSP probe', artifactId); const iframe = document.createElement('iframe'); iframe.dataset.artifactId = artifactId; iframe.setAttribute('sandbox', ''); iframe.setAttribute('credentialless', ''); await new Promise((resolveLoad) => { iframe.addEventListener('load', resolveLoad, { once: true }); iframe.srcdoc = artifact.sandboxedSource; document.body.append(iframe); }); }, { artifactId: payload.id, sourceHtml: payload.html }); } await page.evaluate(async () => { const { prepareHtmlArtifact } = await import('/src/lib/agent-tools.ts'); const artifact = prepareHtmlArtifact( '
Static artifact rendered
', 'Static render probe', 'static-render', ); const iframe = document.createElement('iframe'); iframe.dataset.artifactId = artifact.id; iframe.setAttribute('sandbox', ''); iframe.setAttribute('credentialless', ''); await new Promise((resolveLoad) => { iframe.addEventListener('load', resolveLoad, { once: true }); iframe.srcdoc = artifact.sandboxedSource; document.body.append(iframe); }); }); await new Promise((resolveWait) => setTimeout(resolveWait, 200)); if (probeHits.length > 0) { throw new Error(`Artifact CSP leaked ${probeHits.length} request(s): ${probeHits.join(', ')}`); } const staticCard = page.frameLocator('iframe[data-artifact-id="static-render"]').locator('#static-card'); await staticCard.waitFor(); const staticRender = await staticCard.evaluate((element) => ({ text: element.textContent, color: getComputedStyle(element).color, background: getComputedStyle(element).backgroundColor, })); if (staticRender.text !== 'Static artifact rendered' || staticRender.color !== 'rgb(17, 34, 51)' || staticRender.background !== 'rgb(238, 244, 240)') { throw new Error(`Static HTML/CSS render failed: ${JSON.stringify(staticRender)}`); } console.log(`artifact CSP probe passed: ${payloads.length} bypass payloads emitted 0 requests; static HTML/CSS rendered`); } finally { await browser?.close(); await vite?.close(); await close(probe); }