require 'bundler' require 'shellwords' require 'tmpdir'
namespace :deploy do
namespace :check do desc "Audit the Gemfile.lock for known vulnerabilities" task :bundle_audit do on primary(:app), in: :sequence do |host| # Download the relevant files and run bundle-audit on them locally Dir.mktmpdir do |dir| Dir.chdir dir do download! "#{release_path}/Gemfile.lock", "Gemfile.lock" run_locally do capture %(echo 'gem "bundler-audit"' > Gemfile) bundle_audit_output = Bundler.with_clean_env do capture "bundle-audit check --update #{"--ignore #{Shellwords.join(fetch(:bundle_audit_ignore))}" unless fetch(:bundle_audit_ignore).empty? }" end # bundle-audit includes failures for both gem vulnerabilities # and insecure gem sources, and offers no way to distinguish those cases. # unfortunately, we only want to fail when vulnerable gems are required. # This should only fail if there is a bundle-audit output AND it has # a solution available to upgrade. If no solution is available deploy # will still be allowed. if bundle_audit_output =~ /Solution: upgrade to/ warn bundle_audit_output fail "Bundle audit failed; update your vulnerable dependencies before deploying" else debug bundle_audit_output info bundle_audit_output.split("\n").last end end end end end end end after 'bundler:install', 'deploy:check:bundle_audit' unless ENV['SKIP_BUNDLE_AUDIT']
end
namespace :load do
task :defaults do set :bundle_audit_ignore, %W{#{ENV['BUNDLE_AUDIT_IGNORES']}} set :skip_bundle_audit, !!ENV['SKIP_BUNDLE_AUDIT'] end
end