Skip to content

Release 9.0.0: drop legacy endpoints, Ruby 3.4 + Rails 8.1 support#283

Merged
bartes merged 11 commits into
developfrom
chore/release-9.0.0-modernization
May 26, 2026
Merged

Release 9.0.0: drop legacy endpoints, Ruby 3.4 + Rails 8.1 support#283
bartes merged 11 commits into
developfrom
chore/release-9.0.0-modernization

Conversation

@bartes
Copy link
Copy Markdown
Contributor

@bartes bartes commented May 25, 2026

9.0.0 — release prep

This is the consolidated 9.0.0 release of castle-rb. The goal is to (a) bring the gem onto the modern Ruby/Rails matrix, (b) trim the API surface to only what the Castle HTTP API currently supports, and (c) close the two open GitHub issues against this repo.

Public API

Removed (breaking)

  • Castle::API::Track and Castle::Client#track — superseded by Castle::API::Log and Castle::API::Risk.
  • Castle::API::Authenticate and Castle::Client#authenticate — superseded by Castle::API::Risk.
  • All Device endpoints (ApproveDevice, GetDevice, GetDevicesForUser, ReportDevice) — no longer part of the Castle public API.
  • Impersonation endpoints (StartImpersonation, EndImpersonation) and the Castle::ImpersonationFailed error class.
  • castle/support/hanami (only ever covered the long-EOL Hanami 1.x architecture) and castle/support/padrino (negligible adoption, trivial to inline). README documents the three-line replacement.

Added

  • Castle::API::ListItems::CreateBatchPOST /v1/lists/{list_id}/items/batch. Mirrored on the client as Castle::Client#create_batch_list_items.
  • Castle::API::Privacy::RequestData and Castle::API::Privacy::DeleteData — current POST / DELETE /v1/privacy/users endpoints, taking { identifier:, identifier_type: }. Mirrored on the client as #request_user_data / #delete_user_data. The deprecated path-based variants (/v1/privacy/users/{id}) are intentionally not exposed.

Bug fixes

Issues closed

Tooling and infrastructure

  • Drop Ruby < 3.2 (required_ruby_version >= 3.2 in the gemspec).
  • CI matrix: Ruby 3.2 / 3.3 / 3.4 × Rails 7.0 / 7.1 / 7.2 / 8.0 / 8.1, plus a dedicated RuboCop job.
  • Replace appraisal with hand-maintained gemfiles/rails_*.gemfile for each supported Rails version.
  • Switch from RVM-style .ruby-gemset to asdf-style .tool-versions.
  • Modernize .rubocop.yml (drop deprecated prettier-rubocop inherit, target Ruby 3.2, add rubocop-rake).
  • Replace byebug with stdlib debug; drop coveralls_reborn in favor of simplecov directly.
  • Add bin/lint driving RuboCop + Prettier; add package.json with prettier and @prettier/plugin-ruby.
  • Drop the dormant Coditsu CI integration (.coditsu/ci.yml and the matching CircleCI job).
  • Add modern gemspec metadata (source_code_uri, changelog_uri, bug_tracker_uri, rubygems_mfa_required).
  • Explicitly require/depend on base64 and ostruct, both of which left the default gems in Ruby 3.4+.

Documentation

  • README rewritten to describe only the supported endpoints, with a streamlined configuration section, an Errors table, and an "Upgrading to 9.0" guide.
  • CHANGELOG updated for the full set of changes.

afterdesign and others added 7 commits May 25, 2026 13:27
This is a maintenance / release-prep pass that drops legacy Castle API
endpoints, modernizes the runtime/dev tooling, and lines us up with the
same standards we just applied to castle_devise 0.6.0.

BREAKING:
- Drop /v1/track, /v1/authenticate, all device endpoints
  (approve_device, get_device, get_devices_for_user, report_device),
  and all impersonation endpoints (start/end_impersonation), plus their
  Castle::Client helpers and the Castle::ImpersonationFailed error.
- Drop support for Ruby < 3.2.

Modernization:
- .ruby-version -> 3.4.6, add .tool-versions, drop .ruby-gemset.
- Bump version to 9.0.0; modernize gemspec metadata
  (source_code_uri/changelog_uri/bug_tracker_uri/rubygems_mfa_required).
