Skip to content

Commit

Permalink
fix(purl): percent-encoding is case insensitive (#1382)
Browse files Browse the repository at this point in the history
  • Loading branch information
williamboman authored Jun 28, 2023
1 parent 10da1a3 commit b68d3be
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
8 changes: 7 additions & 1 deletion lua/mason-core/purl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ local function percent_encode(char)
return ("%%%x"):format(string.byte(char, 1, 1))
end

local decode_percent_encoding = _.gsub("%%([A-F0-9][A-F0-9])", _.compose(string.char, parse_hex))
local decode_percent_encoding = _.gsub("%%([A-Fa-f0-9][A-Fa-f0-9])", _.compose(string.char, parse_hex))
local encode_percent_encoding = _.gsub("[!#$&'%(%)%*%+;=%?@%[%] ]", percent_encode)

local function validate_conan(purl)
Expand Down Expand Up @@ -162,6 +162,11 @@ local github = _.evolve {
namespace = _.to_lower,
}

local composer = _.evolve {
name = _.to_lower,
namespace = _.to_lower,
}

local is_mlflow_azuredatabricks = _.all_pass {
_.prop_eq("type", "mlflow"),
_.path_satisfies(_.matches "^https?://.*azuredatabricks%.net", { "qualifiers", "repository_url" }),
Expand All @@ -176,6 +181,7 @@ local type_validations = _.cond {

local type_transforms = _.cond {
{ _.prop_eq("type", "bitbucket"), bitbucket },
{ _.prop_eq("type", "composer"), composer },
{ _.prop_eq("type", "github"), github },
{ _.prop_eq("type", "pypi"), pypi },
{ _.prop_eq("type", "huggingface"), huggingface },
Expand Down
12 changes: 12 additions & 0 deletions tests/fixtures/purl-test-suite-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,18 @@
"subpath": null,
"is_invalid": false
},
{
"description": "composer names are not case sensitive",
"purl": "pkg:composer/Laravel/Laravel@5.5.0",
"canonical_purl": "pkg:composer/laravel/laravel@5.5.0",
"type": "composer",
"namespace": "laravel",
"name": "laravel",
"version": "5.5.0",
"qualifiers": null,
"subpath": null,
"is_invalid": false
},
{
"description": "splits checksum qualifier",
"purl": "pkg:github/rust-lang/rust-analyzer@2022-12-05?download_url=https://github.com/rust-lang/rust-analyzer/releases/download/2022-12-05/rust-analyzer-aarch64-apple-darwin.gz&checksum=sha1:256d83a0a59929099e7564169ef444c5e4088afc,sha256:28461b29ac0da9c653616e1d96092c85f86e24dd448d0fbe1973aa4c6d9b8b44",
Expand Down
32 changes: 23 additions & 9 deletions tests/mason-core/purl_spec.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local Purl = require "mason-core.purl"
local Result = require "mason-core.result"
local purl = require "mason-core.purl"

describe("purl", function()
it("should parse well-formed PURLs", function()
Expand All @@ -16,7 +16,7 @@ describe("purl", function()
version = "2022-11-28",
subpath = "bin/rust-analyzer",
},
purl.parse "pkg:github/rust-lang/rust-analyzer@2022-11-28?target=linux_x64_gnu&download_url=https://github.com/rust-lang/rust-analyzer/releases/download/2022-11-28/rust-analyzer-x86_64-unknown-linux-gnu.gz#bin/rust-analyzer"
Purl.parse "pkg:github/rust-lang/rust-analyzer@2022-11-28?target=linux_x64_gnu&download_url=https://github.com/rust-lang/rust-analyzer/releases/download/2022-11-28/rust-analyzer-x86_64-unknown-linux-gnu.gz#bin/rust-analyzer"
)

assert.same(
Expand All @@ -29,7 +29,7 @@ describe("purl", function()
qualifiers = nil,
subpath = nil,
},
purl.parse "pkg:github/rust-lang/rust-analyzer@2025-04-20"
Purl.parse "pkg:github/rust-lang/rust-analyzer@2025-04-20"
)

assert.same(
Expand All @@ -42,7 +42,7 @@ describe("purl", function()
qualifiers = nil,
subpath = nil,
},
purl.parse "pkg:npm/typescript-language-server@10.23.1"
Purl.parse "pkg:npm/typescript-language-server@10.23.1"
)

assert.same(
Expand All @@ -55,7 +55,7 @@ describe("purl", function()
qualifiers = nil,
subpath = nil,
},
purl.parse "pkg:pypi/python-language-server"
Purl.parse "pkg:pypi/python-language-server"
)

assert.same(
Expand All @@ -65,12 +65,26 @@ describe("purl", function()
scheme = "pkg",
type = "npm",
},
purl.parse "pkg:npm/%40angular/cli"
Purl.parse "pkg:npm/%40angular/cli"
)
end)

it("should fail to parse invalid PURLs", function()
assert.same(Result.failure "Malformed purl (invalid scheme).", purl.parse "scam:github/react@18.0.0")
assert.same(Result.failure "Malformed purl (invalid scheme).", Purl.parse "scam:github/react@18.0.0")
end)

it("should treat percent-encoded components as case insensitive", function()
local purl = {
name = "sonarlint-vscode",
namespace = "sonarsource",
scheme = "pkg",
type = "github",
version = "3.18.0+70423" .. string.char(0xab),
}
assert.same(Result.success(purl), Purl.parse "pkg:github/SonarSource/sonarlint-vscode@3.18.0%2b70423%ab")
assert.same(Result.success(purl), Purl.parse "pkg:github/SonarSource/sonarlint-vscode@3.18.0%2B70423%aB")
assert.same(Result.success(purl), Purl.parse "pkg:github/SonarSource/sonarlint-vscode@3.18.0%2b70423%AB")
assert.same(Result.success(purl), Purl.parse "pkg:github/SonarSource/sonarlint-vscode@3.18.0%2B70423%Ab")
end)
end)

Expand All @@ -89,7 +103,7 @@ describe("purl test suite ::", function()

for _, test in ipairs(test_fixture) do
it(test.description, function()
local result = purl.parse(test.purl)
local result = Purl.parse(test.purl)
if test.is_invalid then
assert.is_true(result:is_failure())
else
Expand All @@ -106,7 +120,7 @@ describe("purl test suite ::", function()
result
)

assert.equals(test.canonical_purl, purl.compile(result:get_or_throw()))
assert.equals(test.canonical_purl, Purl.compile(result:get_or_throw()))
end
end)
end
Expand Down

0 comments on commit b68d3be

Please # to comment.