You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The "nothing inline in the output" invariant is enforced for <script> elements only. Inline event-handler attributes are neither hoisted nor stripped, and script-src 'self' blocks them exactly like an inline script.
The vendored docs-example fixture ships one, and it reaches dist/:
It is dead code in production.script-src 'self' with no 'unsafe-inline' blocks inline handlers, so the button is inert and logs a CSP violation when clicked. scripts/hoist-inline-scripts.js exists precisely so that already-published bundles keep working under the policy; it does not cover this case, so any doc app whose interactivity is written as onclick= is quietly broken instead.
tests/build-integrity.spec.js asserts every <script> has a src, which is why this got through. Nothing asserts on on* attributes.
Suggested fix
Decide between the two available policies and apply it in src/utils/transform.js, where the document is already parsed:
Strip on* attributes. Honest about what production does — the handler cannot run anyway — and closes the dev-mode dark leak. Cost: a doc app's inline interactivity disappears rather than failing loudly.
Hoist them, the way <script> bodies are hoisted: turn onclick="…" into a listener registered from a generated file. Preserves behaviour, but needs a stable element handle and is a good deal more machinery.
Either way, add the assertion to tests/build-integrity.spec.js so the invariant covers attributes and not just elements, and say so in contract/HEADLESS_RULES.md — this is a rule onboarding repositories need to know about.
Separately worth deciding whether the docs-example fixture should keep shipping a dark-mode toggle at all, given the marketplace is light-only.
Summary
The "nothing inline in the output" invariant is enforced for
<script>elements only. Inline event-handler attributes are neither hoisted nor stripped, andscript-src 'self'blocks them exactly like an inline script.The vendored docs-example fixture ships one, and it reaches
dist/:Two problems
script-src 'self'with no'unsafe-inline'blocks inline handlers, so the button is inert and logs a CSP violation when clicked.scripts/hoist-inline-scripts.jsexists precisely so that already-published bundles keep working under the policy; it does not cover this case, so any doc app whose interactivity is written asonclick=is quietly broken instead.astro devandastro previewserve no CSP, so there the toggle works and addsdarkto the sub-app root — the exact thingtransform.jsstrips the theme bootstrap to prevent (transform.js: regex-based HTML surgery silently truncates pages and misses several URL attributes #48).tests/build-integrity.spec.jsasserts every<script>has asrc, which is why this got through. Nothing asserts onon*attributes.Suggested fix
Decide between the two available policies and apply it in
src/utils/transform.js, where the document is already parsed:on*attributes. Honest about what production does — the handler cannot run anyway — and closes the dev-mode dark leak. Cost: a doc app's inline interactivity disappears rather than failing loudly.<script>bodies are hoisted: turnonclick="…"into a listener registered from a generated file. Preserves behaviour, but needs a stable element handle and is a good deal more machinery.Either way, add the assertion to
tests/build-integrity.spec.jsso the invariant covers attributes and not just elements, and say so incontract/HEADLESS_RULES.md— this is a rule onboarding repositories need to know about.Separately worth deciding whether the docs-example fixture should keep shipping a dark-mode toggle at all, given the marketplace is light-only.