Skip to content

Vendor TomSelect 2.4.3 β€” drop CDN dependency for CSP#2716

Open
mroderick wants to merge 1 commit into
masterfrom
feature/vendor-tomselect
Open

Vendor TomSelect 2.4.3 β€” drop CDN dependency for CSP#2716
mroderick wants to merge 1 commit into
masterfrom
feature/vendor-tomselect

Conversation

@mroderick

Copy link
Copy Markdown
Collaborator

Problem

TomSelect is loaded from cdn.jsdelivr.net on 4 admin pages, forcing a script-src + style-src CSP exception for an external CDN. Removing third-party dependencies simplifies the CSP configuration being planned.

Solution

Vendor TomSelect 2.4.3 into public/tom-select/ as static files, outside the Sprockets-managed public/assets/ directory. This makes them immune to assets:clobber.

Had to put them outside Sprockets because SassC chokes on max(var(--ts-pr-caret), .75rem) in the TomSelect CSS β€” it tries to parse custom-property fallbacks and throws SassC::SyntaxError.

Changes

  • public/tom-select/tom-select.complete.min.js β€” vendored TomSelect library (no CDN)
  • public/tom-select/tom-select.bootstrap5.min.css β€” vendored TomSelect Bootstrap 5 theme (no CDN)
  • app/assets/javascripts/admin/tom-select-init.js β€” TomSelect init code extracted from application.js, loads only on admin pages
  • app/assets/javascripts/application.js β€” removed TomSelect init blocks
  • app/views/admin/groups/show.html.haml β€” CDN to vendored /tom-select/ paths
  • app/views/admin/members/index.html.haml β€” CDN to vendored /tom-select/ paths
  • app/views/admin/meetings/_form.html.haml β€” CDN to vendored /tom-select/ paths
  • app/views/admin/meetings/show.html.haml β€” CDN to vendored /tom-select/ paths
  • config/initializers/assets.rb β€” removed tom-select from precompile list (static files)

Why not $(function(){...})

jQuery 1.12.4's ready.promise().done(fn) silently drops callbacks registered after the DOM is already ready β€” even though jQuery.isReady=true, the deferred nullifies its callback list on resolution. This was invisible before because the init code was inside application.js (registered before DOM ready). As a separate script tag loaded after application.js, the callbacks never fired. Fixed by using native DOMContentLoaded.

Verification

All 110 admin RSpec examples pass, including the 2 TomSelect-specific feature specs.

CSP impact

After this PR, cdn.jsdelivr.net can be dropped from both script-src and style-src in the pending CSP config (PR to follow).

jsDelivr script-src/style-src exceptions can now be dropped from CSP.

- Static files in public/tom-select/ (outside Sprockets, immune to
  assets:clobber) β€” SassC chokes on CSS custom-property fallbacks
- Init code extracted from application.js into admin-only file, uses
  DOMContentLoaded (jQuery 1.12.4 ready promise silently drops
  post-resolution callbacks from separate script tags)
- All 4 admin views updated to reference /tom-select/ paths
@mroderick
mroderick marked this pull request as ready for review July 16, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant