Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 832
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839
Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 839 Bundler BlogThe latest news on Bundlerhttps://bundler.io/blog2025-07-17T07:13:00+00:00The Bundler TeamBundler v2.7: last release before Bundler 4https://bundler.io/blog/2025/07/17/bundler-v2-7.html2025-07-17T07:13:00+00:002025-10-20T08:26:09+00:00David Rodríguez<p>A major release of Bundler is finally happening, consolidating unreleased major
changes that had been pending for a decade. It will be named Bundler 4 (skipping
Bundler 3), so that we can release it in lockstep with RubyGems 4, making the
version number of Bundler & RubyGems in sync from now on.</p>
<p>Final Bundler 4 release will happen at the end of 2025, but for now we’re
presenting Bundler 2.7 as the last big step towards this major release.</p>
<p>Bundler 2.7 features a <code>simulate_version</code> configuration that will allow users to
configure Bundler to behave exactly as Bundler 4 will behave, with all major
breaking changes enabled by default. We encourage all users to enable this
setting, experiment with Bundler 4, and leave us feedback. Community feedback is
super important to us, and we’re still open to revisiting the changes that the
final version will include.</p>
<p>You can find more about future Bundler 4 changes and how to enable Bundler 4
mode in our <a href="https://github.com/rubygems/rubygems/blob/ff473128011e7abe1eeb0414d9cd48677acb5487/doc/bundler/UPGRADING.md">upgrade
guide</a></p>
<p>In addition to changes to get ready for Bundler 4, Bundler 2.7 also features
some additional improvements such as:</p>
<ul>
<li>Our gem generator is now more customizable than ever, displays more
informative output, and provides a skeleton with better defaults.</li>
<li>Network errors are better handled to print more actionable errors and avoid
unnecessary retries that will never succeed.</li>
<li>Bundler is now more resilient in presence of incorrect lockfiles, or locally
installed gemspecs with incorrect dependencies.</li>
<li>Several issues have been fixed to make Bundler play nicer with default gems
like <code>rdoc</code> or <code>irb</code>.</li>
<li>Auto-switch and auto-restart mechanism based on locked version of Bundler has
been improved.</li>
<li><code>bundle install</code> can now properly unlock rails (or any other gem including its
own dependencies as a monorepo) when changing its Gemfile <code>git</code> source to pin
it to a specific <code>ref</code>.</li>
</ul>
<p>Happy bundling!</p>
Bundler v2.6: lockfile checksums are finally therehttps://bundler.io/blog/2024/12/19/bundler-v2-6.html2024-12-19T17:01:00+00:002025-10-20T08:26:09+00:00David Rodríguez<p>We’re happy to announce Bundler 2.6, featuring gem checksum verification, right
in the <code>Gemfile.lock</code> file.</p>
<p>This feature has actually been implemented for more than a year. However, it was
merged very close to the Bundler 2.5 release and we did not yet have a good plan for
enabling the feature in a graceful manner, so we’ve kept it hidden until now.</p>
<p>Bundler 2.6 finally officially allows to opt-in into this beta feature.</p>
<h2 id="whats-this-feature-for">What’s this feature for?</h2>
<p>A lockfile is an easy way to ensure all environments will use a consistent
version of every dependency. However, Bundler lockfiles did not protect from
potential tampering of the sources of that specific version. This is what the
this feature does. When enabled, Bundler will keep track of the checksum of
every version in the lockfile, in the lockfile itself. Then, before installing
that lockfile on any machine, it will verify that the checksum of the <code>.gem</code>
file it’s about to install matches the checksum previously recorded in the
lockfile. If they don’t match, Bundler will refuse to install that package and
consider it compromised.</p>
<h3 id="how-to-enable-lockfile-checksums">How to enable lockfile checksums?</h3>
<p>Bundler 2.6 provides two ways of enabling checksums.</p>
<ul>
<li>
<p>For a single lockfile, you can run <code>bundle lock --add-checksums</code>. This will add
a new <code>CHECKSUMS</code> section to the lockfile that Bundler will keep up to date.</p>
</li>
<li>
<p>To configure Bundler to always include checksums in new lockfiles, run <code>bundle
config lockfile_checksums true</code>.</p>
</li>
</ul>
<h3 id="how-does-it-work-once-the-feature-is-enabled">How does it work, once the feature is enabled?</h3>
<p>Hopefully nothing will ever change for you after enabling the feature. However,
if <code>bundle install</code> ever downloads a package (or tries to install it from cache)
the checksum of which does not match what’s recorded in the lockfile for that package,
Bundler will print an error like the following and abort installation:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle install
Fetching gem metadata from https://rubygems.org/........
Bundler found mismatched checksums. This is a potential security risk.
rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d
from the lockfile CHECKSUMS at Gemfile.lock:1241:17
and the API at https://rubygems.org/
rake (13.2.1) sha256=17e8b7c1b247f3349d4a7160c3f587b6c7fd67cf7be3b3710e118b8416f94ddb
from the gem at /my/repo/vendor/cache/rake-13.2.1.gem
If you trust the lockfile CHECKSUMS at Gemfile.lock:1241:17, to resolve this issue you can:
1. remove the gem at /my/repo/vendor/cache/rake-13.2.1.gem
2. run `bundle install`
To ignore checksum security warnings, disable checksum validation with
`bundle config set --local disable_checksum_validation true`
</code></pre></div>
<h2 id="compatibility">Compatibility</h2>
<p>Bundler will keep the <code>CHECKSUMS</code> section in the lockfile up to date if it’s
already there, and verify that <code>.gem</code> packages checksums match what’s recorded
in the lockfile before installing.</p>
<p>On the other hand, Bundler will work like before if it doesn’t find a
<code>CHECKSUMS</code> section in the lockfile.</p>
<p>All lockfiles including a <code>CHECKUMS</code> section should have Bundler >= 2.6 in the
<code>BUNDLED WITH</code> section. Since Bundler internally has a mechanism to make sure it
switches to the version of itself included in the <code>BUNDLED WITH</code> lockfile
section, a lockfile with a <code>CHECKSUMS</code> section should always be run by
Bundler >= 2.6.</p>
<p>Some platforms, like Heroku or Dependabot, don’t respect this auto-switching
mechanism. However, these platforms are already using Bundler >= 2.5 and
since this feature is luckily already present (but hidden) since Bundler 2.5,
they should deal just fine with new lockfiles including the new section.</p>
<h2 id="should-i-take-any-other-steps-before-enabling-this-feature">Should I take any other steps before enabling this feature?</h2>
<p>If your lockfile only includes <code>ruby</code> in the <code>PLATFORMS</code> section, that means
that Bundler is most likely not storing platform-specific variants of your gems
in the <code>Gemfile.lock</code> file. For example, your lockfile may include only
<code>nokogiri-1.18.0</code>, while Bundler will actually install the most appropriate
1.18.0 variant for your platform, say <code>nokogiri-1.18.0-x86_64-linux</code>. However,
that makes the lockfile checksums feature not work fine for <code>nokigiri</code> because
Bundler will only check if the generic variant (what’s in the lockfile) is
changed, but not the variant that’s actually installed.</p>
<p>Because of this, Bundler 2.6 will print a warning when it ends up installing a
different variant than the one included in the lockfile, and tell you to
“normalize” the lockfile and add platform specific variants through <code>bundle lock
--normalize-platforms</code>.</p>
<h2 id="other-notable-changes-in-bundler-26">Other notable changes in Bundler 2.6</h2>
<p>This is a non-exhaustive list of other notable improvements in Bundler 2.6:</p>
<ul>
<li><strong>Better support for switching between different versions of Ruby.</strong></li>
</ul>
<p>Sometimes when switching between different Ruby versions, even if the resolution
recorded in the Gemfile.lock is stable, the most optimal platform-specific
version for a gem may change. For example, <code>nokogiri-1.18.0.rc1-x86_64-darwin</code>
does not support Ruby 3.5, but <code>nokogiri-1.18.0.rc1</code> does. Bundler 2.6 should be
able to keep a consistent lockfile with all platform-specific variants, and use
the one that works best for each Ruby version.</p>
<ul>
<li><strong>Better handling of git dependencies in application caches.</strong></li>
</ul>
<p>Bundler can keep <code>.gem</code> packages for your dependencies in <code>vendor/cache</code> so
that, for example, they can be installed offline on a different machine. This
did not work fine for git gems, though. Bundler 2.6 should now allow properly
caching git gems in <code>vendor/cache</code>. You can enable this with <code>bundle config
cache_all true</code>.</p>
<ul>
<li><strong>More careful redaction of gem server credentials in logs and <code>bundle config</code> output.</strong></li>
</ul>
<p>Bundler already did this but we found a few cases where it was not properly
redacting sensitive info and fixed those.</p>
<ul>
<li><strong>Better <code>bundle exec</code> behaviour on Windows.</strong></li>
</ul>
<p>We have introduced several improvements so that <code>bundle exec</code> works the usual
way, also on Windows.</p>
<ul>
<li><strong>Better documentation of commands and CLI flags.</strong></li>
</ul>
<p>We have introduced changes to make sure that this site, and the <code>bundle</code> CLI,
properly documents all commands and CLI flags, and made sure it will stay like
that going forward.</p>
<p>And like always, many other bug fixes and improvements were implemented. Check
<a href="https://github.com/rubygems/rubygems/releases/tag/bundler-v2.6.0">the full Bundler 2.6 changelog</a> for
details.</p>
<p>Happy bundling!</p>
Bundler v2.4: new resolver, gems with Rust extensions, and morehttps://bundler.io/blog/2023/01/31/bundler-v2-4.html2023-01-31T14:43:00+00:002025-10-20T08:26:09+00:00David Rodríguez<p>2022 has been a busy year for the Bundler team, and we’re glad to present
several improvements that we hope will make our users happy :)</p>
<h2 id="a-better-pubgrub-based-resolver">A better, PubGrub based, resolver</h2>
<p>Bundler now uses the most advanced algorithm to resolve versions, PubGrub.
Kudos to Natalie Weizenbaum for <a href="https://nex3.medium.com/pubgrub-2fb6470504f">inventing
it</a> and to John Hawthorn for
<a href="https://github.com/jhawthorn/pub_grub">porting it to Ruby</a>!</p>
<p>Our previous resolver, <a href="https://github.com/CocoaPods/Molinillo">Molinillo</a>, worked pretty well, but it really got in the
middle when it didn’t.</p>
<p>This may sound familiar for some:</p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle
Fetching gem metadata from https://rubygems.org/............
Resolving dependencies....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................^C
$ # Ok, that was enough waiting
</code></pre></div>
<p>Our new resolver, PubGrub, is usually much faster, because it learns from the
resolution conflicts it finds during the resolution process to avoid redoing the
same work over and over again. You can find more about this “conflict-driven
clause learning” techniques in its <a href="https://nex3.medium.com/pubgrub-2fb6470504f">presentation blog
post</a> back from 2018.</p>
<p>Molinillo sometimes took too long to resolve because it would try the same
things, backtrack, and run into the same conflicts over and over again, having
to traverse very inefficiently a huge search space. But that was a relatively
rare case in the real world.</p>
<p>What’s probably more common is specifying version requirements in your Gemfile,
that can’t be all satisfied at the same time. This is when the version solving
problem does not have a solution, and when it becomes crucial to explain to users
<em>why</em>, so that they can fix their set of version requirements to become
solvable.</p>
<p>Molinillo run into trouble here, and in cases with many moving parts, like
upgrading Rails for example, it could end up printing a lot of conflicts, not
easy to understand and solve. This is an old example from a public ticket:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Bundler could not find compatible versions for gem "actionpack":
In Gemfile:
inherited_resources (= 1.6.0) was resolved to 1.6.0, which depends on
actionpack (>= 3.2, < 5)
rails (= 4.2.0) was resolved to 4.2.0, which depends on
actionpack (= 4.2.0)
Bundler could not find compatible versions for gem "activesupport":
In Gemfile:
inherited_resources (= 1.6.0) was resolved to 1.6.0, which depends on
has_scope (~> 0.6.0.rc) was resolved to 0.6.0, which depends on
activesupport (>= 3.2, < 5)
rails (= 4.2.0) was resolved to 4.2.0, which depends on
activesupport (= 4.2.0)
Bundler could not find compatible versions for gem "railties":
In Gemfile:
inherited_resources (= 1.6.0) was resolved to 1.6.0, which depends on
railties (>= 3.2, < 5)
rails (= 4.2.0) was resolved to 4.2.0, which depends on
railties (= 4.2.0)
inherited_resources (= 1.6.0) was resolved to 1.6.0, which depends on
responders was resolved to 1.1.2, which depends on
railties (>= 3.2, < 4.2)
</code></pre></div>
<p>Not easy to know what to do about it.</p>
<p>With PubGrub, you should now get human-readable explanations of failures. The
most complex cases may are still, well… complex. But explanations should
always make sense and point to the root cause of resolution failures.</p>
<p>Here’s an example from our test suite:</p>
<div class="highlight"><pre class="highlight plaintext"><code>Because every version of c depends on a < 1
and every version of b depends on a >= 2,
every version of c is incompatible with b >= 0.
So, because Gemfile depends on b >= 0
and Gemfile depends on c >= 0,
version solving has failed.
</code></pre></div>
<p>We tried to make this migration as backwards-compatible as possible, but
there’s a chance of experiencing some different solutions to the ones found by
Molinillo, since the version solving problem does not have unique solutions.
Please report any issues you find with the new resolver.</p>
<h3 id="easily-generate-gems-with-rust-extensions-using-bundle-gem">Easily generate gems with Rust extensions using <code>bundle gem</code></h3>
<p>It’s now easier than ever to get started using Rust inside your gems. Check out
<a href="/blog/2023/01/31/rust-gem-skeleton.html">this blog post</a> to learn how to generate a gem with all
the boilerplate necessary with just a few commands.</p>
<h3 id="faster-git-sources">Faster git sources</h3>
<p>In the Bundler world, it’s common to point to git repositories when there’s
no version released to rubygems.org that includes the changes that you need.
This works fine, but it can get slow and use a lot of disk space when dealing
with very big repositories.</p>
<p>We have improved the way we clone these repositories to be faster and use less
disk space. For example, something like</p>
<div class="highlight"><pre class="highlight plaintext"><code>gem "rails", github: "rails/rails"
</code></pre></div>
<p>in your Gemfile could previously take ~30s and use up to 1Gb of disk space,
because we would clone the full Rails repository, which has a large history.</p>
<p>Now we just clone what’s strictly necessary for Bundler to work, resulting in
big disk space savings, and much faster bundling.</p>
<h3 id="new-cli-features">New CLI features</h3>
<p>We added a few small CLI features, such as a new <code>--pre</code> flag to <code>bundle update</code>
and <code>bundle lock</code> to explicitly opt-in to prereleases of selected (of all) gems
without having to explictly change your Gemfile with pre-release requirements
such as <code>>= 7.1.0.beta</code>.</p>
<h3 id="some-minor-breaking-changes">Some minor breaking changes</h3>
<p>We took new year’s release to move on and get rid of some stuff that was causing
maintenance burden for us:</p>
<ul>
<li>Ruby 2.3, 2.4, and 2.5 are no longer supported.</li>
<li>RubyGems 2.5, 2.6, and 2.7 are no longer supported.</li>
</ul>
<p>In general, this support drop should not break anything because RubyGems should
be able to choose the latest supported Bundler on the Ruby version that you’re
using. But there are still some old RubyGems out there that don’t have this
feature, and the <code>gem install bundler</code> command could break there. We have
warned using Bundler on those old rubies for a year now, so we believe it’s time
to move on.</p>
<p>We also completely removed a controversial (mis-)feature from the Bundler code
base, where Bundler would automatically acquire sudo permissions when not having
the proper access rights. A great majority of users considered this feature harmful and
hardly useful, so we decided to get rid of it.</p>
<h3 id="and-bug-fixes">And bug fixes</h3>
<p>As always, we continue to smooth the experience of using Bundler, so that it
gets the job done and does not get in the middle other than that. And we’re also
shipping a bunch of bug fixes to keep moving towards that goal.</p>
<p>That’s all from the Bundler team. Have a happy new year, and enjoy using Bundler
2.4! 🎉</p>
Generate gem skeleton with Rust extensionhttps://bundler.io/blog/2023/01/31/rust-gem-skeleton.html2023-01-31T14:42:00+00:002025-10-20T08:26:09+00:00Josef Šimánek<p>Do you think <a href="https://en.wikipedia.org/wiki/Dynamic_programming_language">dynamically typed</a> <a href="https://en.wikipedia.org/wiki/Interpreter_(computing)">interpreted</a> <a href="https://www.ruby-lang.org/">Ruby language</a> and <a href="https://en.wikipedia.org/wiki/Type_system#Static_type_checking">statically typed</a> <a href="https://en.wikipedia.org/wiki/Compiled_language">compiled</a> <a href="https://www.rust-lang.org/">Rust language</a> could be friends? Yes, they can! And actually, they are!</p>
<p>Officially it all started when <a href="https://github.com/ruby/ruby/blob/d5635dfe36588b04d3dd6065ab4e422f51629b11/doc/yjit/yjit.md">YJIT</a> was <a href="https://bugs.ruby-lang.org/issues/18481">ported to Rust</a> and <a href="https://github.com/ruby/ruby">Ruby codebase</a> has officially <a href="https://github.com/ruby/ruby/tree/master/yjit/src">onboarded Rust code</a>. This friendship matured when RubyGems <a href="https://rubygems.org/gems/rubygems-update/versions/3.3.11">3.3.11</a> (with a new <a href="https://github.com/rubygems/rubygems/pull/5175"><em>Add cargo builder for rust extensions</em></a> feature) <a href="https://blog.rubygems.org/2022/04/07/3.3.11-released.html">was released</a> capable of compiling Rust-based extensions during gem installation process (similar to well-known C-based gem extensions like nokogiri, pg or puma).</p>
<p>And now, with Bundler 2.4, <code>bundle gem</code> skeleton generator can provide all the glue you need to start using Rust inside your gems thanks to the new <code>--ext=rust</code> parameter!</p>
<h2 id="whats-new">What’s new?</h2>
<p>Thanks to new parameter it is possible to generate simple Rust-based gem extension.</p>
<p><em>Make sure to use RubyGems 3.4.6 or higher for the best experience.</em></p>
<p><em>Notice I already have <code>bundle gem</code> command configured. Your output can differ. When running <code>bundle gem</code> for the first time, it will interactively ask you few questions.</em></p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle gem --ext=rust hello_rust
Creating gem 'hello_rust'...
MIT License enabled in config
Initializing git repo in /home/retro/code/hello_rust
create hello_rust/Gemfile
create hello_rust/lib/hello_rust.rb
create hello_rust/lib/hello_rust/version.rb
create hello_rust/sig/hello_rust.rbs
create hello_rust/hello_rust.gemspec
create hello_rust/Rakefile
create hello_rust/README.md
create hello_rust/bin/console
create hello_rust/bin/setup
create hello_rust/.gitignore
create hello_rust/test/test_helper.rb
create hello_rust/test/test_hello_rust.rb
create hello_rust/LICENSE.txt
create hello_rust/Cargo.toml
create hello_rust/ext/hello_rust/Cargo.toml
create hello_rust/ext/hello_rust/extconf.rb
create hello_rust/ext/hello_rust/src/lib.rs
Gem 'hello_rust' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
</code></pre></div>
<p>For Rust-based extension last 4 entries are interesting.</p>
<ul>
<li><code>hello_rust/Cargo.toml</code>
<ul>
<li>Top-level <code>Cargo.toml</code> is just pointing to “nested” <code>Cargo.toml</code> in <code>ext</code> folder.</li>
<li>It is useful to be able to run all <code>cargo</code> commands in top-level directory (next to <code>bundle</code>, <code>gem</code>, …).</li>
<li>It is also useful for your IDE to be able to recognize there is Rust code in this folder, but not in standard path for Rust crate.</li>
</ul>
</li>
<li><code>hello_rust/ext/hello_rust/Cargo.toml</code>
<ul>
<li>Actual <code>Cargo.toml</code> as known from Rust crates. It includes package metadata, configuration and dependencies. You can think of this file as a “gemspec for Rust packages”.</li>
</ul>
</li>
<li><code>hello_rust/ext/hello_rust/extconf.rb</code>
<ul>
<li>Config file responsible for configuration of compilation of your Rust code in Ruby world (for example during gem installation).</li>
<li>Currently based on <a href="https://github.com/oxidize-rb/rb-sys/tree/main/gem#the-rb_sys-gem">rb_sys gem</a>. Check <a href="https://github.com/oxidize-rb/rb-sys/tree/main/gem#create_rust_makefile">project README</a> for more info.</li>
</ul>
</li>
<li><code>hello_rust/ext/hello_rust/src/lib.rs</code>
<ul>
<li>Yes, the holy grail of Rust-based extension - the Rust code!</li>
</ul>
</li>
</ul>
<h2 id="hello-from-rust">Hello from Rust!</h2>
<p>Generated <code>hello_rust/ext/hello_rust/src/lib.rs</code> contains hello world example method defined at base class of extension. In my case it is <code>HelloRust#hello</code> with 1 string argument returning string as well. It is using <a href="https://github.com/matsadler/magnus">magnus</a> Rust bindings to Ruby for super smooth developer experience.</p>
<div class="highlight"><pre class="highlight rust"><code><span class="cs"># hello_rust/ext/hello_rust/src/lib.rs</span>
<span class="k">use</span> <span class="nn">magnus</span><span class="p">::{</span><span class="n">define_module</span><span class="p">,</span> <span class="n">function</span><span class="p">,</span> <span class="nn">prelude</span><span class="p">::</span><span class="o">*</span><span class="p">,</span> <span class="n">Error</span><span class="p">};</span>
<span class="k">fn</span> <span class="nf">hello</span><span class="p">(</span><span class="n">subject</span><span class="p">:</span> <span class="nb">String</span><span class="p">)</span> <span class="k">-></span> <span class="nb">String</span> <span class="p">{</span>
<span class="nd">format!</span><span class="p">(</span><span class="s">"Hello from Rust, {}!"</span><span class="p">,</span> <span class="n">subject</span><span class="p">)</span>
<span class="p">}</span>
<span class="nd">#[magnus::init]</span>
<span class="k">fn</span> <span class="nf">init</span><span class="p">()</span> <span class="k">-></span> <span class="nb">Result</span><span class="o"><</span><span class="p">(),</span> <span class="n">Error</span><span class="o">></span> <span class="p">{</span>
<span class="k">let</span> <span class="n">module</span> <span class="o">=</span> <span class="nf">define_module</span><span class="p">(</span><span class="s">"HelloRust"</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
<span class="n">module</span><span class="nf">.define_singleton_method</span><span class="p">(</span><span class="s">"hello"</span><span class="p">,</span> <span class="nd">function!</span><span class="p">(</span><span class="n">hello</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span><span class="o">?</span><span class="p">;</span>
<span class="nf">Ok</span><span class="p">(())</span>
<span class="p">}</span>
</code></pre></div>
<p>That is equivalent to following Ruby code, including some boilerplate code, to enable Rust extension to communicate with Ruby.</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="k">module</span> <span class="nn">HelloRust</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">hello</span><span class="p">(</span><span class="n">subject</span><span class="p">)</span>
<span class="s2">"Hello from Rust, </span><span class="si">#{</span><span class="n">subject</span><span class="si">}</span><span class="s2">!"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div>
<h2 id="lets-compile-and-run-some-rust">Let’s compile and run some Rust!</h2>
<p>To be able to test this boilerplate code, you need to run <code>bundle install</code> first (to install all Ruby dependencies) followed by <code>bundle exec rake compile</code> compiling Rust code.</p>
<p><em>Notice generated gemspec is not valid by default and running <code>bundle install</code> can break. In that case it is needed to update gemspec first and replace all TODO values with some real ones.</em></p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle install
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 13.0.6
Using bundler 2.4.0
Using hello_rust 0.1.0 from source at `.`
Using minitest 5.16.3
Using rake-compiler 1.2.1
Using rb_sys 0.9.52
Bundle complete! 5 Gemfile dependencies, 6 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
</code></pre></div>
<p>At this stage, everything is ready to compile Rust code and glue it with Ruby.</p>
<p><em>You need to have Rust already installed on your system. See <a href="https://rustup.rs/">rustup</a> for a simple installation experience.</em></p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle exec rake compile
mkdir -p tmp/x86_64-linux/hello_rust/3.1.2
cd tmp/x86_64-linux/hello_rust/3.1.2
/home/retro/.rubies/ruby-3.1.2/bin/ruby -I. -r.rake-compiler-siteconf.rb ../../../../ext/hello_rust/extconf.rb
cd -
cd tmp/x86_64-linux/hello_rust/3.1.2
/usr/bin/gmake
generating target/release/libhello_rust.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/hello_rust/Cargo.toml --lib --release -- -C linker=gcc -L native=/home/retro/.rubies/ruby-3.1.2/lib -C link-arg=-lm
Updating crates.io index
... shortened
Compiling magnus-macros v0.2.0
Compiling rb-sys-build v0.9.52
Compiling rb-sys v0.9.52
Compiling hello_rust v0.1.0 (/home/retro/code/hello_rust/ext/hello_rust)
Finished release [optimized] target(s) in 1m 03s
cd -
mkdir -p tmp/x86_64-linux/stage/lib/hello_rust
/usr/bin/gmake install target_prefix=
generating target/release/libhello_rust.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/hello_rust/Cargo.toml --lib --release -- -C linker=gcc -L native=/home/retro/.rubies/ruby-3.1.2/lib -C link-arg=-lm
Finished release [optimized] target(s) in 0.09s
installing hello_rust.so to /home/retro/code/hello_rust/lib/hello_rust
/usr/bin/install -c -m 0755 hello_rust.so /home/retro/code//hello_rust/lib/hello_rust
cp tmp/x86_64-linux/hello_rust/3.1.2/hello_rust.so tmp/x86_64-linux/stage/lib/hello_rust/hello_rust.so
</code></pre></div>
<p>And finally, it is possible to call <code>hello</code> method defined in Rust returning a string and printing it to the console.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle exec ruby -rhello_rust -e 'puts HelloRust.hello("Josef")'
"Hello from Rust, Josef!"
</code></pre></div>
<p><em>Feel free to try to break this extension. For example you can try to pass different types of argument (like number or symbol). <a href="https://github.com/matsadler/magnus">magnus</a> is doing a great job <a href="https://github.com/matsadler/magnus#defining-methods">automatically converting</a> all those mistakes with friendly error messages.</em></p>
<h2 id="summary">Summary</h2>
<p>Starting Bundler 2.4, you can generate gem skeleton with all boilerplate code needed to start using Rust. But it is not only about your custom Rust code you can easily integrate into gems now. Thanks to integration with <a href="https://doc.rust-lang.org/cargo/">cargo</a> (Rust package manager) you can use any of <a href="https://crates.io/">Rust crates</a> available. Rust ecosystem is well known for highly optimized and memory safe libraries. Thanks to <a href="https://github.com/matsadler/magnus">magnus</a> and <code>bundle gem</code> command, it is possible to glue those Rust libraries into Ruby world smoothly. Sky is the limit ;-)</p>
<p><em>To see real-life example how powerful could be Rust for data processing, I recommend to check <a href="https://github.com/rubytogether/kirby">kirby project</a> parsing logs for <a href="http://rubygems.org/">rubygems.org</a>.</em></p>
Bundler v2.3: Locking the version of Bundler itselfhttps://bundler.io/blog/2022/01/23/bundler-v2-3.html2022-01-23T16:07:00+00:002025-10-20T08:26:09+00:00David Rodríguez<p>2021 saw a fair amount of development in the RubyGems & Bundler repositories. We
tried to release more often than ever to catch and fix bugs and distribute our
improvements as early as possible to our users. That has led to 33 patch-level versions
in the Bundler 2.x series released about a year ago.</p>
<p>Our goal for Bundler 2.3 was to implement a long-wanted feature of being able to
fully control the version of Bundler itself an application runs. There’s a long
story with this feature, because it was shipped a few years ago in a manner that
was too strict and ended up causing more harm than good, so had to be partially
reverted.</p>
<h2 id="so-how-did-things-work-before-bundler-23">So, how did things work before Bundler 2.3?</h2>
<p>Up until now, RubyGems would try to activate the version of Bundler recorded in
the <code>Gemfile.lock</code> file if already installed, and would fall back to the
highest version installed otherwise. That’s better than nothing, but it did not
ensure the exact version in the lockfile was always used, which led to
workarounds like <a href="https://bundler.io/blog/2019/05/14/solutions-for-cant-find-gem-bundler-with-executable-bundle.html">manually parsing the lockfile and then installing that
version</a>.</p>
<h2 id="and-how-do-they-work-now">And how do they work now?</h2>
<p>In Bundler 2.3 and up (if you also have RubyGems 3.3 or higher), running
<code>bundle install</code> will use the exact version from the BUNDLED WITH section of
the lockfile. If that version is not installed before you run <code>bundle
install</code>, the running version of Bundler will install the locked version, and
then run your original command using the newly-installed locked version.</p>
<p>So, if you have a lockfile ending with</p>
<div class="highlight"><pre class="highlight plaintext"><code>BUNDLED WITH
2.2.33
</code></pre></div>
<p>and you only have Bundler 2.3.5 installed, you’ll see the following output when
running <code>bundle install</code>.</p>
<div class="highlight"><pre class="highlight plaintext"><code>$ bundle install
Bundler 2.3.5 is running, but your lockfile was generated with 2.2.33. Installing Bundler 2.2.33 and restarting using that version.
Fetching gem metadata from https://rubygems.org/.
Fetching bundler 2.2.33
Installing bundler 2.2.33
...
</code></pre></div>
<p>After that all your commands will automatically use Bundler 2.2.33, as specified
by your lockfile. If you want to upgrade the Bundler version used by your
application, you can run <code>bundle update --bundler</code>, and your lockfile will be
regenerated using the latest version. From that moment, all users of the
lockfile will automatically pick up the new version, no matter whether they have
a newer or older version installed instead.</p>
<p>But..</p>
<h2 id="why-are-we-doing-this">Why are we doing this?</h2>
<p>Being able to lock the version of Bundler itself, just like Bundler is able to
lock other dependencies, has been a goal of the Bundler team for years. There are
a number of benefits of locking your dependencies, like avoiding dependency
nightmares where your application breaks due to third party releases, or
avoiding “works on my machine” issues. Bundler has a ton of features and edge
cases, and</p>
<ul>
<li>
<p>We sometimes introduce regressions when trying to improve things. Locking the
version of Bundler prevents those issues from hitting you.</p>
</li>
<li>
<p>Once in a while we need to put a security fix out there. Being able to lock
the Bundler version allows you to ensure that every user of your application
gets a secure version of Bundler.</p>
</li>
<li>
<p>Occasionally, you might want to use a new feature of the Bundler DSL in your
Gemfile. However, old versions of Bundler don’t understand this feature and
you don’t want to suddenly break things for the users of yours that use those
old versions. With version locking this is no longer a concern. Bundler is now
able to upgrade itself to the version that your application understands.</p>
</li>
</ul>
<p>All in all, we aim to provide a less surprising, less error prone and more
consistent experience when using Bundler, and let each application be in control
of the version that they use, and the moment that they upgrade.</p>
<h2 id="whats-coming-next">What’s coming next?</h2>
<p>Future enhancements to this feature might include:</p>
<ul>
<li>Full support for <code>gem "bundler", "<arbitrary_requirement>"</code> in <code>Gemfile</code>.</li>
<li>Automatic update of Bundler when running <code>bundle install</code> without a lockfile.</li>
<li>Automatic update of Bundler when running <code>bundle update</code>.</li>
</ul>
<p>In other words, our end goal is to be able to treat Bundler just like any other
dependency of your application.</p>
A more secure bundler: We fixed our source priorities.https://bundler.io/blog/2021/02/15/a-more-secure-bundler-we-fixed-our-source-priorities.html2021-02-15T11:33:00+00:002025-10-20T08:26:09+00:00David Rodríguez<blockquote>
<p><strong>NOTE</strong>: Whereas the issue was initially fixed in bundler 2.2.10, it had to
be reverted due to several problems caused by the initial approach. A proper
fix was finally released with bundler 2.2.18.</p>
</blockquote>
<h2 id="what-happened">What happened?</h2>
<p>Last week <a href="https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610">an article about “Dependency
Confusion”</a>
hit the news, where a developer was able to make thousands of dollars on bug
bounty programs from big tech companies, by pushing libraries to public
repositories that ended up unintentionally being installed into these companies
servers.</p>
<p>The developer was able to expose (in a non-malicious way) a vulnerability
present in well-known dependency managers, where given a library name they will
end up preferring installing it from a public source rather than from a private
source. This is not secure because the name in the public source is controlled
by the first person claiming it, whereas the name in the private source is controlled
by the private source owner.</p>
<p>Unfortunately, Bundler had this vulnerability.</p>
<p>There’s good news though:</p>
<h2 id="things-were-safe-on-the-rubygemsorg-side">Things were safe on the rubygems.org side</h2>
<p>The rubygems.org organization, in collaboration with
<a href="https://diffend.io">diffend.io</a>, have a pretty good malicious code detection
system. In fact, the only reason this developer was able to make all this money
by getting these gems installed in companies private servers is because our
system detected them, flagged them for us, and we determined them to be
non-malicious, and only for research purposes. If those gems had been malicious,
we wouldn’t have allowed them.</p>
<p>Check out the <a href="https://mensfeld.pl/2021/02/rubygems-dependency-confusion-side-of-things/">more detailed blog
post</a>
from our diffend.io friends about what happened in the rubygems.org side of
things, and how things were secure.</p>
<h2 id="the-issue-has-been-fixed-in-bundler-2210">The issue has been fixed in bundler 2.2.10</h2>
<p>We have shipped bundler 2.2.10 with a fix, and now whenever you specify a block
source in your <code>Gemfile</code>, bundler will prioritize it when resolving direct
dependencies specified inside, and also transitive dependencies of those. So in
the following situation both <code>my-private-gem</code> and <code>my-another-private-gem</code> will
be picked up from <code>https://my-private-server</code>, even if someone pushes a higher
version with the same name to <code>rubygems.org</code>:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="c1"># my-private-gem.gemspec</span>
<span class="c1"># ...</span>
<span class="n">gem</span><span class="p">.</span><span class="nf">dependency</span><span class="p">(</span><span class="s2">"my-another-private-gem"</span><span class="p">)</span>
</code></pre></div>
<div class="highlight"><pre class="highlight ruby"><code><span class="c1"># Gemfile</span>
<span class="n">source</span> <span class="s2">"https://rubygems.org"</span>
<span class="n">source</span> <span class="s2">"https://my-private-server"</span> <span class="k">do</span>
<span class="n">gem</span> <span class="s2">"my-private-gem"</span>
<span class="k">end</span>
</code></pre></div>
<p>Make sure you upgrade your bundler version either by running <code>gem install
bundler</code>, or by upgrading rubygems through <code>gem update --system</code> (which will
install bundler 2.2.10 as a default gem).</p>
<h2 id="final-notes">Final notes</h2>
<p>The bundler team had actually been aware of this issue for a while, but
unfortunately lacks resources to take care of everything we need to take care,
so the fix was postponed for too long. Maintaining the rubygems.org
infrastructure and its client libraries requires a big amount of work and we
barely manage to keep up with it. So, if your company really needs us to stay on
top of these issues, please consider funding
<a href="https://rubytogether.org/">RubyTogether</a> ❤️.</p>
<p>That’s all for today,</p>
<p>Happy bundling!</p>
<hr />
<p>Deivid, André and the RubyGems team</p>