From 42ff26d8eee752011cd183e336f5eb0a17ad8762 Mon Sep 17 00:00:00 2001 From: Tungle Duy Date: Tue, 8 Sep 2026 15:25:48 +0700 Subject: [PATCH 1/3] Bump CI to JRuby 10, declare csv as an explicit dependency - CI: bump jruby-9.4.15.0 -> jruby-10.0.6.0 (both mysql2/postgresql matrix legs). - README: update Ruby/JRuby version requirement text accordingly. - kaui.gemspec: csv is a "bundled gem" as of Ruby 3.4 (no longer a default gem), so it must be an explicit dependency for it to be available via Bundler.require. Several controllers (accounts, invoices, payments, audit_logs, account_timelines) `require 'csv'` directly; without this, Rails eager loading (production/WAR boot) crashes with: LoadError: cannot load such file -- csv Validated locally: bundle install + Rails boot + JDBC/SQLite connection all succeed unmodified under real JRuby 10.1.1.0/JDK21 with this change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- README.md | 2 +- kaui.gemspec | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba5393b4..1fd68f2f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: database-password: 'root' database-port: '3306' docker-compose-file: 'docker-compose.ci.mysql.yml' - - ruby-version: 'jruby-9.4.15.0' + - ruby-version: 'jruby-10.0.6.0' database-adapter: 'mysql2' database-user: 'root' database-password: 'root' @@ -36,7 +36,7 @@ jobs: database-password: 'postgres' database-port: '5432' docker-compose-file: 'docker-compose.ci.postgresql.yml' - - ruby-version: 'jruby-9.4.15.0' + - ruby-version: 'jruby-10.0.6.0' database-adapter: 'postgresql' database-user: 'postgres' database-password: 'postgres' diff --git a/README.md b/README.md index 4c220121..27dc2e7c 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Kill Bill compatibility Dependencies ------------ -Ruby 3.1.0+ or JRuby 9.4.15.0+ required. +Ruby 3.1.0+ or JRuby 10.0.6.0+ required. Running Kaui locally --------------------- diff --git a/kaui.gemspec b/kaui.gemspec index c16e96e3..dcd6cd22 100644 --- a/kaui.gemspec +++ b/kaui.gemspec @@ -26,6 +26,10 @@ Gem::Specification.new do |s| s.add_dependency 'cancan' s.add_dependency 'concurrent-ruby' s.add_dependency 'country_select' + # csv is a "bundled gem" as of Ruby 3.4 (no longer a default gem), so it + # must be an explicit dependency for it to be available via Bundler.require + # (affects controllers using CSV export). JRuby 10 targets Ruby 3.4+ compat. + s.add_dependency 'csv' s.add_dependency 'devise' s.add_dependency 'font-awesome-rails' s.add_dependency 'jquery-rails', '~> 4.5.1' From 17a556ec9bf98a4728ad627c7bef3abaed1e77c0 Mon Sep 17 00:00:00 2001 From: Tungle Duy Date: Wed, 9 Sep 2026 11:27:03 +0700 Subject: [PATCH 2/3] Enrich sorbet-runtime workaround comment with confirmed root cause A support engineer independently hit this same crash and pointed to a now-filed JRuby bug (jruby/jruby#9651): assigning to an outer local variable named 'it' inside a block silently creates a block-local shadow instead of updating the outer one on JRuby 10, breaking sorbet-runtime's signature-validation loop counter (T::Private::Methods::Signature#each_args_value_type). No functional change - just documenting the confirmed root cause for future readers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/dummy/config/application.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index aa48bc75..33cd820b 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -15,10 +15,13 @@ require "rails/test_unit/railtie" require 'sprockets/railtie' -# Work around a sorbet-runtime/js-routes crash under JRuby 10 (Ruby 4.0 compat): -# js-routes' sig-decorated methods trigger a sorbet-runtime signature-validation -# NoMethodError at load time. Disabling runtime checks avoids building the -# crashing validation wrapper. See repo memory for details. +# Work around a JRuby 10 bug (jruby/jruby#9651): assigning to an outer local +# variable named `it` inside a block silently creates a block-local shadow +# instead of updating the outer one, so op-assignments raise NoMethodError. +# sorbet-runtime 0.6.x's signature-validation code uses `it` as a loop counter +# (T::Private::Methods::Signature#each_args_value_type), so any call to a +# sig'd method (e.g. js-routes' sig-decorated methods) crashes at load time. +# Disabling runtime checks avoids building the crashing validation wrapper. if defined?(JRUBY_VERSION) require 'sorbet-runtime' T::Configuration.default_checked_level = :never From 7de453c4f9f4660ad440c52844fb856680b29b5a Mon Sep 17 00:00:00 2001 From: Tungle Duy Date: Wed, 9 Sep 2026 12:24:28 +0700 Subject: [PATCH 3/3] Harden json pin to prevent a latent json 3.0/quirks_mode crash Defense-in-depth fix, part of the same root-cause investigation as the CI failures fixed in killbill-kpm-ui and killbill-email-notifications-ui (see their jruby10-upgrade branch commits for full details). This repo currently resolves json 2.x thanks only to an INCIDENTAL transitive constraint (rubocop's own `json ~> 2.3` dependency in whatever version bundler happens to resolve here) - not a real guarantee. rubocop 1.90.0 (released 2026-08-24) loosened its own json dependency to `json >= 2.3` (no upper bound), so this repo's unpinned `gem 'json'` could silently start resolving json 3.x on any future bundle install (Gemfile.lock isn't committed in this repo), exactly as already happened in killbill-kpm-ui and killbill-email-notifications-ui once json 3.0.0/3.0.1 were published (2026-09-07/08). json 3.0 dropped the quirks_mode keyword that ActiveSupport::JSON.encode still passes to JSON.generate (not fixed until Rails 8.1.0), raising ArgumentError on any #to_json call - including killbill-client's model classes, used throughout this engine. Pinned `gem 'json', '~> 2.21'` explicitly rather than relying on rubocop's transitive constraint. Verified: bundle install resolves json (2.21.2); test suite passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Gemfile | 10 +++++++++- test/dummy/config/application.rb | 9 ++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index cf442b2a..c1fefec0 100644 --- a/Gemfile +++ b/Gemfile @@ -14,9 +14,17 @@ gem 'i18n', '~> 1.14.0' # Minitest 6.0.0 was released Dec 2024 with breaking API changes gem 'minitest', '~> 5.0' +# json 3.0 dropped the quirks_mode keyword that ActiveSupport::JSON.encode +# still passes to JSON.generate, raising ArgumentError (breaks any code path +# that calls #to_json, e.g. killbill-client's model classes). This repo's +# rubocop ~> 1.89.0 pin below happens to also constrain json < 3 (rubocop +# 1.89.0 depends on json ~> 2.3), but rubocop 1.90.0 loosened that to +# json >= 2.3 (no upper bound) - pin json explicitly so this doesn't depend +# on the rubocop pin never changing. +gem 'json', '~> 2.21' + group :development do gem 'gem-release' - gem 'json' gem 'listen' gem 'multi_json' gem 'pry-rails' diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 33cd820b..82faf1ab 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -15,13 +15,8 @@ require "rails/test_unit/railtie" require 'sprockets/railtie' -# Work around a JRuby 10 bug (jruby/jruby#9651): assigning to an outer local -# variable named `it` inside a block silently creates a block-local shadow -# instead of updating the outer one, so op-assignments raise NoMethodError. -# sorbet-runtime 0.6.x's signature-validation code uses `it` as a loop counter -# (T::Private::Methods::Signature#each_args_value_type), so any call to a -# sig'd method (e.g. js-routes' sig-decorated methods) crashes at load time. -# Disabling runtime checks avoids building the crashing validation wrapper. +# Work around a JRuby 10 bug (jruby/jruby#9651) that crashes sorbet-runtime's +# signature validation (used by js-routes) at load time. if defined?(JRUBY_VERSION) require 'sorbet-runtime' T::Configuration.default_checked_level = :never