Skip to content

Commit

Permalink
Raise unsupported error when package manager is not supported before …
Browse files Browse the repository at this point in the history
…update starting update process (#10794)

* Raise unsupported error when package manager is not supported before update starting update process
---------

Co-authored-by: Kamil Bukum <kbukum1@github.com>
  • Loading branch information
jakecoffman and kbukum1 authored Oct 15, 2024
1 parent 5751b3d commit 7f120c2
Show file tree
Hide file tree
Showing 15 changed files with 197 additions and 43 deletions.
15 changes: 15 additions & 0 deletions silent/lib/dependabot/silent/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
require "dependabot/dependency"
require "dependabot/file_parsers"
require "dependabot/file_parsers/base"
require "dependabot/package_manager"
require "dependabot/silent/package_manager"
require "sorbet-runtime"

module SilentPackageManager
Expand All @@ -26,6 +28,19 @@ def parse
raise Dependabot::DependencyFileNotParseable, T.must(dependency_files.first).path
end

sig { returns(Dependabot::PackageManagerBase) }
def package_manager
meta_data = JSON.parse(manifest_content)["silent"]
silent_version = if meta_data.nil?
"2"
else
meta_data["version"]
end
Dependabot::Silent::PackageManager.new(silent_version)
rescue JSON::ParserError
raise Dependabot::DependencyFileNotParseable, T.must(dependency_files.first).path
end

private

sig { params(name: String, info: String).returns(Dependabot::Dependency) }
Expand Down
45 changes: 45 additions & 0 deletions silent/lib/dependabot/silent/package_manager.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# typed: strong
# frozen_string_literal: true

require "sorbet-runtime"
require "dependabot/silent/version"
require "dependabot/package_manager"

module Dependabot
module Silent
PACKAGE_MANAGER = "silent"

SUPPORTED_SILENT_VERSIONS = T.let([Version.new("2")].freeze, T::Array[Dependabot::Version])
DEPRECATED_SILENT_VERSIONS = T.let([Version.new("1")].freeze, T::Array[Dependabot::Version])

class PackageManager < PackageManagerBase
extend T::Sig

sig { params(version: T.any(String, Dependabot::Version)).void }
def initialize(version)
@version = T.let(Version.new(version), Dependabot::Version)
@name = T.let(PACKAGE_MANAGER, String)
@deprecated_versions = T.let(DEPRECATED_SILENT_VERSIONS, T::Array[Dependabot::Version])
@supported_versions = T.let(SUPPORTED_SILENT_VERSIONS, T::Array[Dependabot::Version])
end

sig { override.returns(String) }
attr_reader :name

sig { override.returns(Dependabot::Version) }
attr_reader :version

sig { override.returns(T::Array[Dependabot::Version]) }
attr_reader :deprecated_versions

sig { override.returns(T::Array[Dependabot::Version]) }
attr_reader :supported_versions

sig { override.returns(T::Boolean) }
def unsupported?
# Check if the version is not supported
supported_versions.all? { |supported| supported > version }
end
end
end
end
22 changes: 22 additions & 0 deletions silent/tests/testdata/vu-unsupported.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
! dependabot update -f input.yml --local . --updater-image ghcr.io/dependabot/dependabot-updater-silent
! stderr 'created \| dependency-a \( from 1.2.3 to 1.2.5 \)'
! pr-created expected.json
stderr 'Currently, the following silent versions are supported in Dependabot: v2\.*\.'
stdout {"data":{"error-type":"tool_version_not_supported","error-details":{"detected-version":"1","supported-versions":"v2.*","tool-name":"silent"}},"type":"record_update_job_error"}


-- manifest.json --
{
"silent": { "version": "1" },
"dependency-a": { "version": "1.2.3" }
}

-- input.yml --
job:
package-manager: "silent"
source:
directory: "/"
provider: example
hostname: example.com
api-endpoint: https://example.com/api/v3
repo: dependabot/smoke-tests
4 changes: 3 additions & 1 deletion updater/lib/dependabot/dependency_snapshot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,10 @@ def dependency_file_parser
reject_external_code: job.reject_external_code?,
options: job.experiments
)
# Add 'package_manager' to the depedency_snapshopt to use it in operations'
# Add 'package_manager' to the dependency_snapshot to use it in operations
package_manager = parser.package_manager
# Raise an error if the package manager version is unsupported
package_manager&.raise_if_unsupported!

@package_manager[@current_directory] = package_manager

Expand Down
14 changes: 12 additions & 2 deletions updater/lib/dependabot/update_files_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def base_commit_sha
Environment.job_definition["base_commit_sha"]
end

# rubocop:disable Metrics/AbcSize, Layout/LineLength
# rubocop:disable Metrics/AbcSize, Layout/LineLength, Metrics/MethodLength
def handle_parser_error(error)
# This happens if the repo gets removed after a job gets kicked off.
# The service will handle the removal without any prompt from the updater,
Expand All @@ -80,6 +80,16 @@ def handle_parser_error(error)
# Check if the error is a known "run halting" state we should handle
if (error_type = Updater::ErrorHandler::RUN_HALTING_ERRORS[error.class])
{ "error-type": error_type }
elsif error.is_a?(ToolVersionNotSupported)
Dependabot.logger.error(error.message)
{
"error-type": "tool_version_not_supported",
"error-detail": {
"tool-name": error.tool_name,
"detected-version": error.detected_version,
"supported-versions": error.supported_versions
}
}
else
# If it isn't, then log all the details and let the application error
# tracker know about it
Expand Down Expand Up @@ -118,6 +128,6 @@ def handle_parser_error(error)
error_details: error_details[:"error-detail"]
)
end
# rubocop:enable Metrics/AbcSize, Layout/LineLength
# rubocop:enable Metrics/AbcSize, Layout/LineLength, Metrics/MethodLength
end
end
3 changes: 0 additions & 3 deletions updater/lib/dependabot/updater/group_update_creation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,6 @@ def compile_updates_for(dependency, dependency_files, group) # rubocop:disable M
return []
end

# Raise an error if the package manager version is unsupported
dependency_snapshot.package_manager&.raise_if_unsupported!

checker.updated_dependencies(
requirements_to_unlock: requirements_to_unlock
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ def check_and_create_pr_with_error_handling(dependency)
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/CyclomaticComplexity
sig { params(dependency: Dependabot::Dependency).void }
def check_and_create_pull_request(dependency)
dependency = vulnerable_version(dependency) if dependency.metadata[:all_versions]
Expand Down Expand Up @@ -146,9 +145,6 @@ def check_and_create_pull_request(dependency)
log_requirements_for_update(requirements_to_unlock, checker)
return record_security_update_not_possible_error(checker) if requirements_to_unlock == :update_not_possible

# Raise an error if the package manager version is unsupported
dependency_snapshot.package_manager&.raise_if_unsupported!

updated_deps = checker.updated_dependencies(
requirements_to_unlock: requirements_to_unlock
)
Expand Down Expand Up @@ -202,7 +198,6 @@ def check_and_create_pull_request(dependency)
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/CyclomaticComplexity
sig { params(dependency: Dependabot::Dependency).returns(Dependabot::Dependency) }
def vulnerable_version(dependency)
return dependency if dependency.metadata[:all_versions].count == 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ def perform
Dependabot.logger.info("Starting update job for #{job.source.repo}")
Dependabot.logger.info("Checking and updating security pull requests...")

# Raise an error if the package manager version is unsupported
dependency_snapshot.package_manager&.raise_if_unsupported!

# Retrieve the list of initial notices from dependency snapshot
@notices = dependency_snapshot.notices
# More notices can be added during the update process
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,6 @@ def check_and_update_pull_request(dependencies)
return close_pull_request(reason: :update_no_longer_possible)
end

# Raise an error if the package manager version is unsupported
dependency_snapshot.package_manager&.raise_if_unsupported!

updated_deps = checker.updated_dependencies(
requirements_to_unlock: requirements_to_unlock
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,6 @@ def check_and_create_pull_request(dependency)
notices: @notices
)

# Raise an error if the package manager version is unsupported
dependency_snapshot.package_manager&.raise_if_unsupported!

if dependency_change.updated_dependency_files.empty?
raise "UpdateChecker found viable dependencies to be updated, but FileUpdater failed to update any files"
end
Expand Down
49 changes: 49 additions & 0 deletions updater/spec/dependabot/dependency_snapshot_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@
]
end

