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"] } 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 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..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 =~ 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 a344c0cf5c..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 =~ 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 =~ 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 4a7bc221ec..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 =~ /^(::)?Host::/ - self.associated_type = "Host::Base" if associated_type =~ /^(::)?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 =~ /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 076e453621..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) || (file =~ /\/\Z/) || 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/hostext/search.rb b/app/models/concerns/hostext/search.rb index 4ee19858ab..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 =~ /#{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 ffd130221a..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 =~ /\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 f97ee690d4..574180d49a 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.match?(/%|\*/) escape_str_format("%#{value}%") end @@ -13,12 +13,8 @@ def escape_str_format(str) end def cast_facts(table, key, operator, value) - is_int = (value =~ /\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 diff --git a/app/models/fact_value.rb b/app/models/fact_value.rb index 8a60895f31..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 =~ /\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 5cb5faf650..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 =~ /\/$|^$/}" + 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 a2b61924b6..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 =~ FAMILIES[f] + FAMILIES[f].match?(name) end end diff --git a/app/models/setting.rb b/app/models/setting.rb index 2b9c3c415a..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 =~ /\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 bbf2c60dd3..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] =~ /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] =~ /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] =~ /new|create|destroy/ || + /new|create|destroy/.match?(options[:action]) || options[:controller].to_s == 'api/v2/ssh_keys' && - options[:action] =~ /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] =~ /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] =~ /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 6bb201dbc9..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 =~ /\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/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..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 =~ /#{@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 777b686000..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] =~ /^Random/i + /^Random/i.match?(Setting[:name_generator_type]) end delegate :random_based?, :to => :class def self.mac_based? - Setting[:name_generator_type] =~ /^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 0c5afaf735..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 =~ /ubuntu/i + if /ubuntu/i.match?(os_name) 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..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 =~ /^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 d175bd1253..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 =~ /\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 0f5b7fd7a8..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 =~ /\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 2d612a8b74..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 =~ /\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 0be65dbd67..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] =~ /^(journald?|syslog)$/i + pattern = @config[:sys_pattern] if /^(journald?|syslog)$/i.match?(@config[:type]) colorize = nil unless enable_colors case @config[:layout] when 'json'