Skip to content

Modernize the example app: Ruby 3.4, Rails 8.1 and castle-rb 8#17

Merged
bartes merged 5 commits into
masterfrom
modernize-castle-8-and-ruby
Jun 3, 2026
Merged

Modernize the example app: Ruby 3.4, Rails 8.1 and castle-rb 8#17
bartes merged 5 commits into
masterfrom
modernize-castle-8-and-ruby

Conversation

@bartes

@bartes bartes commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

What & why

This example app had drifted well behind the current Castle Ruby SDK and Rails
ecosystem (castle-rb 5, the legacy track/authenticate API, the old browser
snippet, Rails 6.1 on Ruby 2.7). This PR brings it back to a current, runnable
state on Ruby 3.4 / Rails 8.1 and demonstrates the SDK the way it's meant to
be used today.

Castle integration

  • Replace the legacy track/authenticate calls with the risk / filter / log
    endpoints:
    • successful logins → risk, with the session decision driven by the policy
      verdict (allow / challenge / deny);
    • failed logins → filter;
    • logout and profile updates → the non-blocking log endpoint.
  • Mint a request token in the browser with the @castleio/castle-js SDK and
    forward it from the login form to the backend (castle_request_token).
  • Verify incoming webhooks with Castle::Webhooks::Verify instead of the
    hand-rolled HMAC check (the bespoke verifier and its spec are removed).

Stack & tooling

  • Ruby 2.7 → 3.4, Rails 6.1 → 8.1.
  • Bump Devise, switch OmniAuth to the CSRF-protected POST request phase, and
    move to Bootstrap 5 with a refreshed layout and views.
  • Read configuration from environment variables via dotenv (.env.example)
    instead of secrets.yml.
  • Add a hardened multi-stage Dockerfile, entrypoint and .dockerignore; the
    image runs as a non-root user and serves with Puma.
  • Pin Bundler 2.7.2 (regenerated Gemfile.lock, Dockerfile and CI), which
    also drops the Bundler 4 CHECKSUMS section.

Tests

  • Rewrite the existing controller specs for the new API and fill in the
    previously-pending specs (User OAuth lookup, ApplicationRecord/Responder,
    the authenticated ApplicationController, and the registrations/passwords
    controllers).
  • Add coverage for every Castle failure path (risk/filter/log raising) and
    for webhook requests with a missing or mismatched signature.
  • The suite now reports 100% line coverage; the enforced SimpleCov floor is
    raised to 95%.

Known limitations

  • The Twitter/X OAuth callback can't easily capture a browser request token, so
    the OAuth risk call runs without one; any Castle::Error there (and on the
    fire-and-forget log calls) is rescued and treated as allow so Castle can
    never lock a user out of the demo.
  • The User model doesn't enable Devise's :recoverable module, so there are no
    password-reset routes; Users::PasswordsController is therefore covered at the
    unit level only. Left as-is to avoid changing behaviour — happy to wire up
    password reset in a follow-up if wanted.
  • JavaScript assets are no longer minified (the asset pipeline ships them
    as-is), which keeps the Docker image free of a JS runtime.
  • Production still uses SQLite for simplicity, which is fine for a demo only.

bartes added 5 commits June 3, 2026 14:41
Bring the demo up to date with the current Castle Ruby SDK and a supported
Rails/Ruby stack.

- Migrate the Castle integration from the legacy track/authenticate API to the
  risk/filter/log endpoints. Logins are scored with the policy verdict
  (allow/challenge/deny) using request tokens minted by the @castleio/castle-js
  browser SDK; logout and profile updates use the non-blocking log endpoint.
- Verify incoming webhooks with Castle::Webhooks::Verify instead of a
  hand-rolled HMAC check.
- Upgrade to Ruby 3.4 and Rails 7.1; bump Devise, OmniAuth (POST request phase)
  and Bootstrap 5, and refresh the layout and views.
- Read configuration from environment variables via dotenv instead of
  secrets.yml.
- Add a hardened multi-stage Dockerfile, entrypoint and .dockerignore.
- Update the RSpec suite for the new API and modernize CI to Ruby 3.4.
- Regenerate Gemfile.lock with Bundler 2.7.2 so BUNDLED WITH matches the
  toolchain and drop the Bundler 4 CHECKSUMS section; pin the version in the
  Dockerfile and CI.
- Flesh out the previously-pending specs (User.find_or_create_for_oauth,
  ApplicationRecord, ApplicationResponder, ApplicationController auth and the
  registrations/passwords controllers).
- Add coverage for every Castle failure path (risk/filter/log raising) and for
  webhook requests with a missing or mismatched signature.
- Raise the enforced SimpleCov floor to 95%; the app now reports 100% line
  coverage.
Add a GitHub Actions workflow that sets up the database and runs the RSpec
suite on every pull request (and on pushes to master), and drop the CircleCI
config that wasn't reporting checks on PRs.
Bump the app to the current Rails (8.1.3) and Devise (5.0.4), load_defaults
8.1, and sqlite3 2.x (required by the Rails 8 SQLite adapter). The sprockets
asset pipeline is kept explicitly via sprockets-rails. Full spec suite stays
green at 100% line coverage.
@bartes bartes changed the title Modernize the example app: Ruby 3.4, Rails 7.1 and castle-rb 8 Modernize the example app: Ruby 3.4, Rails 8.1 and castle-rb 8 Jun 3, 2026
@bartes bartes merged commit 34718f8 into master Jun 3, 2026
1 check passed
@bartes bartes deleted the modernize-castle-8-and-ruby branch June 6, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant