Bundler BlogThe latest news on Bundlerhttps://bundler.io/blog2023-01-31T14:43:00+00:00The Bundler TeamBundler 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:002024-03-25T20:18:32+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>
<p><code>
gem "rails", github: "rails/rails"
</code></p>
<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:002024-03-25T20:18:32+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:002024-03-25T20:18:32+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:002024-03-25T20:18:32+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>
Bundler v2.2: Multiplatform, Funding, and more.https://bundler.io/blog/2020/12/09/bundler-v2-2.html2020-12-09T16:32:00+00:002024-03-25T20:18:32+00:00David Rodríguez<p>After an intense year of work, we’re finally ready to announce the release of
the final version of bundler 2.2, right in time to be included with Christmas’
eve Ruby 3.0 release.</p>
<h2 id="multiplatform-support">Multiplatform support</h2>
<p>Historically, bundler has had issues when it comes to choosing and prioritizing
platform specific versions of gems during resolution. With this release, we have
made several improvements in this regard and we expect to ship a much more user
friendly behavior here.</p>
<p>Huge thanks to <a href="https://github.com/kou">@kou</a> for contributing awesome fixes in
this area, and to <a href="https://github.com/larskanis">@larskanis</a> for early testing
the improvements and giving us feedback.</p>
<p>Bundler now needs to record the specific platform it used to resolve a given
<code>Gemfile</code> in the lockfile, so you will notice some source control differences
there when you upgrade. Commit these changes for all your supported platforms to
make sure all developers of your application get a consistent resolution under
all platforms.</p>
<h2 id="find-out-about-gems-you-depend-on-that-need-funding">Find out about gems you depend on that need funding</h2>
<p>We really want to help building a more sustainable ruby ecosystem, so we’re
shipping a new <code>bundle fund</code> command that helps you discovering the libraries
you depend on that need funding.</p>
<p>If you develop a gem that needs funding, make sure you fill in the <code>funding_uri</code>
metadata in your gemspec, like this:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="no">Gem</span><span class="o">::</span><span class="no">Specification</span><span class="p">.</span><span class="nf">new</span> <span class="k">do</span> <span class="o">|</span><span class="n">gem</span><span class="o">|</span>
<span class="n">gem</span><span class="p">.</span><span class="nf">name</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="no">GEM_NAME</span><span class="si">}</span><span class="s2">"</span>
<span class="n">gem</span><span class="p">.</span><span class="nf">homepage</span> <span class="o">=</span> <span class="s2">"</span><span class="si">#{</span><span class="no">GEM_HOMEPAGE</span><span class="si">}</span><span class="s2">"</span>
<span class="n">s</span><span class="p">.</span><span class="nf">metadata</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"funding_uri"</span> <span class="o">=></span> <span class="s2">"</span><span class="si">#{</span><span class="no">GEM_FUNDING_PAGE</span><span class="si">}</span><span class="s2">"</span>
<span class="p">}</span>
<span class="k">end</span>
</code></pre></div>
<p>As soon as people start filling this metadata, <code>bundle fund</code> will start
reporting all of your dependencies that need funding.</p>
<p>Big kudos to <a href="https://github.com/gjtorikian">@gjtorikian</a> for coding this
feature both on the server and the client sides, and for waiting so patiently
until we had time to review his work.</p>
<p>And talking about funding, remember: <a href="https://rubytogether.org/">RubyTogether</a> needs ❤️.</p>
<h2 id="improved-windows-support">Improved Windows support</h2>
<p>Partly because of the improved multiplatform support, but also because of many
other fixes, bundler now supports Windows much better. We even have a Windows CI
running to make sure we minimize regressions under that platform.</p>
<h2 id="better-integration-inside-ruby-core">Better integration inside ruby-core</h2>
<p>Since ruby 2.6 bundler is included as default gem with ruby. This change was
exciting but didn’t happen without issues. We have made many fixes in this
regard and we believe things should be much smoother now. As in, you shouldn’t
notice any behavioral difference at all when running bundler as a regular gem vs
as a default gem.</p>
<h2 id="better-support-for-jruby">Better support for JRuby</h2>
<p>We have been working on improving our compatibility with jruby as well. We now
run a small subset of our CI under jruby to prevent regressions and cover the
related bug fixes that we ship.</p>
<h2 id="better-more-flexible-gem-templates">Better, more flexible, gem templates</h2>
<p>We have shipped a lot of improvements to the default <code>bundle gem</code> template. You
can now automatically set up a configuration for the main CI providers, or
include <code>rubocop</code> to check your code style, among other improvements. We also
make sure all gems are now generated with a default minimum supported ruby,
which is a good practice that we really want to promote.</p>
<h2 id="and-a-bunch-of-bug-fixes">And a bunch of bug fixes!</h2>
<p>Last but not least, we have fixed about 60 bugs in this release. Our main focus
at the moment is stability, so we want to kill all those issues that sometimes
make bundler get in the middle.</p>
<h2 id="how-to-get-it">How to get it</h2>
<p>Run <code>gem install bundler</code> to upgrade to the newest version of Bundler.</p>
<hr />
<p>That’s all for now. We really hope you enjoy this release. Happy Bundling!</p>
March Bundler Updatehttps://bundler.io/blog/2020/04/27/march-monthly-update.html2020-04-27T00:00:00+00:002024-03-25T20:18:32+00:00Gift Egwuenu<p>Welcome to the Bundler monthly update! As part of our efforts at <a href="https://rubytogether.org">Ruby Together</a>, we publish a recap of the work that we’ve done the previous month. Read on to find out what updates were made to Bundler in March.</p>
<p>Amazingly, all that work that the entire Bundler and RubyGems teams have been working at for years has paid off in a really big way: Bundler and RubyGems have merged repositories! On GitHub, <code>bundler/bundler</code> is archived, and all ongoing work on both projects now takes place inside <code>RubyGems/RubyGems</code>. All other repositories from the Bundler organization have either been archived (if unused) or moved to the RubyGems organization.</p>
<p>Not just the repositories have changed, either: the Bundler and RubyGems teams have merged as well. It’ll take us some time to work through 20 years worth of documentation and webpages, but we’ll be combining and updating them as fast as we can.</p>
<p>From this point forward, Bundler news will be reported together with RubyGems news. Hooray! 🎉</p>
<hr />
<p>Interested in contributing to Bundler? We always welcome contributions in the forms of triaging bugs, adding new features, writing docs, and engaging with the wider community. Visit the <a href="https://github.com/rubygems/rubygems/blob/master/bundler/doc/contributing/README.md">Bundler Contributor Guidelines</a> on GitHub to get started. Don’t have time to contribute, but want to support our work? Sign up as a member of <a href="https://rubytogether.org/">Ruby Together</a> to help fund our work to keep Bundler working for everyone.</p>