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 +17 -0
- package/lib/cli.js +2 -1
- package/lib/reporters/cyclonedx-1_6-json.js +20 -3
- package/lib/reporters/cyclonedx-json.js +5 -0
- package/lib/reporters/cyclonedx.js +21 -1
- package/lib/reporters/json.js +3 -0
- package/lib/reporters/utils.d.ts +4 -0
- package/lib/reporters/utils.js +9 -0
- package/lib/reporting.d.ts +2 -1
- package/lib/retire.js +1 -1
- package/package.json +3 -7
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
|
|
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:
|
|
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
|
-
|
|
125
|
-
|
|
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, '&')
|
|
136
|
+
.replace(/</g, '<')
|
|
137
|
+
.replace(/>/g, '>')
|
|
138
|
+
.replace(/"/g, '"');
|
|
139
|
+
}
|
|
120
140
|
function mapLicenses(licenses) {
|
|
121
141
|
if (!licenses)
|
|
122
142
|
return '';
|
package/lib/reporters/json.js
CHANGED
|
@@ -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
|
package/lib/reporters/utils.d.ts
CHANGED
|
@@ -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[];
|
package/lib/reporters/utils.js
CHANGED
|
@@ -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
|
+
}
|
package/lib/reporting.d.ts
CHANGED
package/lib/retire.js
CHANGED
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.
|
|
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.
|
|
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": "
|
|
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",
|