bundle-safe-update 1.0.14

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: 92790321156e4545484b954c3f7f0b011172948695a3b7bc7ca74ca0917a3e80
4
+ data.tar.gz: 2616e43947f8e60e1a5ef20b261724edd0fa63637e31db95a5ba37efa8182700
5
+ SHA512:
6
+ metadata.gz: 3cb9bdd4de67e98f238653e60d78552d23e454f3e75fcc654954fd1f65bd328e54b7d9376beead9cb9b2135e4eedc9b70fce2401776929f7715482b34ecc97ed
7
+ data.tar.gz: 4c6ecef10d7c4cdb566d502a52d097b2e99d5d60119f13e752aabe7634acf0235f915969a522152ea9de3db48cb57877b9aacb022604e3ea0405ce0d31285b64
data/CLAUDE.md ADDED
@@ -0,0 +1,4 @@
1
+ # Agents Instructions
2
+
3
+ # currentDate
4
+ Today's date is 2026-02-17.
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ gem 'irb'
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rspec', '~> 3.0'
10
+ gem 'rubocop', '~> 1.21'
11
+ gem 'webmock', '~> 3.0'
data/Gemfile.lock ADDED
@@ -0,0 +1,145 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bundle-safe-update (1.0.14)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.8.8)
10
+ public_suffix (>= 2.0.2, < 8.0)
11
+ ast (2.4.3)
12
+ bigdecimal (3.3.1)
13
+ crack (1.0.1)
14
+ bigdecimal
15
+ rexml
16
+ date (3.5.1)
17
+ diff-lcs (1.6.2)
18
+ erb (6.0.0)
19
+ hashdiff (1.2.1)
20
+ io-console (0.8.1)
21
+ irb (1.15.3)
22
+ pp (>= 0.6.0)
23
+ rdoc (>= 4.0.0)
24
+ reline (>= 0.4.2)
25
+ json (2.18.0)
26
+ language_server-protocol (3.17.0.5)
27
+ lint_roller (1.1.0)
28
+ parallel (1.27.0)
29
+ parser (3.3.10.0)
30
+ ast (~> 2.4.1)
31
+ racc
32
+ pp (0.6.3)
33
+ prettyprint
34
+ prettyprint (0.2.0)
35
+ prism (1.6.0)
36
+ psych (5.3.0)
37
+ date
38
+ stringio
39
+ public_suffix (7.0.0)
40
+ racc (1.8.1)
41
+ rainbow (3.1.1)
42
+ rake (13.3.1)
43
+ rdoc (6.17.0)
44
+ erb
45
+ psych (>= 4.0.0)
46
+ tsort
47
+ regexp_parser (2.11.3)
48
+ reline (0.6.3)
49
+ io-console (~> 0.5)
50
+ rexml (3.4.4)
51
+ rspec (3.13.2)
52
+ rspec-core (~> 3.13.0)
53
+ rspec-expectations (~> 3.13.0)
54
+ rspec-mocks (~> 3.13.0)
55
+ rspec-core (3.13.6)
56
+ rspec-support (~> 3.13.0)
57
+ rspec-expectations (3.13.5)
58
+ diff-lcs (>= 1.2.0, < 2.0)
59
+ rspec-support (~> 3.13.0)
60
+ rspec-mocks (3.13.7)
61
+ diff-lcs (>= 1.2.0, < 2.0)
62
+ rspec-support (~> 3.13.0)
63
+ rspec-support (3.13.6)
64
+ rubocop (1.81.7)
65
+ json (~> 2.3)
66
+ language_server-protocol (~> 3.17.0.2)
67
+ lint_roller (~> 1.1.0)
68
+ parallel (~> 1.10)
69
+ parser (>= 3.3.0.2)
70
+ rainbow (>= 2.2.2, < 4.0)
71
+ regexp_parser (>= 2.9.3, < 3.0)
72
+ rubocop-ast (>= 1.47.1, < 2.0)
73
+ ruby-progressbar (~> 1.7)
74
+ unicode-display_width (>= 2.4.0, < 4.0)
75
+ rubocop-ast (1.48.0)
76
+ parser (>= 3.3.7.2)
77
+ prism (~> 1.4)
78
+ ruby-progressbar (1.13.0)
79
+ stringio (3.1.9)
80
+ tsort (0.2.0)
81
+ unicode-display_width (3.2.0)
82
+ unicode-emoji (~> 4.1)
83
+ unicode-emoji (4.1.0)
84
+ webmock (3.26.1)
85
+ addressable (>= 2.8.0)
86
+ crack (>= 0.3.2)
87
+ hashdiff (>= 0.4.0, < 2.0.0)
88
+
89
+ PLATFORMS
90
+ arm64-darwin-23
91
+ ruby
92
+
93
+ DEPENDENCIES
94
+ bundle-safe-update!
95
+ irb
96
+ rake (~> 13.0)
97
+ rspec (~> 3.0)
98
+ rubocop (~> 1.21)
99
+ webmock (~> 3.0)
100
+
101
+ CHECKSUMS
102
+ addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057
103
+ ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
104
+ bigdecimal (3.3.1) sha256=eaa01e228be54c4f9f53bf3cc34fe3d5e845c31963e7fcc5bedb05a4e7d52218
105
+ bundle-safe-update (1.0.14)
106
+ crack (1.0.1) sha256=ff4a10390cd31d66440b7524eb1841874db86201d5b70032028553130b6d4c7e
107
+ date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
108
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
109
+ erb (6.0.0) sha256=2730893f9d8c9733f16cab315a4e4b71c1afa9cabc1a1e7ad1403feba8f52579
110
+ hashdiff (1.2.1) sha256=9c079dbc513dfc8833ab59c0c2d8f230fa28499cc5efb4b8dd276cf931457cd1
111
+ io-console (0.8.1) sha256=1e15440a6b2f67b6ea496df7c474ed62c860ad11237f29b3bd187f054b925fcb
112
+ irb (1.15.3) sha256=4349edff1efa7ff7bfd34cb9df74a133a588ba88c2718098b3b4468b81184aaa
113
+ json (2.18.0) sha256=b10506aee4183f5cf49e0efc48073d7b75843ce3782c68dbeb763351c08fd505
114
+ language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
115
+ lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
116
+ parallel (1.27.0) sha256=4ac151e1806b755fb4e2dc2332cbf0e54f2e24ba821ff2d3dcf86bf6dc4ae130
117
+ parser (3.3.10.0) sha256=ce3587fa5cc55a88c4ba5b2b37621b3329aadf5728f9eafa36bbd121462aabd6
118
+ pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
119
+ prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
120
+ prism (1.6.0) sha256=bfc0281a81718c4872346bc858dc84abd3a60cae78336c65ad35c8fbff641c6b
121
+ psych (5.3.0) sha256=8976a41ae29ea38c88356e862629345290347e3bfe27caf654f7c5a920e95eeb
122
+ public_suffix (7.0.0) sha256=f7090b5beb0e56f9f10d79eed4d5fbe551b3b425da65877e075dad47a6a1b095
123
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
124
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
125
+ rake (13.3.1) sha256=8c9e89d09f66a26a01264e7e3480ec0607f0c497a861ef16063604b1b08eb19c
126
+ rdoc (6.17.0) sha256=0f50d4e568fc98195f9bb155a9e8dff6c7feabfb515fb22ef6df1d12ad5a02b7
127
+ regexp_parser (2.11.3) sha256=ca13f381a173b7a93450e53459075c9b76a10433caadcb2f1180f2c741fc55a4
128
+ reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
129
+ rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
130
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
131
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
132
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
133
+ rspec-mocks (3.13.7) sha256=0979034e64b1d7a838aaaddf12bf065ea4dc40ef3d4c39f01f93ae2c66c62b1c
134
+ rspec-support (3.13.6) sha256=2e8de3702427eab064c9352fe74488cc12a1bfae887ad8b91cba480ec9f8afb2
135
+ rubocop (1.81.7) sha256=6fb5cc298c731691e2a414fe0041a13eb1beed7bab23aec131da1bcc527af094
136
+ rubocop-ast (1.48.0) sha256=22df9bbf3f7a6eccde0fad54e68547ae1e2a704bf8719e7c83813a99c05d2e76
137
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
138
+ stringio (3.1.9) sha256=c111af13d3a73eab96a3bc2655ecf93788d13d28cb8e25c1dcbff89ace885121
139
+ tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
140
+ unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
141
+ unicode-emoji (4.1.0) sha256=4997d2d5df1ed4252f4830a9b6e86f932e2013fbff2182a9ce9ccabda4f325a5
142
+ webmock (3.26.1) sha256=4f696fb57c90a827c20aadb2d4f9058bbff10f7f043bd0d4c3f58791143b1cd7
143
+
144
+ BUNDLED WITH
145
+ 4.0.0.beta1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Denis Sablic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,314 @@
1
+ # bundle-safe-update
2
+
3
+ A CLI tool that enforces a minimum release age for Ruby gems during updates, preventing installation of gem versions that are "too new" (e.g., less than 14 days old). This helps protect against supply chain attacks by ensuring gems have had time for community review.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ gem install bundle-safe-update
9
+ ```
10
+
11
+ Or add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'bundle-safe-update', group: :development
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Run in your project directory:
20
+
21
+ ```sh
22
+ bundle-safe-update [options] [gem1 gem2 ...]
23
+ ```
24
+
25
+ Check all outdated gems:
26
+
27
+ ```sh
28
+ bundle-safe-update
29
+ ```
30
+
31
+ Check and update specific gems:
32
+
33
+ ```sh
34
+ bundle-safe-update rails sidekiq
35
+ ```
36
+
37
+ ### CLI Options
38
+
39
+ | Option | Description |
40
+ |--------|-------------|
41
+ | `--config PATH` | Path to config file |
42
+ | `--cooldown DAYS` | Minimum age in days (overrides config) |
43
+ | `--update` | Update gems that pass the cooldown check |
44
+ | `--warn-only` | Report violations but exit with success |
45
+ | `--no-audit` | Skip vulnerability audit |
46
+ | `--no-risk` | Skip risk signal checking |
47
+ | `--refresh-cache` | Refresh owner cache without warnings |
48
+ | `--json` | Output in JSON format for CI systems |
49
+ | `--verbose` | Enable verbose output |
50
+ | `--dry-run` | Show configuration without checking |
51
+ | `-v, --version` | Show version |
52
+ | `-h, --help` | Show help |
53
+
54
+ ### Example Output
55
+
56
+ Human-readable output:
57
+
58
+ ```
59
+ Checking gem versions...
60
+ OK: rails (7.1.3.2) - satisfies minimum age (42 days)
61
+ BLOCKED: nokogiri (1.16.4) - published 3 days ago (< 14 required)
62
+
63
+ 1 gem(s) violate minimum release age
64
+ ```
65
+
66
+ JSON output (`--json`):
67
+
68
+ ```json
69
+ {
70
+ "ok": false,
71
+ "cooldown_days": 14,
72
+ "checked": 2,
73
+ "blocked": [
74
+ { "name": "nokogiri", "version": "1.16.4", "age_days": 3 }
75
+ ]
76
+ }
77
+ ```
78
+
79
+ ### Updating Safe Gems
80
+
81
+ By default, `bundle-safe-update` only checks gems and reports results. Use `--update` to automatically update gems that pass the cooldown check:
82
+
83
+ ```sh
84
+ bundle-safe-update --update
85
+ ```
86
+
87
+ Example output:
88
+
89
+ ```
90
+ OK: rails (7.1.3.2) - satisfies minimum age
91
+ BLOCKED: nokogiri (1.16.4) - published 3 days ago (< 14 required)
92
+
93
+ 1 gem(s) violate minimum release age
94
+
95
+ Updating 1 gem(s): rails
96
+ Running: bundle update rails
97
+ Bundle updated successfully.
98
+
99
+ Skipped 1 blocked gem(s): nokogiri
100
+ ```
101
+
102
+ ### Updating Specific Gems
103
+
104
+ To check and update specific gems, pass their names as arguments:
105
+
106
+ ```sh
107
+ bundle-safe-update --update rails sidekiq
108
+ ```
109
+
110
+ Only the specified gems are checked and updated if they pass the cooldown check. Without `--update`, specific gems are checked but not updated:
111
+
112
+ ```sh
113
+ bundle-safe-update rails sidekiq
114
+ ```
115
+
116
+ ### Vulnerability Auditing
117
+
118
+ By default, bundle-safe-update runs `bundle audit` to check for known security vulnerabilities. This requires the `bundler-audit` gem to be installed:
119
+
120
+ ```sh
121
+ gem install bundler-audit
122
+ ```
123
+
124
+ If `bundler-audit` is not installed, a warning is displayed but the check continues. The audit database is automatically updated before each check.
125
+
126
+ Example output with vulnerabilities:
127
+
128
+ ```
129
+ OK: rails (7.1.3.2) - satisfies minimum age
130
+
131
+ Checking for vulnerabilities...
132
+ VULNERABLE: actionpack (CVE-2024-1234) - Possible XSS vulnerability
133
+ Solution: upgrade to >= 7.0.8.1
134
+
135
+ 1 vulnerability(ies) found
136
+ ```
137
+
138
+ To skip the audit check, use `--no-audit` or set `audit: false` in config.
139
+
140
+ ### Risk Intelligence
141
+
142
+ Bundle-safe-update analyzes gems for risk signals that may indicate supply chain threats:
143
+
144
+ | Signal | Description | Default Threshold |
145
+ |--------|-------------|-------------------|
146
+ | Low downloads | Gems with very few total downloads | < 1,000 |
147
+ | Stale gem | Gems not updated recently | > 3 years |
148
+ | New owner | Gems with recent ownership changes | Ownership changed since last run |
149
+ | Version jump | Major version bumps | Any major bump |
150
+
151
+ Example output with risk warnings:
152
+
153
+ ```
154
+ OK: rails (7.1.3.2) - satisfies minimum age
155
+
156
+ Risk signals:
157
+ WARNING: tiny-lib (2.0.0) - low downloads (847 total)
158
+ WARNING: old-parser (1.5.0) - stale gem (last release 4.2 years ago)
159
+ BLOCKED: some-gem (5.0.0) - major version jump (was 2.3.1)
160
+
161
+ 1 gem(s) blocked by risk signals
162
+ 2 risk warning(s)
163
+ ```
164
+
165
+ Each signal can be set to `warn` (default), `block`, or `off`:
166
+
167
+ ```yaml
168
+ risk_signals:
169
+ low_downloads:
170
+ mode: warn # off | warn | block
171
+ threshold: 1000 # minimum total downloads
172
+
173
+ stale_gem:
174
+ mode: warn
175
+ threshold_years: 3 # years since last release
176
+
177
+ new_owner:
178
+ mode: block # block on ownership changes
179
+ threshold_days: 90 # (reserved for future use)
180
+
181
+ version_jump:
182
+ mode: warn
183
+ ```
184
+
185
+ Owner changes are detected by caching gem owners locally (`.bundle/bundle-safe-update-cache.yml`). On first run, no warnings are generated - owners are just cached. Subsequent runs detect changes.
186
+
187
+ Use `--refresh-cache` to rebuild the cache without triggering warnings (useful after intentional ownership changes). Use `--no-risk` to skip risk checking entirely.
188
+
189
+ ## Configuration
190
+
191
+ Create `.bundle-safe-update.yml` in your project root or home directory:
192
+
193
+ ```yaml
194
+ # Minimum age in days for gem versions (default: 14)
195
+ cooldown_days: 14
196
+
197
+ # Gems to ignore completely (e.g., internal gems)
198
+ ignore_gems:
199
+ - rails
200
+ - sidekiq
201
+
202
+ # Prefixes to ignore (e.g., company gems)
203
+ ignore_prefixes:
204
+ - mycompany-
205
+ - internal-
206
+
207
+ # Trust gems from specific sources (skip cooldown check)
208
+ # Useful for private gem servers where gems are already vetted
209
+ trusted_sources:
210
+ - gems.mycompany.com
211
+ - gemserver.internal.example.com
212
+
213
+ # Trust gems by RubyGems owner/publisher (skip cooldown check)
214
+ # Useful for well-known publishers like AWS, Google, etc.
215
+ trusted_owners:
216
+ - awscloud # AWS SDK gems
217
+
218
+ # Automatically update gems that pass the cooldown check (default: false)
219
+ update: false
220
+
221
+ # Run vulnerability audit with bundler-audit (default: true)
222
+ audit: true
223
+
224
+ # Report violations but always exit with success (default: false)
225
+ warn_only: false
226
+
227
+ # Enable verbose output
228
+ verbose: false
229
+ ```
230
+
231
+ ### Trusted Sources
232
+
233
+ Gems from trusted sources skip the cooldown check entirely. The source is determined by parsing `Gemfile.lock`. This is useful for:
234
+
235
+ - Private gem servers (Cloudsmith, Gemfury, self-hosted)
236
+ - Internal gems that are already vetted by your organization
237
+
238
+ Example output for trusted gems:
239
+ ```
240
+ OK: mycompany-auth (1.2.0) - trusted source
241
+ ```
242
+
243
+ ### Trusted Owners
244
+
245
+ Gems owned by trusted RubyGems users skip the cooldown check. The owner is fetched from the RubyGems API. This is useful for:
246
+
247
+ - Well-known publishers (AWS, Google, Rails core team, etc.)
248
+ - Organizations with strong security practices
249
+
250
+ Example output for trusted owner gems:
251
+ ```
252
+ OK: aws-sdk-s3 (1.180.0) - trusted owner
253
+ ```
254
+
255
+ To find a gem's owner, visit `https://rubygems.org/gems/{gem_name}` and look at the "Owners" section, or use:
256
+ ```sh
257
+ curl https://rubygems.org/api/v1/gems/{gem_name}/owners.json
258
+ ```
259
+
260
+ ### Config Resolution Order
261
+
262
+ 1. CLI flags (highest priority)
263
+ 2. Project `.bundle-safe-update.yml`
264
+ 3. Home directory `~/.bundle-safe-update.yml`
265
+ 4. Built-in defaults
266
+
267
+ ## Exit Codes
268
+
269
+ | Code | Meaning |
270
+ |------|---------|
271
+ | 0 | All checks passed |
272
+ | 1 | Blocked by cooldown, risk signals, or vulnerabilities |
273
+ | 2 | Unexpected error |
274
+
275
+ ## CI Integration
276
+
277
+ ### AWS CodeBuild
278
+
279
+ ```yaml
280
+ version: 0.2
281
+ phases:
282
+ install:
283
+ commands:
284
+ - gem install bundle-safe-update
285
+ build:
286
+ commands:
287
+ - bundle-safe-update --json
288
+ ```
289
+
290
+ ### GitHub Actions
291
+
292
+ ```yaml
293
+ - name: Check gem versions
294
+ run: |
295
+ gem install bundle-safe-update
296
+ bundle-safe-update --json
297
+ ```
298
+
299
+ ## Development
300
+
301
+ ```sh
302
+ # Install dependencies
303
+ bundle install
304
+
305
+ # Run tests
306
+ bundle exec rspec
307
+
308
+ # Run linter
309
+ bundle exec rubocop
310
+ ```
311
+
312
+ ## License
313
+
314
+ MIT License. See [LICENSE.txt](LICENSE.txt).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'bundle_safe_update'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require 'irb'
11
+ IRB.start(__FILE__)
data/bin/install-hooks ADDED
@@ -0,0 +1,42 @@
1
+ #!/bin/bash
2
+ # Install git hooks for bundle-safe-update development
3
+
4
+ set -e
5
+
6
+ HOOKS_DIR=".git/hooks"
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
9
+
10
+ if [ ! -d "$PROJECT_DIR/.git" ]; then
11
+ echo "Error: Not a git repository"
12
+ exit 1
13
+ fi
14
+
15
+ # Create post-commit hook
16
+ cat > "$HOOKS_DIR/post-commit" << 'EOF'
17
+ #!/bin/bash
18
+ # Auto-tag when version.rb changes
19
+
20
+ VERSION_FILE="lib/bundle_safe_update/version.rb"
21
+
22
+ # Check if version.rb was in the commit
23
+ if git diff-tree --no-commit-id --name-only -r HEAD | grep -q "$VERSION_FILE"; then
24
+ VERSION=$(grep -o "VERSION = '[^']*'" "$VERSION_FILE" | cut -d"'" -f2)
25
+ TAG="v$VERSION"
26
+
27
+ if [ -z "$VERSION" ]; then
28
+ echo "Warning: Could not extract version from $VERSION_FILE"
29
+ exit 0
30
+ fi
31
+
32
+ if ! git tag | grep -q "^$TAG$"; then
33
+ git tag "$TAG"
34
+ git push origin "$TAG"
35
+ echo "Tagged and pushed $TAG"
36
+ fi
37
+ fi
38
+ EOF
39
+
40
+ chmod +x "$HOOKS_DIR/post-commit"
41
+
42
+ echo "Installed post-commit hook"
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/bundle_safe_update/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'bundle-safe-update'
7
+ spec.version = BundleSafeUpdate::VERSION
8
+ spec.authors = ['Denis Sablic']
9
+ spec.email = ['denis.sablic@gmail.com']
10
+
11
+ spec.summary = 'Enforce minimum release age for Ruby gems during updates'
12
+ spec.description = 'A CLI tool that prevents installation of gem versions ' \
13
+ 'that are too new (e.g., <14 days old), helping protect ' \
14
+ 'against supply chain attacks.'
15
+ spec.homepage = 'https://github.com/dsablic/bundle-safe-update'
16
+ spec.license = 'MIT'
17
+ spec.required_ruby_version = '>= 3.2.0'
18
+ spec.metadata['rubygems_mfa_required'] = 'true'
19
+ spec.metadata['source_code_uri'] = 'https://github.com/dsablic/bundle-safe-update'
20
+ spec.metadata['changelog_uri'] = 'https://github.com/dsablic/bundle-safe-update/releases'
21
+
22
+ spec.files = Dir.chdir(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ f.start_with?('spec/', '.git', '.rspec', '.rubocop', 'TODO.md')
25
+ end
26
+ end
27
+ spec.bindir = 'exe'
28
+ spec.executables = ['bundle-safe-update']
29
+ spec.require_paths = ['lib']
30
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundle_safe_update'
5
+
6
+ exit(BundleSafeUpdate::CLI.run(ARGV))