diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb index 0c5ff421f8d..502a7d886a7 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/vulnerability_auditor.rb @@ -106,6 +106,8 @@ def explain_fix_unavailable(validation_result, dependency) case validation_result when :fix_unavailable, :dependency_still_vulnerable, :downgrades_dependencies "No patched version available for #{dependency.name}" + when :fix_incomplete + "The lockfile might be out of sync?" when :vulnerable_dependency_removed "#{dependency.name} was removed in the update. Dependabot is not able to " \ "deal with this yet, but you can still upgrade manually." @@ -117,6 +119,7 @@ def validate_audit_result(audit_result, security_advisories) return :vulnerable_dependency_removed if !@allow_removal && vulnerable_dependency_removed?(audit_result) return :dependency_still_vulnerable if dependency_still_vulnerable?(audit_result, security_advisories) return :downgrades_dependencies if downgrades_dependencies?(audit_result) + return :fix_incomplete if fix_incomplete?(audit_result) :viable end @@ -149,6 +152,11 @@ def downgrades_version?(current_version, target_version) current > target end + def fix_incomplete?(audit_result) + audit_result["fix_updates"].any? { |update| !update.key?("target_version") } || + audit_result["fix_updates"].empty? + end + def log_helper_subprocess_failure(dependency, error) # See `Dependabot::SharedHelpers.run_helper_subprocess` for details on error context context = error.error_context || {} diff --git a/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/vulnerability_auditor_spec.rb b/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/vulnerability_auditor_spec.rb index ebc6fe1633e..31f69bbfe85 100644 --- a/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/vulnerability_auditor_spec.rb +++ b/npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/vulnerability_auditor_spec.rb @@ -231,6 +231,28 @@ end end + context "when the vulnerability only exists in an out of date lockfile" do + let(:dependency_files) { project_dependency_files("npm8/locked_transitive_dependency_outdated") } + + it "logs fix_incomplete and returns fix_available => false" do + security_advisories = [ + Dependabot::SecurityAdvisory.new( + dependency_name: dependency.name, + package_manager: "npm_and_yarn", + vulnerable_versions: ["<1.0.1"], + safe_versions: ["1.0.1"] + ) + ] + + expect(Dependabot.logger).to receive(:info).with(/audit result not viable: fix_incomplete/i) + expect(subject.audit(dependency: dependency, security_advisories: security_advisories)). + to include( + "fix_available" => false, + "explanation" => "The lockfile might be out of sync?" + ) + end + end + context "in a project with no lockfile" do let(:dependency_files) { project_dependency_files("npm6/no_lockfile") } diff --git a/npm_and_yarn/spec/fixtures/projects/npm8/locked_transitive_dependency_outdated/package-lock.json b/npm_and_yarn/spec/fixtures/projects/npm8/locked_transitive_dependency_outdated/package-lock.json new file mode 100644 index 00000000000..eb679fbce62 --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/npm8/locked_transitive_dependency_outdated/package-lock.json @@ -0,0 +1,60 @@ +{ + "name": "locked-transitive-dependency-outdated", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "locked-transitive-dependency-outdated", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@dependabot-fixtures/npm-parent-dependency": "2.0.0" + } + }, + "node_modules/@dependabot-fixtures/npm-intermediate-dependency": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-intermediate-dependency/-/npm-intermediate-dependency-0.0.1.tgz", + "integrity": "sha512-/N77Dzpfg8BIfFgpJrMk86ueUYTVhmpc4RobuHpIpKSc3GZr4Ltu4au92brnUGk66UkzgrMmtgqRXO8OrOspKQ==", + "dependencies": { + "@dependabot-fixtures/npm-transitive-dependency": "1.0.0" + } + }, + "node_modules/@dependabot-fixtures/npm-parent-dependency": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-parent-dependency/-/npm-parent-dependency-2.0.0.tgz", + "integrity": "sha512-5LtLEL1yzO2TdkNX3R9cvr+nKmhw5h4xM0wkFTJeK14wxlI9d8gEYA+I2hUi+IP96ucBSztAnOgZVwoJHEZb6A==", + "dependencies": { + "@dependabot-fixtures/npm-intermediate-dependency": "0.0.1" + } + }, + "node_modules/@dependabot-fixtures/npm-transitive-dependency": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-transitive-dependency/-/npm-transitive-dependency-1.0.0.tgz", + "integrity": "sha512-nFbzQH0TRgdzSA2/FH6MPnxZDpD+5Bgz00aD5Edgbc1wY/k8VC9s7lnk22dBTgJLwoY7MgbrnAf9rAvN08hHVg==" + } + }, + "dependencies": { + "@dependabot-fixtures/npm-intermediate-dependency": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-intermediate-dependency/-/npm-intermediate-dependency-0.0.1.tgz", + "integrity": "sha512-/N77Dzpfg8BIfFgpJrMk86ueUYTVhmpc4RobuHpIpKSc3GZr4Ltu4au92brnUGk66UkzgrMmtgqRXO8OrOspKQ==", + "requires": { + "@dependabot-fixtures/npm-transitive-dependency": "1.0.0" + } + }, + "@dependabot-fixtures/npm-parent-dependency": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-parent-dependency/-/npm-parent-dependency-2.0.0.tgz", + "integrity": "sha512-5LtLEL1yzO2TdkNX3R9cvr+nKmhw5h4xM0wkFTJeK14wxlI9d8gEYA+I2hUi+IP96ucBSztAnOgZVwoJHEZb6A==", + "requires": { + "@dependabot-fixtures/npm-intermediate-dependency": "0.0.1" + } + }, + "@dependabot-fixtures/npm-transitive-dependency": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@dependabot-fixtures/npm-transitive-dependency/-/npm-transitive-dependency-1.0.0.tgz", + "integrity": "sha512-nFbzQH0TRgdzSA2/FH6MPnxZDpD+5Bgz00aD5Edgbc1wY/k8VC9s7lnk22dBTgJLwoY7MgbrnAf9rAvN08hHVg==" + } + } +} diff --git a/npm_and_yarn/spec/fixtures/projects/npm8/locked_transitive_dependency_outdated/package.json b/npm_and_yarn/spec/fixtures/projects/npm8/locked_transitive_dependency_outdated/package.json new file mode 100644 index 00000000000..2bdb5741d9f --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/npm8/locked_transitive_dependency_outdated/package.json @@ -0,0 +1,14 @@ +{ + "name": "locked-transitive-dependency-outdated", + "version": "1.0.0", + "description": "test fixture where the lockfile contains a vulnerability but it's not in sync with this file", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + } +}