UNPKG

5.41 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.validatePackageURL = exports.validateGraph = void 0;
4const graphlib = require("../graphlib");
5const packageurl_js_1 = require("packageurl-js");
6const errors_1 = require("./errors");
7const reGolangPseudoVersion = /(v\d+\.\d+\.\d+)-(.*?)(\d{14})-([0-9a-f]{12})/;
8const reGolangExactVersion = /^(.*?)(\+incompatible)?$/;
9function assert(condition, msg) {
10 if (!condition) {
11 throw new errors_1.ValidationError(msg);
12 }
13}
14function validateGraph(graph, rootNodeId, pkgs, pkgNodes) {
15 assert((graph.predecessors(rootNodeId) || []).length === 0, `"${rootNodeId}" is not really the root`);
16 const reachableFromRoot = graphlib.alg.postorder(graph, [rootNodeId]);
17 const nodeIds = graph.nodes();
18 assert(JSON.stringify(nodeIds.sort()) === JSON.stringify(reachableFromRoot.sort()), 'not all graph nodes are reachable from root');
19 const pkgIds = Object.keys(pkgs);
20 const pkgsWithoutInstances = pkgIds.filter((pkgId) => !pkgNodes[pkgId] || pkgNodes[pkgId].size === 0);
21 assert(pkgsWithoutInstances.length === 0, 'not all pkgs have instance nodes');
22 for (const pkgId in pkgs) {
23 try {
24 validatePackageURL(pkgs[pkgId]);
25 }
26 catch (e) {
27 throw new errors_1.ValidationError(`invalid pkg ${pkgId}: ${e}`);
28 }
29 }
30}
31exports.validateGraph = validateGraph;
32function validatePackageURL(pkg) {
33 var _a;
34 if (!pkg.purl) {
35 return;
36 }
37 try {
38 const purl = packageurl_js_1.PackageURL.fromString(pkg.purl);
39 // validate package name
40 switch (purl.type) {
41 // Within Snyk, maven packages use <namespace>:<name> as their *name*, but
42 // we expect those to be separated correctly in the PackageURL.
43 case 'maven':
44 assert(pkg.name === purl.namespace + ':' + purl.name, `name and packageURL name do not match`);
45 break;
46 // CocoaPods have an optional subspec encoded in the subpath
47 // component of the purl, which – if present – should
48 // be appended to the spec.
49 case 'cocoapods':
50 assert(pkg.name ===
51 (purl.subpath ? `${purl.name}/${purl.subpath}` : purl.name), `name and packageURL name do not match`);
52 break;
53 case 'golang': {
54 let expected = purl.namespace
55 ? `${purl.namespace}/${purl.name}`
56 : purl.name;
57 if (purl.subpath)
58 expected += `/${purl.subpath}`;
59 assert(pkg.name === expected, `name and packageURL name do not match`);
60 break;
61 }
62 case 'composer':
63 case 'npm':
64 case 'swift':
65 assert(pkg.name ===
66 (purl.namespace ? `${purl.namespace}/${purl.name}` : purl.name), `name and packageURL name do not match`);
67 break;
68 // The PURL spec for Linux distros does not include the source in the name.
69 // This is why we relax the assertion here and match only on the package name:
70 // <source name>/<package name> - we omit the source name
71 // For now, make this exception only for deb to cover a support case.
72 case 'deb': {
73 const pkgName = pkg.name.split('/').pop();
74 assert(pkgName === purl.name, 'name and packageURL name do not match');
75 if (((_a = purl.qualifiers) === null || _a === void 0 ? void 0 : _a['upstream']) && pkg.name.includes('/')) {
76 const pkgSrc = pkg.name.split('/')[0];
77 const pkgUpstream = purl.qualifiers['upstream'].split('@')[0];
78 assert(pkgSrc === pkgUpstream, 'source and packageURL source do not match');
79 }
80 break;
81 }
82 default:
83 assert(pkg.name === purl.name, `name and packageURL name do not match`);
84 }
85 // validate package version
86 switch (purl.type) {
87 // the Snyk version of a golang module is either
88 // - the version without "v", e.g. v1.2.3 -> 1.2.3
89 // - the pseudo-version hash, e.g. v0.0.0-000-acf48ae230a1 -> #acf48ae230a1
90 case 'golang': {
91 let version = purl.version;
92 if (purl.version) {
93 const maybePseudoVersion = reGolangPseudoVersion.exec(purl.version);
94 const maybeExactVersion = reGolangExactVersion.exec(purl.version);
95 if (maybePseudoVersion) {
96 version = `#${maybePseudoVersion[4]}`;
97 }
98 else if (maybeExactVersion) {
99 version = maybeExactVersion[1].replace(/^v/, '');
100 }
101 }
102 assert(pkg.version === version, `version and packageURL version do not match. want ${pkg.version} have: ${version}`);
103 break;
104 }
105 default:
106 assert(pkg.version === purl.version, `version and packageURL version do not match`);
107 }
108 }
109 catch (e) {
110 throw new errors_1.ValidationError(`packageURL validation failed: ${e}`);
111 }
112}
113exports.validatePackageURL = validatePackageURL;
114//# sourceMappingURL=validate-graph.js.map
\No newline at end of file