Summary
DocsUI::Shell emits inline <script> (and inline <style> via DocsUI::Code) without a CSP nonce. On a host app that enforces a nonce-based script-src (the Rails default when content_security_policy_nonce_directives includes script-src, typically with strict-dynamic in production), the browser blocks these inline scripts. The most visible casualty is the theme-restore script — the persisted theme never applies, so the page renders the server default and there's no way to fix it without bypassing the shell.
Where
app/components/docs_ui/shell.rb → theme_restore_script (the inline <script> around line 83–85) and render_head.
app/components/docs_ui/code.rb → the inline <style> block that injects the Rouge theme CSS. (style-src commonly still allows 'unsafe_inline', so this one often survives, but it's the same class of problem and worth fixing together.)
Repro
- Mount docs-kit in a Rails app that sets:
config.content_security_policy_nonce_generator = ->(_req) { SecureRandom.base64(16) }
config.content_security_policy_nonce_directives = %w[script-src]
config.content_security_policy do |p|
p.script_src :self, :strict_dynamic
end
- Load any docs page.
- Observe a CSP violation for the inline theme-restore script in the console; the persisted theme is not applied.
Expected
DocsUI::Shell should nonce its inline <script> (and ideally its inline <style>) when a nonce is available, e.g. script(nonce: request.content_security_policy_nonce) { ... }, falling back to the un-nonced form when there's no nonce (dev, or apps not using nonces). phlex-rails already exposes the CSP helpers the shell includes (CSPMetaTag), so the nonce is reachable from the render context.
Current workaround
Subclass DocsUI::Shell and override the private theme_restore_script to re-emit the identical script with nonce: request.content_security_policy_nonce. It works but relies on overriding a private method and duplicating the script body, so it silently breaks if the upstream body changes.
Possible fix
Read the request nonce inside render_head/theme_restore_script and pass it to the script/style tags when present. Happy to send a PR if the approach sounds right.
Summary
DocsUI::Shellemits inline<script>(and inline<style>viaDocsUI::Code) without a CSP nonce. On a host app that enforces a nonce-basedscript-src(the Rails default whencontent_security_policy_nonce_directivesincludesscript-src, typically withstrict-dynamicin production), the browser blocks these inline scripts. The most visible casualty is the theme-restore script — the persisted theme never applies, so the page renders the server default and there's no way to fix it without bypassing the shell.Where
app/components/docs_ui/shell.rb→theme_restore_script(the inline<script>around line 83–85) andrender_head.app/components/docs_ui/code.rb→ the inline<style>block that injects the Rouge theme CSS. (style-srccommonly still allows'unsafe_inline', so this one often survives, but it's the same class of problem and worth fixing together.)Repro
Expected
DocsUI::Shellshould nonce its inline<script>(and ideally its inline<style>) when a nonce is available, e.g.script(nonce: request.content_security_policy_nonce) { ... }, falling back to the un-nonced form when there's no nonce (dev, or apps not using nonces).phlex-railsalready exposes the CSP helpers the shell includes (CSPMetaTag), so the nonce is reachable from the render context.Current workaround
Subclass
DocsUI::Shelland override the privatetheme_restore_scriptto re-emit the identical script withnonce: request.content_security_policy_nonce. It works but relies on overriding a private method and duplicating the script body, so it silently breaks if the upstream body changes.Possible fix
Read the request nonce inside
render_head/theme_restore_scriptand pass it to thescript/styletags when present. Happy to send a PR if the approach sounds right.