retire 5.2.8 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.4.0]
4
+
5
+ ### Improvements
6
+
7
+ - Add possibility to exclude specific versions for a vulnerability (example: jquery-1.12.4-aem which has some extra patches).
8
+
9
+ ## [5.3.0]
10
+
11
+ ### Improvement
12
+
13
+ - Add cyclonedxJSON1_6_VEX as output format for CycloneDX 1.6 with vulnerability information
14
+
3
15
  ## [5.2.8]
4
16
 
5
17
  ### Bugfix
package/lib/cli.js CHANGED
@@ -70,7 +70,7 @@ const prg = commander_1.program
70
70
  .option('--jsrepo <path|url>', "Local or internal version of repo. Can be multiple comma separated. Default: 'central')")
71
71
  .option('--cachedir <path>', 'Path to use for local cache instead of /tmp/.retire-cache')
72
72
  .option('--proxy <url>', 'Proxy url (http://some.host:8080)')
73
- .option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx, cyclonedxJSON and cyclonedxJSON1_6')
73
+ .option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx, cyclonedxJSON, cyclonedxJSON1_6, cyclonedxJSON1_6_VEX')
74
74
  .option('--outputpath <path>', 'File to which output should be written')
75
75
  .option('--ignore <paths>', 'Comma delimited list of paths to ignore')
76
76
  .option('--ignorefile <path>', 'Custom ignore file, defaults to .retireignore / .retireignore.json')
@@ -88,7 +88,7 @@ const colorwarn = prg.colors ? ansi_colors_1.default.red : (x) => x;
88
88
  const jsrepolocation = (prg.jsrepo ?? "'central'")
89
89
  .split(',')
90
90
  .map((x) => x === "'central'"
91
- ? 'https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository-v4.json'
91
+ ? 'https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository-v5.json'
92
92
  : x);
93
93
  const ignorefile = prg.ignorefile ?? defaultIgnoreFiles.filter((x) => fs_1.default.existsSync(x))[0];
94
94
  const scanpath = prg.path ?? prg.jspath ?? '.';
package/lib/repo.js CHANGED
@@ -54,6 +54,7 @@ function validateRepository(repo, replacer) {
54
54
  .object({
55
55
  below: versionValidator,
56
56
  atOrAbove: versionValidator.optional(),
57
+ excludes: z.array(versionValidator).optional(),
57
58
  severity: z.enum(keys),
58
59
  cwe: z.array(z.string().regex(/^CWE-[0-9]+$/)).min(1),
59
60
  identifiers: z
@@ -66,6 +66,8 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
66
66
  logger.close = function (callback) {
67
67
  const write = vulnsFound ? writer.err : writer.out;
68
68
  const seen = new Map();
69
+ const vulnerabilitiesCyclone = new Map();
70
+ const includeVEX = config.outputformat === 'cyclonedxJSON1_6_VEX';
69
71
  const components = finalResults.data
70
72
  .filter((d) => d.results)
71
73
  .map((r) => r.results
@@ -93,7 +95,39 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
93
95
  return undefined;
94
96
  }
95
97
  const nameParts = dep.component.split('/').reverse();
98
+ const bomRef = purl;
99
+ dep.vulnerabilities?.forEach((vuln) => {
100
+ // Pick valid identifiers for VEX
101
+ const ids = vuln.identifiers?.CVE ?? (vuln.identifiers?.githubID ? [vuln.identifiers.githubID] : undefined);
102
+ if (!ids)
103
+ return;
104
+ ids.forEach((id) => {
105
+ if (!vulnerabilitiesCyclone.has(id)) {
106
+ const { references, advisories } = mapUrls(vuln);
107
+ vulnerabilitiesCyclone.set(id, {
108
+ id,
109
+ cwes: vuln.cwe.map((c) => parseInt(c.split("-")[1])),
110
+ description: vuln.identifiers.summary,
111
+ advisories: advisories,
112
+ references: references,
113
+ ratings: [
114
+ {
115
+ source: 'Retire.js',
116
+ severity: vuln.severity,
117
+ },
118
+ ],
119
+ affects: [],
120
+ });
121
+ }
122
+ vulnerabilitiesCyclone.get(id).affects.push({
123
+ ref: bomRef,
124
+ // "vers:npm/1.2.3|>=2.0.0|<5.0.0"
125
+ range: "vers:npm/" + (vuln.atOrAbove ? ">=" + vuln.atOrAbove + "|" : "") + "<" + vuln.below,
126
+ });
127
+ });
128
+ });
96
129
  const result = {
130
+ "bom-ref": bomRef,
97
131
  type: 'library',
98
132
  name: nameParts[0],
99
133
  group: nameParts[1],
@@ -118,12 +152,13 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
118
152
  tools: [
119
153
  {
120
154
  vendor: 'RetireJS',
121
- name: 'retire.js',
155
+ name: 'retire',
122
156
  version: retire.version,
123
157
  },
124
158
  ],
125
159
  },
126
160
  components: components,
161
+ vulnerabilities: includeVEX ? Array.from(vulnerabilitiesCyclone.values()) : undefined,
127
162
  }, undefined, 2));
128
163
  writer.close(callback);
129
164
  };
