retire 3.0.7 → 3.1.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/README.md +1 -1
- package/bin/retire +4 -4
- package/lib/reporters/cyclonedx-json.js +68 -0
- package/lib/reporters/cyclonedx.js +41 -32
- package/lib/reporters/depcheck.js +4 -4
- package/lib/reporters/json.js +1 -1
- package/lib/reporting.js +9 -6
- package/lib/retire.js +1 -1
- package/lib/utils.js +2 -2
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Options:
|
|
|
31
31
|
--noderepo <path|url> Local or internal version of repo
|
|
32
32
|
--cachedir <path> Path to use for local cache instead of /tmp/.retire-cache
|
|
33
33
|
--proxy <url> Proxy url (http://some.sever:8080)
|
|
34
|
-
--outputformat <format> Valid formats: text, json, jsonsimple, depcheck (experimental) and
|
|
34
|
+
--outputformat <format> Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx and cyclonedxJSON
|
|
35
35
|
--outputpath <path> File to which output should be written
|
|
36
36
|
--ignore <paths> Comma delimited list of paths to ignore
|
|
37
37
|
--ignorefile <path> Custom ignore file, defaults to .retireignore / .retireignore.json
|
package/bin/retire
CHANGED
|
@@ -54,7 +54,7 @@ program
|
|
|
54
54
|
.option('--noderepo <path|url>', 'Local or internal version of repo')
|
|
55
55
|
.option('--cachedir <path>', 'Path to use for local cache instead of /tmp/.retire-cache')
|
|
56
56
|
.option('--proxy <url>', 'Proxy url (http://some.sever:8080)')
|
|
57
|
-
.option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental) and
|
|
57
|
+
.option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx and cyclonedxJSON')
|
|
58
58
|
.option('--outputpath <path>', 'File to which output should be written')
|
|
59
59
|
.option('--ignore <paths>', 'Comma delimited list of paths to ignore')
|
|
60
60
|
.option('--ignorefile <path>', 'Custom ignore file, defaults to .retireignore / .retireignore.json')
|
|
@@ -113,13 +113,13 @@ if(config.ignorefile) {
|
|
|
113
113
|
if (config.ignorefile.substr(-5) === ".json") {
|
|
114
114
|
try {
|
|
115
115
|
var ignored = JSON.parse(fs.readFileSync(config.ignorefile).toString());
|
|
116
|
-
}
|
|
116
|
+
} catch(e) {
|
|
117
117
|
exitWithError('Error: Invalid ignore file: ' + config.ignorefile, e);
|
|
118
118
|
}
|
|
119
119
|
config.ignore.descriptors = ignored;
|
|
120
120
|
var ignoredPaths = ignored
|
|
121
121
|
.map(function(x) { return x.path; })
|
|
122
|
-
.filter(function(x) { return x;
|
|
122
|
+
.filter(function(x) { return x; });
|
|
123
123
|
config.ignore.paths = config.ignore.paths.concat(ignoredPaths);
|
|
124
124
|
} else {
|
|
125
125
|
var lines = fs.readFileSync(config.ignorefile).toString().split(/\r\n|\n/g).filter(function(e) { return e !== ''; });
|
|
@@ -191,7 +191,7 @@ events.on('scan-js', function() {
|
|
|
191
191
|
scanner.scanJsFile(file, jsRepo, config);
|
|
192
192
|
})
|
|
193
193
|
.on('bowerfile', function(bowerfile) {
|
|
194
|
-
bowerRepo = bowerRepo ||
|
|
194
|
+
bowerRepo = bowerRepo || repo.asbowerrepo(jsRepo);
|
|
195
195
|
scanner.scanBowerFile(bowerfile, bowerRepo, config);
|
|
196
196
|
})
|
|
197
197
|
.on('end', function() {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*jshint esversion: 6 */
|
|
2
|
+
|
|
3
|
+
var retire = require('../retire');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var uuidv4 = require('uuid').v4;
|
|
6
|
+
|
|
7
|
+
function configureCycloneDXJSONLogger(logger, writer, config, hash) {
|
|
8
|
+
var vulnsFound = false;
|
|
9
|
+
var finalResults = { version: retire.version, start: new Date(), data: [], messages: [], errors: [] };
|
|
10
|
+
logger.info = finalResults.messages.push;
|
|
11
|
+
logger.debug = config.verbose ? finalResults.messages.push : function() {};
|
|
12
|
+
logger.warn = logger.error = finalResults.errors.push;
|
|
13
|
+
logger.logVulnerableDependency = function(finding) {
|
|
14
|
+
vulnsFound = true;
|
|
15
|
+
finalResults.data.push(finding);
|
|
16
|
+
};
|
|
17
|
+
logger.logDependency = function(finding) {
|
|
18
|
+
if (finding.results.length > 0) {
|
|
19
|
+
finalResults.data.push(finding);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
logger.close = function(callback) {
|
|
24
|
+
var write = vulnsFound ? writer.err : writer.out;
|
|
25
|
+
finalResults.start = finalResults.start.toISOString();
|
|
26
|
+
var seen = {};
|
|
27
|
+
var components = finalResults.data.filter(d => d.results).map(r => r.results.map(dep => {
|
|
28
|
+
dep.version = (dep.version.split(".").length >= 3 ? dep.version : dep.version + ".0").replace(/-/g, ".");
|
|
29
|
+
var filepath = r.file || dep.file;
|
|
30
|
+
var file = fs.readFileSync(filepath);
|
|
31
|
+
var purl = `pkg:npm/${dep.component}@${dep.version}`;
|
|
32
|
+
if (seen[purl]) return '';
|
|
33
|
+
seen[purl] = true;
|
|
34
|
+
return {
|
|
35
|
+
type: "library",
|
|
36
|
+
name: dep.component,
|
|
37
|
+
version: dep.version,
|
|
38
|
+
purl: purl,
|
|
39
|
+
hashes: [
|
|
40
|
+
{ "alg" : "MD5", "content" : hash.md5(file) },
|
|
41
|
+
{ "alg" : "SHA-1", "content" : hash.sha1(file) },
|
|
42
|
+
{ "alg" : "SHA-256", "content" : hash.sha256(file) },
|
|
43
|
+
{ "alg" : "SHA-512", "content" : hash.sha512(file) },
|
|
44
|
+
]
|
|
45
|
+
};
|
|
46
|
+
}));
|
|
47
|
+
write(JSON.stringify({
|
|
48
|
+
bomFormat : "CycloneDX",
|
|
49
|
+
specVersion : "1.4",
|
|
50
|
+
serialNumber : `urn:uuid:${ uuidv4() }`,
|
|
51
|
+
version : 1,
|
|
52
|
+
components : components,
|
|
53
|
+
metadata : {
|
|
54
|
+
timestamp : finalResults.start,
|
|
55
|
+
tools : [
|
|
56
|
+
{
|
|
57
|
+
vendor : "RetireJS",
|
|
58
|
+
name : "retire.js",
|
|
59
|
+
version : retire.version
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}, undefined, 2));
|
|
64
|
+
writer.close(callback);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
exports.configure = configureCycloneDXJSONLogger;
|
|
@@ -2,37 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
var retire = require('../retire');
|
|
4
4
|
var fs = require('fs');
|
|
5
|
+
var uuidv4 = require('uuid').v4;
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
function configureCycloneDXLogger(logger, writer, config, hash) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
var vulnsFound = false;
|
|
10
|
+
var finalResults = { version: retire.version, start: new Date(), data: [], messages: [], errors: [] };
|
|
11
|
+
logger.info = finalResults.messages.push;
|
|
12
|
+
logger.debug = config.verbose ? finalResults.messages.push : function() {};
|
|
13
|
+
logger.warn = logger.error = finalResults.errors.push;
|
|
14
|
+
logger.logVulnerableDependency = function(finding) {
|
|
15
|
+
vulnsFound = true;
|
|
16
|
+
finalResults.data.push(finding);
|
|
17
|
+
};
|
|
18
|
+
logger.logDependency = function(finding) {
|
|
19
|
+
if (finding.results.length > 0) {
|
|
20
|
+
finalResults.data.push(finding);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return `
|
|
24
|
+
logger.close = function(callback) {
|
|
25
|
+
var write = vulnsFound ? writer.err : writer.out;
|
|
26
|
+
var seen = {};
|
|
27
|
+
var components = finalResults.data.filter(d => d.results).map(r => r.results.map(dep => {
|
|
28
|
+
dep.version = (dep.version.split(".").length >= 3 ? dep.version : dep.version + ".0").replace(/-/g, ".");
|
|
29
|
+
var filepath = r.file || dep.file;
|
|
30
|
+
var filename = filepath.split("/").slice(-1);
|
|
31
|
+
var file = fs.readFileSync(filepath);
|
|
32
|
+
var purl = `pkg:npm/${dep.component}@${dep.version}`;
|
|
33
|
+
if (seen[purl]) return '';
|
|
34
|
+
seen[purl] = true;
|
|
35
|
+
return `
|
|
36
36
|
<component type="library">
|
|
37
37
|
<name>${dep.component}</name>
|
|
38
38
|
<version>${dep.version}</version>
|
|
@@ -42,18 +42,27 @@ function configureCycloneDXLogger(logger, writer, config, hash) {
|
|
|
42
42
|
<hash alg="SHA-256">${hash.sha256(file)}</hash>
|
|
43
43
|
<hash alg="SHA-512">${hash.sha512(file)}</hash>
|
|
44
44
|
</hashes>
|
|
45
|
-
<licenses><license></license></licenses>
|
|
46
45
|
<purl>${purl}</purl>
|
|
47
46
|
<modified>false</modified>
|
|
48
47
|
</component>`;
|
|
49
48
|
}).join("")).join("");
|
|
50
|
-
|
|
51
|
-
<bom xmlns="http://cyclonedx.org/schema/bom/1.
|
|
49
|
+
write(`<?xml version="1.0"?>
|
|
50
|
+
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:${ uuidv4() }" version="1">
|
|
51
|
+
<metadata>
|
|
52
|
+
<timestamp>${finalResults.start.toISOString()}</timestamp>
|
|
53
|
+
<tools>
|
|
54
|
+
<tool>
|
|
55
|
+
<vendor>RetireJS</vendor>
|
|
56
|
+
<name>retire.js</name>
|
|
57
|
+
<version>${ retire.version }</version>
|
|
58
|
+
</tool>
|
|
59
|
+
</tools>
|
|
60
|
+
</metadata>
|
|
52
61
|
<components>${components}
|
|
53
62
|
</components>
|
|
54
63
|
</bom>`);
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
writer.close(callback);
|
|
65
|
+
};
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
exports.configure = configureCycloneDXLogger;
|
|
@@ -14,7 +14,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
|
|
|
14
14
|
vulnsFound = true;
|
|
15
15
|
finalResults.data.push(finding);
|
|
16
16
|
};
|
|
17
|
-
logger.logDependency = function(finding) {
|
|
17
|
+
logger.logDependency = function(finding) {
|
|
18
18
|
if (config.verbose && finding.results.length > 0) {
|
|
19
19
|
finalResults.data.push(finding);
|
|
20
20
|
}
|
|
@@ -28,7 +28,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
|
|
|
28
28
|
<scanInfo>
|
|
29
29
|
<engineVersion>${retire.version}</engineVersion>
|
|
30
30
|
<dataSource><name>${config.jsRepo || "Retire.js github js repo"}</name><timestamp>${finalResults.start}</timestamp></dataSource>
|
|
31
|
-
<dataSource><name>${config.nodeRepo ||
|
|
31
|
+
<dataSource><name>${config.nodeRepo || "Retire.js github node repo"}</name><timestamp>${finalResults.start}</timestamp></dataSource>
|
|
32
32
|
</scanInfo>
|
|
33
33
|
<projectInfo>
|
|
34
34
|
<name>${config.path}</name>
|
|
@@ -37,7 +37,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
|
|
|
37
37
|
</projectInfo>
|
|
38
38
|
<dependencies>`);
|
|
39
39
|
write(finalResults.data.filter(d => d.results).map(r => r.results.map((dep, i) => {
|
|
40
|
-
var filepath = r.file ||
|
|
40
|
+
var filepath = r.file || dep.file;
|
|
41
41
|
var filename = filepath.split("/").slice(-1);
|
|
42
42
|
var file = fs.readFileSync(filepath);
|
|
43
43
|
var md5 = hash.md5(file);
|
|
@@ -82,7 +82,7 @@ function configureDepCheckLogger(logger, writer, config, hash) {
|
|
|
82
82
|
<availabilityImpact>PARTIAL</availabilityImpact>
|
|
83
83
|
<severity>${v.severity || "medium"}</severity>
|
|
84
84
|
</cvssV2>
|
|
85
|
-
<description>${v.identifiers && v.identifiers.summary ||
|
|
85
|
+
<description>${v.identifiers && v.identifiers.summary || "None"}</description>
|
|
86
86
|
<references>${references}
|
|
87
87
|
</references>
|
|
88
88
|
<vulnerableSoftware>
|
package/lib/reporters/json.js
CHANGED
|
@@ -13,7 +13,7 @@ function configureJsonLogger(logger, writer, config) {
|
|
|
13
13
|
vulnsFound = true;
|
|
14
14
|
finalResults.data.push(finding);
|
|
15
15
|
};
|
|
16
|
-
logger.logDependency = function(finding) {
|
|
16
|
+
logger.logDependency = function(finding) {
|
|
17
17
|
if (config.verbose && finding.results.length > 0) {
|
|
18
18
|
finalResults.data.push(finding);
|
|
19
19
|
}
|
package/lib/reporting.js
CHANGED
|
@@ -6,16 +6,17 @@ var fs = require('fs');
|
|
|
6
6
|
var crypto = require('crypto');
|
|
7
7
|
|
|
8
8
|
var loggers = {
|
|
9
|
-
console
|
|
10
|
-
text
|
|
11
|
-
json
|
|
12
|
-
depcheck
|
|
13
|
-
cyclonedx: require("./reporters/cyclonedx")
|
|
9
|
+
console : require("./reporters/console"),
|
|
10
|
+
text : require("./reporters/console"),
|
|
11
|
+
json : require("./reporters/json"),
|
|
12
|
+
depcheck : require("./reporters/depcheck"),
|
|
13
|
+
cyclonedx : require("./reporters/cyclonedx"),
|
|
14
|
+
cyclonedxJSON : require("./reporters/cyclonedx-json")
|
|
14
15
|
};
|
|
16
|
+
|
|
15
17
|
loggers.clean = loggers.console;
|
|
16
18
|
loggers.jsonsimple = loggers.json;
|
|
17
19
|
|
|
18
|
-
|
|
19
20
|
var colorwarn = function(x) { return x; };
|
|
20
21
|
|
|
21
22
|
var verbose = false;
|
|
@@ -91,3 +92,5 @@ exports.open = function(config) {
|
|
|
91
92
|
}
|
|
92
93
|
return logger;
|
|
93
94
|
};
|
|
95
|
+
|
|
96
|
+
exports.hash = hash;
|
package/lib/retire.js
CHANGED
package/lib/utils.js
CHANGED
|
@@ -31,8 +31,8 @@ exports.map = function(o, fn) {
|
|
|
31
31
|
return Object.keys(o).map(function(k) { return fn(o[k], k); });
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
exports.find = function(ar, fn)
|
|
35
|
-
for(var i in ar)
|
|
34
|
+
exports.find = function(ar, fn) {
|
|
35
|
+
for(var i in ar) {
|
|
36
36
|
if (fn(ar[i])) return ar[i];
|
|
37
37
|
}
|
|
38
38
|
return 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": "3.0
|
|
5
|
+
"version": "3.1.0",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -17,11 +17,14 @@
|
|
|
17
17
|
"commander": "2.5.x",
|
|
18
18
|
"proxy-agent": "^5.0.0",
|
|
19
19
|
"read-installed": "^4.0.3",
|
|
20
|
+
"uuid": "^8.3.2",
|
|
20
21
|
"walkdir": "0.4.1"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"chai": "^4.3.4",
|
|
24
25
|
"jshint": "^2.13.4",
|
|
26
|
+
"jsonschema": "^1.4.1",
|
|
27
|
+
"libxmljs": "^0.19.10",
|
|
25
28
|
"mocha": "^9.2.0"
|
|
26
29
|
},
|
|
27
30
|
"scripts": {
|