From c9b1917886d10b9b359333daea2722eaa29ba041 Mon Sep 17 00:00:00 2001 From: gabrieljablonski Date: Fri, 17 Apr 2026 23:48:46 -0300 Subject: [PATCH] fix(installation_config): restore coder that accepts both jsonb hash and YAML string Upstream migration 20260324102005_repurpose_response_bot_flag_for_custom_tools calls InstallationConfig.value before the normalization migration (20260418020000) runs. On instances whose serialized_value column holds native jsonb hashes, that read raises "TypeError: no implicit conversion of Hash into String" and aborts the whole migration chain, leaving db:migrate stuck and production unable to deploy. Restore SerializedValueCoder.load that tolerates either shape. dump is updated to always emit YAML strings so new writes converge on the upstream format; the 20260418020000 migration still normalizes the backlog. --- app/models/installation_config.rb | 32 ++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/app/models/installation_config.rb b/app/models/installation_config.rb index 19252de50..f93948096 100644 --- a/app/models/installation_config.rb +++ b/app/models/installation_config.rb @@ -15,11 +15,33 @@ # index_installation_configs_on_name_and_created_at (name,created_at) UNIQUE # class InstallationConfig < ApplicationRecord - # https://stackoverflow.com/questions/72970170/upgrading-to-rails-6-1-6-1-causes-psychdisallowedclass-tried-to-load-unspecif - # https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017 - # FIX ME : fixes breakage of installation config. we need to migrate. - # Fix configuration in application.rb - serialize :serialized_value, coder: YAML, type: ActiveSupport::HashWithIndifferentAccess, default: {}.with_indifferent_access + # The serialized_value column is jsonb but production data is mixed: older rows + # were written as YAML strings by upstream's serialize :coder => YAML chain, + # and some rows were written as native jsonb hashes. The stock YAML coder + # raises TypeError on native-hash rows. This coder reads either shape and + # always writes YAML strings so data converges on a single format over time. + class SerializedValueCoder # rubocop:disable Style/OneClassPerFile + def self.dump(value) + hash = value.is_a?(Hash) ? value : { value: value } + YAML.dump(hash.with_indifferent_access) + end + + def self.load(value) + return {}.with_indifferent_access if value.blank? + + case value + when String + YAML.safe_load(value, permitted_classes: [ActiveSupport::HashWithIndifferentAccess, Symbol]) + .with_indifferent_access + when Hash + value.with_indifferent_access + else + {}.with_indifferent_access + end + end + end + + serialize :serialized_value, coder: SerializedValueCoder before_validation :set_lock validates :name, presence: true