From 89dfc8f7ae2bb536622f55fadf849ebc157a0b0d Mon Sep 17 00:00:00 2001 From: jleo3 Date: Tue, 18 Aug 2026 16:25:55 -0400 Subject: [PATCH] Add bundler-audit to the local gate and CI (herb-embedded-fa6) guides.rubygems.org/security recommends running bundler-audit against ruby-advisory-db in CI: it catches "the exact versions currently pinned in Gemfile.lock have a known CVE" the moment they land, a different signal from Dependabot's weekly "a newer version exists" check. Wires Bundler::Audit::Task (the gem's own Rake::TaskLib, matching how RSpec::Core::RakeTask/RuboCop::RakeTask are already used) into the default rake task. Local runs use bundle:audit (check only, auto-clones the advisory db if missing but doesn't force-refresh an existing clone, to avoid requiring network access on every bundle exec rake). CI explicitly runs bundle:audit:update before bundle:audit:check, so it never checks against a stale snapshot regardless of what a prior run left behind. Verified against the current Gemfile.lock: no vulnerabilities found, both via a fresh database pull (1233 advisories) and the cached local check. --- .github/workflows/ci.yml | 3 +++ Gemfile | 1 + Gemfile.lock | 7 +++++++ Rakefile | 11 ++++++++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af77ccb..bc5f7ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,9 @@ jobs: - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: { bundler-cache: true } + # update: refresh the local ruby-advisory-db clone first so check + # never runs against a stale snapshot cached from a prior run. + - run: bundle exec rake bundle:audit:update bundle:audit:check # Node present ONLY to build the bundle and run conformance reference - uses: actions/setup-node@v4 with: { node-version: "22" } diff --git a/Gemfile b/Gemfile index 29e4898..f9e977b 100644 --- a/Gemfile +++ b/Gemfile @@ -7,6 +7,7 @@ ruby file: ".ruby-version" gemspec group :development do + gem "bundler-audit", require: false gem "rake", "13.4.2" gem "rspec", "3.13.2" gem "rubocop", require: false diff --git a/Gemfile.lock b/Gemfile.lock index fa84a5e..16dbef3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,6 +9,9 @@ GEM remote: https://rubygems.org/ specs: ast (2.4.3) + bundler-audit (0.9.3) + bundler (>= 1.2.0) + thor (~> 1.0) diff-lcs (1.6.2) herb (0.10.3) herb (0.10.3-aarch64-linux-gnu) @@ -73,6 +76,7 @@ GEM regexp_parser (>= 2.0) rubocop (~> 1.86, >= 1.86.2) ruby-progressbar (1.13.0) + thor (1.5.0) unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.2.0) @@ -87,6 +91,7 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES + bundler-audit herb-embedded! rake (= 13.4.2) rspec (= 3.13.2) @@ -97,6 +102,7 @@ DEPENDENCIES CHECKSUMS ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 bundler (4.0.16) sha256=d6ca5dd440c24f9abce9844cf44cc8e18c6a553de65a47efb4544137af92c47d + bundler-audit (0.9.3) sha256=81c8766c71e47d0d28a0f98c7eed028539f21a6ea3cd8f685eb6f42333c9b4e9 diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962 herb (0.10.3) sha256=da76e8bfbb302586ee51a4fb608624f48218fbfea198a9493540b42f7654024b herb (0.10.3-aarch64-linux-gnu) sha256=1eaea87e6577557492a1b0ddaae989fba8a8ddd382e888ee5f939ce6ded06eb8 @@ -134,6 +140,7 @@ CHECKSUMS rubocop-rake (0.7.1) sha256=3797f2b6810c3e9df7376c26d5f44f3475eda59eb1adc38e6f62ecf027cbae4d rubocop-rspec (3.10.2) sha256=0b3e2ecc592cd10ecbf0095bb58d1e357905276e069643523cc19eb7495f65e2 ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 + thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73 unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42 unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f diff --git a/Rakefile b/Rakefile index 971d985..9a3bc13 100644 --- a/Rakefile +++ b/Rakefile @@ -1,10 +1,19 @@ # frozen_string_literal: true require "bundler/gem_tasks" +require "bundler/audit/task" require "rspec/core/rake_task" require "rubocop/rake_task" RSpec::Core::RakeTask.new(:spec) RuboCop::RakeTask.new +Bundler::Audit::Task.new -task default: %i[rubocop spec] +# bundle:audit only checks against whatever local ruby-advisory-db clone it +# finds (cloning it fresh if missing, but not refreshing an existing one) — +# see guides.rubygems.org/security. CI always refreshes it explicitly +# (bundle:audit:update, see .github/workflows/ci.yml) so that check never +# runs against a stale snapshot there; a local clone only goes stale between +# `bundle exec rake bundle:audit:update` runs, which is an acceptable +# trade-off against forcing network access on every local `rake` invocation. +task default: %i[rubocop spec bundle:audit]