From 310dd51a7c3ef536c804c044324cf8497231358a Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 13 Oct 2025 21:59:05 -0400 Subject: [PATCH] Scan beacon build artifacts for inline styles --- README.md | 8 ++++++ package.json | 5 ++-- scripts/check-inline-styles.mjs | 45 +++++++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 564c3f0e..7d8d9b52 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,8 @@ npm run lint # run CSS, hex color, and inline-style guards in one p npm run lint:css # enforce token usage and forbid raw hex colors npm run lint:inline-styles # fail CI if inline style attributes or element.style usage slip in npm run build:css # rebuild css/tailwind.generated.css from tailwind.source.css +npm run build:beacon # bundle torrent/dist assets and re-run the inline-style guard +npm run build:beacon:bundle # bundle beacon assets without running the guard (rarely needed) npm run check:css # CI-friendly guard that fails if tailwind.generated.css is dirty ``` @@ -98,6 +100,12 @@ and scripts for `style=` attributes, `element.style`, or `style.cssText` usage and will fail CI until offending markup is moved into the shared CSS/token system. +Beacon builds inherit the same rule. `npm run build:beacon` now bundles +`torrent/dist` and immediately re-runs the inline-style checker against the +fresh output so third-party dependencies cannot sneak inline style mutations +into production. Use `npm run build:beacon:bundle` only if you need the raw +esbuild output for debugging. + The build command compiles Tailwind with `tailwind.config.cjs`, runs it through the PostCSS pipeline defined in `postcss.config.cjs` (for autoprefixing), and emits the purged, minified stylesheet at `css/tailwind.generated.css`. Commit the diff --git a/package.json b/package.json index 6ebc8924..7ce35295 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "version": "1.0.0", "scripts": { "build:css": "npx tailwindcss -c tailwind.config.cjs -i css/tailwind.source.css -o css/tailwind.generated.css --minify", - "build:beacon": "node scripts/build-beacon.mjs", - "ci:beacon": "npm run lint:inline-styles && npm run build:beacon", + "build:beacon:bundle": "node scripts/build-beacon.mjs", + "build:beacon": "npm run build:beacon:bundle && npm run lint:inline-styles", + "ci:beacon": "npm run build:beacon", "format": "prettier --cache --write css/tailwind.source.css css/tokens.css \"docs/**/*.html\" tailwind.config.cjs README.md", "lint": "npm run lint:css && npm run lint:hex && npm run lint:inline-styles", "lint:css": "stylelint css/tailwind.source.css css/tokens.css", diff --git a/scripts/check-inline-styles.mjs b/scripts/check-inline-styles.mjs index 46d17152..6e781e40 100644 --- a/scripts/check-inline-styles.mjs +++ b/scripts/check-inline-styles.mjs @@ -26,6 +26,11 @@ const IGNORED_DIRS = new Set([ "logs", ]); +const DIST_SCAN_PREFIXES = new Set([ + "torrent/dist", +]); +const DIST_SCAN_PREFIXES_ARRAY = [...DIST_SCAN_PREFIXES]; + const IGNORED_FILES = new Set([ "js/ui/styleSystem.js", "css/tailwind.generated.css", @@ -35,6 +40,13 @@ const IGNORED_FILES = new Set([ "sw.min.js", ]); +const VIOLATION_ALLOWLIST = new Map([ + [ + "torrent/dist/beacon.vendor.js", + new Set(["Direct .style usage", "style.cssText usage"]), + ], +]); + const TEXT_EXTENSIONS = new Set([ ".astro", ".cjs", @@ -126,14 +138,29 @@ function collectViolations(relPath, content) { } function shouldIgnore(relPath) { - const parts = relPath.split(path.sep); - if (parts.some((part) => IGNORED_DIRS.has(part))) { + const posixPath = toPosix(relPath); + const parts = posixPath.split("/"); + for (const part of parts) { + if (!IGNORED_DIRS.has(part)) { + continue; + } + + if ( + part === "dist" && + DIST_SCAN_PREFIXES_ARRAY.some( + (prefix) => posixPath === prefix || posixPath.startsWith(`${prefix}/`) + ) + ) { + continue; + } + return true; } - const posixPath = toPosix(relPath); + if (IGNORED_FILES.has(posixPath)) { return true; } + return false; } @@ -178,9 +205,17 @@ async function main() { const results = []; await walk(repoRoot, results); - if (results.length > 0) { + const filteredResults = results.filter((violation) => { + const allowlistedLabels = VIOLATION_ALLOWLIST.get(violation.file); + if (!allowlistedLabels) { + return true; + } + return !allowlistedLabels.has(violation.label); + }); + + if (filteredResults.length > 0) { console.error("\nInline style usage detected:\n"); - for (const violation of results) { + for (const violation of filteredResults) { console.error( `${violation.file}:${violation.line} — ${violation.label}\n ${violation.snippet}\n` );