retire 5.4.3 → 5.6.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,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.6.0]
4
+
5
+ ### Improvements
6
+
7
+ - Report when repository certificate errors are ignored (`--insecure`): as `ignoreRepositoryCertificateErrors` in the JSON report, and as a `retirejs:ignore-repository-certificate-errors` entry under `metadata.properties` in all CycloneDX reports. The entry is only present when the option is set.
8
+
9
+ ## [5.5.0]
10
+
11
+ ### Improvements
12
+
13
+ - Include the vulnerability repositories used for the scan in the output: as `vulnerabilityRepositories` in the JSON report, and as `retirejs:vulnerability-repository` entries under `metadata.properties` in all CycloneDX reports.
14
+ - CycloneDX 1.6 VEX output now identifies Retire.js as the source of each vulnerability and rating, including the repository URL when a single repository is used.
15
+
16
+ ### Bugfixes
17
+
18
+ - CycloneDX 1.6 VEX output was not schema valid: `ratings[].source` was a string rather than an object, and version ranges were reported as `affects[].range` rather than nested under `affects[].versions[]`.
19
+
3
20
  ## [5.4.3]
4
21
 
5
22
  * Remove dependencies that are not needed anymore
package/lib/cli.js CHANGED
@@ -95,7 +95,8 @@ const scanpath = prg.path ?? prg.jspath ?? '.';
95
95
  const log = reporting.open({
96
96
  colors: !!prg.colors,
97
97
  colorwarn,
98
- jsRepo: jsrepolocation.join(', '),
98
+ jsRepo: jsrepolocation,
99
+ insecure: prg.insecure,
99
100
  outputformat: prg.outputformat,
100
101
  outputpath: prg.outputpath,
101
102
  path: scanpath,
@@ -68,6 +68,16 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
68
68
  const seen = new Map();
69
69
  const vulnerabilitiesCyclone = new Map();
70
70
  const includeVEX = config.outputformat === 'cyclonedxJSON1_6_VEX';
71
+ const vulnerabilityRepositoriesList = (0, utils_1.vulnerabilityRepositories)(config.jsRepo);
72
+ // Only attributable to a single URL when exactly one repository was used
73
+ const retireSource = {
74
+ name: 'Retire.js',
75
+ url: vulnerabilityRepositoriesList.length === 1 ? vulnerabilityRepositoriesList[0] : undefined,
76
+ };
77
+ const properties = vulnerabilityRepositoriesList.map((repo) => ({ name: 'retirejs:vulnerability-repository', value: repo }));
78
+ if (config.insecure) {
79
+ properties.push({ name: 'retirejs:ignore-repository-certificate-errors', value: 'true' });
80
+ }
71
81
  const components = finalResults.data
72
82
  .filter((d) => d.results)
73
83
  .map((r) => r.results
@@ -106,13 +116,14 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
106
116
  const { references, advisories } = mapUrls(vuln);
107
117
  vulnerabilitiesCyclone.set(id, {
108
118
  id,
119
+ source: retireSource,
109
120
  cwes: vuln.cwe.map((c) => parseInt(c.split("-")[1])),
110
121
  description: vuln.identifiers.summary,
111
122
  advisories: advisories,
112
123
  references: references,
113
124
  ratings: [
114
125
  {
115
- source: 'Retire.js',
126
+ source: retireSource,
116
127
  severity: vuln.severity,
117
128
  },
118
129
  ],
@@ -121,8 +132,13 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
121
132
  }
122
133
  vulnerabilitiesCyclone.get(id).affects.push({
123
134
  ref: bomRef,
124
- // "vers:npm/1.2.3|>=2.0.0|<5.0.0"
125
- range: "vers:npm/" + (vuln.atOrAbove ? ">=" + vuln.atOrAbove + "|" : "") + "<" + vuln.below,
135
+ versions: [
136
+ {
137
+ // "vers:npm/1.2.3|>=2.0.0|<5.0.0"
138
+ range: 'vers:npm/' + (vuln.atOrAbove ? '>=' + vuln.atOrAbove + '|' : '') + '<' + vuln.below,
139
+ status: 'affected',
140
+ },
141
+ ],
126
142
  });
127
143
  });
128
144
  });
