diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e7728d..90f7ad15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## main (unreleased) +* Add an opt-in `update` option to `BundleAudit` to refresh ruby-advisory-db before checking (#812). + * Include command file contents in hook signatures when an absolute path is configured. * Add a configurable `Vale` pre-commit hook to check spelling and style in text and source files (#758). diff --git a/config/default.yml b/config/default.yml index fd94358c..27527163 100644 --- a/config/default.yml +++ b/config/default.yml @@ -169,6 +169,7 @@ PreCommit: description: 'Check for vulnerable versions of gems' required_executable: 'bundle-audit' install_command: 'gem install bundler-audit' + update: false # Update ruby-advisory-db before checking for vulnerabilities BundleCheck: enabled: false diff --git a/lib/overcommit/hook/pre_commit/bundle_audit.rb b/lib/overcommit/hook/pre_commit/bundle_audit.rb index 1f9f24c7..5446ac29 100644 --- a/lib/overcommit/hook/pre_commit/bundle_audit.rb +++ b/lib/overcommit/hook/pre_commit/bundle_audit.rb @@ -3,6 +3,8 @@ module Overcommit::Hook::PreCommit # Checks for vulnerable versions of gems in Gemfile.lock. # + # Set `update: true` to refresh ruby-advisory-db before checking. Defaults to false. + # # @see https://github.com/rubysec/bundler-audit class BundleAudit < Base LOCK_FILE = 'Gemfile.lock' @@ -13,7 +15,10 @@ def run stdout.split("\n") return :pass if ignored_files.include?(LOCK_FILE) - result = execute(command) + audit_command = command + audit_command << '--update' if config['update'] + + result = execute(audit_command) if result.success? :pass else diff --git a/spec/overcommit/hook/pre_commit/bundle_audit_spec.rb b/spec/overcommit/hook/pre_commit/bundle_audit_spec.rb index b8360e2e..1e04e30f 100644 --- a/spec/overcommit/hook/pre_commit/bundle_audit_spec.rb +++ b/spec/overcommit/hook/pre_commit/bundle_audit_spec.rb @@ -3,10 +3,19 @@ require 'spec_helper' describe Overcommit::Hook::PreCommit::BundleAudit do - let(:config) { Overcommit::ConfigurationLoader.default_configuration } + let(:config) do + Overcommit::ConfigurationLoader.default_configuration.merge( + Overcommit::Configuration.new('PreCommit' => { 'BundleAudit' => hook_config }) + ) + end + let(:hook_config) { {} } let(:context) { double('context') } subject { described_class.new(config, context) } + it 'defaults to not updating the advisory database' do + subject.config['update'].should == false + end + context 'when Gemfile.lock is ignored' do around do |example| repo do @@ -19,9 +28,22 @@ end it { should pass } + + context 'when updating the advisory database is enabled' do + let(:hook_config) { { 'update' => true } } + + before do + subject.stub(:execute).and_call_original + subject.should_not_receive(:execute).with(%w[bundle-audit --update]) + end + + it { should pass } + end end context 'when Gemfile.lock is not ignored' do + let(:audit_command) { %w[bundle-audit] } + around do |example| repo do example.run @@ -31,7 +53,7 @@ before do subject.stub(:execute).with(%w[git ls-files -o -i --exclude-standard -- Gemfile.lock]). and_return(double(stdout: '')) - subject.stub(:execute).with(%w[bundle-audit]).and_return(result) + subject.stub(:execute).with(audit_command).and_return(result) end context 'and it reports some outdated gems' do @@ -73,6 +95,30 @@ it { should warn } + context 'when updating the advisory database is enabled' do + let(:audit_command) { %w[bundle-audit --update] } + let(:hook_config) { { 'update' => true } } + + it { should warn(result.stdout) } + + context 'and no vulnerabilities are found' do + let(:result) { double(success?: true, stdout: 'No vulnerabilities found') } + + it { should pass } + end + + context 'with a custom command and flags' do + let(:audit_command) { %w[bundle exec bundle-audit check --ignore CVE-2020-12345 --update] } + + let(:hook_config) do + super().merge('command' => %w[bundle exec bundle-audit], + 'flags' => %w[check --ignore CVE-2020-12345]) + end + + it { should warn(result.stdout) } + end + end + context 'and it reports bundle up to date' do let(:result) do double(success?: true, stdout: 'No vulnerabilities found')