bundler-resolutions 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5a9bc7c0b4191b262edcc52111b78fb8c67b74b0c9642ddec0036142d46c2989
4
+ data.tar.gz: bb5c955b6db7a14e56e8d5048c98709a36f634f25364a14cbe22d6606d3faeab
5
+ SHA512:
6
+ metadata.gz: 2d0f016d3a21dd98fe3d175d015fd4e526a514f32acf8283205db330ac9e52df4444e59a12e761882580790c8bccc1599739d3375291f598b810b4e7800b0705
7
+ data.tar.gz: cf1c8bee485fa053ec3de1ac094638381d9153796de7e77f5add4ee31953f41889f3563f6413830a5351633cb2f7960d5557447f66d52aca69ac175293696646
data/README.md ADDED
@@ -0,0 +1,93 @@
1
+ bundler-resolutions
2
+ ===================
3
+
4
+ [![Gem Version](https://img.shields.io/gem/v/bundler-resolutions?color=green)](https://rubygems.org/gems/bundler-resolutions)
5
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ [bundler-resolutions](https://github.com/hlascelles/bundler-resolutions) is a [bundler](https://bundler.io/)
8
+ plugin that allows you to specify gem version requirements in your `Gemfile` without explicitly declaring
9
+ a concrete dependency on those gems. It acts much like the
10
+ [resolutions](https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/) feature in
11
+ [Yarn](https://yarnpkg.com/).
12
+
13
+ > [!WARNING]
14
+ > This is an experimental project and neither its API stability nor correctness should be assumed
15
+
16
+ ## Usage
17
+
18
+ Add `bundler-resolutions` to your Gemfile, and add a `resolutions` group to specify the gems you
19
+ want to specify versions requirements for.
20
+
21
+ The resulting `Gemfile.lock` in this example will have nokogiri locked to `1.16.5` or above.
22
+
23
+ ```ruby
24
+ plugin 'bundler-resolutions'
25
+
26
+ gem "rails"
27
+
28
+ group :resolutions do
29
+ gem "nokogiri", ">= 1.16.5" # CVE-2024-34459
30
+ end
31
+ ```
32
+
33
+ However the `Gemfile.lock` from this example will not have nokogiri at all, as it is neither
34
+ explicitly declared, nor brought in as a transitive dependency.
35
+
36
+ ```ruby
37
+ plugin 'bundler-resolutions'
38
+
39
+ group :resolutions do
40
+ gem "nokogiri", ">= 1.16.5" # CVE-2024-34459
41
+ end
42
+ ```
43
+
44
+ ## Detail
45
+
46
+ `bundler-resolutions` allows you to specify version requirements using standard gem syntax in your
47
+ Gemfile to indicate that you have version requirements for those gems *if* they were to be brought
48
+ in as transitive dependencies, but that you don't depend on them yourself directly.
49
+
50
+ An example use case is in the Gemfile given below. Here we are saying that although we do not use nokogiri
51
+ specifically ourselves, we want to ensure that if it is pulled in by other gems then it will
52
+ always be above the know version with a CVE.
53
+
54
+ ```ruby
55
+ source "https://rubygems.org"
56
+
57
+ plugin 'bundler-resolutions'
58
+
59
+ gem "rails"
60
+
61
+ group :resolutions do
62
+ gem "nokogiri", ">= 1.16.5" # CVE-2024-34459
63
+ end
64
+ ```
65
+
66
+ The big difference between doing this and just declaring it in your Gemfile is that it will only
67
+ be used in resolutions (and be written to your lock file) if the gems you do directly depend on
68
+ continue to use it. If they stop using it, then your resolutions will take no part in the
69
+ bundler lock resolution.
70
+
71
+ The other difference is that even if it does take part in the resolutions, it will not be
72
+ present in the `DEPENDENCIES` section of the lock file, as it is not a direct dependency.
73
+
74
+ ## Use cases
75
+
76
+ There are a number of reasons you may want to prevent the usage of some gem versions, without
77
+ direct use, such as:
78
+
79
+ 1. You have learnt of a CVE of a gem.
80
+ 2. You have internal processes that mandate the usage of certain gem versions for legal or sign off reasons.
81
+ 3. You know of gem incompatibilities in later versions.
82
+ 4. You know that different OS architectures do not work with some versions.
83
+
84
+ ## How it works
85
+
86
+ `bundler-resolutions` works by patching the Gemfile DSL to allow for special processing
87
+ of the `resolutions` group. It also patches the bundler `filtered_versions_for` method to
88
+ allow for the resolution restrictions from the versions specified in the `resolutions` group.
89
+
90
+ This is a very early version, and it should be considered experimental.
91
+
92
+ Future work may include relating this to bundler-audit, and other security tools, so you
93
+ will automatically gain version restrictions against known CVEs.
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../resolutions"
4
+
5
+ module Bundler
6
+ class Resolutions
7
+ VERSION = "0.1.0"
8
+ end
9
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class Resolutions
5
+ GROUP_NAME = :resolutions
6
+
7
+ attr_reader :resolutions
8
+
9
+ def initialize
10
+ @resolutions = {}
11
+ end
12
+
13
+ # This method is called by the DSL to set the resolution for a given gem. It is effectively
14
+ # an override of the normal gem method.
15
+ def gem(name, requirements)
16
+ resolutions[name.to_sym] = requirements
17
+ end
18
+
19
+ class << self
20
+ def instance = @instance ||= new
21
+ end
22
+
23
+ # A module we prepend to Bundler::Resolutions::Resolver
24
+ module Resolver
25
+ # This overrides the default behaviour of the resolver to filter out versions that don't
26
+ # satisfy the requirements specified in RESOLVER_RESOLUTIONS.
27
+ def filtered_versions_for(package)
28
+ super.select do |pkg|
29
+ req = Bundler::Resolutions.instance.resolutions[package.name.to_sym]
30
+ req ? Gem::Requirement.new(*req.split(",")).satisfied_by?(pkg.version) : true
31
+ end
32
+ end
33
+ end
34
+
35
+ # A module we prepend to Bundler::Dsl
36
+ module Dsl
37
+ # Here we override the normal group function to capture the resolutions, and ensure any
38
+ # gem calls are effectively a no-op as regards to adding them to dependencies.
39
+ def group(*args, &blk)
40
+ args.first == GROUP_NAME ? Bundler::Resolutions.instance.instance_eval(&blk) : super
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ Bundler::Resolver.prepend(Bundler::Resolutions::Resolver)
47
+ Bundler::Dsl.prepend(Bundler::Resolutions::Dsl)
data/plugins.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/resolutions"
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bundler-resolutions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Harry Lascelles
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A bundler plugin to enforce resolutions without specifying a concrete
14
+ dependency
15
+ email:
16
+ - harry@harrylascelles.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - README.md
22
+ - lib/bundler/resolutions.rb
23
+ - lib/bundler/resolutions/version.rb
24
+ - plugins.rb
25
+ homepage: https://github.com/hlascelles/bundler-resolutions
26
+ licenses:
27
+ - MIT
28
+ metadata:
29
+ homepage_uri: https://github.com/hlascelles/bundler-resolutions
30
+ documentation_uri: https://github.com/hlascelles/bundler-resolutions
31
+ changelog_uri: https://github.com/hlascelles/bundler-resolutions/blob/master/CHANGELOG.md
32
+ source_code_uri: https://github.com/hlascelles/bundler-resolutions/
33
+ bug_tracker_uri: https://github.com/hlascelles/bundler-resolutions/issues
34
+ rubygems_mfa_required: 'true'
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubygems_version: 3.5.11
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: A bundler plugin to enforce resolutions without specifying a concrete dependency
54
+ test_files: []