Skip to content

Commit

Permalink
Error handler for Dependabot::Updater::SubprocessFailed: Subprocess i…
Browse files Browse the repository at this point in the history
…ssues (#10512)

* error handling for NPM and YARN errors
  • Loading branch information
sachin-sandhu authored Aug 29, 2024
1 parent 7e1007c commit 07998eb
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 2 deletions.
54 changes: 53 additions & 1 deletion npm_and_yarn/lib/dependabot/npm_and_yarn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ module NpmAndYarn

SOCKET_HANG_UP = /(?<url>.*?): socket hang up/

# Misc errors
EEXIST = /EEXIST: file already exists, mkdir '(?<regis>.*)'/

# registry access errors
REQUEST_ERROR_E403 = /Request "(?<url>.*)" returned a 403/ # Forbidden access to the URL.
AUTH_REQUIRED_ERROR = /(?<url>.*): authentication required/ # Authentication is required for the URL.
PERMISSION_DENIED = /(?<url>.*): Permission denied/ # Lack of permission to access the URL.
BAD_REQUEST = /(?<url>.*): bad_request/ # Inconsistent request while accessing resource.
INTERNAL_SERVER_ERROR = /Request failed "500 Internal Server Error"/ # Server error response by remote registry.

# Used to identify git unreachable error
UNREACHABLE_GIT_CHECK_REGEX = /ls-remote --tags --heads (?<url>.*)/

Expand All @@ -79,6 +89,8 @@ module NpmAndYarn
PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE = "package_req"
PACKAGE_NOT_FOUND_PACKAGE_NAME_CAPTURE_SPLIT_REGEX = /(?<=\w)\@/

YARN_PACKAGE_NOT_FOUND_CODE = /npm package "(?<dep>.*)" does not exist under owner "(?<regis>.*)"/

YN0035 = T.let({
PACKAGE_NOT_FOUND: %r{(?<package_req>@[\w-]+\/[\w-]+@\S+): Package not found},
FAILED_TO_RETRIEVE: %r{(?<package_req>@[\w-]+\/[\w-]+@\S+): The remote server failed to provide the requested resource} # rubocop:disable Layout/LineLength
Expand All @@ -97,6 +109,9 @@ module NpmAndYarn

DEPENDENCY_NO_VERSION_FOUND = "Couldn't find any versions"

# Manifest not found
MANIFEST_NOT_FOUND = /Cannot read properties of undefined \(reading '(?<file>.*)'\)/

# Used to identify error if node_modules state file not resolved
NODE_MODULES_STATE_FILE_NOT_FOUND = "Couldn't find the node_modules state file"

Expand Down Expand Up @@ -512,8 +527,45 @@ def self.sanitize_resolvability_message(error_message, dependencies, yarn_lock)
},
in_usage: false,
matchfn: nil
}
},
{
patterns: [YARN_PACKAGE_NOT_FOUND_CODE],
handler: lambda { |message, _error, _params|
msg = message.match(YARN_PACKAGE_NOT_FOUND_CODE)

Dependabot::DependencyFileNotResolvable.new(msg)
},
in_usage: false,
matchfn: nil
},
{
patterns: [REQUEST_ERROR_E403, AUTH_REQUIRED_ERROR, PERMISSION_DENIED, BAD_REQUEST],
handler: lambda { |message, _error, _params|
dependency_url = T.must(URI.decode_www_form_component(message).split("https://").last).split("/").first

Dependabot::PrivateSourceAuthenticationFailure.new(dependency_url)
},
in_usage: false,
matchfn: nil
},
{
patterns: [MANIFEST_NOT_FOUND],
handler: lambda { |message, _error, _params|
msg = message.match(MANIFEST_NOT_FOUND)
Dependabot::DependencyFileNotResolvable.new(msg)
},
in_usage: false,
matchfn: nil
},
{
patterns: [INTERNAL_SERVER_ERROR],
handler: lambda { |message, _error, _params|
msg = message.match(INTERNAL_SERVER_ERROR)
Dependabot::DependencyFileNotResolvable.new(msg)
},
in_usage: false,
matchfn: nil
}
].freeze, T::Array[{
patterns: T::Array[T.any(String, Regexp)],
handler: ErrorHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def updated_lockfile_reponse(response)

NPM_PACKAGE_NOT_FOUND_CODES = T.let([
/Couldn't find package "(?<pkg>.*)" on the "(?<regis>.*)" registry./,
/Couldn't find package "(?<pkg>.*)" "\required by "(?<dep>.*)" on the "(?<regis>.*)" registry./
/Couldn't find package "(?<pkg>.*)" required by "(?<dep>.*)" on the "(?<regis>.*)" registry./
].freeze, T::Array[Regexp])

# TODO: look into fixing this in npm, seems like a bug in the git
Expand Down
100 changes: 100 additions & 0 deletions npm_and_yarn/spec/dependabot/npm_and_yarn/yarn_error_handler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,106 @@
end
end

context "when the error message contains undefined manifest error" do
let(:error_message) do
"Cannot read properties of undefined (reading 'manifest')"
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::DependencyFileNotResolvable,
"Cannot read properties of undefined (reading 'manifest')")
end
end

context "when the error message contains 403 error" do
let(:error_message) do
"https://artifactory.wikia-inc.com/artifactory/api/npm/wikia-npm/@fandom-frontend%2fdesign-system: " \
"Request \"https://artifactory.wikia-inc.com/artifactory/api/npm/wikia-npm/@fandom-frontend%2fdes" \
"ign-system\" returned a 403"
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::PrivateSourceAuthenticationFailure,
"The following source could not be reached" \
" as it requires authentication " \
"(and any provided details were invalid or lacked " \
"the required permissions): artifactory.wikia-inc.com")
end
end

context "when the error message contains authentication required error" do
let(:error_message) do
"https://npm.shopify.io/node/@shopify%2fpolaris-icons: authentication required"
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::PrivateSourceAuthenticationFailure,
"The following source could not be reached" \
" as it requires authentication " \
"(and any provided details were invalid or lacked " \
"the required permissions): npm.shopify.io")
end
end

context "when the error message contains Permission denied error" do
let(:error_message) do
"https://npm.pkg.github.com/breakthroughbehavioralinc/webpack: Permission denied"
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::PrivateSourceAuthenticationFailure,
"The following source could not be reached" \
" as it requires authentication " \
"(and any provided details were invalid or lacked " \
"the required permissions): npm.pkg.github.com")
end
end

context "when the error message contains Permission denied error" do
let(:error_message) do
"https://npm-proxy.fury.io/rps/webpack: bad_request"
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::PrivateSourceAuthenticationFailure,
"The following source could not be reached" \
" as it requires authentication " \
"(and any provided details were invalid or lacked " \
"the required permissions): npm-proxy.fury.io")
end
end

context "when the error message contains Internal Server Error error" do
let(:error_message) do
"ResponseError: Request failed \"500 Internal Server Error\"" \
"at params.callback [as _callback] (/opt/npm_and_yarn/node_modules/"
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::DependencyFileNotResolvable,
"Request failed \"500 Internal Server Error\"")
end
end

context "when the error message contains no package found error" do
let(:error_message) do
"https://npm.pkg.github.com/@graphql-codegen%2ftypescript-react-apollo:" \
" npm package \"typescript-react-apollo\" does not exist under owner \"graphql-codegen\""
end

it "raises the corresponding error class with the correct message" do
expect { error_handler.handle_group_patterns(error, usage_error_message, { yarn_lock: yarn_lock }) }
.to raise_error(Dependabot::DependencyFileNotResolvable,
"npm package \"typescript-react-apollo\" does not exist under owner \"graphql-codegen\"")
end
end

context "when the error message contains YARNRC_ENV_NOT_FOUND" do
let(:error_message) do
"Usage Error: Environment variable not found (GITHUB_TOKEN) in /home/dependabot/dependabot-" \
Expand Down

0 comments on commit 07998eb

Please sign in to comment.