From 47443df651117a197ee7b50f7b9eb5cd147c984f Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Wed, 27 May 2026 12:27:29 +0000 Subject: [PATCH 1/5] Fixes #39361 - Add Ruby 3.3 to CI --- .github/matrix.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/matrix.json b/.github/matrix.json index d09ceee255..911f80b11e 100644 --- a/.github/matrix.json +++ b/.github/matrix.json @@ -1,5 +1,5 @@ { "postgresql": ["13"], - "ruby": ["3.0"], + "ruby": ["3.0", "3.3"], "node": ["22"] } From b5ca7abda38ce76d41b38e4ae631b2a6ab150231 Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Wed, 27 May 2026 13:33:40 +0000 Subject: [PATCH 2/5] Refs #39361 - Set RuboCops TargetRubyVersion to 3.0 --- .rubocop.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9b1850652a..5ccfdfaa26 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,7 +6,7 @@ inherit_gem: inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.0 Bundler/OrderedGems: Enabled: false From 66bc8cdc547b57947915328ac7bbaeea91a668a0 Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Fri, 29 May 2026 13:37:28 +0000 Subject: [PATCH 3/5] Refs #39361 - Ensure =~ is run on a string --- app/controllers/api/base_controller.rb | 2 +- app/controllers/application_controller.rb | 2 +- app/lib/foreman/http_proxy.rb | 2 +- app/lib/net/validations.rb | 4 ++-- app/models/concerns/audit_extensions.rb | 6 +++--- app/models/concerns/host_common.rb | 2 +- app/models/concerns/hostext/search.rb | 2 +- app/models/concerns/parameterizable.rb | 2 +- app/models/concerns/scoped_search_extensions.rb | 4 ++-- app/models/fact_value.rb | 2 +- app/models/medium.rb | 2 +- app/models/operatingsystem.rb | 2 +- app/models/setting.rb | 2 +- app/models/user.rb | 12 ++++++------ app/registries/setting_registry.rb | 2 +- app/services/fact_parser.rb | 10 +++++----- app/services/foreman/parameters/validator.rb | 2 +- app/services/name_generator.rb | 4 ++-- app/services/puppet_fact_parser.rb | 4 ++-- app/services/sso/oauth.rb | 2 +- app/validators/alphanumeric_validator.rb | 2 +- app/validators/no_whitespace_validator.rb | 2 +- app/validators/url_schema_validator.rb | 2 +- lib/foreman/logging.rb | 2 +- 24 files changed, 39 insertions(+), 39 deletions(-) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 0e4521d03e..bd9256070c 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -311,7 +311,7 @@ def add_info_headers def setup_search_options params[:search] ||= "" params.each do |param, value| - if param =~ /(\w+)_id$/ && value.present? + if param.to_s =~ /(\w+)_id$/ && value.present? query = " #{Regexp.last_match(1)} = #{value}" params[:search] += query unless params[:search].include? query end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 7d7701d5e6..92965ccc31 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -196,7 +196,7 @@ def setup_search_options @original_search_parameter = params[:search] params[:search] ||= "" params.each do |param, value| - if param =~ /(\w+)_id$/ && value.present? + if param.to_s =~ /(\w+)_id$/ && value.present? query = "#{Regexp.last_match(1)} = #{value}" unless params[:search].include? query params[:search] += ' and ' if params[:search].present? diff --git a/app/lib/foreman/http_proxy.rb b/app/lib/foreman/http_proxy.rb index 2e798fd109..8fb4015469 100644 --- a/app/lib/foreman/http_proxy.rb +++ b/app/lib/foreman/http_proxy.rb @@ -60,7 +60,7 @@ def log_proxied_request(lib, current_proxy, requested_host) def http_host_excepted_by_wildcard?(host) return false if http_proxy_except_list.empty? - host =~ Setting.convert_array_to_regexp(http_proxy_except_list) + host.to_s =~ Setting.convert_array_to_regexp(http_proxy_except_list) end def http_host_excepted?(host) diff --git a/app/lib/net/validations.rb b/app/lib/net/validations.rb index a344c0cf5c..717e8e6e9b 100644 --- a/app/lib/net/validations.rb +++ b/app/lib/net/validations.rb @@ -44,7 +44,7 @@ def self.validate_ip6!(ip) # validates a network mask def self.validate_mask(mask) - mask =~ MASK_REGEXP + mask.to_s =~ MASK_REGEXP end # validates a network mask and raises an error @@ -90,7 +90,7 @@ def self.validate_mac!(mac) # validates the hostname def self.validate_hostname(hostname) - hostname =~ HOST_REGEXP + hostname.to_s =~ HOST_REGEXP end # validates the hostname and raises an error diff --git a/app/models/concerns/audit_extensions.rb b/app/models/concerns/audit_extensions.rb index 4a7bc221ec..3e08a4e2c0 100644 --- a/app/models/concerns/audit_extensions.rb +++ b/app/models/concerns/audit_extensions.rb @@ -222,11 +222,11 @@ def ensure_username def fix_auditable_type # STI Host class should use the stub module instead of Host::Base - self.auditable_type = "Host::Base" if auditable_type =~ /^(::)?Host::/ - self.associated_type = "Host::Base" if associated_type =~ /^(::)?Host::/ + self.auditable_type = "Host::Base" if auditable_type.to_s =~ /^(::)?Host::/ + self.associated_type = "Host::Base" if associated_type.to_s =~ /^(::)?Host::/ self.auditable_type = auditable.type if ["Taxonomy", "LookupKey"].include?(auditable_type) && auditable self.associated_type = associated.type if ["Taxonomy", "LookupKey"].include?(associated_type) && associated - self.auditable_type = auditable.type if auditable_type =~ /Nic::/ + self.auditable_type = auditable.type if auditable_type.to_s =~ /Nic::/ end def ensure_auditable_and_associated_name diff --git a/app/models/concerns/host_common.rb b/app/models/concerns/host_common.rb index 076e453621..2f28544ed1 100644 --- a/app/models/concerns/host_common.rb +++ b/app/models/concerns/host_common.rb @@ -143,7 +143,7 @@ def default_image_file def image_file=(file) # We only save a value into the image_file field if the value is not the default path, (which was placed in the entry when it was displayed,) # and it is not a directory, (ends in /) - value = ((default_image_file == file) || (file =~ /\/\Z/) || file == "") ? nil : file + value = ((default_image_file == file) || (file.to_s =~ /\/\Z/) || file == "") ? nil : file self[:image_file] = value end diff --git a/app/models/concerns/hostext/search.rb b/app/models/concerns/hostext/search.rb index 4ee19858ab..7cb0c00e2f 100644 --- a/app/models/concerns/hostext/search.rb +++ b/app/models/concerns/hostext/search.rb @@ -267,7 +267,7 @@ def search_by_os_minor(key, operator, value) operator_addition2 = (operator == "=") ? "=" : "" operator = '!=' if operator == '<>' if operator =~ /ILIKE/ - match = os.minor =~ /#{value}/ + match = os.minor.to_s =~ /#{value}/ match = !match if operator.start_with?('NOT') operatingsystem_ids.append(os.id) if match elsif os_y.to_i.public_send(operator + operator_addition1, y.to_i) diff --git a/app/models/concerns/parameterizable.rb b/app/models/concerns/parameterizable.rb index ffd130221a..03f9437472 100644 --- a/app/models/concerns/parameterizable.rb +++ b/app/models/concerns/parameterizable.rb @@ -27,7 +27,7 @@ def to_param end def self.from_param(id_name) - find_by_id(id_name.to_i) if id_name =~ /\A\d+-/ + find_by_id(id_name.to_i) if id_name.to_s =~ /\A\d+-/ end end end diff --git a/app/models/concerns/scoped_search_extensions.rb b/app/models/concerns/scoped_search_extensions.rb index f97ee690d4..5a8850d2d3 100644 --- a/app/models/concerns/scoped_search_extensions.rb +++ b/app/models/concerns/scoped_search_extensions.rb @@ -4,7 +4,7 @@ module ScopedSearchExtensions module ClassMethods def value_to_sql(operator, value) return value if operator !~ /LIKE/i - return value.tr_s('%*', '%') if (value =~ /%|\*/) + return value.tr_s('%*', '%') if (value.to_s =~ /%|\*/) escape_str_format("%#{value}%") end @@ -13,7 +13,7 @@ def escape_str_format(str) end def cast_facts(table, key, operator, value) - is_int = (value =~ /\A[-+]?\d+\z/) || value.is_a?(Integer) + is_int = (value.to_s =~ /\A[-+]?\d+\z/) || value.is_a?(Integer) is_pg = ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'postgresql' # Once Postgresql 8 support is removed (used in CentOS 6), this could be replaced to only keep the first form (working well with PG 9) if (is_int && !is_pg) diff --git a/app/models/fact_value.rb b/app/models/fact_value.rb index 8a60895f31..7c84c01409 100644 --- a/app/models/fact_value.rb +++ b/app/models/fact_value.rb @@ -49,7 +49,7 @@ class FactValue < ApplicationRecord def self.search_by_host_or_hostgroup(key, operator, value) host_or_hg = (key == 'host.hostgroup') ? 'hostgroup' : 'host' - search_term = (value =~ /\A\d+\Z/) ? 'id' : 'name' + search_term = (value.to_s =~ /\A\d+\Z/) ? 'id' : 'name' conditions = sanitize_sql_for_conditions(["#{host_or_hg.pluralize}.#{search_term} #{operator} ?", value_to_sql(operator, value)]) { :joins => host_or_hg.to_sym, :conditions => conditions } end diff --git a/app/models/medium.rb b/app/models/medium.rb index 5cb5faf650..ed7947ce9a 100644 --- a/app/models/medium.rb +++ b/app/models/medium.rb @@ -56,7 +56,7 @@ def jumpstart_dir # Write the image path, with a trailing "/" if required def image_path=(path) - self[:image_path] = "#{path}#{'/' unless path =~ /\/$|^$/}" + self[:image_path] = "#{path}#{'/' unless path.to_s =~ /\/$|^$/}" end def ensure_hosts_not_in_build diff --git a/app/models/operatingsystem.rb b/app/models/operatingsystem.rb index a2b61924b6..7a4842d9ee 100644 --- a/app/models/operatingsystem.rb +++ b/app/models/operatingsystem.rb @@ -299,7 +299,7 @@ def shorten_description(description) def self.deduce_family(name) families.find do |f| - name =~ FAMILIES[f] + name.to_s =~ FAMILIES[f] end end diff --git a/app/models/setting.rb b/app/models/setting.rb index 2b9c3c415a..5e0adbccfd 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -133,7 +133,7 @@ def parse_string_value(val) end when "array" - if val =~ /\A\[.*\]\Z/ + if val.to_s =~ /\A\[.*\]\Z/ begin self.value = YAML.safe_load(val.gsub(/(,)(\S)/, "\\1 \\2")) rescue => e diff --git a/app/models/user.rb b/app/models/user.rb index bbf2c60dd3..167a308c94 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -464,22 +464,22 @@ def can_change_admin_flag? def editing_self?(options = {}) options[:controller].to_s == 'users' && - options[:action] =~ /edit|update|invalidate_jwt/ && + options[:action].to_s =~ /edit|update|invalidate_jwt/ && options[:id].to_i == id || options[:controller].to_s =~ /\Aapi\/v\d+\/users\Z/ && - options[:action] =~ /show|update/ && + options[:action].to_s =~ /show|update/ && (options[:id].to_i == id || options[:id] == login) || options[:controller].to_s == 'ssh_keys' && options[:user_id].to_i == id && - options[:action] =~ /new|create|destroy/ || + options[:action].to_s =~ /new|create|destroy/ || options[:controller].to_s == 'api/v2/ssh_keys' && - options[:action] =~ /show|destroy|index|create/ && + options[:action].to_s =~ /show|destroy|index|create/ && options[:user_id].to_i == id || options[:controller].to_s == 'api/v2/personal_access_tokens' && - options[:action] =~ /show|destroy|index|create/ && + options[:action].to_s =~ /show|destroy|index|create/ && options[:user_id].to_i == id || options[:controller].to_s == 'api/v2/registration_tokens' && - options[:action] =~ /invalidate_jwt/ && + options[:action].to_s =~ /invalidate_jwt/ && options[:id].to_i == id end diff --git a/app/registries/setting_registry.rb b/app/registries/setting_registry.rb index 6bb201dbc9..d144549803 100644 --- a/app/registries/setting_registry.rb +++ b/app/registries/setting_registry.rb @@ -36,7 +36,7 @@ def complete_value_from_db(field, val) count = 20 case field.field when :name - results = @registry.filter_map { |set| ((set.full_name =~ /\s/) ? "\"#{set.full_name.gsub('"', '\"')}\"" : set.full_name) if set.name.include?(val) || set.full_name&.include?(val) } + results = @registry.filter_map { |set| ((set.full_name.to_s =~ /\s/) ? "\"#{set.full_name.gsub('"', '\"')}\"" : set.full_name) if set.name.include?(val) || set.full_name&.include?(val) } results.first(count) when :description [] diff --git a/app/services/fact_parser.rb b/app/services/fact_parser.rb index 8954d2e1d4..454a658947 100644 --- a/app/services/fact_parser.rb +++ b/app/services/fact_parser.rb @@ -218,17 +218,17 @@ def find_virtual_interface(interfaces) # adds attributes like virtual def set_additional_attributes(attributes, name) - if name =~ VIRTUAL_NAMES + if name.to_s =~ VIRTUAL_NAMES attributes[:virtual] = true - if Regexp.last_match(1).nil? && name =~ BRIDGES + if Regexp.last_match(1).nil? && name.to_s =~ BRIDGES attributes[:bridge] = true - elsif name =~ ALIASES + elsif name.to_s =~ ALIASES attributes[:attached_to] = Regexp.last_match(1) attributes[:tag] = '' - elsif name =~ VLANS + elsif name.to_s =~ VLANS attributes[:attached_to] = Regexp.last_match(1) attributes[:tag] = Regexp.last_match(2) - elsif name =~ VIRTUAL + elsif name.to_s =~ VIRTUAL # Legacy: facter < v3.0 # vlans fact has been removed in facter 3.0 attributes[:attached_to] = Regexp.last_match(1) diff --git a/app/services/foreman/parameters/validator.rb b/app/services/foreman/parameters/validator.rb index fb4d00b094..1e6b3f69ec 100644 --- a/app/services/foreman/parameters/validator.rb +++ b/app/services/foreman/parameters/validator.rb @@ -25,7 +25,7 @@ def value def validate_regexp return true if value.contains_erb? && Setting[:interpolate_erb_in_parameters] - unless value =~ /#{@options[:validate_with]}/ + unless value.to_s =~ /#{@options[:validate_with]}/ add_error(_("is invalid")) return false end diff --git a/app/services/name_generator.rb b/app/services/name_generator.rb index 777b686000..378db01d35 100644 --- a/app/services/name_generator.rb +++ b/app/services/name_generator.rb @@ -6,12 +6,12 @@ class NameGenerator }.freeze def self.random_based? - Setting[:name_generator_type] =~ /^Random/i + Setting[:name_generator_type].to_s =~ /^Random/i end delegate :random_based?, :to => :class def self.mac_based? - Setting[:name_generator_type] =~ /^MAC/i + Setting[:name_generator_type].to_s =~ /^MAC/i end delegate :mac_based?, :to => :class diff --git a/app/services/puppet_fact_parser.rb b/app/services/puppet_fact_parser.rb index 0c5afaf735..87d4829ad2 100644 --- a/app/services/puppet_fact_parser.rb +++ b/app/services/puppet_fact_parser.rb @@ -7,7 +7,7 @@ def operatingsystem args = { :name => os_name } if orel.present? - if os_name =~ /ubuntu/i + if os_name.to_s =~ /ubuntu/i major = os_major_version.to_s minor = os_minor_version.to_s else @@ -79,7 +79,7 @@ def domain def ipmi_interface # ipmi_ facts are custom facts in foreman-discovery-image - ipmi = facts.select { |name, _| name =~ /\Aipmi_(.*)\Z/ }.map { |name, value| [name.sub(/\Aipmi_/, ''), value] } + ipmi = facts.select { |name, _| name.to_s =~ /\Aipmi_(.*)\Z/ }.map { |name, value| [name.to_s.sub(/\Aipmi_/, ''), value] } Hash[ipmi].with_indifferent_access end diff --git a/app/services/sso/oauth.rb b/app/services/sso/oauth.rb index 7e6c161221..47f1514aab 100644 --- a/app/services/sso/oauth.rb +++ b/app/services/sso/oauth.rb @@ -3,7 +3,7 @@ module SSO class Oauth < Base def available? - controller.api_request? && !!(request.authorization =~ /^OAuth/) + controller.api_request? && !!(request.authorization.to_s =~ /^OAuth/) end def authenticate! diff --git a/app/validators/alphanumeric_validator.rb b/app/validators/alphanumeric_validator.rb index d175bd1253..5d7a729831 100644 --- a/app/validators/alphanumeric_validator.rb +++ b/app/validators/alphanumeric_validator.rb @@ -1,5 +1,5 @@ class AlphanumericValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) - record.errors.add(attribute, _("must only contain alphanumeric or underscore characters")) unless value =~ /\A\w+\Z/ + record.errors.add(attribute, _("must only contain alphanumeric or underscore characters")) unless value.to_s =~ /\A\w+\Z/ end end diff --git a/app/validators/no_whitespace_validator.rb b/app/validators/no_whitespace_validator.rb index 0f5b7fd7a8..9b24ee042f 100644 --- a/app/validators/no_whitespace_validator.rb +++ b/app/validators/no_whitespace_validator.rb @@ -1,5 +1,5 @@ class NoWhitespaceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) - record.errors.add(attribute, _("can't contain spaces.")) if value =~ /\s/ + record.errors.add(attribute, _("can't contain spaces.")) if value.to_s =~ /\s/ end end diff --git a/app/validators/url_schema_validator.rb b/app/validators/url_schema_validator.rb index 2d612a8b74..99ab44f697 100644 --- a/app/validators/url_schema_validator.rb +++ b/app/validators/url_schema_validator.rb @@ -5,7 +5,7 @@ def initialize(args) end def validate_each(record, attribute, value) - unless value =~ /\A#{URI.regexp(@schemas)}\z/ + unless value.to_s =~ /\A#{URI.regexp(@schemas)}\z/ error_message = _('URL must be valid and schema must be one of %s') % @schemas.to_sentence record.errors.add(attribute, error_message) diff --git a/lib/foreman/logging.rb b/lib/foreman/logging.rb index 0be65dbd67..1ee2f8c044 100644 --- a/lib/foreman/logging.rb +++ b/lib/foreman/logging.rb @@ -222,7 +222,7 @@ def build_file_appender(name, options) def build_layout(enable_colors = true) pattern, colorize = @config[:pattern], @config[:colorize] - pattern = @config[:sys_pattern] if @config[:type] =~ /^(journald?|syslog)$/i + pattern = @config[:sys_pattern] if @config[:type].to_s =~ /^(journald?|syslog)$/i colorize = nil unless enable_colors case @config[:layout] when 'json' From 359eeafc5ba5265fc662fc0a5c51cccb64f841b1 Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Fri, 29 May 2026 14:57:34 +0000 Subject: [PATCH 4/5] Refs #39361 - Use .match? instead of .to_s =~ combo --- app/lib/foreman/http_proxy.rb | 2 +- app/lib/net/validations.rb | 4 ++-- app/models/concerns/audit_extensions.rb | 6 +++--- app/models/concerns/host_common.rb | 2 +- app/models/concerns/hostext/search.rb | 2 +- app/models/concerns/parameterizable.rb | 2 +- app/models/concerns/scoped_search_extensions.rb | 4 ++-- app/models/fact_value.rb | 2 +- app/models/medium.rb | 2 +- app/models/operatingsystem.rb | 2 +- app/models/setting.rb | 2 +- app/models/user.rb | 14 +++++++------- app/registries/setting_registry.rb | 2 +- app/services/foreman/parameters/validator.rb | 2 +- app/services/name_generator.rb | 4 ++-- app/services/puppet_fact_parser.rb | 2 +- app/services/sso/oauth.rb | 2 +- app/validators/alphanumeric_validator.rb | 2 +- app/validators/no_whitespace_validator.rb | 2 +- app/validators/url_schema_validator.rb | 2 +- lib/foreman/logging.rb | 2 +- 21 files changed, 32 insertions(+), 32 deletions(-) diff --git a/app/lib/foreman/http_proxy.rb b/app/lib/foreman/http_proxy.rb index 8fb4015469..2548e1172e 100644 --- a/app/lib/foreman/http_proxy.rb +++ b/app/lib/foreman/http_proxy.rb @@ -60,7 +60,7 @@ def log_proxied_request(lib, current_proxy, requested_host) def http_host_excepted_by_wildcard?(host) return false if http_proxy_except_list.empty? - host.to_s =~ Setting.convert_array_to_regexp(http_proxy_except_list) + Setting.convert_array_to_regexp(http_proxy_except_list).match?(host) end def http_host_excepted?(host) diff --git a/app/lib/net/validations.rb b/app/lib/net/validations.rb index 717e8e6e9b..e596d70c10 100644 --- a/app/lib/net/validations.rb +++ b/app/lib/net/validations.rb @@ -44,7 +44,7 @@ def self.validate_ip6!(ip) # validates a network mask def self.validate_mask(mask) - mask.to_s =~ MASK_REGEXP + MASK_REGEXP.match?(mask) end # validates a network mask and raises an error @@ -90,7 +90,7 @@ def self.validate_mac!(mac) # validates the hostname def self.validate_hostname(hostname) - hostname.to_s =~ HOST_REGEXP + HOST_REGEXP.match?(hostname) end # validates the hostname and raises an error diff --git a/app/models/concerns/audit_extensions.rb b/app/models/concerns/audit_extensions.rb index 3e08a4e2c0..acc2f5ef68 100644 --- a/app/models/concerns/audit_extensions.rb +++ b/app/models/concerns/audit_extensions.rb @@ -222,11 +222,11 @@ def ensure_username def fix_auditable_type # STI Host class should use the stub module instead of Host::Base - self.auditable_type = "Host::Base" if auditable_type.to_s =~ /^(::)?Host::/ - self.associated_type = "Host::Base" if associated_type.to_s =~ /^(::)?Host::/ + self.auditable_type = "Host::Base" if /^(::)?Host::/.match?(auditable_type) + self.associated_type = "Host::Base" if /^(::)?Host::/.match?(associated_type) self.auditable_type = auditable.type if ["Taxonomy", "LookupKey"].include?(auditable_type) && auditable self.associated_type = associated.type if ["Taxonomy", "LookupKey"].include?(associated_type) && associated - self.auditable_type = auditable.type if auditable_type.to_s =~ /Nic::/ + self.auditable_type = auditable.type if /Nic::/.match?(auditable_type) end def ensure_auditable_and_associated_name diff --git a/app/models/concerns/host_common.rb b/app/models/concerns/host_common.rb index 2f28544ed1..7e4ea2b979 100644 --- a/app/models/concerns/host_common.rb +++ b/app/models/concerns/host_common.rb @@ -143,7 +143,7 @@ def default_image_file def image_file=(file) # We only save a value into the image_file field if the value is not the default path, (which was placed in the entry when it was displayed,) # and it is not a directory, (ends in /) - value = ((default_image_file == file) || (file.to_s =~ /\/\Z/) || file == "") ? nil : file + value = ((default_image_file == file) || /\/\Z/.match?(file) || file == "") ? nil : file self[:image_file] = value end diff --git a/app/models/concerns/hostext/search.rb b/app/models/concerns/hostext/search.rb index 7cb0c00e2f..b162120b4f 100644 --- a/app/models/concerns/hostext/search.rb +++ b/app/models/concerns/hostext/search.rb @@ -267,7 +267,7 @@ def search_by_os_minor(key, operator, value) operator_addition2 = (operator == "=") ? "=" : "" operator = '!=' if operator == '<>' if operator =~ /ILIKE/ - match = os.minor.to_s =~ /#{value}/ + match = /#{value}/.match?(os.minor) match = !match if operator.start_with?('NOT') operatingsystem_ids.append(os.id) if match elsif os_y.to_i.public_send(operator + operator_addition1, y.to_i) diff --git a/app/models/concerns/parameterizable.rb b/app/models/concerns/parameterizable.rb index 03f9437472..b19d2c63f5 100644 --- a/app/models/concerns/parameterizable.rb +++ b/app/models/concerns/parameterizable.rb @@ -27,7 +27,7 @@ def to_param end def self.from_param(id_name) - find_by_id(id_name.to_i) if id_name.to_s =~ /\A\d+-/ + find_by_id(id_name.to_i) if /\A\d+-/.match?(id_name) end end end diff --git a/app/models/concerns/scoped_search_extensions.rb b/app/models/concerns/scoped_search_extensions.rb index 5a8850d2d3..c65468a7d6 100644 --- a/app/models/concerns/scoped_search_extensions.rb +++ b/app/models/concerns/scoped_search_extensions.rb @@ -4,7 +4,7 @@ module ScopedSearchExtensions module ClassMethods def value_to_sql(operator, value) return value if operator !~ /LIKE/i - return value.tr_s('%*', '%') if (value.to_s =~ /%|\*/) + return value.tr_s('%*', '%') if value.to_s.match?(/%|\*/) escape_str_format("%#{value}%") end @@ -13,7 +13,7 @@ def escape_str_format(str) end def cast_facts(table, key, operator, value) - is_int = (value.to_s =~ /\A[-+]?\d+\z/) || value.is_a?(Integer) + is_int = value.to_s.match?(/\A[-+]?\d+\z/) || value.is_a?(Integer) is_pg = ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'postgresql' # Once Postgresql 8 support is removed (used in CentOS 6), this could be replaced to only keep the first form (working well with PG 9) if (is_int && !is_pg) diff --git a/app/models/fact_value.rb b/app/models/fact_value.rb index 7c84c01409..f0df424307 100644 --- a/app/models/fact_value.rb +++ b/app/models/fact_value.rb @@ -49,7 +49,7 @@ class FactValue < ApplicationRecord def self.search_by_host_or_hostgroup(key, operator, value) host_or_hg = (key == 'host.hostgroup') ? 'hostgroup' : 'host' - search_term = (value.to_s =~ /\A\d+\Z/) ? 'id' : 'name' + search_term = /\A\d+\Z/.match?(value) ? 'id' : 'name' conditions = sanitize_sql_for_conditions(["#{host_or_hg.pluralize}.#{search_term} #{operator} ?", value_to_sql(operator, value)]) { :joins => host_or_hg.to_sym, :conditions => conditions } end diff --git a/app/models/medium.rb b/app/models/medium.rb index ed7947ce9a..441887f233 100644 --- a/app/models/medium.rb +++ b/app/models/medium.rb @@ -56,7 +56,7 @@ def jumpstart_dir # Write the image path, with a trailing "/" if required def image_path=(path) - self[:image_path] = "#{path}#{'/' unless path.to_s =~ /\/$|^$/}" + self[:image_path] = "#{path}#{'/' unless /\/$|^$/.match?(path)}" end def ensure_hosts_not_in_build diff --git a/app/models/operatingsystem.rb b/app/models/operatingsystem.rb index 7a4842d9ee..468e1a30a2 100644 --- a/app/models/operatingsystem.rb +++ b/app/models/operatingsystem.rb @@ -299,7 +299,7 @@ def shorten_description(description) def self.deduce_family(name) families.find do |f| - name.to_s =~ FAMILIES[f] + FAMILIES[f].match?(name) end end diff --git a/app/models/setting.rb b/app/models/setting.rb index 5e0adbccfd..bf4e8144a6 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -133,7 +133,7 @@ def parse_string_value(val) end when "array" - if val.to_s =~ /\A\[.*\]\Z/ + if /\A\[.*\]\Z/.match?(val) begin self.value = YAML.safe_load(val.gsub(/(,)(\S)/, "\\1 \\2")) rescue => e diff --git a/app/models/user.rb b/app/models/user.rb index 167a308c94..dd70668532 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -464,22 +464,22 @@ def can_change_admin_flag? def editing_self?(options = {}) options[:controller].to_s == 'users' && - options[:action].to_s =~ /edit|update|invalidate_jwt/ && + /edit|update|invalidate_jwt/.match?(options[:action]) && options[:id].to_i == id || - options[:controller].to_s =~ /\Aapi\/v\d+\/users\Z/ && - options[:action].to_s =~ /show|update/ && + /\Aapi\/v\d+\/users\Z/.match?(options[:controller]) && + /show|update/.match?(options[:action]) && (options[:id].to_i == id || options[:id] == login) || options[:controller].to_s == 'ssh_keys' && options[:user_id].to_i == id && - options[:action].to_s =~ /new|create|destroy/ || + /new|create|destroy/.match?(options[:action]) || options[:controller].to_s == 'api/v2/ssh_keys' && - options[:action].to_s =~ /show|destroy|index|create/ && + /show|destroy|index|create/.match?(options[:action]) && options[:user_id].to_i == id || options[:controller].to_s == 'api/v2/personal_access_tokens' && - options[:action].to_s =~ /show|destroy|index|create/ && + /show|destroy|index|create/.match?(options[:action]) && options[:user_id].to_i == id || options[:controller].to_s == 'api/v2/registration_tokens' && - options[:action].to_s =~ /invalidate_jwt/ && + /invalidate_jwt/.match?(options[:action]) && options[:id].to_i == id end diff --git a/app/registries/setting_registry.rb b/app/registries/setting_registry.rb index d144549803..9a4059aa67 100644 --- a/app/registries/setting_registry.rb +++ b/app/registries/setting_registry.rb @@ -36,7 +36,7 @@ def complete_value_from_db(field, val) count = 20 case field.field when :name - results = @registry.filter_map { |set| ((set.full_name.to_s =~ /\s/) ? "\"#{set.full_name.gsub('"', '\"')}\"" : set.full_name) if set.name.include?(val) || set.full_name&.include?(val) } + results = @registry.filter_map { |set| (/\s/.match?(set.full_name) ? "\"#{set.full_name.gsub('"', '\"')}\"" : set.full_name) if set.name.include?(val) || set.full_name&.include?(val) } results.first(count) when :description [] diff --git a/app/services/foreman/parameters/validator.rb b/app/services/foreman/parameters/validator.rb index 1e6b3f69ec..113a2679c0 100644 --- a/app/services/foreman/parameters/validator.rb +++ b/app/services/foreman/parameters/validator.rb @@ -25,7 +25,7 @@ def value def validate_regexp return true if value.contains_erb? && Setting[:interpolate_erb_in_parameters] - unless value.to_s =~ /#{@options[:validate_with]}/ + unless /#{@options[:validate_with]}/.match?(value) add_error(_("is invalid")) return false end diff --git a/app/services/name_generator.rb b/app/services/name_generator.rb index 378db01d35..e3264bc09f 100644 --- a/app/services/name_generator.rb +++ b/app/services/name_generator.rb @@ -6,12 +6,12 @@ class NameGenerator }.freeze def self.random_based? - Setting[:name_generator_type].to_s =~ /^Random/i + /^Random/i.match?(Setting[:name_generator_type]) end delegate :random_based?, :to => :class def self.mac_based? - Setting[:name_generator_type].to_s =~ /^MAC/i + /^MAC/i.match?(Setting[:name_generator_type]) end delegate :mac_based?, :to => :class diff --git a/app/services/puppet_fact_parser.rb b/app/services/puppet_fact_parser.rb index 87d4829ad2..e7024aa35f 100644 --- a/app/services/puppet_fact_parser.rb +++ b/app/services/puppet_fact_parser.rb @@ -7,7 +7,7 @@ def operatingsystem args = { :name => os_name } if orel.present? - if os_name.to_s =~ /ubuntu/i + if /ubuntu/i.match?(os_name) major = os_major_version.to_s minor = os_minor_version.to_s else diff --git a/app/services/sso/oauth.rb b/app/services/sso/oauth.rb index 47f1514aab..4b56d4bb9c 100644 --- a/app/services/sso/oauth.rb +++ b/app/services/sso/oauth.rb @@ -3,7 +3,7 @@ module SSO class Oauth < Base def available? - controller.api_request? && !!(request.authorization.to_s =~ /^OAuth/) + controller.api_request? && /^OAuth/.match?(request.authorization) end def authenticate! diff --git a/app/validators/alphanumeric_validator.rb b/app/validators/alphanumeric_validator.rb index 5d7a729831..6ccd1e1f66 100644 --- a/app/validators/alphanumeric_validator.rb +++ b/app/validators/alphanumeric_validator.rb @@ -1,5 +1,5 @@ class AlphanumericValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) - record.errors.add(attribute, _("must only contain alphanumeric or underscore characters")) unless value.to_s =~ /\A\w+\Z/ + record.errors.add(attribute, _("must only contain alphanumeric or underscore characters")) unless /\A\w+\Z/.match?(value) end end diff --git a/app/validators/no_whitespace_validator.rb b/app/validators/no_whitespace_validator.rb index 9b24ee042f..a2a1d4de34 100644 --- a/app/validators/no_whitespace_validator.rb +++ b/app/validators/no_whitespace_validator.rb @@ -1,5 +1,5 @@ class NoWhitespaceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) - record.errors.add(attribute, _("can't contain spaces.")) if value.to_s =~ /\s/ + record.errors.add(attribute, _("can't contain spaces.")) if /\s/.match?(value) end end diff --git a/app/validators/url_schema_validator.rb b/app/validators/url_schema_validator.rb index 99ab44f697..2a65618e77 100644 --- a/app/validators/url_schema_validator.rb +++ b/app/validators/url_schema_validator.rb @@ -5,7 +5,7 @@ def initialize(args) end def validate_each(record, attribute, value) - unless value.to_s =~ /\A#{URI.regexp(@schemas)}\z/ + unless /\A#{URI.regexp(@schemas)}\z/.match?(value) error_message = _('URL must be valid and schema must be one of %s') % @schemas.to_sentence record.errors.add(attribute, error_message) diff --git a/lib/foreman/logging.rb b/lib/foreman/logging.rb index 1ee2f8c044..64c40954f0 100644 --- a/lib/foreman/logging.rb +++ b/lib/foreman/logging.rb @@ -222,7 +222,7 @@ def build_file_appender(name, options) def build_layout(enable_colors = true) pattern, colorize = @config[:pattern], @config[:colorize] - pattern = @config[:sys_pattern] if @config[:type].to_s =~ /^(journald?|syslog)$/i + pattern = @config[:sys_pattern] if /^(journald?|syslog)$/i.match?(@config[:type]) colorize = nil unless enable_colors case @config[:layout] when 'json' From 106bd184653546ede190e0b52b5fae701ef15cf7 Mon Sep 17 00:00:00 2001 From: Oleh Fedorenko Date: Mon, 1 Jun 2026 11:38:38 +0000 Subject: [PATCH 5/5] Refs #39361 - Drop old code --- app/models/concerns/host_common.rb | 2 +- app/models/concerns/scoped_search_extensions.rb | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/models/concerns/host_common.rb b/app/models/concerns/host_common.rb index 7e4ea2b979..e3c2d36dcc 100644 --- a/app/models/concerns/host_common.rb +++ b/app/models/concerns/host_common.rb @@ -143,7 +143,7 @@ def default_image_file def image_file=(file) # We only save a value into the image_file field if the value is not the default path, (which was placed in the entry when it was displayed,) # and it is not a directory, (ends in /) - value = ((default_image_file == file) || /\/\Z/.match?(file) || file == "") ? nil : file + value = ((default_image_file == file) || file.blank? || file.end_with?('/')) ? nil : file self[:image_file] = value end diff --git a/app/models/concerns/scoped_search_extensions.rb b/app/models/concerns/scoped_search_extensions.rb index c65468a7d6..574180d49a 100644 --- a/app/models/concerns/scoped_search_extensions.rb +++ b/app/models/concerns/scoped_search_extensions.rb @@ -13,12 +13,8 @@ def escape_str_format(str) end def cast_facts(table, key, operator, value) - is_int = value.to_s.match?(/\A[-+]?\d+\z/) || value.is_a?(Integer) - is_pg = ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'postgresql' - # Once Postgresql 8 support is removed (used in CentOS 6), this could be replaced to only keep the first form (working well with PG 9) - if (is_int && !is_pg) - casted = "CAST(#{table}.value AS DECIMAL) #{operator} #{value}" - elsif (is_int && is_pg && operator !~ /LIKE/i) + is_int = value.to_s.match?(/\A[-+]?\d+\z/) + if is_int && operator !~ /LIKE/i casted = "#{table}.value ~ E'^\\\\d+$' AND CAST(#{table}.value AS DECIMAL) #{operator} #{value}" else # Escape string formatting with %, as conditions will be re-sanitized through scoped_search