- Replace appraisal with hand-maintained gemfiles for Rails
  7.0 / 7.1 / 7.2 / 8.0 / 8.1.
- CircleCI matrix: Ruby 3.2/3.3/3.4 x Rails 7.0/7.1/7.2/8.0/8.1
  + dedicated rubocop job.
- .rubocop.yml: target Ruby 3.2, drop dead `prettier` inherit, add
  rubocop-rake.
- Drop deprecated `coveralls_reborn` and `byebug` deps; rely on
  simplecov + stdlib `debug`.
- Update Rails integration test + README to use the modern Risk API.
- Rewrite README around the actually-supported endpoints (Risk, Filter,
  Log, Lists, List Items, Webhooks). Move the noisy header allow/deny
  and IP-detection options into a dedicated `Advanced configuration`
  section so the basic config block stays focused on api_secret /
  failover_strategy / request_timeout. Add Quick start, Errors table,
  Upgrading-to-9.0 migration table, and Contributing notes.
- Ruby 3.4 unbundled `ostruct` and `base64` from stdlib:
  - require 'ostruct' in spec_helper (still used by response specs)
  - require 'base64' from lib/castle.rb so webhook signature
    computation keeps working without ActiveSupport in scope
  - declare `base64 ~> 0.2` as a runtime gem dep so 3.5+ stays green
- lib/castle/core/process_webhook.rb no longer relies on AS's
  `String#blank?` (it was only working accidentally via Rails
  autoloading); use `nil? || empty?`.
- Modernize .rubocop.yml: switch `require:` -> `plugins:`, exclude
  spec dirs from `Style/OpenStructUse`, silence stylistic noise on
  pre-existing patterns, document inline disables for
  `Lint/MissingSuper` (RequestError) and `Lint/StructNewOverride`
  (`Castle::Command`).
- Rakefile gets a `desc` line on the `test` alias.
- Skip the Rails integration spec gracefully when Rails isn't loaded
  (so `bundle exec rspec` works under the root Gemfile).
- Refresh Gemfile.lock for the new toolchain.
- castle/support/hanami targeted Hanami 1.x and the framework's 2.x
  rewrite has obsoleted `Hanami::Application` + `controller.prepare`,
  so the helper has been silently broken for years.
- castle/support/padrino has negligible real-world adoption and the
  helper is a 3-line wrapper that anyone still on Padrino can paste
  inline (documented in the README).

Rails and Sinatra remain first-class. CHANGELOG entry added under 9.0.0.
`~> 3.13` on rspec and `~> 3.26` on webmock were added in the previous
commit but aren't required and don't match the sibling castle_devise
Gemfile. For a gem's own dev/test Gemfile we want to track latest by
default; the runtime gemspec is what consumers actually depend on.

Rails pins (`~> 7.0.0`, `~> 7.1.0`, ...) stay in place because that's
the test-matrix axis.
- #279: `Castle::API::Filter`/`Risk`/`Log` failover handlers crashed
  with NoMethodError when `options[:user]` was missing, e.g. for the
  recommended `$login.$attempted` filter payload that has no user
  block. Switch to `options.dig(:user, :id)`, fall back to
  `matching_user_id` for /v1/filter, and add a regression spec.
- Drop the Coditsu CI integration (.coditsu/ci.yml + the `coditsu`
  CircleCI job + the .gitignore line). The service was wound down a
  while ago and the job was effectively a no-op.
- bin/lint: rewrite to mirror ../web — RuboCop -A first, Prettier
  second; auto-bootstrap node_modules and asdf-shimmed Ruby so the
  plugin-ruby parser doesn't pick up macOS system Ruby 2.6.
- Add package.json (prettier 3.8.3 + @prettier/plugin-ruby 4.0.4),
  refresh .prettierrc/.prettierignore, ignore /node_modules/.
- .rubocop.yml: exclude node_modules from inspection.
- Castle::API::ListItems::CreateBatch (POST /v1/lists/{id}/items/batch)
  plus Castle::Client#create_batch_list_items.