let(:dependency_files_for_unsupported) do
[
Dependabot::DependencyFile.new(
name: "Gemfile",
content: fixture("bundler/unsupported/Gemfile"),
directory: directory
),
Dependabot::DependencyFile.new(
name: "Gemfile.lock",
content: fixture("bundler/unsupported/Gemfile.lock"),
directory: directory
)
]
end

let(:dependency_groups) do
[
{
Expand All @@ -84,6 +99,21 @@
"mock-sha"
end

let(:unsupported_error_enabled) { false }

before do
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:bundler_v1_unsupported_error)
.and_return(unsupported_error_enabled)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:add_deprecation_warn_to_pr_message)
.and_return(true)
end

after do
Dependabot::Experiments.reset!
end

describe "::add_handled_dependencies" do
subject(:create_dependency_snapshot) do
described_class.create_from_job_definition(
Expand All @@ -92,6 +122,8 @@
)
end

let(:unsupported_error_enabled) { false }

let(:job_definition) do
{
"base_commit_sha" => base_commit_sha,
Expand Down Expand Up @@ -148,6 +180,23 @@
)
end

context "when the package manager version is unsupported" do
let(:unsupported_error_enabled) { true }

let(:job_definition) do
{
"base_commit_sha" => base_commit_sha,
"base64_dependency_files" => encode_dependency_files(dependency_files_for_unsupported)
}
end

it "raises ToolVersionNotSupported error" do
expect do
create_dependency_snapshot
end.to raise_error(Dependabot::ToolVersionNotSupported)
end
end

context "when the job definition includes valid information prepared by the file fetcher step" do
let(:job_definition) do
{
Expand Down
27 changes: 27 additions & 0 deletions updater/spec/dependabot/update_files_command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

require "spec_helper"
require "dependabot/update_files_command"
require "dependabot/bundler"
require "tmpdir"

RSpec.describe Dependabot::UpdateFilesCommand do
Expand Down Expand Up @@ -112,6 +113,32 @@
end
end

context "when there is an unsupported package manager version" do
let(:error) do
Dependabot::ToolVersionNotSupported.new(
"bundler", # tool name
"1.0.0", # detected version
">= 2.0.0" # supported versions
)
end

it_behaves_like "a fast-failed job"

it "records the unsupported version error with details" do
expect(service).to receive(:record_update_job_error).with(
error_type: "tool_version_not_supported",
error_details: {
"tool-name": "bundler",
"detected-version": "1.0.0",
"supported-versions": ">= 2.0.0"
}
)
expect(service).to receive(:mark_job_as_processed)

perform_job
end
end

context "with an update files error (cloud)" do
let(:error) { StandardError.new("hell") }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,29 +305,6 @@
perform
end
end

context "when package manager version is unsupported" do
let(:package_manager_version) { "1" }
let(:supported_versions) { %w(2 3) }

before do
# Enable the feature flag for unsupported version
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:bundler_v1_unsupported_error)
.and_return(true)

# Ensure unsupported? method returns true so the error is triggered
allow(package_manager).to receive(:unsupported?).and_return(true)
end

it "logs the ToolVersionNotSupported error to the error handler" do
# Ensure the error handler receives the expected error
expect(mock_error_handler).to receive(:handle_dependency_error)
.with(hash_including(error: instance_of(Dependabot::ToolVersionNotSupported)))

perform
end
end
end

describe "#check_and_create_pull_request" do
Expand Down
8 changes: 8 additions & 0 deletions updater/spec/fixtures/bundler/unsupported/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

source "https://rubygems.org"

gem "bundler", "~> 1.15.0"

gem "business", "~> 1.4.0"
gem "statesman", "~> 1.2.0"
16 changes: 16 additions & 0 deletions updater/spec/fixtures/bundler/unsupported/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
GEM
remote: https://rubygems.org/
specs:
business (1.4.0)
statesman (1.2.1)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.15.0)
business (~> 1.4.0)
statesman (~> 1.2.0)

BUNDLED WITH
1.15.4

0 comments on commit 7f120c2

Please sign in to comment.