Skip to content

[pull] master from ruby:master#1071

Merged
pull[bot] merged 30 commits into
turkdevops:masterfrom
ruby:master
Jun 2, 2026
Merged

[pull] master from ruby:master#1071
pull[bot] merged 30 commits into
turkdevops:masterfrom
ruby:master

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Jun 2, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

tenderlove and others added 30 commits June 1, 2026 19:30
Fold arithmetic identity operations such as `x + 0`, `x - 0`, `x * 1`, `x / 1` in `fold_constants`.
When VM state is corrupted enough, we can call abort() from the SIGABRT
handler. Previously, we would spam until the stack is full:

    ABRT received in SEGV handler
    SEGV received in ABRT handler
    ABRT received in SEGV handler
    ABRT received in ABRT handler
    ABRT received in ABRT handler
    ABRT received in ABRT handler
    [...]

We've seen this on CI:
https://github.com/ruby/ruby/actions/runs/26591192708/job/78350130653

To test this situation locally, temporarily patch in a call to abort()
in rb_bug_for_fatal_signal() then use `Process.kill(:ABRT, Process.pid)`.

Fix by restoring the default signal handler before aborting.
The completeness check skips the download once every expected file exists,
but File.write truncates before writing, so an install interrupted partway
leaves a half-written file in place. A later run would see it, treat the
vendor tree as complete, and load a truncated source.

Download each file to a sibling .tmp path and rename it into place. The
rename stays within the vendor tree, so it is atomic and a target file is
only ever observed fully written.

ruby/rubygems@a2f265f579

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When captured subprocess output contained a byte that isn't valid UTF-8,
normalize tagged the buffer as UTF-8 and then ran gsub over it, which
scans the whole string and raised Encoding::CompatibilityError: invalid
byte sequence in UTF-8. The error surfaced from inside the test harness
rather than on an assertion, so RSpec reported "Unable to find matching
line from backtrace" and the real output was lost.

Scrub the string after forcing the encoding so normalize never raises on
malformed bytes, and dup it first so forcing the encoding no longer
mutates the stored capture buffer.

ruby/rubygems@e236edcb6d

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ions

Installing a git source clones the local cache repo into bundler/gems with
git's hardlink optimization. Git 2.54 kicks off commit-graph writes as part
of automatic maintenance after a fetch or clone, and when that background
write touches the cache while the hardlinking clone is enumerating it, the
clone aborts with "hardlink different from source" pointing at a
tmp_graph_* file. It shows up as a flaky failure on CI.

Pass gc.auto=0 and maintenance.auto=false to every git invocation so no
background maintenance is ever spawned for these throwaway repos, removing
the race. The options are injected only at the command-execution layer, so
redacted command strings in error messages are unaffected.

ruby/rubygems@7bc41a21fa

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_with_webauthn_enabled_failure checked the Authorization header on
@stub_fetcher.last_request, but the webauthn flow runs a real polling
thread that issues its own request concurrently. On Rubies without a GIL
the poll request can land last, so last_request was not the
webauthn_verification request and the assertion saw a nil header.

Look up the webauthn_verification request explicitly and assert on its
Authorization header, which the main thread always records. This is the
invariant the test means to check and it is no longer order dependent, so
the TruffleRuby pend that papered over the same race can go too.

ruby/rubygems@98efee308a

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
io_reader trusted IO#read to honour its size argument and copied
RSTRING_LEN(string) bytes into libyaml's fixed-capacity buffer. An
IO-like object whose #read over-returns wrote past the buffer end, a
heap out-of-bounds write reachable from Psych.load/safe_load/parse.
Clamp the copied length to the requested size.

ruby/psych@99ecd94560

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Clamping the over-read at exactly the requested size could split a
multibyte character, since the string an IO returns may carry a
non-binary encoding. Round the cut down to the last character boundary
at or before the size so the bytes handed to libyaml are always whole
characters.

ruby/psych@6201ae17c1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
End procs are executed in reverse order of registration.  Since the
crypt provider is initialized very early on via `Init_RandomSeedCore`,
no other end procs are executed after the crypt provider is released.
Finalizers are called after end procs, but their order is unspecified,
so there is still no guarantee that this crypt provider will be
available for use by other end procs.
…st colon

The upcoming compact index v2 format introduced by rubygems.org appends a
`created_at:ISO8601` field to each info line, and the timestamp's internal
colons were being treated as additional split delimiters. Splitting only on
the first colon keeps existing keys like `ruby:>= 2.7.0` intact while letting
multi-colon values pass through untouched.

rubygems/rubygems.org#6504

ruby/rubygems@227b3d6f94

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The cooldown feature needs each gem version's publish timestamp on the
client side. Compact index v2 exposes it as a `created_at:ISO8601`
entry in the info-line metadata; expose a Time-typed `created_at`
attribute on the spec so the resolver can consult it later.

Parsing is defensive against older rubygems whose APISet GemParser
splits ISO8601 timestamps on every colon, accepting both Array and
flat String shapes and silently dropping malformed values. The time
stdlib is required lazily inside the case branch so loading the file
does not activate the `time` default gem during Bundler.setup.

ruby/rubygems@cd61070cfc

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds `cooldown` to NUMBER_KEYS so that `BUNDLE_COOLDOWN` and
`bundle config set cooldown` are parsed as integer days. Reading the
value is enough for now; later commits plumb it into the resolver and
the Gemfile DSL.

ruby/rubygems#9113

ruby/rubygems@478c3ff09f

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Lets `source "https://rubygems.org", cooldown: 7` attach a per-remote
value to the global Rubygems source, which the new
`Remote#effective_cooldown` reads with CLI > config > Gemfile
per-source precedence. The cooldown is stored on Source::Rubygems
keyed by URI so that several top-level `source` lines can carry
independent values onto the same global source.

Non-negative Integer values are required at parse time; everything
else (strings, floats, arrays, negative numbers) raises InvalidOption
so a typo can't silently disable the filter.

ruby/rubygems@5bd253f11f

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the CLI flag and routes it through `set_command_option_if_given`
so the value lands in Bundler.settings' temporary store. This keeps the
CLI > config > Gemfile precedence implicit in the existing settings
layering. The resolver does not yet consult the value.

ruby/rubygems#9113

ruby/rubygems@b3a8b2e082

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…in errors

Adds a per-version filter to `Resolver#filter_specs` that drops specs
whose `created_at` falls within the effective cooldown window. The
filter only runs over `@all_specs`, so lockfile-pinned versions in
`@base` survive even if a newer release would now be excluded. Specs
without `created_at` are kept so historical versions and indexes that
do not yet expose timestamps remain usable.

A shared `cooldown_now` memoization ensures every comparison within
one resolve sees the same timestamp, stabilizing tests near a
threshold boundary. When the resolver fails because every matching
version is in cooldown, both `raise_not_found!` and
`no_versions_incompatibility_for` surface a hint suggesting
`--cooldown 0` to bypass; a small `cooldown_hint` helper keeps the
wording in sync between the two error paths and is locked down with
unit specs.

ruby/rubygems@82dcf047ff

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
bundle outdated still surfaces newer-but-cooldown'd versions instead of
hiding them, so the user knows an upgrade is pending rather than
silently missing. The prose form gains ", in cooldown for Nd more days"
and the table form appends "(cooldown Nd)" to the Latest column.

ruby/rubygems@66b5ab78e0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds the `--cooldown=NUMBER` option to the install, update, add, and
outdated man pages and describes the `cooldown` / `BUNDLE_COOLDOWN`
setting in bundle-config, regenerating the rendered .1 files via
`rake man:build`.

ruby/rubygems@6f4b30491d

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…d-to-end

A `CompactIndexCooldownAPI` subclass overrides `build_gem_version` to
emit `CompactIndex::GemVersionV2` with `created_at` sourced from
`spec.date`, letting tests carry a deterministic timestamp per built
gem. `spec/install/cooldown_spec.rb` exercises the source DSL keyword,
`--cooldown` flag, `BUNDLE_COOLDOWN`, `bundle config set cooldown`,
the rolling-delay filter, the lockfile bypass, and the CLI vs Gemfile
precedence against the new artifice.

ruby/rubygems@1f1309a809

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Gemfile DSL already rejects `cooldown: -7`, but `--cooldown -7` on
install/update/add/outdated slipped through Thor and ended up
disabling the filter silently via the `days <= 0` short-circuit in
the resolver. Add a shared CLI::Common.validate_cooldown! guard so the
CLI surface fails loud with the same message as the DSL.

ruby/rubygems@45e54d5b4c

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds three E2E checks against the v2 cooldown artifice: the negative
CLI value is rejected at parse time, `bundle outdated --cooldown` tags
the latest-but-cooled version in both table and parseable output, and
`bundle update --cooldown 99999` surfaces the cooldown hint when every
candidate is filtered. These were the remaining coverage gaps called
out in the adversarial review.

ruby/rubygems@3df6b300f7

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A full ISO-8601 timestamp with seconds (the format compact index v2
sends, e.g. 2026-05-30T08:52:10Z) is recognised by Time.new directly,
so we can drop the require "time" and the indirection through
Time.iso8601 while keeping the same ArgumentError fallback for
malformed input.

ruby/rubygems@d14e3ce964

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@pull pull Bot locked and limited conversation to collaborators Jun 2, 2026
@pull pull Bot added the ⤵️ pull label Jun 2, 2026
@pull pull Bot merged commit abef26e into turkdevops:master Jun 2, 2026
0 of 2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants