Skip to content

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

Merged
mroderick merged 2 commits into
masterfrom
feature/vendor-tomselect
Jul 28, 2026
Merged

Vendor TomSelect 2.4.3 β€” drop CDN dependency for CSP#2716
mroderick merged 2 commits 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
@mroderick
mroderick merged commit 3ffef23 into master Jul 28, 2026
9 checks passed
@mroderick
mroderick deleted the feature/vendor-tomselect branch July 28, 2026 13:01
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