Skip to content

Commit

Permalink
Refine purl parsing and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
juxtin authored Apr 28, 2024
1 parent 1dd418b commit fcc66c2
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 49 deletions.
6 changes: 4 additions & 2 deletions __tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,15 @@ test('it raises an error if an empty allow list is specified', async () => {
test('it raises an error when an invalid package-url is used for deny-packages', async () => {
setInput('deny-packages', 'not-a-purl')

await expect(readConfig()).rejects.toThrow(`Error parsing purl`)
await expect(readConfig()).rejects.toThrow(`Error parsing package-url`)
})

test('it raises an error when an argument to deny-groups is missing a namespace', async () => {
setInput('deny-groups', 'pkg:npm/my-fun-org')

await expect(readConfig()).rejects.toThrow(`purl must have a namespace`)
await expect(readConfig()).rejects.toThrow(
`package-url must have a namespace`
)
})

test('it raises an error when given an unknown severity', async () => {
Expand Down
30 changes: 26 additions & 4 deletions __tests__/purl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import {parsePURL} from '../src/purl'
test('parsePURL returns an error if the purl does not start with "pkg:"', () => {
const purl = 'not-a-purl'
const result = parsePURL(purl)
expect(result.error).toEqual('purl must start with "pkg:"')
expect(result.error).toEqual('package-url must start with "pkg:"')
})

test('parsePURL returns an error if the purl does not contain an ecosystem', () => {
test('parsePURL returns an error if the purl does not contain a type', () => {
const purl = 'pkg:/'
const result = parsePURL(purl)
expect(result.error).toEqual('purl must contain an ecosystem')
expect(result.error).toEqual('package-url must contain a type')
})

test('parsePURL returns an error if the purl does not contain a namespace or name', () => {
const purl = 'pkg:ecosystem/'
const result = parsePURL(purl)
expect(result.type).toEqual('ecosystem')
expect(result.error).toEqual('purl must contain a namespace or name')
expect(result.error).toEqual('package-url must contain a namespace or name')
})

test('parsePURL returns a PURL with the correct values in the happy case', () => {
Expand Down Expand Up @@ -88,6 +88,28 @@ test('parsePURL table test', () => {
error: null
}
},
{
purl: 'pkg:/?',
expected: {
type: '',
namespace: null,
name: null,
version: null,
original: 'pkg:/?',
error: 'package-url must contain a type'
}
},
{
purl: 'pkg:ecosystem/#',
expected: {
type: 'ecosystem',
namespace: null,
name: null,
version: null,
original: 'pkg:ecosystem/#',
error: 'package-url must contain a namespace or name'
}
},
{
purl: 'pkg:ecosystem/name@version#subpath?attributes=123',
expected: {
Expand Down
64 changes: 36 additions & 28 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions src/purl.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as z from 'zod'

// the basic purl type, containing ecosystem, namespace, name, and version.
// other than ecosystem, all fields are nullable. this is for maximum flexibility
// the basic purl type, containing type, namespace, name, and version.
// other than type, all fields are nullable. this is for maximum flexibility
// at the cost of strict adherence to the package-url spec.
export const PurlSchema = z.object({
type: z.string(),
Expand All @@ -14,7 +14,7 @@ export const PurlSchema = z.object({

export type PackageURL = z.infer<typeof PurlSchema>

const PURL_ECOSYSTEM = /pkg:([a-zA-Z0-9-_]+)\/.*/
const PURL_TYPE = /pkg:([a-zA-Z0-9-_]+)\/.*/

export function parsePURL(purl: string): PackageURL {
const result: PackageURL = {
Expand All @@ -26,19 +26,19 @@ export function parsePURL(purl: string): PackageURL {
error: null
}
if (!purl.startsWith('pkg:')) {
result.error = 'purl must start with "pkg:"'
result.error = 'package-url must start with "pkg:"'
return result
}
const ecosystem = purl.match(PURL_ECOSYSTEM)
if (ecosystem === null) {
result.error = 'purl must contain an ecosystem'
const type = purl.match(PURL_TYPE)
if (!type) {
result.error = 'package-url must contain a type'
return result
}
result.type = ecosystem[1]
result.type = type[1]
const parts = purl.split('/')
// the first 'part' should be 'pkg:ecosystem'
if (parts.length < 2 || parts[1].length === 0) {
result.error = 'purl must contain a namespace or name'
if (parts.length < 2 || !parts[1]) {
result.error = 'package-url must contain a namespace or name'
return result
}
let namePlusRest: string
Expand All @@ -49,13 +49,17 @@ export function parsePURL(purl: string): PackageURL {
namePlusRest = parts[2]
}
const name = namePlusRest.match(/([^@#?]+)[@#?]?.*/)
if (name === null) {
if (!result.namespace && !name) {
result.error = 'package-url must contain a namespace or name'
return result
}
if (!name) {
// we're done here
return result
}
result.name = decodeURIComponent(name[1])
const version = namePlusRest.match(/@([^#?]+)[#?]?.*/)
if (version === null) {
if (!version) {
return result
}
result.version = decodeURIComponent(version[1])
Expand Down
4 changes: 2 additions & 2 deletions src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const PackageURL = z
if (purl.error) {
context.addIssue({
code: z.ZodIssueCode.custom,
message: `Error parsing purl: ${purl.error}`
message: `Error parsing package-url: ${purl.error}`
})
}
})
Expand All @@ -35,7 +35,7 @@ const PackageURLWithNamespace = z
if (purl.namespace === null) {
context.addIssue({
code: z.ZodIssueCode.custom,
message: `purl must have a namespace, and the namespace must be followed by '/'`
message: `package-url must have a namespace, and the namespace must be followed by '/'`
})
}
})
Expand Down

0 comments on commit fcc66c2

Please sign in to comment.