From a9dfe2920004e744954e97307c5279a94a8f3b20 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Mon, 28 Sep 2026 08:43:59 +0000 Subject: [PATCH] Close the browser guard's path-shaped bypass: check-experimental-shelf imported playwright by file path check-experimental-shelf imported resolve(ROOT, 'node_modules/playwright/index.mjs') dynamically, named no package specifier, and so launched Chromium outside the slot while check:browser-gates-guarded passed it (upg100 found and measured it). It now imports the guard, and an unslotted run exits 75. The check also fails a path to node_modules/playwright (or playwright-core) anywhere in code; with the old import restored it fails that file. --- internal/check-browser-gates-guarded.mjs | 5 ++++- internal/check-experimental-shelf.mjs | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/check-browser-gates-guarded.mjs b/internal/check-browser-gates-guarded.mjs index aee78d09a..0271de52b 100644 --- a/internal/check-browser-gates-guarded.mjs +++ b/internal/check-browser-gates-guarded.mjs @@ -26,7 +26,10 @@ if (process.argv.includes('--list')) { // dynamic import or require of the playwright package. The detectors (browser-gates.mjs, this file) spell the // pattern inside regex literals, escaped, which none of these match, so they need no exclusion and a real // import added to one still fails. Only the guard itself imports playwright, by design. -const DIRECT = /^\s*import\b[^;\n]*\bfrom\s+['"]playwright['"]|\bimport\(\s*['"]playwright['"]\s*\)|\brequire\(\s*['"]playwright['"]\s*\)/m +// Also a PATH to the package (node_modules/playwright…, or playwright-core) anywhere in code: a gate imported +// resolve(ROOT, 'node_modules/playwright/index.mjs') dynamically, named no specifier, and launched outside the +// slot while this check passed it (upg100 found and measured it). +const DIRECT = /^\s*import\b[^;\n]*\bfrom\s+['"]playwright(?:-core)?['"]|\bimport\(\s*['"]playwright(?:-core)?['"]\s*\)|\brequire\(\s*['"]playwright(?:-core)?['"]\s*\)|node_modules[\/\\]playwright(?:-core)?\b/m const files = execFileSync('git', ['ls-files', '--', 'internal', 'plugin-designs'], { cwd: ROOT, encoding: 'utf8' }) .split('\n').filter((f) => /\.(mjs|js|cjs)$/.test(f) && f !== 'internal/lib/playwright-guarded.mjs') const bad = [] diff --git a/internal/check-experimental-shelf.mjs b/internal/check-experimental-shelf.mjs index 4ea59d47d..6e5362235 100644 --- a/internal/check-experimental-shelf.mjs +++ b/internal/check-experimental-shelf.mjs @@ -70,7 +70,9 @@ const WAIT_MS = Number(process.env.SHELF_WAIT_MS || 75000) const MIN_COLOURS = Number(process.env.MIN_MAP_COLOURS || 40) const MIN_FILL = Number(process.env.MIN_MAP_FILL || 0.7) -const { chromium } = await import(resolve(ROOT, 'node_modules/playwright/index.mjs')) +// Through the slot guard like every repo browser gate (it imported node_modules/playwright by path and so +// launched outside the slot; upg100 measured it). +const { chromium } = await import('./lib/playwright-guarded.mjs') const manifest = JSON.parse(readFileSync(resolve(ROOT, `public/${TREE_NAME}/manifest.json`), 'utf8')) const spa = readFileSync(resolve(ROOT, 'plugin-designs/doxa-maps-spa/doxa-maps-spa.vue'), 'utf8') const cfg = JSON.parse(readFileSync(resolve(ROOT, 'vite.doxa-maps-build-config.json'), 'utf8'))