- Castle::API::Privacy::RequestData (POST /v1/privacy/users) and
  Castle::API::Privacy::DeleteData (DELETE /v1/privacy/users) plus
  matching Castle::Client#request_user_data and #delete_user_data.
  Closes #261. The deprecated path-based privacy endpoints
  (POST/DELETE /v1/privacy/users/{id}) are intentionally not exposed.
- README and CHANGELOG updated for the new surface and to call out
  the #279 failover-handler fix.
@bartes bartes force-pushed the chore/release-9.0.0-modernization branch from 868f1b7 to 4cfa67f Compare May 25, 2026 11:27
bartes added 4 commits May 25, 2026 13:48
CircleCI's repo-level checkout SSH key for castle/castle-ruby has
been unauthorized since June 2025, blocking every build (including
the rack CVE merges into develop) at the `Checkout code` step. Rather
than rotate that key, switch to GitHub Actions — same pattern as
castle_devise — so CI uses the built-in GITHUB_TOKEN and there is no
per-repo deploy key to manage.

- .github/workflows/specs.yml: Ruby 3.2/3.3/3.4 x Rails 7.0/7.1/7.2/
  8.0/8.1 matrix running bundle exec rspec
- .github/workflows/lint.yml: single rubocop job on Ruby 3.4
- Drop .circleci/config.yml and the badge in the README
Real fixes uncovered during a release-readiness pass:

- Client do-not-track path mirrored the #279 bug: `Client#filter`/
  `#risk`/`#log` did `options[:user][:id]` unconditionally when
  tracking was disabled. Switch all three to a shared helper that
  uses `options.dig(:user, :id)` with a `matching_user_id` fallback,
  and add a regression spec for each action.
- Per-call `config:` now reaches `GetConnection.call(config)`, so a
  custom `Castle::Configuration` actually drives host/port/SSL/
  timeout — not just the request body. Spec asserts both the
  resolved address and the timeout values.
- `GetConnection` now sets `open_timeout` in addition to
  `read_timeout`, so a slow TCP/TLS handshake hits the configured
  budget instead of Net::HTTP's 60 s default.
- Backfill `Castle::API::Risk` and `Castle::API::Log` API specs (they
  were `pending` placeholders). Each covers the success path and the
  three failover branches, including the missing-`:user` regression.

Housekeeping:

- Drop the Appraisal-generated `gemfiles/rails_8.gemfile` and stale
  `gemfiles/*.gemfile.lock` artifacts left over from the
  pre-modernization branch.
- Add `nodejs` and `yarn` to `.tool-versions` so contributors get the
  Node toolchain that `bin/lint` needs without manually installing it.
- Trim the CHANGELOG matrix line to match the actual nine combos in
  `.github/workflows/specs.yml`.
- Gemspec `summary` is now an actual one-liner; `description`
  describes the surface area users will install for.
- Fix two long-standing comment typos (`Namesapce`, `ednpoints`) and
  the missing default arg on `Client#unarchive_list_item`.
- README contributing block points at `bin/lint` instead of
  `bundle exec rubocop` and clarifies which command does what.
Use Castle's own product framing instead of "Castle protects your users
from account compromise". The previous text predated several major
product lines; the new copy is plain, factual, and lists the gem's
actual responsibilities without enumerating individual endpoints.
@prettier/plugin-ruby is fully functional with prettier 3.x. The
crash CodeRabbit's hint guarded against (non-deterministic load
order via `Dir['...']`) doesn't apply on our supported runtimes
either: Ruby 3.0+ already returns Dir.glob results sorted by
default, and the gem requires Ruby >= 3.2 — RuboCop's
Lint/RedundantDirGlobSort enforces that we don't add a redundant
`.sort` call.
@bartes bartes requested review from mknapik and zuchmanski May 25, 2026 12:43
@bartes bartes marked this pull request as ready for review May 25, 2026 12:43
@bartes bartes merged commit 9dce01b into develop May 26, 2026
10 checks passed
@bartes bartes deleted the chore/release-9.0.0-modernization branch May 26, 2026 09:01
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.

Error handler in Filter.call assumes presence of deprecated user[:id] node GDPR/Privacy API for data access/purge requests

3 participants