@@ -156,6 +172,7 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
156
172
  version: retire.version,
157
173
  },
158
174
  ],
175
+ properties: properties.length ? properties : undefined,
159
176
  },
160
177
  components: components,
161
178
  vulnerabilities: includeVEX ? Array.from(vulnerabilitiesCyclone.values()) : undefined,
@@ -65,6 +65,10 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
65
65
  };
66
66
  logger.close = function (callback) {
67
67
  const write = vulnsFound ? writer.err : writer.out;
68
+ const properties = (0, utils_1.vulnerabilityRepositories)(config.jsRepo).map((repo) => ({ name: 'retirejs:vulnerability-repository', value: repo }));
69
+ if (config.insecure) {
70
+ properties.push({ name: 'retirejs:ignore-repository-certificate-errors', value: 'true' });
71
+ }
68
72
  const seen = new Map();
69
73
  const components = finalResults.data
70
74
  .filter((d) => d.results)
@@ -122,6 +126,7 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
122
126
  version: retire.version,
123
127
  },
124
128
  ],
129
+ properties: properties.length ? properties : undefined,
125
130
  },
126
131
  components: components,
127
132
  }, undefined, 2));
@@ -65,6 +65,17 @@ function configureCycloneDXLogger(logger, writer, config, hash) {
65
65
  };
