From 9cc2902e69b7a42b5c3e935b360d8f9f60d52dfd Mon Sep 17 00:00:00 2001 From: Jarek Prokop Date: Mon, 2 Sep 2024 12:04:28 +0200 Subject: [PATCH] Upgrade to Ruby 3.3.5. Fix DoS vulnerability in rexml. (CVE-2024-39908) (CVE-2024-41946) (CVE-2024-43398) Fix REXML DoS when parsing an XML having many specific characters such as whitespace character, >] and ]>. (CVE-2024-41123) Upgrade by merging Fedora changes up to commit: https://src.fedoraproject.org/rpms/ruby/c/b7e197fb887200e4faaf8fae663a9df00bdc09d3 Exclude: - Generate RPM dependencies with RPM 4.20 API https://src.fedoraproject.org/rpms/ruby/c/6bed1e3bd563b1844762d9715285d1ed3bb4dc91 We don't have new enough RPM. Resolves: RHEL-59035 Resolves: RHEL-57047 Resolves: RHEL-57059 Resolves: RHEL-57070 Resolves: RHEL-52802 --- rpm_test_helper.rb | 166 ++++++++++ ...0-Enable-configuration-of-archlibdir.patch | 2 +- ...ed-paths-when-empty-version-string-i.patch | 2 +- ruby-2.1.0-always-use-i386.patch | 2 +- ruby-2.1.0-custom-rubygems-location.patch | 4 +- ruby-2.3.0-ruby_version.patch | 12 +- ruby-2.7.0-Initialize-ABRT-hook.patch | 2 +- ...ocations-in-Hash-compare_by_identity.patch | 92 ------ ...GS-to-a-special-hardenflags-variable.patch | 302 ++++++++++++++++++ ruby-3.4.0-Fix-pointer-incompatiblity.patch | 24 -- ...ranch-protection-compilation-for-arm.patch | 24 -- ruby.spec | 109 +++++-- ...-another-race-condition-of-open-mode.patch | 45 +++ ...17-Remove-the-lock-file-for-binstubs.patch | 183 +++++++++++ rubygems.con | 4 +- rubygems.req | 4 +- sources | 2 +- test_rubygems_con.rb | 124 +++++++ test_rubygems_prov.rb | 52 +++ test_rubygems_req.rb | 205 ++++++++++++ 20 files changed, 1171 insertions(+), 189 deletions(-) create mode 100644 rpm_test_helper.rb delete mode 100644 ruby-3.3.0-Revert-Optimize-allocations-in-Hash-compare_by_identity.patch create mode 100644 ruby-3.4.0-Extract-hardening-CFLAGS-to-a-special-hardenflags-variable.patch delete mode 100644 ruby-3.4.0-Fix-pointer-incompatiblity.patch delete mode 100644 ruby-3.4.0-fix-branch-protection-compilation-for-arm.patch create mode 100644 rubygems-3.5.17-Avoid-another-race-condition-of-open-mode.patch create mode 100644 rubygems-3.5.17-Remove-the-lock-file-for-binstubs.patch create mode 100644 test_rubygems_con.rb create mode 100644 test_rubygems_prov.rb create mode 100644 test_rubygems_req.rb diff --git a/rpm_test_helper.rb b/rpm_test_helper.rb new file mode 100644 index 0000000..671ca55 --- /dev/null +++ b/rpm_test_helper.rb @@ -0,0 +1,166 @@ +require 'tmpdir' +require 'tempfile' +require 'fileutils' +# Available in Ruby upstream sources under tool/lib/envutil.rb +# Required for finding and setting up the built ruby binary. +require 'envutil' + +module RPMTestHelper + def setup + @tmpdir = Dir.mktmpdir + @tempfiles = [] + end + + def teardown + @tempfiles.each do |file| + file.close + file.unlink + end + + FileUtils.rmtree(@tmpdir) + end + + GENERATOR_SCRIPT = ENV['GENERATOR_SCRIPT'].clone.freeze + if GENERATOR_SCRIPT.nil? || GENERATOR_SCRIPT == '' + raise "GENERATOR_SCRIPT is not specified." \ + "Specify the ENV variable with absolute path to the generator." + end + + Dependency = Struct.new('Dependency', :name, :requirements) do + def to_rpm_str + "rubygem(#{self.name})" + end + end + + def make_gemspec(gem_info) + file = Tempfile.new('req_gemspec', @tmpdir) + # Fake gemspec with enough to pass most checks + # Rubygems uses to validate the format. + gemspec_contents = <<~EOF + # -*- encoding: utf-8 -*- + # stub: #{gem_info.name} #{gem_info.version} ruby lib + + Gem::Specification.new do |s| + s.name = "#{gem_info.name}".freeze + s.version = "#{gem_info.version}" + + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib".freeze] + s.authors = ["John Doe".freeze] + s.bindir = "bin".freeze + s.date = "2023-12-15" + s.description = "Fake gemspec helper for testing Rubygem Generators".freeze + s.email = ["example@example.com".freeze] + s.files = ["LICENSE.txt".freeze, "lib/#{gem_info.name}.rb".freeze, "#{gem_info.name}.gemspec".freeze] + s.homepage = "https://pkgs.fedoraproject.org/rpms/ruby".freeze + s.licenses = ["MIT".freeze] + s.required_ruby_version = Gem::Requirement.new(">= 2.5.0".freeze) + s.rubygems_version = "3.3.5".freeze + s.summary = "Fake gemspec for testing Rubygem Generators".freeze + + if s.respond_to? :specification_version then + s.specification_version = 4 + end + + if s.respond_to? :add_runtime_dependency then + #{gem_info.gemspec_runtime_dep_str} + else + #{gem_info.gemspec_dep_str} + end + end + EOF + + file.write gemspec_contents + file.rewind + @tempfiles << file + file + end + + # Caller is expected to close subprocess stdin via #close_write + # in order to let subprocess proceed if the process is reading + # from STDIN in a loop. + def rb_subprocess(*args) + args = [GENERATOR_SCRIPT] if args.empty? + ruby = EnvUtil.rubybin + f = IO.popen([ruby] + args, 'r+') #, external_encoding: external_encoding) + yield(f) + ensure + f.close unless !f || f.closed? + end + + def run_generator_single_file(gem_info) + lines = [] + gemspec_f = make_gemspec(gem_info) + + rb_subprocess do |io| + io.write gemspec_f.path + io.close_write + lines = io.readlines + end + + lines + end + + def helper_rubygems_dependency + "ruby(rubygems)" + end + + class GemInfo + attr_accessor :name, :version, :dependencies + + def initialize(name: 'foo', version: '1.2.3', dependencies: []) + @name = name + @version = version + @dependencies = dependencies + end + + def dependencies=(other) + raise ArgumentError, "#{self.class.name}##{__method__.to_s}: Expected array of `Dependency' elements" \ + unless other.is_a?(Array) && other.all? { |elem| elem.respond_to?(:name) && elem.respond_to?(:requirements) } + + @dependencies = other + end + + def to_rpm_str + "rubygem(#{self.name})" + end + + def gemspec_dep_str + return '' if self.dependencies.nil? || self.dependencies.empty? + @dependencies.inject("") do |memo, dep| + memo += if dep.requirements && !dep.requirements.empty? + %Q|s.add_dependency(%q<#{dep.name}>.freeze, #{handle_dep_requirements(dep.requirements)})| + else + %Q|s.add_dependency(%q<#{dep.name}>.freeze)| + end + + memo += "\n" + end + end + + def gemspec_runtime_dep_str + return '' if self.dependencies.nil? || self.dependencies.empty? + + @dependencies.inject("") do |memo, dep| + memo += if dep.requirements && !dep.requirements.empty? + %Q|s.add_runtime_dependency(%q<#{dep.name}>.freeze, #{handle_dep_requirements(dep.requirements)})| + else + %Q|s.add_runtime_dependency(%q<#{dep.name}>.freeze)| + end + + memo += "\n" + end + end + + private + + def handle_dep_requirements(reqs) + raise ArgumentError, "#{self.class.name}##{__method__.to_s}: Reqs must be an array." \ + unless reqs.is_a? Array + raise ArgumentError, "#{self.class.name}##{__method__.to_s}: Reqs must not be empty for this method." \ + if reqs.empty? + + '[ "' + reqs.join('", "') + '" ]' + end + end +end diff --git a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch index acd58b9..4cd8dd1 100644 --- a/ruby-2.1.0-Enable-configuration-of-archlibdir.patch +++ b/ruby-2.1.0-Enable-configuration-of-archlibdir.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index d261ea57b5..3c13076b82 100644 --- a/configure.ac +++ b/configure.ac -@@ -3473,6 +3473,11 @@ AS_IF([test ${multiarch+set}], [ +@@ -3482,6 +3482,11 @@ AS_IF([test ${multiarch+set}], [ ]) archlibdir='${libdir}/${arch}' diff --git a/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch index 996486a..e6315c0 100644 --- a/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch +++ b/ruby-2.1.0-Prevent-duplicated-paths-when-empty-version-string-i.patch @@ -14,7 +14,7 @@ diff --git a/configure.ac b/configure.ac index c42436c23d..d261ea57b5 100644 --- a/configure.ac +++ b/configure.ac -@@ -4312,7 +4312,8 @@ AS_CASE(["$ruby_version_dir_name"], +@@ -4321,7 +4321,8 @@ AS_CASE(["$ruby_version_dir_name"], ruby_version_dir=/'${ruby_version_dir_name}' if test -z "${ruby_version_dir_name}"; then diff --git a/ruby-2.1.0-always-use-i386.patch b/ruby-2.1.0-always-use-i386.patch index 38eba5e..8e1b4fe 100644 --- a/ruby-2.1.0-always-use-i386.patch +++ b/ruby-2.1.0-always-use-i386.patch @@ -11,7 +11,7 @@ diff --git a/configure.ac b/configure.ac index 3c13076b82..93af30321d 100644 --- a/configure.ac +++ b/configure.ac -@@ -4376,6 +4376,8 @@ AC_SUBST(vendorarchdir)dnl +@@ -4385,6 +4385,8 @@ AC_SUBST(vendorarchdir)dnl AC_SUBST(CONFIGURE, "`echo $0 | sed 's|.*/||'`")dnl AC_SUBST(configure_args, "`echo "${ac_configure_args}" | sed 's/\\$/$$/g'`")dnl diff --git a/ruby-2.1.0-custom-rubygems-location.patch b/ruby-2.1.0-custom-rubygems-location.patch index 98dd7ac..7dc8eca 100644 --- a/ruby-2.1.0-custom-rubygems-location.patch +++ b/ruby-2.1.0-custom-rubygems-location.patch @@ -15,7 +15,7 @@ diff --git a/configure.ac b/configure.ac index 93af30321d..bc13397e0e 100644 --- a/configure.ac +++ b/configure.ac -@@ -4348,6 +4348,10 @@ AC_ARG_WITH(vendorarchdir, +@@ -4357,6 +4357,10 @@ AC_ARG_WITH(vendorarchdir, [vendorarchdir=$withval], [vendorarchdir=${multiarch+'${rubysitearchprefix}/vendor_ruby'${ruby_version_dir}}${multiarch-'${vendorlibdir}/${sitearch}'}]) @@ -26,7 +26,7 @@ index 93af30321d..bc13397e0e 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) RUBY_EXEC_PREFIX='' -@@ -4372,6 +4376,7 @@ AC_SUBST(sitearchdir)dnl +@@ -4381,6 +4385,7 @@ AC_SUBST(sitearchdir)dnl AC_SUBST(vendordir)dnl AC_SUBST(vendorlibdir)dnl AC_SUBST(vendorarchdir)dnl diff --git a/ruby-2.3.0-ruby_version.patch b/ruby-2.3.0-ruby_version.patch index 6ba802e..50b4466 100644 --- a/ruby-2.3.0-ruby_version.patch +++ b/ruby-2.3.0-ruby_version.patch @@ -20,7 +20,7 @@ diff --git a/configure.ac b/configure.ac index 80b137e380..63cd3b4f8b 100644 --- a/configure.ac +++ b/configure.ac -@@ -4262,9 +4262,6 @@ AS_CASE(["$target_os"], +@@ -4271,9 +4271,6 @@ AS_CASE(["$target_os"], rubyw_install_name='$(RUBYW_INSTALL_NAME)' ]) @@ -30,7 +30,7 @@ index 80b137e380..63cd3b4f8b 100644 rubyarchprefix=${multiarch+'${archlibdir}/${RUBY_BASE_NAME}'}${multiarch-'${rubylibprefix}/${arch}'} AC_ARG_WITH(rubyarchprefix, AS_HELP_STRING([--with-rubyarchprefix=DIR], -@@ -4287,57 +4284,63 @@ AC_ARG_WITH(ridir, +@@ -4296,57 +4293,63 @@ AC_ARG_WITH(ridir, AC_SUBST(ridir) AC_SUBST(RI_BASE_NAME) @@ -122,7 +122,7 @@ index 80b137e380..63cd3b4f8b 100644 AS_IF([test "${LOAD_RELATIVE+set}"], [ AC_DEFINE_UNQUOTED(LOAD_RELATIVE, $LOAD_RELATIVE) -@@ -4354,6 +4357,7 @@ AC_SUBST(sitearchincludedir)dnl +@@ -4363,6 +4366,7 @@ AC_SUBST(sitearchincludedir)dnl AC_SUBST(arch)dnl AC_SUBST(sitearch)dnl AC_SUBST(ruby_version)dnl @@ -227,7 +227,7 @@ diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index b25068405d..e9fef4a311 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb -@@ -1351,7 +1351,8 @@ def test_self_use_paths +@@ -1353,7 +1353,8 @@ def test_self_use_paths def test_self_user_dir parts = [@userhome, ".gem", Gem.ruby_engine] @@ -237,7 +237,7 @@ index b25068405d..e9fef4a311 100644 FileUtils.mkdir_p File.join(parts) -@@ -1427,7 +1428,7 @@ def test_self_vendor_dir +@@ -1429,7 +1430,7 @@ def test_self_vendor_dir vendordir(File.join(@tempdir, "vendor")) do expected = File.join RbConfig::CONFIG["vendordir"], "gems", @@ -262,7 +262,7 @@ diff --git a/configure.ac b/configure.ac index a00f2b6776..999e2d6d5d 100644 --- a/configure.ac +++ b/configure.ac -@@ -135,7 +135,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` +@@ -136,7 +136,7 @@ RUBY_BASE_NAME=`echo ruby | sed "$program_transform_name"` RUBYW_BASE_NAME=`echo rubyw | sed "$program_transform_name"` AC_SUBST(RUBY_BASE_NAME) AC_SUBST(RUBYW_BASE_NAME) diff --git a/ruby-2.7.0-Initialize-ABRT-hook.patch b/ruby-2.7.0-Initialize-ABRT-hook.patch index 0f32243..309507f 100644 --- a/ruby-2.7.0-Initialize-ABRT-hook.patch +++ b/ruby-2.7.0-Initialize-ABRT-hook.patch @@ -58,7 +58,7 @@ diff --git a/ruby.c b/ruby.c index 60c57d6259..1eec16f2c8 100644 --- a/ruby.c +++ b/ruby.c -@@ -1724,10 +1724,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) +@@ -1722,10 +1722,14 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt) void Init_builtin_features(void); diff --git a/ruby-3.3.0-Revert-Optimize-allocations-in-Hash-compare_by_identity.patch b/ruby-3.3.0-Revert-Optimize-allocations-in-Hash-compare_by_identity.patch deleted file mode 100644 index 23a6db8..0000000 --- a/ruby-3.3.0-Revert-Optimize-allocations-in-Hash-compare_by_identity.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 8944a064d0fd7947b8c2b6c761be3e3a0c9073af Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Fri, 22 Dec 2023 14:16:48 +0100 -Subject: [PATCH 1/2] Revert "compare_by_identity: remove alloc for non-empty - Hash" - -This reverts commit 11fa76b1b521072c200c78ea023960221ff426d6. ---- - hash.c | 13 ++++--------- - 1 file changed, 4 insertions(+), 9 deletions(-) - -diff --git a/hash.c b/hash.c -index 78e9d9a2d6..f6525ba4a5 100644 ---- a/hash.c -+++ b/hash.c -@@ -4385,16 +4385,13 @@ rb_hash_compare_by_id(VALUE hash) - if (hash_iterating_p(hash)) { - rb_raise(rb_eRuntimeError, "compare_by_identity during iteration"); - } -+ ar_force_convert_table(hash, __FILE__, __LINE__); -+ HASH_ASSERT(RHASH_ST_TABLE_P(hash)); - - if (RHASH_TABLE_EMPTY_P(hash)) { - // Fast path: There's nothing to rehash, so we don't need a `tmp` table. -- // We're most likely an AR table, so this will need an allocation. -- ar_force_convert_table(hash, __FILE__, __LINE__); -- HASH_ASSERT(RHASH_ST_TABLE_P(hash)); -- - RHASH_ST_TABLE(hash)->type = &identhash; -- } -- else { -+ } else { - // Slow path: Need to rehash the members of `self` into a new - // `tmp` table using the new `identhash` compare/hash functions. - tmp = hash_alloc(0); -@@ -4402,10 +4399,8 @@ rb_hash_compare_by_id(VALUE hash) - identtable = RHASH_ST_TABLE(tmp); - - rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); -- rb_hash_free(hash); - -- // We know for sure `identtable` is an st table, -- // so we can skip `ar_force_convert_table` here. -+ rb_hash_free(hash); - RHASH_ST_TABLE_SET(hash, identtable); - RHASH_ST_CLEAR(tmp); - } - -From f5c415300ffe63e41e46c6b88b8634a3bad0c7c2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?V=C3=ADt=20Ondruch?= -Date: Fri, 22 Dec 2023 14:17:14 +0100 -Subject: [PATCH 2/2] Revert "compare_by_identity: remove alloc for empty Hash" - -This reverts commit b5c6c0122f5b010cb5f43e7a236c4ba2b1d56a2a. ---- - hash.c | 21 +++++++-------------- - 1 file changed, 7 insertions(+), 14 deletions(-) - -diff --git a/hash.c b/hash.c -index f6525ba4a5..cf83675c70 100644 ---- a/hash.c -+++ b/hash.c -@@ -4388,22 +4388,15 @@ rb_hash_compare_by_id(VALUE hash) - ar_force_convert_table(hash, __FILE__, __LINE__); - HASH_ASSERT(RHASH_ST_TABLE_P(hash)); - -- if (RHASH_TABLE_EMPTY_P(hash)) { -- // Fast path: There's nothing to rehash, so we don't need a `tmp` table. -- RHASH_ST_TABLE(hash)->type = &identhash; -- } else { -- // Slow path: Need to rehash the members of `self` into a new -- // `tmp` table using the new `identhash` compare/hash functions. -- tmp = hash_alloc(0); -- hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash)); -- identtable = RHASH_ST_TABLE(tmp); -+ tmp = hash_alloc(0); -+ hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash)); -+ identtable = RHASH_ST_TABLE(tmp); - -- rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); -+ rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp); - -- rb_hash_free(hash); -- RHASH_ST_TABLE_SET(hash, identtable); -- RHASH_ST_CLEAR(tmp); -- } -+ rb_hash_free(hash); -+ RHASH_ST_TABLE_SET(hash, identtable); -+ RHASH_ST_CLEAR(tmp); - - return hash; - } diff --git a/ruby-3.4.0-Extract-hardening-CFLAGS-to-a-special-hardenflags-variable.patch b/ruby-3.4.0-Extract-hardening-CFLAGS-to-a-special-hardenflags-variable.patch new file mode 100644 index 0000000..d0c10a0 --- /dev/null +++ b/ruby-3.4.0-Extract-hardening-CFLAGS-to-a-special-hardenflags-variable.patch @@ -0,0 +1,302 @@ +From 3d405634f43d39079ee93cdc59ed7fc0a5e8917a Mon Sep 17 00:00:00 2001 +From: KJ Tsanaktsidis +Date: Sun, 9 Jun 2024 21:15:39 +1000 +Subject: [PATCH] Extract hardening CFLAGS to a special $hardenflags variable + +This changes the automatic detection of -fstack-protector, +-D_FORTIFY_SOURCE, and -mbranch-protection to write to $hardenflags +instead of $XCFLAGS. The definition of $cflags is changed to +"$hardenflags $orig_cflags $optflags $debugflags $warnflags" to match. + +Furthermore, these flags are _prepended_ to $hardenflags, rather than +appended. + +The implications of doing this are as follows: + +* If a CRuby builder specifies cflags="-mbranch-protection=foobar" at + the ./configure script, and the configure script detects that + -mbranch-protection=pac-ret is accepted, then GCC will be invoked as + "gcc -mbranch-protection=pac-ret -mbranch-protection=foobar". Since + the last flags take precedence, that means that user-supplied values + of these flags in $cflags will take priority. +* Likewise, if a CRuby builder explicitly specifies + "hardenflags=-mbranch-protection=foobar", because we _prepend_ to + $hardenflags in our autoconf script, we will still invoke GCC as + "gcc -mbranch-protection=pac-ret -mbranch-protection=foobar". +* If a CRuby builder specifies CFLAGS="..." at the configure line, + automatic detection of hardening flags is ignored as before. +* C extensions will _also_ be built with hardening flags now as well + (this was not the case by default before because the detected flags + went into $XCFLAGS). + +Additionally, as part of this work, I changed how the detection of +PAC/BTI in Context.S works. Rather than appending the autodetected +option to ASFLAGS, we simply compile a set of test programs with the +actual CFLAGS in use to determine what PAC/BTI settings were actually +chosen by the builder. Context.S is made aware of these choices through +some custom macros. + +The result of this work is that: + +* Ruby will continue to choose some sensible defaults for hardening + options for the C compiler +* Distributors are able to specify CFLAGS that are consistent with their + distribution and override these defaults +* Context.S will react to whatever -mbranch-protection is actually in + use, not what was autodetected +* Extensions get built with hardening flags too. + +[Bug #20154] +[Bug #20520] +--- + configure.ac | 81 ++++++++++++++++++++++++++++++----- + coroutine/arm64/Context.S | 14 +++--- + template/Makefile.in | 1 + + tool/m4/ruby_append_option.m4 | 4 ++ + tool/m4/ruby_try_cflags.m4 | 17 ++++++++ + 5 files changed, 100 insertions(+), 17 deletions(-) + +diff --git a/configure.ac b/configure.ac +index f35fad6a362611..0da15772d36671 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -354,7 +354,7 @@ test -z "$warnflags" || + AS_IF([test -z "${CFLAGS+set}"], [ + cflags=`echo " $cflags " | sed "$cflagspat;s/^ *//;s/ *$//"` + orig_cflags="$cflags" +- cflags="$cflags "'${optflags} ${debugflags} ${warnflags}' ++ cflags='${hardenflags} '"$cflags "'${optflags} ${debugflags} ${warnflags}' + ]) + dnl AS_IF([test -z "${CXXFLAGS+set}"], [ + dnl cxxflags=`echo " $cxxflags " | sed "$cflagspat;s/^ *//;s/ *$//"` +@@ -802,7 +802,7 @@ AS_IF([test "$GCC" = yes], [ + [fortify_source=$enableval]) + AS_IF([test "x$fortify_source" != xno], [ + RUBY_TRY_CFLAGS([$optflags -D_FORTIFY_SOURCE=2], +- [RUBY_APPEND_OPTION(XCFLAGS, -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2)], [], ++ [RUBY_PREPEND_OPTION(hardenflags, -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2)], [], + [@%:@include ]) + ]) + +@@ -823,20 +823,24 @@ AS_IF([test "$GCC" = yes], [ + AC_MSG_CHECKING([for -fstack-protector]) + AC_MSG_RESULT(["$stack_protector"]) + AS_CASE(["$stack_protector"], [-*], [ +- RUBY_APPEND_OPTION(XCFLAGS, $stack_protector) +- RUBY_APPEND_OPTION(XLDFLAGS, $stack_protector) +- RUBY_APPEND_OPTION(LDFLAGS, $stack_protector) ++ RUBY_PREPEND_OPTION(hardenflags, $stack_protector) ++ RUBY_APPEND_OPTION(XLDFLAGS, $stack_protector) ++ RUBY_APPEND_OPTION(LDFLAGS, $stack_protector) + ]) + + # aarch64 branch protection + AS_CASE(["$target_cpu"], [aarch64], [ + AS_FOR(option, opt, [-mbranch-protection=pac-ret -msign-return-address=all], [ +- RUBY_TRY_CFLAGS(option, [branch_protection=yes], [branch_protection=no]) ++ # Try these flags in the _prepended_ position - i.e. we want to try building a program ++ # with CFLAGS="-mbranch-protection=pac-ret $CFLAGS". If the builder has provided different ++ # branch protection flags in CFLAGS, we don't want to overwrite those. We just want to ++ # find some branch protection flags which work if none were provided. ++ RUBY_TRY_CFLAGS_PREPEND(option, [branch_protection=yes], [branch_protection=no]) + AS_IF([test "x$branch_protection" = xyes], [ +- # C compiler and assembler must be consistent for -mbranch-protection +- # since they both check `__ARM_FEATURE_PAC_DEFAULT` definition. +- RUBY_APPEND_OPTION(XCFLAGS, option) +- RUBY_APPEND_OPTION(ASFLAGS, option) ++ # _prepend_ the options to CFLAGS, so that user-provided flags will overwrite them. ++ # These CFLAGS are used during the configure script to compile further test programs; ++ # however, $harden_flags is prepended separately to CFLAGS at the end of the script. ++ RUBY_PREPEND_OPTION(hardenflags, $opt) + break + ]) + ]) +@@ -985,6 +989,59 @@ test -z "${ac_env_CFLAGS_set}" -a -n "${cflags+set}" && eval CFLAGS="\"$cflags $ + test -z "${ac_env_CXXFLAGS_set}" -a -n "${cxxflags+set}" && eval CXXFLAGS="\"$cxxflags $ARCH_FLAG\"" + } + ++# The lines above expand out the $cflags/$optflags/$debugflags/$hardenflags variables into the ++# CFLAGS variable. So, at this point, we have a $CFLAGS var with the actual compiler flags we're ++# going to use. ++# That means this is the right time to check what branch protection flags are going to be in use ++# and define appropriate macros for use in Context.S based on this ++AS_CASE(["$target_cpu"], [aarch64], [ ++ AC_CACHE_CHECK([whether __ARM_FEATURE_BTI_DEFAULT is defined], ++ rb_cv_aarch64_bti_enabled, ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM([[ ++ @%:@ifndef __ARM_FEATURE_BTI_DEFAULT ++ @%:@error "__ARM_FEATURE_BTI_DEFAULT not defined" ++ @%:@endif ++ ]])], ++ [rb_cv_aarch64_bti_enabled=yes], ++ [rb_cv_aarch64_bti_enabled=no]) ++ ) ++ AS_IF([test "$rb_cv_aarch64_bti_enabled" = yes], ++ AC_DEFINE(RUBY_AARCH64_BTI_ENABLED, 1)) ++ AC_CACHE_CHECK([whether __ARM_FEATURE_PAC_DEFAULT is defined], ++ rb_cv_aarch64_pac_enabled, ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM([[ ++ @%:@ifndef __ARM_FEATURE_PAC_DEFAULT ++ @%:@error "__ARM_FEATURE_PAC_DEFAULT not defined" ++ @%:@endif ++ ]])], ++ [rb_cv_aarch64_pac_enabled=yes], ++ [rb_cv_aarch64_pac_enabled=no]) ++ ) ++ AS_IF([test "$rb_cv_aarch64_pac_enabled" = yes], ++ AC_DEFINE(RUBY_AARCH64_PAC_ENABLED, 1)) ++ # Context.S will only ever sign its return address with the A-key; it doesn't support ++ # the B-key at the moment. ++ AS_IF([test "$rb_cv_aarch64_pac_enabled" = yes], [ ++ AC_CACHE_CHECK([whether __ARM_FEATURE_PAC_DEFAULT specifies the b-key bit 0x02], ++ rb_cv_aarch64_pac_b_key, ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM([[ ++ @%:@ifdef __ARM_FEATURE_PAC_DEFAULT ++ @%:@if __ARM_FEATURE_PAC_DEFAULT & 0x02 ++ @%:@error "__ARM_FEATURE_PAC_DEFAULT specifies B key" ++ @%:@endif ++ @%:@endif ++ ]])], ++ [rb_cv_aarch64_pac_b_key=no], ++ [rb_cv_aarch64_pac_b_key=yes]) ++ ) ++ AS_IF([test "$rb_cv_aarch64_pac_b_key" = yes], ++ AC_MSG_ERROR(-mbranch-protection flag specified b-key but Ruby's Context.S does not support this yet.)) ++ ]) ++]) ++ + AC_CACHE_CHECK([whether compiler has statement and declarations in expressions], + rb_cv_have_stmt_and_decl_in_expr, + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[ __extension__ ({ int a = 0; a; }); ]])], +@@ -4215,12 +4272,13 @@ AS_IF([test "${ARCH_FLAG}"], [ + rb_cv_warnflags=`echo "$rb_cv_warnflags" | sed 's/^ *//;s/ *$//'` + warnflags="$rb_cv_warnflags" + AC_SUBST(cppflags)dnl +-AC_SUBST(cflags, ["${orig_cflags:+$orig_cflags }"'${optflags} ${debugflags} ${warnflags}'])dnl ++AC_SUBST(cflags, ['${hardenflags} '"${orig_cflags:+$orig_cflags }"' ${optflags} ${debugflags} ${warnflags}'])dnl + AC_SUBST(cxxflags)dnl + AC_SUBST(optflags)dnl + AC_SUBST(debugflags)dnl + AC_SUBST(warnflags)dnl + AC_SUBST(strict_warnflags)dnl ++AC_SUBST(hardenflags)dnl + AC_SUBST(XCFLAGS)dnl + AC_SUBST(XLDFLAGS)dnl + AC_SUBST(EXTLDFLAGS)dnl +@@ -4688,6 +4746,7 @@ config_summary "DLDFLAGS" "$DLDFLAGS" + config_summary "optflags" "$optflags" + config_summary "debugflags" "$debugflags" + config_summary "warnflags" "$warnflags" ++config_summary "hardenflags" "$hardenflags" + config_summary "strip command" "$STRIP" + config_summary "install doc" "$DOCTARGETS" + config_summary "YJIT support" "$YJIT_SUPPORT" +diff --git a/coroutine/arm64/Context.S b/coroutine/arm64/Context.S +index 5251ab214df1f0..54611a247e2f66 100644 +--- a/coroutine/arm64/Context.S ++++ b/coroutine/arm64/Context.S +@@ -5,6 +5,8 @@ + ## Copyright, 2018, by Samuel Williams. + ## + ++#include "ruby/config.h" ++ + #define TOKEN_PASTE(x,y) x##y + #define PREFIXED_SYMBOL(prefix,name) TOKEN_PASTE(prefix,name) + +@@ -27,10 +29,10 @@ + .global PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer) + PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer): + +-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0) ++#if defined(RUBY_AARCH64_PAC_ENABLED) + # paciasp (it also acts as BTI landing pad, so no need to insert BTI also) + hint #25 +-#elif defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT != 0) ++#elif defined(RUBY_AARCH64_BTI_ENABLED) + # For the the case PAC is not enabled but BTI is. + # bti c + hint #34 +@@ -73,7 +75,7 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer): + # Pop stack frame + add sp, sp, 0xa0 + +-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0) ++#if defined(RUBY_AARCH64_PAC_ENABLED) + # autiasp: Authenticate x30 (LR) with SP and key A + hint #29 + #endif +@@ -85,18 +87,18 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer): + .section .note.GNU-stack,"",%progbits + #endif + +-#if __ARM_FEATURE_BTI_DEFAULT != 0 || __ARM_FEATURE_PAC_DEFAULT != 0 ++#if defined(RUBY_AARCH64_BTI_ENABLED) || defined(RUBY_AARCH64_PAC_ENABLED) + /* See "ELF for the Arm 64-bit Architecture (AArch64)" + https://github.com/ARM-software/abi-aa/blob/2023Q3/aaelf64/aaelf64.rst#program-property */ + # define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1<<0) + # define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1<<1) + +-# if __ARM_FEATURE_BTI_DEFAULT != 0 ++# if defined(RUBY_AARCH64_BTI_ENABLED) + # define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI + # else + # define BTI_FLAG 0 + # endif +-# if __ARM_FEATURE_PAC_DEFAULT != 0 ++# if defined(RUBY_AARCH64_PAC_ENABLED) + # define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC + # else + # define PAC_FLAG 0 +diff --git a/template/Makefile.in b/template/Makefile.in +index 033ac56cb38886..abb4469777ce8a 100644 +--- a/template/Makefile.in ++++ b/template/Makefile.in +@@ -89,6 +89,7 @@ cflags = @cflags@ + optflags = @optflags@ + debugflags = @debugflags@ + warnflags = @warnflags@ @strict_warnflags@ ++hardenflags = @hardenflags@ + cppflags = @cppflags@ + incflags = @incflags@ + RUBY_DEVEL = @RUBY_DEVEL@ # "yes" or empty +diff --git a/tool/m4/ruby_append_option.m4 b/tool/m4/ruby_append_option.m4 +index ff828d2162c22f..98359fa1f95f52 100644 +--- a/tool/m4/ruby_append_option.m4 ++++ b/tool/m4/ruby_append_option.m4 +@@ -3,3 +3,7 @@ AC_DEFUN([RUBY_APPEND_OPTION], + [# RUBY_APPEND_OPTION($1) + AS_CASE([" [$]{$1-} "], + [*" $2 "*], [], [' '], [ $1="$2"], [ $1="[$]$1 $2"])])dnl ++AC_DEFUN([RUBY_PREPEND_OPTION], ++ [# RUBY_APPEND_OPTION($1) ++ AS_CASE([" [$]{$1-} "], ++ [*" $2 "*], [], [' '], [ $1="$2"], [ $1="$2 [$]$1"])])dnl +diff --git a/tool/m4/ruby_try_cflags.m4 b/tool/m4/ruby_try_cflags.m4 +index b74718fe5e1cef..b397642aad9ca2 100644 +--- a/tool/m4/ruby_try_cflags.m4 ++++ b/tool/m4/ruby_try_cflags.m4 +@@ -22,3 +22,20 @@ AC_DEFUN([RUBY_TRY_CFLAGS], [ + AC_MSG_RESULT(no)], + [$4], [$5]) + ])dnl ++ ++AC_DEFUN([_RUBY_TRY_CFLAGS_PREPEND], [ ++ RUBY_WERROR_FLAG([ ++ CFLAGS="$1 [$]CFLAGS" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$4]], [[$5]])], ++ [$2], [$3]) ++ ])dnl ++])dnl ++AC_DEFUN([RUBY_TRY_CFLAGS_PREPEND], [ ++ AC_MSG_CHECKING([whether ]$1[ is accepted as CFLAGS])dnl ++ _RUBY_TRY_CFLAGS_PREPEND([$1], ++ [$2 ++ AC_MSG_RESULT(yes)], ++ [$3 ++ AC_MSG_RESULT(no)], ++ [$4], [$5]) ++])dnl diff --git a/ruby-3.4.0-Fix-pointer-incompatiblity.patch b/ruby-3.4.0-Fix-pointer-incompatiblity.patch deleted file mode 100644 index 2bd7a53..0000000 --- a/ruby-3.4.0-Fix-pointer-incompatiblity.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 055613fd868a8c94e43893f8c58a00cdd2a81f6d Mon Sep 17 00:00:00 2001 -From: Nobuyoshi Nakada -Date: Fri, 22 Mar 2024 18:18:35 +0900 -Subject: [PATCH] Fix pointer incompatiblity - -Since the subsecond part is discarded, WIDEVAL to VALUE conversion is -needed. ---- - time.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/time.c b/time.c -index 6179b081c02fc9..3304b2f4f4856a 100644 ---- a/time.c -+++ b/time.c -@@ -2342,7 +2342,7 @@ zone_timelocal(VALUE zone, VALUE time) - struct time_object *tobj = RTYPEDDATA_GET_DATA(time); - wideval_t t, s; - -- split_second(tobj->timew, &t, &s); -+ wdivmod(tobj->timew, WINT2FIXWV(TIME_SCALE), &t, &s); - tm = tm_from_time(rb_cTimeTM, time); - utc = rb_check_funcall(zone, id_local_to_utc, 1, &tm); - if (UNDEF_P(utc)) return 0; diff --git a/ruby-3.4.0-fix-branch-protection-compilation-for-arm.patch b/ruby-3.4.0-fix-branch-protection-compilation-for-arm.patch deleted file mode 100644 index de93143..0000000 --- a/ruby-3.4.0-fix-branch-protection-compilation-for-arm.patch +++ /dev/null @@ -1,24 +0,0 @@ -From db4ba95bf12f9303e38a9a78979cd363cb9a19fb Mon Sep 17 00:00:00 2001 -From: Jarek Prokop -Date: Fri, 12 Jan 2024 18:33:34 +0100 -Subject: [PATCH] aarch64: Prepend -mbranch-protection=standard option when - checking branch protection. - -Related Upstream issue: https://bugs.ruby-lang.org/issues/20154 ---- - configure.ac | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 18b4247991..5ea8ada8f7 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -827,7 +827,7 @@ AS_IF([test "$GCC" = yes], [ - - # aarch64 branch protection - AS_CASE(["$target_cpu"], [aarch64], [ -- AS_FOR(option, opt, [-mbranch-protection=pac-ret -msign-return-address=all], [ -+ AS_FOR(option, opt, [-mbranch-protection=standard -mbranch-protection=pac-ret -msign-return-address=all], [ - RUBY_TRY_CFLAGS(option, [branch_protection=yes], [branch_protection=no]) - AS_IF([test "x$branch_protection" = xyes], [ - # C compiler and assembler must be consistent for -mbranch-protection diff --git a/ruby.spec b/ruby.spec index 0e74cec..afe5fb1 100644 --- a/ruby.spec +++ b/ruby.spec @@ -1,6 +1,6 @@ %global major_version 3 %global minor_version 3 -%global teeny_version 1 +%global teeny_version 5 %global major_minor_version %{major_version}.%{minor_version} %global ruby_version %{major_minor_version}.%{teeny_version} @@ -10,7 +10,7 @@ #%%global milestone rc1 # Keep the revision enabled for pre-releases from GIT. -#%%global revision 5124f9ac75 +#%%global revision ef084cc8f4 %global ruby_archive %{name}-%{ruby_version} @@ -27,7 +27,7 @@ %global rubygems_dir %{_datadir}/rubygems # Bundled libraries versions -%global rubygems_version 3.5.9 +%global rubygems_version 3.5.16 %global rubygems_molinillo_version 0.8.0 %global rubygems_net_http_version 0.4.0 %global rubygems_net_protocol_version 0.2.2 @@ -38,7 +38,7 @@ %global rubygems_uri_version 0.13.0 # Default gems. -%global bundler_version 2.5.9 +%global bundler_version 2.5.16 %global bundler_connection_pool_version 2.4.1 %global bundler_fileutils_version 1.7.2 %global bundler_net_http_persistent_version 4.0.2 @@ -86,7 +86,7 @@ %global prettyprint_version 0.2.0 %global pstore_version 0.1.3 %global readline_version 0.0.4 -%global reline_version 0.4.1 +%global reline_version 0.5.7 %global resolv_version 0.3.0 %global resolv_replace_version 0.1.1 %global rinda_version 0.2.0 @@ -95,8 +95,8 @@ %global set_version 1.1.0 %global shellwords_version 0.2.0 %global singleton_version 0.2.0 -%global stringio_version 3.1.0 -%global strscan_version 3.0.7 +%global stringio_version 3.1.1 +%global strscan_version 3.0.9 %global syntax_suggest_version 2.0.0 %global syslog_version 0.1.2 %global tempfile_version 0.2.1 @@ -105,17 +105,17 @@ %global tmpdir_version 0.2.0 %global tsort_version 0.2.0 %global un_version 0.3.0 -%global uri_version 0.13.0 +%global uri_version 0.13.1 %global weakref_version 0.1.3 %global win32ole_version 1.8.10 %global yaml_version 0.3.0 %global prism_version 0.19.0 -%global zlib_version 3.1.0 +%global zlib_version 3.1.1 # Gemified default gems. %global bigdecimal_version 3.1.5 %global io_console_version 0.7.1 -%global irb_version 1.11.0 +%global irb_version 1.13.1 %global json_version 2.7.1 %global psych_version 5.1.2 %global rdoc_version 6.6.3.1 @@ -133,8 +133,8 @@ %global racc_version 1.7.3 %global rake_version 13.1.0 %global rbs_version 3.4.0 -%global rexml_version 3.2.6 -%global rss_version 0.3.0 +%global rexml_version 3.3.6 +%global rss_version 0.3.1 %global test_unit_version 3.6.1 %global typeprof_version 0.21.9 @@ -171,7 +171,7 @@ Summary: An interpreter of object-oriented scripting language Name: ruby Version: %{ruby_version}%{?development_release} -Release: 6%{?dist} +Release: 7%{?dist} # Licenses, which are likely not included in binary RPMs: # Apache-2.0: # benchmark/gc/redblack.rb @@ -191,10 +191,6 @@ Release: 6%{?dist} # .bundle/gems/net-imap-0.4.9/LICENSE.txt # https://gitlab.com/fedora/legal/fedora-license-data/-/issues/506 # -# Approved license without SPDX identifier: -# ext/pty/pty.c -# https://gitlab.com/fedora/legal/fedora-license-data/-/issues/503 -# # BSD-3-Clause: missing/{crypt,mt19937,setproctitle}.c, addr2line.c:2652 # CC0: ccan/{build_assert/build_assert.h,check_type/check_type.h, # container_of/container_of.h,str/str.h} @@ -209,11 +205,12 @@ Release: 6%{?dist} # https://gitlab.com/fedora/legal/fedora-license-data/-/merge_requests/145 # MIT: ccan/list/list.h # Ruby OR BSD-2-Clause OR GPL-1.0-or-later: lib/net/protocol.rb +# Ruby-pty: ext/pty/pty.c # Unicode-DFS-2015: some of enc/trans/**/*.src # There is also license review ticket here: # https://gitlab.com/fedora/legal/fedora-license-data/-/issues/500 # zlib: ext/digest/md5/md5.*, ext/nkf/nkf-utf8/nkf.c -License: (Ruby OR BSD-2-Clause) AND (Ruby OR BSD-2-Clause OR GPL-1.0-or-later) AND BSD-3-Clause AND (GPL-3.0-or-later WITH Bison-exception-2.2) AND ISC AND LicenseRef-Fedora-Public-Domain AND MIT AND CC0 AND zlib AND Unicode-DFS-2015 AND HPND-Markus-Kuhn +License: (Ruby OR BSD-2-Clause) AND (Ruby OR BSD-2-Clause OR GPL-1.0-or-later) AND BSD-3-Clause AND (GPL-3.0-or-later WITH Bison-exception-2.2) AND ISC AND LicenseRef-Fedora-Public-Domain AND MIT AND CC0 AND zlib AND Unicode-DFS-2015 AND HPND-Markus-Kuhn AND Ruby-pty URL: https://www.ruby-lang.org/ Source0: https://cache.ruby-lang.org/pub/%{name}/%{major_minor_version}/%{ruby_archive}.tar.xz Source1: operating_system.rb @@ -233,16 +230,21 @@ Source13: test_abrt.rb Source14: test_systemtap.rb # Ruby OpenSSL FIPS tests. Source15: test_openssl_fips.rb +# RPM gem Requires dependency generator tests. +Source16: rpm_test_helper.rb +Source17: test_rubygems_req.rb +Source18: test_rubygems_prov.rb +Source19: test_rubygems_con.rb # The load directive is supported since RPM 4.12, i.e. F21+. The build process # fails on older Fedoras. %{load:%{SOURCE4}} %{load:%{SOURCE5}} -%global __local_generator_requires make -C %{_builddir}/%{buildsubdir}/%{_vpath_builddir} -s runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE9}" -%global __local_generator_provides make -C %{_builddir}/%{buildsubdir}/%{_vpath_builddir} -s runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE10}" -%global __local_generator_conflicts make -C %{_builddir}/%{buildsubdir}/%{_vpath_builddir} -s runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE11}" -%global __local_generator_path ^%{gem_dir}/specifications/.*\.gemspec$ +%define __local_generator_requires make -C %{_builddir}/%{buildsubdir}/%{_vpath_builddir} -s runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE9}" +%define __local_generator_provides make -C %{_builddir}/%{buildsubdir}/%{_vpath_builddir} -s runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE10}" +%define __local_generator_conflicts make -C %{_builddir}/%{buildsubdir}/%{_vpath_builddir} -s runruby TESTRUN_SCRIPT="--enable-gems %{SOURCE11}" +%define __local_generator_path ^%{gem_dir}/specifications/.*\.gemspec$ # Fix ruby_version abuse. # https://bugs.ruby-lang.org/issues/11002 @@ -271,16 +273,21 @@ Patch6: ruby-2.7.0-Initialize-ABRT-hook.patch # Disable syntax_suggest test suite, which tries to download its dependencies. # https://bugs.ruby-lang.org/issues/19297 Patch9: ruby-3.3.0-Disable-syntax-suggest-test-case.patch -# Revert patches causing segfaults in alexandria package. -# https://bugs.ruby-lang.org/issues/20079 -Patch10: ruby-3.3.0-Revert-Optimize-allocations-in-Hash-compare_by_identity.patch # Armv8.3+ capable CPUs might segfault with incorrect compilation options. # See related upstream report: https://bugs.ruby-lang.org/issues/20085 # https://bugs.ruby-lang.org/issues/20154 -Patch12: ruby-3.4.0-fix-branch-protection-compilation-for-arm.patch -# Fix build issue on i686 due to "incompatible pointer type" error. -# https://bugs.ruby-lang.org/issues/20447 -Patch13: ruby-3.4.0-Fix-pointer-incompatiblity.patch +# Make sure hardeding flags are correctly applied. +# https://bugs.ruby-lang.org/issues/20520 +Patch12: ruby-3.4.0-Extract-hardening-CFLAGS-to-a-special-hardenflags-variable.patch +# Fix build error: +# RPM build errors: +# error: Installed (but unpackaged) file(s) found: +# /usr/bin/bundle.lock +# This would break not only Ruby itself, but allso all rubygem-packages. +# https://github.com/rubygems/rubygems/pull/7931 +Patch13: rubygems-3.5.17-Avoid-another-race-condition-of-open-mode.patch +# https://github.com/rubygems/rubygems/pull/7939 +Patch14: rubygems-3.5.17-Remove-the-lock-file-for-binstubs.patch Requires: %{name}-libs%{?_isa} = %{version}-%{release} %{?with_rubypick:Suggests: rubypick} @@ -298,6 +305,7 @@ BuildRequires: openssl-devel BuildRequires: zlib-devel %{?with_gmp:BuildRequires: gmp-devel} %{?with_systemtap:BuildRequires: %{_bindir}/dtrace} +%{?with_systemtap:BuildRequires: systemtap-sdt-devel} %{?with_yjit:BuildRequires: %{_bindir}/rustc} # Install section @@ -757,9 +765,9 @@ analysis result in RBS format, a standard type description format for Ruby %patch 4 -p1 %patch 6 -p1 %patch 9 -p1 -%patch 10 -p1 %patch 12 -p1 %patch 13 -p1 +%patch 14 -p1 # Provide an example of usage of the tapset: cp -a %{SOURCE3} . @@ -962,8 +970,15 @@ sed -i 's/^/%lang(ja) /' .ruby-doc.ja %check %if 0%{?with_hardening_test} # Check Ruby hardening. -checksec --file=%{_vpath_builddir}/libruby.so.%{ruby_version} | \ - grep "Full RELRO.*Canary found.*NX enabled.*DSO.*No RPATH.*No RUNPATH.*Yes.*\d*.*\d*.*libruby.so.%{ruby_version}" +%define fortification_x86_64 fortified="11" fortify-able="28" +%define fortification_i686 fortified="10" fortify-able="26" +%define fortification_aarch64 fortified="10" fortify-able="26" +%define fortification_ppc64le fortified="7" fortify-able="24" +%define fortification_s390x fortified="10" fortify-able="24" +# https://unix.stackexchange.com/questions/366/convince-grep-to-output-all-lines-not-just-those-with-matches +checksec --format=xml --file=%{_vpath_builddir}/libruby.so.%{ruby_version} | \ + sed -r "s//\1/" | \ + sed -nr $'/relro="full" canary="yes" nx="yes" pie="dso" rpath="no" runpath="no" symbols="yes" fortify_source="partial" %{expand:%{fortification_%{_target_cpu}}} filename='\''redhat-linux-build\/libruby.so.%{ruby_version}'\''/h; ${p;x;/./Q0;Q1}' %endif # Check RubyGems version. @@ -1135,6 +1150,21 @@ ln -sfr probes.d %{_vpath_builddir}/ make -C %{_vpath_builddir} runruby TESTRUN_SCRIPT=%{SOURCE14} %endif +# Test dependency generators for RPM +GENERATOR_SCRIPT="%{SOURCE9}" \ +make -C %{_vpath_builddir} runruby TESTRUN_SCRIPT=" \ + -I%{_builddir}/%{buildsubdir}/tool/lib -I%{_sourcedir} --enable-gems \ + %{SOURCE17} --verbose" +GENERATOR_SCRIPT="%{SOURCE10}" \ +make -C %{_vpath_builddir} runruby TESTRUN_SCRIPT=" \ + -I%{_builddir}/%{buildsubdir}/tool/lib -I%{_sourcedir} --enable-gems \ + %{SOURCE18} --verbose" +GENERATOR_SCRIPT="%{SOURCE11}" \ +make -C %{_vpath_builddir} runruby TESTRUN_SCRIPT=" \ + -I%{_builddir}/%{buildsubdir}/tool/lib -I%{_sourcedir} --enable-gems \ + %{SOURCE19} --verbose" + + DISABLE_TESTS="" MSPECOPTS="" @@ -1722,6 +1752,21 @@ make -C %{_vpath_builddir} runruby TESTRUN_SCRIPT=" \ %changelog +* Wed Sep 04 2024 Jarek Prokop - 3.3.5-7 +- Upgrade to Ruby 3.3.5 + Resolves: RHEL-59035 +- Fix DoS vulnerability in rexml. + (CVE-2024-39908) + (CVE-2024-41946) + (CVE-2024-43398) + Resolves: RHEL-57047 + Resolves: RHEL-57059 + Resolves: RHEL-57070 +- Fix REXML DoS when parsing an XML having many specific characters such as + whitespace character, >] and ]>. + (CVE-2024-41123) + Resolves: RHEL-52802 + * Mon Jun 24 2024 Troy Dawson - Bump release for June 2024 mass rebuild diff --git a/rubygems-3.5.17-Avoid-another-race-condition-of-open-mode.patch b/rubygems-3.5.17-Avoid-another-race-condition-of-open-mode.patch new file mode 100644 index 0000000..c700539 --- /dev/null +++ b/rubygems-3.5.17-Avoid-another-race-condition-of-open-mode.patch @@ -0,0 +1,45 @@ +From 2daad257bee7a500e18ebe553e79487b267fb140 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Mon, 12 Aug 2024 20:18:34 +0900 +Subject: [PATCH] Avoid another race condition of open mode + +Instead, just open in CREATE and APPEND mode. +Also, move the workaround for old Solaris as fallback to retry. +--- + lib/rubygems.rb | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index 2b52cde0a749..c51ba69203cb 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -778,24 +778,20 @@ def self.open_file(path, flags, &block) + File.open(path, flags, &block) + end + ++ MODE_TO_FLOCK = IO::RDONLY | IO::APPEND | IO::CREAT # :nodoc: ++ + ## + # Open a file with given flags, and protect access with flock + + def self.open_file_with_flock(path, &block) +- flags = File.exist?(path) ? "r+" : "a+" +- +- File.open(path, flags) do |io| ++ File.open(path, MODE_TO_FLOCK) do |io| + begin + io.flock(File::LOCK_EX) + rescue Errno::ENOSYS, Errno::ENOTSUP ++ rescue Errno::ENOLCK # NFS ++ raise unless Thread.main == Thread.current + end + yield io +- rescue Errno::ENOLCK # NFS +- if Thread.main != Thread.current +- raise +- else +- open_file(path, flags, &block) +- end + end + end + diff --git a/rubygems-3.5.17-Remove-the-lock-file-for-binstubs.patch b/rubygems-3.5.17-Remove-the-lock-file-for-binstubs.patch new file mode 100644 index 0000000..0af11cf --- /dev/null +++ b/rubygems-3.5.17-Remove-the-lock-file-for-binstubs.patch @@ -0,0 +1,183 @@ +From ace303c2d7bc0d98407e5e8b1ca77de07aa0eb75 Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Tue, 13 Aug 2024 17:19:41 +0900 +Subject: [PATCH 1/3] Remove the lock file for binstubs + +https://github.com/rubygems/rubygems/pull/7806#issuecomment-2241662488 +--- + lib/rubygems.rb | 2 +- + lib/rubygems/installer.rb | 3 ++- + test/rubygems/test_gem_installer.rb | 10 ++++++++++ + 3 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index bd9f240e2091..7626ccfdf0d6 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -778,7 +778,7 @@ def self.open_file(path, flags, &block) + File.open(path, flags, &block) + end + +- MODE_TO_FLOCK = IO::RDONLY | IO::APPEND | IO::CREAT # :nodoc: ++ MODE_TO_FLOCK = IO::RDONLY | IO::APPEND | IO::CREAT | IO::SHARE_DELETE | IO::BINARY # :nodoc: + + ## + # Open a file with given flags, and protect access with flock +diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb +index d558c0be2bfa..8f95bab733f8 100644 +--- a/lib/rubygems/installer.rb ++++ b/lib/rubygems/installer.rb +@@ -538,7 +538,7 @@ def generate_plugins # :nodoc: + def generate_bin_script(filename, bindir) + bin_script_path = File.join bindir, formatted_program_filename(filename) + +- Gem.open_file_with_flock("#{bin_script_path}.lock") do ++ Gem.open_file_with_flock("#{bin_script_path}.lock") do |lock| + require "fileutils" + FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers + +@@ -546,6 +546,7 @@ def generate_bin_script(filename, bindir) + file.write app_script_text(filename) + file.chmod(options[:prog_mode] || 0o755) + end ++ File.unlink(lock.path) + end + + verbose bin_script_path +diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb +index a61d1b6fff28..2f4ff7349db4 100644 +--- a/test/rubygems/test_gem_installer.rb ++++ b/test/rubygems/test_gem_installer.rb +@@ -1083,6 +1083,8 @@ def test_install_creates_working_binstub + end + + assert_match(/ran executable/, e.message) ++ ++ assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) + end + + def test_conflicting_binstubs +@@ -1131,6 +1133,8 @@ def test_conflicting_binstubs + # We expect the bin stub to activate the version that actually contains + # the binstub. + assert_match("I have an executable", e.message) ++ ++ assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) + end + + def test_install_creates_binstub_that_understand_version +@@ -1160,6 +1164,8 @@ def test_install_creates_binstub_that_understand_version + end + + assert_includes(e.message, "can't find gem a (= 3.0)") ++ ++ assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) + end + + def test_install_creates_binstub_that_prefers_user_installed_gem_to_default +@@ -1192,6 +1198,8 @@ def test_install_creates_binstub_that_prefers_user_installed_gem_to_default + end + + assert_equal(e.message, "ran executable") ++ ++ assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) + end + + def test_install_creates_binstub_that_dont_trust_encoding +@@ -1222,6 +1230,8 @@ def test_install_creates_binstub_that_dont_trust_encoding + end + + assert_match(/ran executable/, e.message) ++ ++ assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) + end + + def test_install_with_no_prior_files + +From fa0700e0f52827ae05da59a331a2917a12c09b8a Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Thu, 15 Aug 2024 16:20:46 +0900 +Subject: [PATCH 2/3] Workaround for TruffleRuby + +--- + lib/rubygems.rb | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/lib/rubygems.rb b/lib/rubygems.rb +index 7626ccfdf0d6..9d40fcc2f77a 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -778,7 +778,9 @@ def self.open_file(path, flags, &block) + File.open(path, flags, &block) + end + +- MODE_TO_FLOCK = IO::RDONLY | IO::APPEND | IO::CREAT | IO::SHARE_DELETE | IO::BINARY # :nodoc: ++ mode = IO::RDONLY | IO::APPEND | IO::CREAT | IO::BINARY ++ mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE) ++ MODE_TO_FLOCK = mode # :nodoc: + + ## + # Open a file with given flags, and protect access with flock + +From 6548e7aa17186687d0a8b99571885f148363016d Mon Sep 17 00:00:00 2001 +From: Nobuyoshi Nakada +Date: Fri, 16 Aug 2024 20:19:22 +0900 +Subject: [PATCH 3/3] Ensure that the lock file will be removed + +--- + lib/rubygems/installer.rb | 3 ++- + test/rubygems/test_gem_installer.rb | 27 +++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+), 1 deletion(-) + +diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb +index 8f95bab733f8..1085f73fca53 100644 +--- a/lib/rubygems/installer.rb ++++ b/lib/rubygems/installer.rb +@@ -546,7 +546,8 @@ def generate_bin_script(filename, bindir) + file.write app_script_text(filename) + file.chmod(options[:prog_mode] || 0o755) + end +- File.unlink(lock.path) ++ ensure ++ FileUtils.rm_f lock.path + end + + verbose bin_script_path +diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb +index 2f4ff7349db4..ad5b1a244e80 100644 +--- a/test/rubygems/test_gem_installer.rb ++++ b/test/rubygems/test_gem_installer.rb +@@ -1234,6 +1234,33 @@ def test_install_creates_binstub_that_dont_trust_encoding + assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) + end + ++ def test_install_does_not_leave_lockfile_for_binstub ++ installer = util_setup_installer ++ ++ installer.wrappers = true ++ ++ File.class_eval do ++ alias_method :original_chmod, :chmod ++ define_method(:chmod) do |mode| ++ original_chmod(mode) ++ raise Gem::Ext::BuildError if path.end_with?("/executable") ++ end ++ end ++ ++ assert_raise(Gem::Ext::BuildError) do ++ installer.install ++ end ++ ++ assert_path_not_exist(File.join(installer.bin_dir, "executable.lock")) ++ # assert_path_not_exist(File.join(installer.bin_dir, "executable")) ++ ensure ++ File.class_eval do ++ remove_method :chmod ++ alias_method :chmod, :original_chmod ++ remove_method :original_chmod ++ end ++ end ++ + def test_install_with_no_prior_files + installer = util_setup_installer + diff --git a/rubygems.con b/rubygems.con index 1a99ed0..bcdeddc 100644 --- a/rubygems.con +++ b/rubygems.con @@ -19,7 +19,7 @@ module RubyGemsReq end # Report conflicting gem dependencies including their version. - def self.gem_depenencies(specification) + def self.gem_dependencies(specification) specification.runtime_dependencies.each do |dependency| conflict_strings = Helpers::requirement_versions_to_rpm(dependency.requirement).map do |requirement| requirement_string = "rubygem(#{dependency.name}) #{requirement}" @@ -39,7 +39,7 @@ module RubyGemsReq begin specification = Gem::Specification.load filename - gem_depenencies(specification) + gem_dependencies(specification) rescue => e # Ignore all errors. end diff --git a/rubygems.req b/rubygems.req index 38e4a9c..70aebd4 100644 --- a/rubygems.req +++ b/rubygems.req @@ -58,7 +58,7 @@ module RubyGemsReq end # Report all gem dependencies including their version. - def self.gem_depenencies(specification) + def self.gem_dependencies(specification) specification.runtime_dependencies.each do |dependency| dependency_name = "rubygem(#{dependency.name})" requirements = Helpers::requirement_versions_to_rpm(dependency.requirement) @@ -75,7 +75,7 @@ module RubyGemsReq specification = Gem::Specification.load filename rubygems_dependency(specification) - gem_depenencies(specification) + gem_dependencies(specification) rescue => e # Ignore all errors. end diff --git a/sources b/sources index f475c60..001c1d3 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ruby-3.3.1.tar.xz) = c58e9be9b5ab48191fbf7d67e13f0ec42ee71ed338170e0f7b246708e9cfc617ce65098f5ce7ab32d4305e785642d3e44253462104d5b9c4abcb1a4113f48347 +SHA512 (ruby-3.3.5.tar.xz) = dd5c6a7f74854e143e0ca46b9d7c0d1983fc4886f5f733cd108345dbf4b21f61ad978ad6806e05a57b7af28fd9216dd38d7145808188bbb3695a7f3a4eda3883 diff --git a/test_rubygems_con.rb b/test_rubygems_con.rb new file mode 100644 index 0000000..e124a49 --- /dev/null +++ b/test_rubygems_con.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +require 'test/unit' +require 'rpm_test_helper' + +class TestRubyGemsCon < Test::Unit::TestCase + include RPMTestHelper + + def test_filter_out_regular_requirements + gem_i = GemInfo.new + + lines = run_generator_single_file(gem_i) + + assert_equal(0, lines.size) + + deps = [ Dependency.new('bar') ] + gem_i.dependencies = deps + + lines = run_generator_single_file(gem_i) + + assert_equal(0, lines.size) + + deps = [ + Dependency.new('bar'), + Dependency.new('baq'), + Dependency.new('quz') + ] + + gem_i.dependencies = deps + lines = run_generator_single_file(gem_i) + + assert_equal(0, lines.size) + + deps = [ + Dependency.new('bar', ['>= 4.1']), + Dependency.new('baz', ['~> 3.2']), + Dependency.new('quz', ['>= 5.6']) + ] + + gem_i.dependencies = deps + + lines = run_generator_single_file(gem_i) + + assert_equal(0, lines.size) + end + + def test_single_gem_single_version_conflict + con = Dependency.new('bar', ['!= 0.4.4']) + + gem_i = GemInfo.new(dependencies: [ con ]) + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{con.to_rpm_str} = 0.4.4\n", lines.first) + end + + def test_multiple_gems_with_single_conflict + cons = [ + Dependency.new('bar', ['!= 1.1']), + Dependency.new('baq', ['!= 1.2.2']), + Dependency.new('quz', ['!= 1.3']) + ] + + gem_i = GemInfo.new(dependencies: cons) + + lines = run_generator_single_file(gem_i) + + assert_equal(3, lines.size) + + assert_equal("#{cons[0].to_rpm_str} = 1.1\n" , lines[0]) + assert_equal("#{cons[1].to_rpm_str} = 1.2.2\n", lines[1]) + assert_equal("#{cons[2].to_rpm_str} = 1.3\n" , lines[2]) + end + + def test_multiple_conflicts_on_single_gem + con = Dependency.new('bar', ['!= 2.3', '!= 2.4']) + + gem_i = GemInfo.new(dependencies: [con]) + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + rpm_name = con.to_rpm_str + left_rpm_constraint = "(#{rpm_name} = 2.3 with " + right_rpm_constraint = "#{rpm_name} = 2.4)\n" + assert_equal((left_rpm_constraint + right_rpm_constraint), lines[0]) + + con = Dependency.new('bar', ['!= 2.3', '!= 2.4', '!= 4.5']) + + gem_i = GemInfo.new(dependencies: [ con ]) + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + + rpm_name = con.to_rpm_str + left_rpm_constraint = "(#{rpm_name} = 2.3 with " + middle_rpm_constraint = "#{rpm_name} = 2.4 with " + right_rpm_constraint = "#{rpm_name} = 4.5)\n" + + assert_equal((left_rpm_constraint + middle_rpm_constraint + right_rpm_constraint), lines[0]) + end + + def test_generates_conflicts_while_ignoring_regular_requirements + deps = [ + Dependency.new('bar', ['>= 2.3', '!= 2.4.2']), + Dependency.new('quz', ['~> 3.0', '!= 3.2']) + ] + + gem_i = GemInfo.new(dependencies: deps) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + + rpm_name = deps[0].to_rpm_str + rpm_constraint = "#{rpm_name} = 2.4.2\n" + assert_equal(rpm_constraint, lines[0]) + + rpm_name = deps[1].to_rpm_str + rpm_constraint = "#{rpm_name} = 3.2\n" + assert_equal(rpm_constraint, lines[1]) + end +end diff --git a/test_rubygems_prov.rb b/test_rubygems_prov.rb new file mode 100644 index 0000000..b660ff6 --- /dev/null +++ b/test_rubygems_prov.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +require 'test/unit' +require 'rpm_test_helper' + +class TestRubyGemsProv < Test::Unit::TestCase + include RPMTestHelper + + def test_provides_the_gem_version + gem_i = GemInfo.new(version: '1.2') + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{gem_i.to_rpm_str} = #{gem_i.version}\n", lines.first) + + gem_i = GemInfo.new(name: 'somegem_foo', version: '4.5.6') + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{gem_i.to_rpm_str} = #{gem_i.version}\n", lines.first) + + deps = [ + Dependency.new('bar'), + Dependency.new('baq', [">= 1.2"]), + Dependency.new('quz', ["!= 3.2"]) + ] + gem_i = GemInfo.new(dependencies: deps) + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{gem_i.to_rpm_str} = #{gem_i.version}\n", lines.first) + end + + def test_translates_prelease_version_provides_from_rubygems_to_rpm + gem_i = GemInfo.new(version: '1.2.3.dev') + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{gem_i.to_rpm_str} = 1.2.3~dev\n", lines.first) + + gem_i = GemInfo.new(name: 'foo2', version: '1.2.3.dev.2') + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{gem_i.to_rpm_str} = 1.2.3~dev.2\n", lines.first) + end +end diff --git a/test_rubygems_req.rb b/test_rubygems_req.rb new file mode 100644 index 0000000..490923e --- /dev/null +++ b/test_rubygems_req.rb @@ -0,0 +1,205 @@ +# frozen_string_literal: true + +require 'test/unit' +require 'rpm_test_helper' + +class TestRubyGemsReq < Test::Unit::TestCase + include RPMTestHelper + + def test_depends_on_rubygems + gem_i = GemInfo.new + + lines = run_generator_single_file(gem_i) + + assert_equal(1, lines.size) + assert_equal("#{helper_rubygems_dependency}\n", lines.first) + end + + def test_requires_rubygems_and_dependency + dep = Dependency.new('bar') + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + assert_equal("#{helper_rubygems_dependency}\n", lines.first) + assert_equal("#{dep.to_rpm_str}\n", lines[1]) + end + + def test_requires_multiple_dependencies_with_constraint + constraints = [ + '>= 3.0', + '>= 3.0.0', + '>= 3', + '= 1.0.2', + '= 3.0', + '< 3.2', + '<= 3.4' + ] + + dependencies = [] + constraints.each_with_index do |constraint, idx| + dependencies << Dependency.new("bar#{idx}", [constraint]) + end + + gem_i = GemInfo.new(dependencies: dependencies) + + lines = run_generator_single_file(gem_i) + # + 1 for the rubygems dependency + assert_equal(constraints.size + 1, lines.size) + dependencies.each_with_index do |dep, idx| + rpm_dep_name = dep.to_rpm_str + # Start indexing lines at 1, to jump over rubygems dependency + assert_equal("#{rpm_dep_name} #{constraints[idx]}\n", lines[idx + 1]) + end + end + + def test_expands_pessimistic_constraint_for_rpm + dep = Dependency.new('bar', ['~> 1.2']) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + + rpm_dep_name = dep.to_rpm_str + left_constraint = "#{rpm_dep_name} >= 1.2" + right_constraint = "#{rpm_dep_name} < 2" + expected_constraint = "(#{left_constraint} with #{right_constraint})\n" + assert_equal(expected_constraint, lines[1]) + end + + def test_multiple_pessimistically_constrained_dependencies + dependencies = [] + dep_map = [ + { + constraint: '~> 1.2.3', + expanded_left: '>= 1.2.3', + expanded_rigth: '< 1.3', + gem_name: 'bar1' + }, + { + constraint: '~> 1.2', + expanded_left: '>= 1.2', + expanded_rigth: '< 2', + gem_name: 'bar2' + }, + { + constraint: '~> 3', + expanded_left: '>= 3', + expanded_rigth: '< 4', + gem_name: 'bar3' + } + ].each do |deps| + dependencies << Dependency.new(deps[:gem_name], [deps[:constraint]]) + end + + gem_i = GemInfo.new(dependencies: dependencies) + + lines = run_generator_single_file(gem_i) + + assert_equal(dep_map.size + 1, lines.size) + + dep_map.each_with_index do |hash, idx| + rpm_dep_name = dependencies[idx].to_rpm_str + left_constraint = rpm_dep_name + ' ' + hash[:expanded_left] + right_constraint = rpm_dep_name + ' ' + hash[:expanded_rigth] + expected_constraint = "(#{left_constraint} with #{right_constraint})\n" + assert_equal(expected_constraint, lines[idx + 1]) + end + end + + def test_multiple_constraints_on_one_dependency_composes_constraints_for_RPM + # The quoting here depends on how the constraint is expanded in the helpers. + # right now the form is `["#{constraint}"]`, therefore we have to not specify + # left and right quotes. + constraints = ['>= 0.2.3', '<= 0.2.5'] + dep = Dependency.new('baz', constraints) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + rpm_dep_name = dep.to_rpm_str + assert_equal("(#{rpm_dep_name} >= 0.2.3 with #{rpm_dep_name} <= 0.2.5)\n", lines[1]) + + # Not sure who would compose a dependency like this, but it's possible + # to do with the current generator + constraints = ['> 0.4.5', '< 0.6.4', '>= 2.3', '<= 2.5.3'] + dep = Dependency.new('qux', constraints) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + rpm_dep = dep.to_rpm_str + expected_str = "(#{rpm_dep} > 0.4.5 with #{rpm_dep} < 0.6.4 with " \ + "#{rpm_dep} >= 2.3 with #{rpm_dep} <= 2.5.3)\n" + + assert_equal(2, lines.size) + assert_equal(expected_str, lines[1]) + end + + # https://bugzilla.redhat.com/show_bug.cgi?id=1561487 + def test_depends_on_gem_with_version_conflict + dep = Dependency.new('baz', ['!= 0.4']) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + assert_equal("#{dep.to_rpm_str}\n", lines[1]) + end + + def test_filters_conflict_from_regular_version_constraints + constraint = ['> 1.2.4', '!= 1.2.7'] + dep = Dependency.new('baq', constraint) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + assert_equal("#{dep.to_rpm_str} > 1.2.4\n", lines[1]) + end + + def test_filtering_conflicts_is_not_depending_on_contraint_ordering + constraints = ['!= 1.2.7', '> 1.2.4'] + dep = Dependency.new('baq', constraints) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + assert_equal("#{dep.to_rpm_str} > 1.2.4\n", lines[1]) + end + + def test_filters_multiple_conflicts_from_dependency + omit "Case not yet supported." + constraints = ['!= 1.2.4', '!= 1.2.5', '!= 2.3', '!= 4.8'] + dep = Dependency.new('baf', constraints) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + assert_equal("#{dep.to_rpm_str}\n", lines[1]) + end + + def test_filters_multiple_conflicts_from_dependency_but_keeps_regular_constraint + constraints = ['!= 1.2.4', '!= 1.2.5', '!= 2.3', '<= 4.8'] + dep = Dependency.new('bam', constraints) + + gem_i = GemInfo.new(dependencies: [dep]) + + lines = run_generator_single_file(gem_i) + + assert_equal(2, lines.size) + assert_equal("#{dep.to_rpm_str} <= 4.8\n", lines[1]) + end +end