Skip to content

fix(shell): nonce inline theme-restore script and code style under a nonce-based CSP#7

Merged
mhenrixon merged 1 commit into
mainfrom
fix/csp-nonce-shell
Jul 3, 2026
Merged

fix(shell): nonce inline theme-restore script and code style under a nonce-based CSP#7
mhenrixon merged 1 commit into
mainfrom
fix/csp-nonce-shell

Conversation

@mhenrixon

Copy link
Copy Markdown
Owner

Problem

DocsUI::Shell emits an inline <script> (the theme-restore script) and DocsUI::Code emits an inline <style> — neither carried a CSP nonce. On a host app that enforces a nonce-based script-src (Rails' default when content_security_policy_nonce_directives includes script-src), the browser blocks these inline tags. The visible casualty: the persisted theme never applied on first paint.

Fix

  • DocsUI::Shell and DocsUI::Code now include Phlex::Rails::Helpers::ContentSecurityPolicyNonce and emit their inline tag with nonce: from a small private #csp_nonce.
  • #csp_nonce guards on view_context before delegating to the phlex-rails value helper. In phlex-rails 2.4.0 the content_security_policy_nonce helper delegates to the view context — which is nil in an isolated render (or on a host that doesn't nonce script-src) and would otherwise raise — so we return nil there. Phlex omits a nil-valued attribute, so the un-nonced markup stays byte-identical to before.
  • style-src often still allows 'unsafe-inline', but Code's inline <style> is nonced too, for symmetry and future-proofing.

Graceful degradation is the whole point: on a host without a nonce, nothing changes; on a host with one, the tag carries it and the browser allows it.

Test plan

  • spec/docs_ui/shell_spec.rb (new): the theme-restore <script> renders the JS; with no nonce it carries no nonce attribute; with a nonce it renders nonce="testnonce". Plus a focused proof that Phlex omits a nil-valued attribute (the primitive the fix relies on).
  • spec/docs_ui/code_spec.rb: the inline <style> carries no nonce with no view context and nonce="testnonce" when a nonce is present.
  • spec/spec_helper.rb loads phlex-rails (plus the two ActiveSupport core-exts it and the theme-restore script need) so DocsUI:: components that compose phlex-rails helpers render standalone in the suite.

Verification

  • bundle exec rspec55 examples, 0 failures (stable across seeds 1, 42, 999, and random).
  • bundle exec rubocop app lib spec31 files, no offenses.
  • No-nonce path is byte-identical: no nonce attribute is emitted when there is no CSP nonce, so existing consuming sites and all prior specs are unaffected.

Closes #2

…nonce-based CSP

DocsUI::Shell emits an inline <script> (the theme-restore script) and
DocsUI::Code emits an inline <style>. Neither carried a CSP nonce, so a host
app enforcing a nonce-based script-src (Rails' default when script-src is in
content_security_policy_nonce_directives) blocked them — the visible casualty
being that the persisted theme never applied.

Summary
- Shell and Code now include Phlex::Rails::Helpers::ContentSecurityPolicyNonce
  and emit the inline tag with `nonce:` from a private #csp_nonce.
- #csp_nonce guards on `view_context` before delegating to the phlex-rails
  value helper: in phlex-rails 2.4.0 the helper delegates to the view context
  (which is nil in an isolated render / a host without a nonce and would raise),
  so we return nil there. Phlex omits a nil-valued attribute, keeping the
  un-nonced markup byte-identical to before.
- style-src often still allows 'unsafe-inline', but Code is nonced too for
  symmetry and future-proofing.

Test Coverage
- spec/docs_ui/shell_spec.rb (new): the theme-restore <script> renders the JS;
  with no nonce it carries NO nonce attribute; with a nonce it renders
  nonce="testnonce". Plus a focused proof that Phlex omits a nil-valued
  attribute (the graceful-degradation primitive).
- spec/docs_ui/code_spec.rb: the inline <style> carries NO nonce with no
  context and nonce="testnonce" when present.
- spec/spec_helper.rb loads phlex-rails (+ the two ActiveSupport core-exts it
  and the theme-restore script need) so DocsUI:: components that compose
  phlex-rails helpers render standalone.

Verification
- [x] bundle exec rspec — 55 examples, 0 failures (stable across seeds)
- [x] bundle exec rubocop (app lib spec) — 31 files, no offenses
- [x] No-nonce path is byte-identical (no nonce attribute emitted)

Closes #2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DocsUI::Shell inline scripts are not nonce-aware — blocked under a nonce-based CSP

1 participant