66
66
  logger.close = function (callback) {
67
67
  const write = vulnsFound ? writer.err : writer.out;
68
+ const propertyList = (0, utils_1.vulnerabilityRepositories)(config.jsRepo).map((repo) => ({
69
+ name: 'retirejs:vulnerability-repository',
70
+ value: repo,
71
+ }));
72
+ if (config.insecure) {
73
+ propertyList.push({ name: 'retirejs:ignore-repository-certificate-errors', value: 'true' });
74
+ }
75
+ const properties = propertyList
76
+ .map((property) => `
77
+ <property name="${escapeXml(property.name)}">${escapeXml(property.value)}</property>`)
78
+ .join('');
68
79
  const seen = new Set();
69
80
  const components = finalResults.data
70
81
  .filter((d) => d.results.length > 0)
@@ -109,7 +120,9 @@ function configureCycloneDXLogger(logger, writer, config, hash) {
109
120
  <name>retire.js</name>
110
121
  <version>${retire.version}</version>
111
122
  </tool>
112
- </tools>
123
+ </tools>${properties ? `
124
+ <properties>${properties}
125
+ </properties>` : ''}
113
126
  </metadata>
114
127
  <components>${components}
115
128
  </components>
@@ -117,6 +130,13 @@ function configureCycloneDXLogger(logger, writer, config, hash) {
117
130
  writer.close(callback);
118
131
  };
119
132
  }
133
+ function escapeXml(value) {
134
+ return value
135
+ .replace(/&/g, '&amp;')
136
+ .replace(/</g, '&lt;')
137
+ .replace(/>/g, '&gt;')
138
+ .replace(/"/g, '&quot;');
139
+ }
120
140
  function mapLicenses(licenses) {
121
141
  if (!licenses)
122
142
  return '';
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
37
  const retire = __importStar(require("../retire"));
38
+ const utils_1 = require("./utils");
38
39
  exports.default = {
39
40
  configure: (logger, writer, config) => {
40
41
  const scanStart = Date.now();
@@ -45,6 +46,8 @@ exports.default = {
45
46
  messages: [],
46
47
  errors: [],
47
48
  time: undefined,
49
+ vulnerabilityRepositories: (0, utils_1.vulnerabilityRepositories)(config.jsRepo),
50
+ ignoreRepositoryCertificateErrors: config.insecure,
48
51
  };
49
52
  logger.info = finalResults.messages.push;
50
53
  logger.debug = config.verbose
@@ -1,2 +1,6 @@
1
1
  import { Component } from '../types';
2
2
  export declare function generatePURL(component: Component): string;
3
+ /**
4
+ * The vulnerability repositories used for the scan, as configured via --jsrepo.
5
+ */
6
+ export declare function vulnerabilityRepositories(jsRepo: string[] | undefined): string[];
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generatePURL = generatePURL;
4
+ exports.vulnerabilityRepositories = vulnerabilityRepositories;
4
5
  function encodePURLchars(str) {
5
6
  return str.replace(/[^A-Za-z0-9.+/=%-]/g, (match) => '%' + ('0' + match.charCodeAt(0).toString(16).toUpperCase()).slice(-2));
6
7
  }
@@ -13,3 +14,11 @@ function generatePURL(component) {
13
14
  const compName = component.npmname || component.component;
14
15
  return `pkg:npm/${encodePURLchars(compName)}@${encodePURLchars(component.version)}`;
15
16
  }
17
+ /**
18
+ * The vulnerability repositories used for the scan, as configured via --jsrepo.
19
+ */
20
+ function vulnerabilityRepositories(jsRepo) {
21
+ if (!jsRepo)
22
+ return [];
23
+ return jsRepo.map((repo) => repo.trim()).filter((repo) => repo.length > 0);
24
+ }
@@ -4,7 +4,8 @@ export type LoggerOptions = {
4
4
  verbose: boolean;
5
5
  colors: boolean;
6
6
  outputformat: string;
7
- jsRepo: string;
7
+ jsRepo: string[];
8
+ insecure?: boolean;
8
9
  path: string;
9
10
  colorwarn: (s: string) => string;
10
11
  };
package/lib/retire.js CHANGED
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  var exports = exports || {};
7
- exports.version = '5.4.3';
7
+ exports.version = '5.6.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.4.3",
5
+ "version": "5.6.0",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -14,30 +14,26 @@
14
14
  "main": "./lib/retire.js",
15
15
  "dependencies": {
16
16
  "ansi-colors": "^4.1.1",
17
- "astronomical": "^3.0.0",
17
+ "astronomical": "^3.2.0",
18
18
  "commander": "^10.0.1",
19
19
  "proxy-agent": "^6.4.0",
20
20
  "walkdir": "0.4.1",
21
21
  "zod": "^3.22.4"
22
22
  },
23
23
  "devDependencies": {
24
- "@types/chai": "^4.3.17",
25
- "@types/jest": "^29.5.14",
26
24
  "@types/node": "^18.13.0",
27
25
  "@types/uuid": "^9.0.0",
28
26
  "@typescript-eslint/eslint-plugin": "^7.1.1",
29
27
  "@typescript-eslint/parser": "^7.1.1",
30
- "chai": "^4.x.x",
31
28
  "eslint": "^8.34.0",
32
29
  "eslint-config-prettier": "^9.0.0",
33
30
  "jsonschema": "^1.4.1",
34
31
  "prettier": "^3.1.0",
35
- "ts-jest": "^29.3.4",
36
32
  "ts-node": "^10.9.2",
37
33
  "typescript": "^5.0.4"
38
34
  },
39
35
  "scripts": {
40
- "test": "rm -rf spec/out && mkdir -p spec/out && jest --ci --runInBand",
36
+ "test": "TS_NODE_PROJECT=tsconfig.spec.json node --require ts-node/register --test \"spec/tests/**/*.spec.ts\"",
41
37
  "build": "tsc && chmod ugo+x lib/cli.js && cp src/retire.d.ts lib/retire.d.ts && cp ../LICENSE.md .",
42
38
  "watch": "tsc --watch ",
43
39
  "typecheck": "tsc --noEmit",