Skip to content

Commit

Permalink
NPM: fix security update for indirect and direct dependencies (#10371)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakecoffman committed Aug 7, 2024
1 parent 1cdce62 commit 4aac28c
Show file tree
Hide file tree
Showing 5 changed files with 11,875 additions and 1 deletion.
5 changes: 4 additions & 1 deletion npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def latest_resolvable_version
end

def lowest_security_fix_version
# This will require a full unlock to update multiple top level ancestors.
return if vulnerability_audit["fix_available"] && vulnerability_audit["top_level_ancestors"].count > 1

latest_version_finder.lowest_security_fix_version
end

Expand Down Expand Up @@ -183,7 +186,7 @@ def latest_version_resolvable_with_full_unlock?
end

def updated_dependencies_after_full_unlock
return conflicting_updated_dependencies if !dependency.top_level? && security_advisories.any?
return conflicting_updated_dependencies if security_advisories.any? && vulnerability_audit["fix_available"]

version_resolver.dependency_updates_from_full_unlock
.map { |update_details| build_updated_dependency(update_details) }
Expand Down
67 changes: 67 additions & 0 deletions npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,26 @@
expect(lowest_security_fix).to eq(Gem::Version.new("1.2.1"))
end
end

context "when the VulnerabilityAudit finds multiple top-level ancestors" do
let(:vulnerability_auditor) do
instance_double(described_class::VulnerabilityAuditor)
end

before do
allow(described_class::VulnerabilityAuditor).to receive(:new).and_return(vulnerability_auditor)
allow(vulnerability_auditor).to receive(:audit).and_return(
{
"fix_available" => true,
"top_level_ancestors" => %w(applause lodash)
}
)
end

it "returns nil to force a full unlock" do
expect(lowest_security_fix).to be_nil
end
end
end

describe "#latest_resolvable_version" do
Expand Down Expand Up @@ -1405,6 +1425,53 @@ def eq_including_metadata(expected_array)
eq(expected_array).and contain_exactly_including_metadata(*expected_array)
end

context "when a top-level dependency and a transitive dependency both need updating" do
let(:dependency_files) { project_dependency_files("npm8/top_level_and_transitive") }
let(:registry_listing_url) { "https://registry.npmjs.org/top-level-and-transitive" }
let(:security_advisories) do
[
Dependabot::SecurityAdvisory.new(
dependency_name: "lodash",
package_manager: "npm_and_yarn",
vulnerable_versions: ["< 4.17.21"]
)
]
end
let(:dependency_version) { "3.10.0" }
let(:dependency) do
Dependabot::Dependency.new(
name: "lodash",
version: dependency_version,
requirements: [{
file: "package.json",
requirement: "^3.10.0",
groups: ["dependencies"],
source: {
type: "registry",
url: "https://registry.npmjs.org"
}
}],
package_manager: "npm_and_yarn"
)
end

before do
stub_request(:get, "https://registry.npmjs.org/lodash")
.and_return(status: 200, body: fixture("npm_responses", "lodash.json"))
stub_request(:head, "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz")
.and_return(status: 200)
end

it "correctly selects both top-level and parent of transitive" do
updated_dependencies = checker.send(:updated_dependencies_after_full_unlock)
expect(updated_dependencies.count).to eq(2)
expect(updated_dependencies.first.name).to eq("lodash")
expect(updated_dependencies.first.version).to eq("4.17.21")
expect(updated_dependencies.last.name).to eq("applause")
expect(updated_dependencies.last.version).to eq("2.0.4")
end
end

context "when dealing with a security update for a locked transitive dependency" do
let(:dependency_files) { project_dependency_files("npm8/locked_transitive_dependency") }
let(:registry_listing_url) { "https://registry.npmjs.org/locked-transitive-dependency" }
Expand Down
Loading

0 comments on commit 4aac28c

Please sign in to comment.