Skip to content

ci: Apply a Bundler cooldown to dependency resolution - #425

Draft
kinyoklion wants to merge 2 commits into
mainfrom
devin/1787848500-bundler-cooldown
Draft

ci: Apply a Bundler cooldown to dependency resolution#425
kinyoklion wants to merge 2 commits into
mainfrom
devin/1787848500-bundler-cooldown

Conversation

@kinyoklion

@kinyoklion kinyoklion commented Aug 27, 2026

Copy link
Copy Markdown
Member

Resolve dependencies only to gem versions that have been public for at least seven days, using Bundler's cooldown. Equivalent of launchdarkly/openfeature-ruby-server#35.

  • No pinning and no lockfile: we still get the newest version matching each constraint, just not one published in the last week
  • ld-eventsource is exempt, so the exact-version bump right after one of its releases still resolves
  • Requires Bundler >= 4.0.13, so CI pins Bundler to 4.0.19 — except on jruby-9.4, which is Ruby 3.1 and cannot install Bundler 4 at all, so it stays on Bundler 2 and resolves without a cooldown
  • Because that job has no cooldown, this PR also runs RuboCop serially (openfeature-ruby-server#34): --parallel is broken under JRuby as of RuboCop 1.90.0, which the jruby-9.4 job picks up regardless
  • Contributors on Bundler 2.x are unaffected — the setting is silently ignored, so they simply resolve to the newest versions

Requirements

  • I have added test coverage for new or changed functionality
  • I have followed the repository's pull request submission guidelines
  • I have validated my changes against all supported platform versions

Related issues

Port of launchdarkly/openfeature-ruby-server#35 and, for the RuboCop step, launchdarkly/openfeature-ruby-server#34.

Implementation details

How cooldown works

source "https://rubygems.org", cooldown: 7 makes Bundler consult the per-version created_at timestamp in rubygems.org's v2 compact index during resolution and pass over any version younger than the window. Versions whose source does not expose created_at (private registries, pre-v2 entries) stay resolvable, so this never silently blocks a resolution. --cooldown 0 / BUNDLE_COOLDOWN=0 is the escape hatch when the newest release is exactly the one you want, e.g. a security fix.

Why the second source block

Cooldown is stored per remote URI (Bundler::Source::Rubygems#remote_cooldowns), with no per-gem option, and a second source block for the same URI does not get its own value. Naming the registry's index host gives a distinct remote that can carry cooldown: 0:

source "https://index.rubygems.org", cooldown: 0 do
  gem "ld-eventsource"
end

The gemspec requires ld-eventsource at an exact version, deliberately, so that bugfixes there are always tied to a new SDK version. Without the exemption, the first seven days after each ld-eventsource release would be un-resolvable: every candidate satisfying the new exact constraint is inside the cooldown window. Exempting it is also the right policy — we publish that gem, so it is not the untrusted-third-party case cooldown defends against.

The jruby-9.4 exception, and the RuboCop step

Bundler 4.0.19 requires Ruby >= 3.2, and JRuby 9.4 reports RUBY_VERSION 3.1.7:

ERROR:  Error installing bundler:
	bundler-4.0.19 requires Ruby version >= 3.2.0. The current ruby version is 3.1.7.

So the shared setup action selects the Bundler version per runtime rather than pinning one for all of them, and the jruby-9.4 job resolves with Bundler 2, which ignores cooldown:. That job therefore keeps installing brand-new gem versions — including RuboCop 1.90.0, whose --parallel mode is broken under JRuby, which failed the first CI run on this branch:

1.90.0 (using Parser 3.3.12.0, rubocop-ast 1.50.0, analyzing as Ruby 3.1, running on jruby 3.1.7) [java]

On JRuby the parallel gem cannot fork, so it runs work in threads; RuboCop 1.90 began preserving cop instances across files, and shared cop instances seeing concurrent processed_source values produce thousands of internal cop errors and phantom offenses. Dropping --parallel fixes it, and parallelism is a negligible speedup on 185 files. openfeature-ruby-server does not have the Bundler gap because its matrix is on jruby-10.0 (Ruby 3.4); moving this repo's matrix to jruby-10 would let cooldown apply everywhere, but that is a supported-platform change and out of scope here.

Verification

Ran locally in containers against this branch (no lockfile):

Runtime Bundler Result
CRuby 3.4.10 4.0.19 rubocop 1.90.0 (available in 4 days), resolved 1.89.0 instead, same for aws-partitions; 1046 examples 0 failures; RuboCop clean
CRuby 3.2 4.0.19 same cooldown skips, resolution succeeds
CRuby 3.4.10 2.6.9 resolves the same Gemfile without error, ignoring cooldown:
JRuby 9.4.15 2.6.9 resolves without error (no cooldown), RuboCop 1.90.0: --parallel → 37497 internal cop errors and 965 phantom offenses; serial → 185 files inspected, no offenses

Alternatives considered

  • Pin Bundler 4.0.19 for every job: breaks the jruby-9.4 job outright.
  • cooldown: 3 with no exemption: shorter window, and still breaks for three days after each ld-eventsource release.
  • Commit a Gemfile.lock and let Dependabot bump it with a cooldown: gives an auditable dependency history, but pins a library to specific versions and stops testing against the newest supported ones.
  • bundle config set cooldown / BUNDLE_COOLDOWN in CI only: leaves local bundle install unprotected, and cannot express a per-source exemption.

Link to Devin session: https://app.devin.ai/sessions/9e2aad687cd743149ff71c0a1fcfd936
Open in Devin Desktop: https://app.devin.ai/desktop/session/9e2aad687cd743149ff71c0a1fcfd936?variant=devin
Requested by: @kinyoklion

@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration

Copy link
Copy Markdown
Contributor

@cursor review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant