Skip to content

Commit

Permalink
fix: allow for namespaces in Purl validation
Browse files Browse the repository at this point in the history
Ecosystems composer, golang, npm and swift allow for namespaces, which are encoded in the package name. Prior to this, including the Purl namespace in the package name would cause an exception to be thrown during validation.
  • Loading branch information
mcombuechen committed Jul 17, 2023
1 parent 8fe5a91 commit 625e03e
Show file tree
Hide file tree
Showing 2 changed files with 214 additions and 1 deletion.
13 changes: 13 additions & 0 deletions src/core/validate-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ export function validatePackageURL(pkg: types.PkgInfo): void {
);
break;

case 'composer':
case 'golang':
case 'npm':
case 'swift':
assert(
pkg.name ===
(purlPkg.namespace
? `${purlPkg.namespace}/${purlPkg.name}`
: purlPkg.name),
`name and packageURL name do not match`,
);
break;

// The PURL spec for Linux distros does not include the source in the name.
// This is why we relax the assertion here and match only on the package name:
// <source name>/<package name> - we omit the source name
Expand Down
202 changes: 201 additions & 1 deletion test/core/validate-graph.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { validatePackageURL } from '../../src/core/validate-graph';

describe('validatePackageURL', () => {
describe('deb package type tests', () => {
describe('deb Purl type tests', () => {
it.each([
[
'package name includes source',
Expand Down Expand Up @@ -87,4 +87,204 @@ describe('validatePackageURL', () => {
expect(() => validatePackageURL(pkg)).toThrow();
});
});

describe('composer Purl type tests', () => {
it.each([
[
'composer package without namespace',
{
name: 'bar',
version: '1.2.3',
purl: 'pkg:composer/bar@1.2.3',
},
],
[
'composer package with namespace',
{
name: 'vendor/bar',
version: '1.2.3',
purl: 'pkg:composer/vendor/bar@1.2.3',
},
],
])('validates composer Purls: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).not.toThrow();
});

it.each([
[
'package name does not match purl name',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:composer/baz@1.2.3',
},
],
[
'package name does not match purl namespace',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:composer/baz/bar@1.2.3',
},
],
[
'package name does not include purl namespace',
{
name: 'bar',
version: '1.2.3',
purl: 'pkg:composer/baz/bar@1.2.3',
},
],
])('should throw on invalid purl: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).toThrow();
});
});

describe('golang Purl type tests', () => {
it.each([
[
'golang package with namespace',
{
name: 'github.com/foo/bar',
version: '1.2.3',
purl: 'pkg:golang/github.com/foo/bar@1.2.3',
},
],
[
'golang package without namespace',
{
name: 'foo',
version: '1.2.3',
purl: 'pkg:golang/foo@1.2.3',
},
],
])('validates golang Purls: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).not.toThrow();
});

it.each([
[
'package name does not match purl name',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:golang/baz@1.2.3',
},
],
[
'package name does not match purl namespace',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:golang/google.golang.org/bar@1.2.3',
},
],
[
'package name does not include purl namespace',
{
name: 'bar',
version: '1.2.3',
purl: 'pkg:golang/google.golang.org/bar@1.2.3',
},
],
])('should throw on invalid purl: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).toThrow();
});
});

describe('npm Purl type tests', () => {
it.each([
[
'npm package without namespace',
{
name: 'bar',
version: '1.2.3',
purl: 'pkg:npm/bar@1.2.3',
},
],
[
'npm package with namespace',
{
name: '@foo/bar',
version: '1.2.3',
purl: 'pkg:npm/%40foo/bar@1.2.3',
},
],
])('validates npm Purls: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).not.toThrow();
});

it.each([
[
'package name does not match purl name',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:npm/baz@1.2.3',
},
],
[
'package name does not match purl namespace',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:npm/%40baz/bar@1.2.3',
},
],
[
'package name does not include purl namespace',
{
name: 'bar',
version: '1.2.3',
purl: 'pkg:npm/%40baz/bar@1.2.3',
},
],
])('should throw on invalid purl: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).toThrow();
});
});

describe('swift Purl type tests', () => {
it.each([
[
'swift package with namespace',
{
name: 'github.com/foo/bar',
version: '1.2.3',
purl: 'pkg:swift/github.com/foo/bar@1.2.3',
},
],
])('validates swift Purls: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).not.toThrow();
});

it.each([
[
'package name does not match purl name',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:swift/baz@1.2.3',
},
],
[
'package name does not match purl namespace',
{
name: 'foo/bar',
version: '1.2.3',
purl: 'pkg:swift/baz/bar@1.2.3',
},
],
[
'package name does not include purl namespace',
{
name: 'bar',
version: '1.2.3',
purl: 'pkg:swift/baz/bar@1.2.3',
},
],
])('should throw on invalid purl: %s', (name, pkg) => {
expect(() => validatePackageURL(pkg)).toThrow();
});
});
});

0 comments on commit 625e03e

Please sign in to comment.