retire 5.2.8 → 5.3.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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.3.0]
4
+
5
+ ### Improvement
6
+
7
+ - Add cyclonedxJSON1_6_VEX as output format for CycloneDX 1.6 with vulnerability information
8
+
3
9
  ## [5.2.8]
4
10
 
5
11
  ### 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')
@@ -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.3.0';
8
8
 
9
9
  function isDefined(o) {
10
10
  return typeof o !== 'undefined';
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.3.0",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",