@@ -137,6 +172,21 @@ function mapLicenses(licenses) {
137
172
  return [{ license: { name: 'Commercial' } }];
138
173
  return [{ expression: licenses[0] }];
139
174
  }
175
+ function mapUrls(vulnerability) {
176
+ const references = [];
177
+ if (vulnerability.identifiers.CVE) {
178
+ const nvdlink = `https://nvd.nist.gov/vuln/detail/${vulnerability.identifiers.CVE[0]}`;
179
+ references.push({ id: vulnerability.identifiers.CVE[0], source: { name: 'NVD', url: nvdlink } });
180
+ }
181
+ if (vulnerability.identifiers.githubID) {
182
+ const ghsa = `https://github.com/advisories/${vulnerability.identifiers.githubID}`;
183
+ references.push({ id: vulnerability.identifiers.githubID, source: { name: 'GitHub Advisories', url: ghsa } });
184
+ }
185
+ const advisories = vulnerability.info
186
+ .filter((url) => !url.startsWith('https://nvd.nist.gov/vuln/detail/') && !url.startsWith('https://github.com/advisories/'))
187
+ .map((u) => ({ url: u }));
188
+ return { references, advisories };
189
+ }
140
190
  exports.default = {
141
191
  configure: configureCycloneDXJSONLogger,
142
192
  };
package/lib/reporting.js CHANGED
@@ -54,6 +54,7 @@ const loggers = {
54
54
  cyclonedx: cyclonedx_1.default,
55
55
  cyclonedxJSON: cyclonedx_json_1.default,
56
56
  cyclonedxJSON1_6: cyclonedx_1_6_json_1.default,
57
+ cyclonedxJSON1_6_VEX: cyclonedx_1_6_json_1.default,
57
58
  clean: console_1.default,
58
59
  jsonsimple: json_1.default,
59
60
  };
package/lib/retire.js CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  var exports = exports || {};
7
- exports.version = '5.2.8';
7
+ exports.version = '5.4.0';
8
8
 
9
9
  function isDefined(o) {
10
10
  return typeof o !== 'undefined';
@@ -103,6 +103,9 @@ function check(results, repo) {
103
103
  if (isDefined(vulns[i].atOrAbove) && !isAtOrAbove(result.version, vulns[i].atOrAbove)) {
104
104
  continue;
105
105
  }
106
+ if (isDefined(vulns[i].excludes) && vulns[i].excludes.includes(result.version)) {
107
+ continue;
108
+ }
106
109
  var vulnerability = { info: vulns[i].info, below: vulns[i].below, atOrAbove: vulns[i].atOrAbove };
107
110
  if (vulns[i].severity) {
108
111
  vulnerability.severity = vulns[i].severity;
package/lib/types.d.ts CHANGED
@@ -18,6 +18,7 @@ export type Repository = Record<string, {
18
18
  export type Vulnerability = {
19
19
  below: string;
20
20
  atOrAbove?: string;
21
+ excludes?: string[];
21
22
  severity: SeverityLevel;
22
23
  cwe: string[];
23
24
  identifiers: {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Erlend Oftedal <erlend@oftedal.no>",
3
3
  "name": "retire",
4
4
  "description": "Retire is a tool for detecting use of vulnerable libraries",
5
- "version": "5.2.8",
5
+ "version": "5.4.0",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -14,7 +14,7 @@
14
14
  "main": "./lib/retire.js",
15
15
  "dependencies": {
16
16
  "ansi-colors": "^4.1.1",
17
- "astronomical": "^2.0.1",
17
+ "astronomical": "^2.1.1-rc.1",
18
18
  "commander": "^10.0.1",
19
19
  "proxy-agent": "^6.4.0",
20
20
  "uuid": "^9.0.1",
@@ -22,8 +22,8 @@
22
22
  "zod": "^3.22.4"
23
23
  },
24
24
  "devDependencies": {
25
- "@types/jest": "^29.5.14",
26
25
  "@types/chai": "^4.3.17",
26
+ "@types/jest": "^29.5.14",
27
27
  "@types/node": "^18.13.0",
28
28
  "@types/uuid": "^9.0.0",
29
29
  "@typescript-eslint/eslint-plugin": "^7.1.1",