From 44d587ec1a35be6859825ca5ba5c39e37b126766 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Sat, 24 Oct 2026 18:30:51 -0400 Subject: [PATCH 1/4] Switch the MySQL adapter from Trilogy to mysql2 Connect to MySQL with mysql2, the driver our other apps use. Register the UUID type and the MySQL extensions for the Mysql2 adapter, and read server error numbers from Mysql2::Error#error_number in SQL redaction. The images, CI and Brewfile install the MySQL client library that mysql2 links against. --- .github/workflows/test.yml | 2 +- Brewfile | 1 + Dockerfile | 4 ++-- Gemfile | 2 +- Gemfile.lock | 8 +++---- Gemfile.saas.lock | 8 +++---- app/models/board/accessible.rb | 2 +- app/models/search/record.rb | 2 +- config/database.mysql.yml | 2 +- config/initializers/uuid_primary_keys.rb | 4 ++-- lib/rails_ext/active_record_sql_redaction.rb | 8 +++---- .../active_record_trilogy_quote_string.rb | 14 ----------- lib/rails_ext/active_record_uuid_type.rb | 4 ++-- saas/Dockerfile | 4 ++-- saas/config/database.yml | 2 +- .../structured_log_redaction_test.rb | 4 ++-- test/lib/database_adapter_test.rb | 23 +++++++++++++++++++ .../active_record_sql_redaction_test.rb | 12 ++++++++++ 18 files changed, 64 insertions(+), 42 deletions(-) delete mode 100644 lib/rails_ext/active_record_trilogy_quote_string.rb create mode 100644 test/lib/database_adapter_test.rb diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a58a6db68f..b92d34bec2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -55,7 +55,7 @@ jobs: steps: - name: Install system packages timeout-minutes: 10 - run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libsqlite3-0 libvips curl ffmpeg + run: sudo apt-get update && sudo apt-get install --no-install-recommends -y libmysqlclient-dev libsqlite3-0 libvips curl ffmpeg - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: diff --git a/Brewfile b/Brewfile index ce2b67921c..5f1e5c71fd 100644 --- a/Brewfile +++ b/Brewfile @@ -1,4 +1,5 @@ brew "imagemagick" +brew "mysql-client" brew "openslide" brew "vips" brew "gitleaks" diff --git a/Dockerfile b/Dockerfile index 93460dabe2..1425517d23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ WORKDIR /rails # Install base packages RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y ca-certificates curl libjemalloc2 libvips sqlite3 libssl-dev && \ + apt-get install --no-install-recommends -y ca-certificates curl libjemalloc2 libmariadb3 libvips sqlite3 libssl-dev && \ ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so && \ rm -rf /var/lib/apt/lists /var/cache/apt/archives @@ -32,7 +32,7 @@ FROM base AS build # Install packages needed to build gems RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \ + apt-get install --no-install-recommends -y build-essential default-libmysqlclient-dev git libyaml-dev pkg-config && \ rm -rf /var/lib/apt/lists /var/cache/apt/archives # Install application gems diff --git a/Gemfile b/Gemfile index 20989cfd19..10792a8251 100644 --- a/Gemfile +++ b/Gemfile @@ -23,7 +23,7 @@ gem "solid_cache", "~> 1.0" gem "solid_queue", "~> 1.7" gem "sqlite3", ">= 2.0" gem "thruster", require: false -gem "trilogy", "~> 2.13" +gem "mysql2", "~> 0.5" gem "tzinfo-data" # Bundled zone data; the base image's tzdata package lags IANA # Features diff --git a/Gemfile.lock b/Gemfile.lock index 1ba6b2406f..4e1a83b153 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -308,6 +308,8 @@ GEM mocha (3.1.0) ruby2_keywords (>= 0.0.5) msgpack (1.8.5) + mysql2 (0.5.7) + bigdecimal net-http-persistent (4.0.8) connection_pool (>= 2.2.4, < 4) net-imap (0.6.6) @@ -490,8 +492,6 @@ GEM thruster (0.1.26-x86_64-darwin) thruster (0.1.26-x86_64-linux) timeout (0.6.1) - trilogy (2.13.1) - bigdecimal tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -553,6 +553,7 @@ DEPENDENCIES mission_control-jobs mittens mocha + mysql2 (~> 0.5) net-http-persistent platform_agent propshaft @@ -573,7 +574,6 @@ DEPENDENCIES stimulus-rails surfguard! thruster - trilogy (~> 2.13) turbo-rails! tzinfo-data useragent! @@ -680,6 +680,7 @@ CHECKSUMS mittens (0.3.4) sha256=baa8e35c24bc06d6ed5c51633c800e8b6108ebcbd8efb1782d7146923797b383 mocha (3.1.0) sha256=75f42d69ebfb1f10b32489dff8f8431d37a418120ecdfc07afe3bc183d4e1d56 msgpack (1.8.5) sha256=97419eaa7b35dfe3e462c0e6c1a3dfdcbfc8756605c09e46e4c6daef127517ba + mysql2 (0.5.7) sha256=ba09ede515a0ae8a7192040a1b778c0fb0f025fa5877e9be895cd325fa5e9d7b net-http-persistent (4.0.8) sha256=ef3de8319d691537b329053fae3a33195f8b070bbbfae8bf1a58c796081960e6 net-imap (0.6.6) sha256=96aa4ee50df3060203e649efc341f53480b791d49e150f2fdebf68beb141a8df net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 @@ -767,7 +768,6 @@ CHECKSUMS thruster (0.1.26-x86_64-darwin) sha256=c7f7f0cbefd8030ea03bf88f6a988f595a0618a35a1a0d358e729c6898eb5b6a thruster (0.1.26-x86_64-linux) sha256=3117a6ee430663f845a0457699fe9a05232dcc6c396e2cc83504de5a223c60e8 timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb - trilogy (2.13.1) sha256=fbfb17c439b347e4240be70b80facf0f6f9c417b34c528179ff065b3d53635c9 tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f turbo-rails (2.0.23) tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b diff --git a/Gemfile.saas.lock b/Gemfile.saas.lock index 796a4afacd..9e2bd795c9 100644 --- a/Gemfile.saas.lock +++ b/Gemfile.saas.lock @@ -428,6 +428,8 @@ GEM ruby2_keywords (>= 0.0.5) msgpack (1.8.5) multi_json (1.19.1) + mysql2 (0.5.7) + bigdecimal net-http (0.9.1) uri (>= 0.11.1) net-http-persistent (4.0.8) @@ -668,8 +670,6 @@ GEM thruster (0.1.26-x86_64-darwin) thruster (0.1.26-x86_64-linux) timeout (0.6.1) - trilogy (2.13.1) - bigdecimal tsort (0.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) @@ -771,6 +771,7 @@ DEPENDENCIES mission_control-jobs mittens mocha + mysql2 (~> 0.5) net-http-persistent platform_agent prometheus-client-mmap (~> 1.3) @@ -796,7 +797,6 @@ DEPENDENCIES stimulus-rails surfguard! thruster - trilogy (~> 2.13) turbo-rails! tzinfo-data useragent! @@ -934,6 +934,7 @@ CHECKSUMS mocha (3.1.0) sha256=75f42d69ebfb1f10b32489dff8f8431d37a418120ecdfc07afe3bc183d4e1d56 msgpack (1.8.5) sha256=97419eaa7b35dfe3e462c0e6c1a3dfdcbfc8756605c09e46e4c6daef127517ba multi_json (1.19.1) sha256=7aefeff8f2c854bf739931a238e4aea64592845e0c0395c8a7d2eea7fdd631b7 + mysql2 (0.5.7) sha256=ba09ede515a0ae8a7192040a1b778c0fb0f025fa5877e9be895cd325fa5e9d7b net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996 net-http-persistent (4.0.8) sha256=ef3de8319d691537b329053fae3a33195f8b070bbbfae8bf1a58c796081960e6 net-imap (0.6.6) sha256=96aa4ee50df3060203e649efc341f53480b791d49e150f2fdebf68beb141a8df @@ -1040,7 +1041,6 @@ CHECKSUMS thruster (0.1.26-x86_64-darwin) sha256=c7f7f0cbefd8030ea03bf88f6a988f595a0618a35a1a0d358e729c6898eb5b6a thruster (0.1.26-x86_64-linux) sha256=3117a6ee430663f845a0457699fe9a05232dcc6c396e2cc83504de5a223c60e8 timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb - trilogy (2.13.1) sha256=fbfb17c439b347e4240be70b80facf0f6f9c417b34c528179ff065b3d53635c9 tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f turbo-rails (2.0.23) tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b diff --git a/app/models/board/accessible.rb b/app/models/board/accessible.rb index 984e9ec94a..3000510279 100644 --- a/app/models/board/accessible.rb +++ b/app/models/board/accessible.rb @@ -85,7 +85,7 @@ def notifications_for_user(user) # # Notification->Event->Mention->Card and Notification->Event->Mention->Comment->Card are # handled by destroying mentions_for_user. - uuid_type = ActiveRecord::Type.lookup(:uuid, adapter: :trilogy) + uuid_type = ActiveRecord::Type.lookup(:uuid, adapter: :mysql2) board_id_binary = uuid_type.serialize(id) user.notifications diff --git a/app/models/search/record.rb b/app/models/search/record.rb index 52ab6cd80f..124778107d 100644 --- a/app/models/search/record.rb +++ b/app/models/search/record.rb @@ -1,5 +1,5 @@ class Search::Record < ApplicationRecord - if connection.adapter_name == "Trilogy" + if connection.adapter_name == "Mysql2" self.abstract_class = true # MySQL uses sharded tables; shard models set their own table_name else self.table_name = "search_records" diff --git a/config/database.mysql.yml b/config/database.mysql.yml index 2f72f6e989..a42f15a815 100644 --- a/config/database.mysql.yml +++ b/config/database.mysql.yml @@ -1,5 +1,5 @@ default: &default - adapter: trilogy + adapter: mysql2 host: <%= ENV.fetch("MYSQL_HOST", "127.0.0.1") %> port: <%= ENV.fetch("MYSQL_PORT", "3306") %> username: <%= ENV.fetch("MYSQL_USER", "root") %> diff --git a/config/initializers/uuid_primary_keys.rb b/config/initializers/uuid_primary_keys.rb index 4b4bc8fdf7..7131d9c56d 100644 --- a/config/initializers/uuid_primary_keys.rb +++ b/config/initializers/uuid_primary_keys.rb @@ -35,7 +35,7 @@ module MysqlUuidAdapter # Override lookup_cast_type to recognize binary(16) as UUID type def lookup_cast_type(sql_type) if sql_type == "binary(16)" - ActiveRecord::Type.lookup(:uuid, adapter: :trilogy) + ActiveRecord::Type.lookup(:uuid, adapter: :mysql2) else super end @@ -116,7 +116,7 @@ def uuid(name, **options) ActiveRecord::ConnectionAdapters::TableDefinition.prepend(TableDefinitionUuidSupport) end -ActiveSupport.on_load(:active_record_trilogyadapter) do +ActiveSupport.on_load(:active_record_mysql2adapter) do ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.prepend(MysqlUuidAdapter) ActiveRecord::ConnectionAdapters::MySQL::SchemaDumper.prepend(SchemaDumperUuidType) end diff --git a/lib/rails_ext/active_record_sql_redaction.rb b/lib/rails_ext/active_record_sql_redaction.rb index 74d2d01be2..06d21cdd70 100644 --- a/lib/rails_ext/active_record_sql_redaction.rb +++ b/lib/rails_ext/active_record_sql_redaction.rb @@ -1,4 +1,4 @@ -# Trilogy runs without prepared statements, so a value reaches the SQL text as a quoted literal. The +# MySQL runs without prepared statements, so a value reaches the SQL text as a quoted literal. The # sql.active_record notification carries that text to every consumer, and with Rails.event in debug mode # (config/application.rb) it reaches the log: in SaaS mode, the structured log line for the request or # job, and from there Loki. Sentry breadcrumbs and spans read it too, and a database error can quote a @@ -72,7 +72,7 @@ def mentions_redacted_table?(text) def filter_error(error) filtered = \ if server_error_code(error) - [ error.error_code, FILTERED_ERROR ].join(": ") + [ error.error_number, FILTERED_ERROR ].join(": ") else redact_error_message(error.message) end @@ -89,7 +89,7 @@ def redact_error_message(message) private def server_error_code(error) - error.respond_to?(:error_code) && error.error_code + error.respond_to?(:error_number) && error.error_number end def reference_to(table) @@ -123,7 +123,7 @@ module ActiveRecordSqlRedaction::ErrorTranslation private def translate_exception_class(native_error, sql, binds) if ActiveRecordSqlRedaction.redacted_statement?(sql) && \ - ActiveRecordSqlRedaction::UNFILTERED_ERROR_CODES.exclude?(native_error.try(:error_code)) + ActiveRecordSqlRedaction::UNFILTERED_ERROR_CODES.exclude?(native_error.try(:error_number)) ActiveRecordSqlRedaction.filter_error(native_error) end diff --git a/lib/rails_ext/active_record_trilogy_quote_string.rb b/lib/rails_ext/active_record_trilogy_quote_string.rb deleted file mode 100644 index 9447fae7a5..0000000000 --- a/lib/rails_ext/active_record_trilogy_quote_string.rb +++ /dev/null @@ -1,14 +0,0 @@ -# Match mysql2 behavior -module ActiveRecordTrilogyQuoteString - def quote_string(string) - unless string.encoding == Encoding::UTF_8 || string.encoding == Encoding::BINARY || @config[:encoding] == "binary" - string = string.encode(Encoding::UTF_8) - end - - super - end -end - -ActiveSupport.on_load :active_record_trilogyadapter do - prepend ActiveRecordTrilogyQuoteString -end diff --git a/lib/rails_ext/active_record_uuid_type.rb b/lib/rails_ext/active_record_uuid_type.rb index f2004f2493..e3357505af 100644 --- a/lib/rails_ext/active_record_uuid_type.rb +++ b/lib/rails_ext/active_record_uuid_type.rb @@ -41,6 +41,6 @@ def cast(value) end end -# Register the UUID type for Trilogy (MySQL) and SQLite3 adapters -ActiveRecord::Type.register(:uuid, ActiveRecord::Type::Uuid, adapter: :trilogy) +# Register the UUID type for the Mysql2 and SQLite3 adapters +ActiveRecord::Type.register(:uuid, ActiveRecord::Type::Uuid, adapter: :mysql2) ActiveRecord::Type.register(:uuid, ActiveRecord::Type::Uuid, adapter: :sqlite3) diff --git a/saas/Dockerfile b/saas/Dockerfile index 9f6e75e13b..9dc962f7b8 100644 --- a/saas/Dockerfile +++ b/saas/Dockerfile @@ -25,7 +25,7 @@ FROM base AS build # Install packages needed to build gems RUN apt-get update -qq && \ - apt-get install -y --no-install-recommends -y build-essential pkg-config git libvips libyaml-dev libssl-dev && \ + apt-get install -y --no-install-recommends -y build-essential default-libmysqlclient-dev pkg-config git libvips libyaml-dev libssl-dev && \ rm -rf /var/lib/apt/lists /var/cache/apt/archives # Install application gems @@ -63,7 +63,7 @@ FROM base # library (ActiveStorage::VIPS_AVAILABLE=false), and config/initializers/vips.rb only demands it # when no cell is registered. RUN apt-get update -qq && \ - apt-get install --no-install-recommends -y libsqlite3-0 sqlite3 libjemalloc-dev && \ + apt-get install --no-install-recommends -y libmariadb3 libsqlite3-0 sqlite3 libjemalloc-dev && \ rm -rf /var/lib/apt/lists /var/cache/apt/archives # The eMudhra intermediate CAs' private keys leaked in October 2026, and they chain to these two roots. diff --git a/saas/config/database.yml b/saas/config/database.yml index eff904609b..07004c9aa2 100644 --- a/saas/config/database.yml +++ b/saas/config/database.yml @@ -33,7 +33,7 @@ %> default: &default - adapter: trilogy + adapter: mysql2 host: <%= ENV.fetch "FIZZY_DB_HOST", "127.0.0.1" %> port: <%= ENV.fetch "FIZZY_DB_PORT", 3306 %> pool: 50 diff --git a/saas/test/integration/structured_log_redaction_test.rb b/saas/test/integration/structured_log_redaction_test.rb index 3e7f492f9d..998b5e5891 100644 --- a/saas/test/integration/structured_log_redaction_test.rb +++ b/saas/test/integration/structured_log_redaction_test.rb @@ -118,7 +118,7 @@ def perform(identity) ActiveRecord::Base.cache { 2.times { assert MagicLink.find_by(code: CODE) } } assert_raises(ActiveRecord::RecordNotUnique) { identities(:kevin).magic_links.new(code: CODE, expires_at: 1.minute.from_now).save!(validate: false) } transaction.finish - Sentry.capture_exception(ActiveRecord::RecordNotUnique.new("Trilogy::ProtocolError: 1062: Duplicate entry '#{CODE}' for key 'magic_links.index_magic_links_on_code'")) + Sentry.capture_exception(ActiveRecord::RecordNotUnique.new("Mysql2::Error: Duplicate entry '#{CODE}' for key 'magic_links.index_magic_links_on_code'")) assert sentry_events.many? assert_no_secret CODE, sentry_events.map { |event| event.to_h.to_json } @@ -139,7 +139,7 @@ def perform(identity) unclosed = Sentry::Breadcrumb.new(category: "sql.active_record", data: { sql: "SELECT * FROM magic_links WHERE purpose = '0' AND code = '#{CODE}" }) assert_no_secret CODE, [ config.before_breadcrumb.call(unclosed, {}).data[:sql] ] - error = ActiveRecord::RecordNotUnique.new("Trilogy::ProtocolError: 1062: Duplicate entry '#{CODE}' for key 'magic_links.index_magic_links_on_code'") + error = ActiveRecord::RecordNotUnique.new("Mysql2::Error: Duplicate entry '#{CODE}' for key 'magic_links.index_magic_links_on_code'") event = Sentry::ErrorEvent.new(configuration: config).tap { |event| event.add_exception_interface(error, mechanism: Sentry::Mechanism.new) } assert_no_secret CODE, [ config.before_send.call(event, {}).exception.values.map(&:value).inspect ] diff --git a/test/lib/database_adapter_test.rb b/test/lib/database_adapter_test.rb new file mode 100644 index 0000000000..e3aa2ccf61 --- /dev/null +++ b/test/lib/database_adapter_test.rb @@ -0,0 +1,23 @@ +require "test_helper" + +class DatabaseAdapterTest < ActiveSupport::TestCase + unless Fizzy.db_adapter.sqlite? + test "MySQL connects with mysql2" do + assert_equal "Mysql2", connection.adapter_name + end + + test "MySQL connects in utf8mb4" do + assert_equal "utf8mb4", connection.select_value("SELECT @@character_set_connection") + assert_equal "🗂️", connection.select_value("SELECT #{connection.quote("🗂️")}") + end + + test "MySQL reads binary(16) columns as UUIDs" do + assert_equal :uuid, Card.columns_hash["id"].type + end + end + + private + def connection + ActiveRecord::Base.connection + end +end diff --git a/test/lib/rails_ext/active_record_sql_redaction_test.rb b/test/lib/rails_ext/active_record_sql_redaction_test.rb index 8ca4c5692e..e95b9cd02a 100644 --- a/test/lib/rails_ext/active_record_sql_redaction_test.rb +++ b/test/lib/rails_ext/active_record_sql_redaction_test.rb @@ -175,6 +175,18 @@ class ActiveRecordSqlRedactionTest < ActiveSupport::TestCase assert_no_secret CODE, seen.join("\n") end + unless Fizzy.db_adapter.sqlite? + test "a MySQL server error keeps only its code" do + identities(:kevin).magic_links.create!(code: CODE) + + error = assert_raises ActiveRecord::RecordNotUnique do + identities(:kevin).magic_links.new(code: CODE, expires_at: 1.minute.from_now).save!(validate: false) + end + + assert_equal "1062: #{ActiveRecordSqlRedaction::FILTERED_ERROR}", error.cause.message + end + end + test "an invalid statement's error, which can quote the statement, carries no value" do error = assert_raises ActiveRecord::StatementInvalid do MagicLink.connection.select_all("SELECT * FROM magic_links WHERE code = '#{CODE}' INVALID") From b72ffee87c2517e0f4ed02ce8b518a1c828ec88c Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Sat, 24 Oct 2026 18:37:54 -0400 Subject: [PATCH 2/4] Name the SaaS development and test MySQL user mysql2 connected as the OS user when the config named none, so SaaS tests could not sign in to MySQL. --- saas/config/database.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/saas/config/database.yml b/saas/config/database.yml index 07004c9aa2..51f918d587 100644 --- a/saas/config/database.yml +++ b/saas/config/database.yml @@ -36,6 +36,7 @@ default: &default adapter: mysql2 host: <%= ENV.fetch "FIZZY_DB_HOST", "127.0.0.1" %> port: <%= ENV.fetch "FIZZY_DB_PORT", 3306 %> + username: root # mysql2 falls back to the OS user; production names its own pool: 50 timeout: 5000 <% unless ENV["MIGRATE"].present? %> From ced30be5b26aca7ab75fe6198eb5c246bc4ce39d Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 26 Oct 2026 18:00:53 -0400 Subject: [PATCH 3/4] Refuse MYSQL_SSL_MODE=verify_ca With mysql2 in the Docker image, `verify_ca` connected without checking the server certificate. Raise at boot and point to `verify_identity`. --- config/initializers/mysql_ssl_mode.rb | 5 ++++ test/initializers/mysql_ssl_mode_test.rb | 31 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 config/initializers/mysql_ssl_mode.rb create mode 100644 test/initializers/mysql_ssl_mode_test.rb diff --git a/config/initializers/mysql_ssl_mode.rb b/config/initializers/mysql_ssl_mode.rb new file mode 100644 index 0000000000..1d7f470b12 --- /dev/null +++ b/config/initializers/mysql_ssl_mode.rb @@ -0,0 +1,5 @@ +# mysql2 built against MariaDB Connector/C, as in the Docker image, ignores verify_ca and +# connects without checking the server certificate. +if ENV["MYSQL_SSL_MODE"].to_s.casecmp?("verify_ca") + raise "MYSQL_SSL_MODE=verify_ca is not supported. Use verify_identity, which checks the server certificate and its host name." +end diff --git a/test/initializers/mysql_ssl_mode_test.rb b/test/initializers/mysql_ssl_mode_test.rb new file mode 100644 index 0000000000..5b5be80992 --- /dev/null +++ b/test/initializers/mysql_ssl_mode_test.rb @@ -0,0 +1,31 @@ +require "test_helper" + +class MysqlSslModeTest < ActiveSupport::TestCase + test "verify_ca is refused" do + %w[ verify_ca VERIFY_CA ].each do |mode| + with_mysql_ssl_mode(mode) do + error = assert_raises(RuntimeError) { load_initializer } + assert_match "verify_identity", error.message + end + end + end + + test "other modes are allowed" do + [ nil, "disabled", "required", "verify_identity" ].each do |mode| + with_mysql_ssl_mode(mode) { assert_nothing_raised { load_initializer } } + end + end + + private + def with_mysql_ssl_mode(mode) + original = ENV["MYSQL_SSL_MODE"] + ENV["MYSQL_SSL_MODE"] = mode + yield + ensure + ENV["MYSQL_SSL_MODE"] = original + end + + def load_initializer + load Rails.root.join("config/initializers/mysql_ssl_mode.rb").to_s + end +end From 03881fd9d4b91e3fd36937cc6ebc6a125ebae5b0 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 26 Oct 2026 18:11:33 -0400 Subject: [PATCH 4/4] Update net-ssh to 7.3.8 for bundler-audit --- Gemfile.lock | 5 +++-- Gemfile.saas.lock | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4e1a83b153..0bd866cdf7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -325,7 +325,8 @@ GEM net-ssh (>= 5.0.0, < 8.0.0) net-smtp (0.5.1) net-protocol - net-ssh (7.3.3) + net-ssh (7.3.8) + logger nio4r (2.7.5) nokogiri (1.19.4-aarch64-linux-gnu) racc (~> 1.4) @@ -688,7 +689,7 @@ CHECKSUMS net-scp (4.1.0) sha256=a99b0b92a1e5d360b0de4ffbf2dc0c91531502d3d4f56c28b0139a7c093d1a5d net-sftp (4.0.0) sha256=65bb91c859c2f93b09826757af11b69af931a3a9155050f50d1b06d384526364 net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 - net-ssh (7.3.3) sha256=831def58b2c51dcef66ec00d29397d4f210de89c19fe78f95873ca30f386e86a + net-ssh (7.3.8) sha256=16bb1fccc4d9a580decdeea8ddb98e8544df29b7e6ac8cb94d4b379cfe4bee9f nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af diff --git a/Gemfile.saas.lock b/Gemfile.saas.lock index 9e2bd795c9..f55a9c74d8 100644 --- a/Gemfile.saas.lock +++ b/Gemfile.saas.lock @@ -447,7 +447,8 @@ GEM net-ssh (>= 5.0.0, < 8.0.0) net-smtp (0.5.1) net-protocol - net-ssh (7.3.3) + net-ssh (7.3.8) + logger nio4r (2.7.5) nokogiri (1.19.4-aarch64-linux-gnu) racc (~> 1.4) @@ -943,7 +944,7 @@ CHECKSUMS net-scp (4.1.0) sha256=a99b0b92a1e5d360b0de4ffbf2dc0c91531502d3d4f56c28b0139a7c093d1a5d net-sftp (4.0.0) sha256=65bb91c859c2f93b09826757af11b69af931a3a9155050f50d1b06d384526364 net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736 - net-ssh (7.3.3) sha256=831def58b2c51dcef66ec00d29397d4f210de89c19fe78f95873ca30f386e86a + net-ssh (7.3.8) sha256=16bb1fccc4d9a580decdeea8ddb98e8544df29b7e6ac8cb94d4b379cfe4bee9f nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1 nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af