Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,8 @@ def npm_lockfile_updater_for(file)
lockfile: file,
dependencies: dependencies,
dependency_files: dependency_files,
credentials: credentials
credentials: credentials,
security_updates_only: options.fetch(:security_updates_only, false)
)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ class NpmLockfileUpdater
lockfile: Dependabot::DependencyFile,
dependencies: T::Array[Dependabot::Dependency],
dependency_files: T::Array[Dependabot::DependencyFile],
credentials: T::Array[Credential]
credentials: T::Array[Credential],
security_updates_only: T::Boolean
)
.void
end
def initialize(lockfile:, dependencies:, dependency_files:, credentials:)
def initialize(lockfile:, dependencies:, dependency_files:, credentials:, security_updates_only: false)
@lockfile = lockfile
@dependencies = dependencies
@dependency_files = dependency_files
@credentials = credentials
@security_updates_only = T.let(security_updates_only, T::Boolean)
end

sig { returns(Dependabot::DependencyFile) }
Expand Down Expand Up @@ -72,6 +74,11 @@ def updated_lockfile_reponse(response)
sig { returns(T::Array[Credential]) }
attr_reader :credentials

sig { returns(T::Boolean) }
def security_updates_only?
@security_updates_only
end

UNREACHABLE_GIT = /fatal: repository '(?<url>.*)' not found/
FORBIDDEN_GIT = /fatal: Authentication failed for '(?<url>.*)'/
FORBIDDEN_PACKAGE = %r{(?<package_req>[^/]+) - (Forbidden|Unauthorized)}
Expand Down Expand Up @@ -394,6 +401,9 @@ def run_npm_install_lockfile_only(install_args = [], has_optional_dependencies:
]

command_args << "--save-optional" if has_optional_dependencies
# Override any min-release-age set in .npmrc: security fixes must not be
# blocked by a release-age gate the user configured for regular updates.
command_args << "--min-release-age=0" if security_updates_only?

command = command_args.join(" ")

Expand All @@ -406,6 +416,7 @@ def run_npm_install_lockfile_only(install_args = [], has_optional_dependencies:
]

fingerprint_args << "--save-optional" if has_optional_dependencies
fingerprint_args << "--min-release-age=0" if security_updates_only?

fingerprint = fingerprint_args.join(" ")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,46 @@
end
end

describe "#run_npm_install_lockfile_only" do
let(:files) { project_dependency_files("npm8/simple") }
let(:install_args) { ["lodash@4.18.1"] }

context "when security_updates_only is true" do
let(:updater) do
described_class.new(
lockfile: package_lock,
dependency_files: files,
dependencies: dependencies,
credentials: credentials,
security_updates_only: true
)
end

it "passes --min-release-age=0 to override the .npmrc setting" do
expect(Dependabot::NpmAndYarn::Helpers).to receive(:run_npm_command) do |command, _options|
expect(command).to include("--min-release-age=0")
expect(command).to include("--package-lock-only")
expect(command).to include("--force")
""
end

updater.send(:run_npm_install_lockfile_only, install_args)
end
end

context "when security_updates_only is false (default)" do
it "does not pass --min-release-age=0" do
expect(Dependabot::NpmAndYarn::Helpers).to receive(:run_npm_command) do |command, _options|
expect(command).not_to include("--min-release-age=0")
expect(command).to include("--package-lock-only")
""
end

updater.send(:run_npm_install_lockfile_only, install_args)
end
end
end

describe "#optional_dependency?" do
it "correctly identifies optional dependencies" do
optional_dep = Dependabot::Dependency.new(
Expand Down
2 changes: 1 addition & 1 deletion updater/lib/dependabot/dependency_change_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def file_updater_for(dependencies)
dependency_files: dependency_files,
repo_contents_path: job.repo_contents_path,
credentials: job.credentials,
options: job.experiments
options: job.experiments.merge(security_updates_only: job.security_updates_only?)
)
end
end
Expand Down
35 changes: 35 additions & 0 deletions updater/spec/dependabot/dependency_change_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
}
],
experiments: {},
security_updates_only?: false,
source: source
)
end
Expand Down Expand Up @@ -125,6 +126,40 @@ def dependency_group_source
Dependabot::DependencyGroup.new(name: "dummy-pkg-*", rules: { patterns: ["dummy-pkg-*"] })
end

context "when the job is a security update" do
let(:change_source) { lead_dependency_change_source }

before do
allow(job).to receive(:security_updates_only?).and_return(true)
stub_file_updater(updated_dependency_files: dependency_files.reject(&:support_file?))
end

it "passes security_updates_only: true in options to the file updater" do
create_change

expect(file_updater_class).to have_received(:new).with(
hash_including(options: hash_including(security_updates_only: true))
)
end
end

context "when the job is not a security update" do
let(:change_source) { lead_dependency_change_source }

before do
allow(job).to receive(:security_updates_only?).and_return(false)
stub_file_updater(updated_dependency_files: dependency_files.reject(&:support_file?))
end

it "passes security_updates_only: false in options to the file updater" do
create_change

expect(file_updater_class).to have_received(:new).with(
hash_including(options: hash_including(security_updates_only: false))
)
end
end

context "when the source is a lead dependency" do
let(:change_source) { lead_dependency_change_source }

Expand Down
4 changes: 2 additions & 2 deletions updater/spec/dependabot/updater_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ def expect_update_checker_with_ignored_versions(versions, dependency_matcher: an
dependency_files: default_dependency_files,
repo_contents_path: nil,
credentials: anything,
options: { cloning: true }
options: hash_including(cloning: true)
).and_call_original

expect(service).to receive(:create_pull_request).once
Expand Down Expand Up @@ -2165,7 +2165,7 @@ def expect_update_checker_with_ignored_versions(versions, dependency_matcher: an
],
repo_contents_path: nil,
credentials: anything,
options: { large_hadron_collider: true }
options: hash_including(large_hadron_collider: true)
).and_call_original

updater.run
Expand Down
Loading