Skip to content

Commit b94fc30

Browse files
Andras Tothdszakallas
authored andcommitted
feat(security): include snyk patches
1 parent 907be52 commit b94fc30

File tree

3 files changed

+349
-10
lines changed

3 files changed

+349
-10
lines changed

lib/agent/security/security.js

Lines changed: 127 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
var childProcess = require('child_process')
2+
var fs = require('fs')
23
var debug = require('debug')('risingstack/trace')
4+
var yaml = require('js-yaml')
5+
var forEach = require('lodash.foreach')
6+
var uniq = require('lodash.uniq')
37

48
function Security (options) {
59
this.name = 'Security'
@@ -14,7 +18,96 @@ function Security (options) {
1418
}
1519
}
1620

17-
Security.prototype.collectDependencies = function (callback) {
21+
Security.prototype.collectSnykFlags = function collectSnykFlags (callback) {
22+
fs.readFile('.snyk', function (error, data) {
23+
if (error) {
24+
// .snyk file is not present, not an error
25+
callback(null, [])
26+
return
27+
}
28+
29+
var patch
30+
try {
31+
patch = yaml.safeLoad(data).patch
32+
} catch (ex) {
33+
debug('error collecting snyk flags', ex)
34+
callback(null, [])
35+
return
36+
}
37+
38+
// no patches
39+
if (!patch || !Object.keys(patch).length) {
40+
callback(null, [])
41+
return
42+
}
43+
44+
var patchedVulnIds = Object.keys(patch)
45+
var packageNames = patchedVulnIds
46+
.map(function (patch) {
47+
return patch.split(':')[1]
48+
})
49+
50+
childProcess.execFile('npm', ['ls'].concat(uniq(packageNames)).concat(['--parseable', '--long']), function (_error, stdout, stderr) {
51+
if (_error) {
52+
// ignore
53+
debug('`npm ls <package_names> --long --parseable` returned error', _error)
54+
}
55+
56+
var pkgs = stdout.split('\n')
57+
.filter(function (string) {
58+
return string !== ''
59+
})
60+
.map(function (pkg) {
61+
return {
62+
nameWithVersion: pkg.split(':')[1].trim(),
63+
path: pkg.split(':')[0].trim()
64+
}
65+
})
66+
67+
var flags = {}
68+
var pending = pkgs.length
69+
pkgs.forEach(function (pkg) {
70+
flags[pkg.nameWithVersion] = []
71+
72+
// read dependency directory
73+
fs.readdir(pkg.path, function (__error, files) {
74+
if (__error) {
75+
pending -= 1
76+
return
77+
}
78+
79+
var vulnIds = files
80+
// filter snyk flag files
81+
.filter(function (file) {
82+
return /.snyk-.*-\d*.flag/.test(file)
83+
})
84+
// turn them into vulnIds
85+
.map(function (file) {
86+
return file.split(/-|\./g)
87+
.filter(function (string) {
88+
return string !== ''
89+
})
90+
.slice(1, 4)
91+
.join(':')
92+
})
93+
// filter for patched vulnIds
94+
.filter(function (fileVulnId) {
95+
return patchedVulnIds.indexOf(fileVulnId) > -1
96+
})
97+
98+
Array.prototype.push.apply(flags[pkg.nameWithVersion], vulnIds)
99+
100+
pending -= 1
101+
if (!pending) {
102+
callback(null, flags)
103+
}
104+
})
105+
})
106+
})
107+
})
108+
}
109+
110+
Security.prototype.collectDependencies = function collectDependencies (callback) {
18111
var maxBuffer = 10 * 1024 * 1024 // 10mb
19112
childProcess.execFile('npm', ['ls', '--json', '--production'], {
20113
maxBuffer: maxBuffer
@@ -28,26 +121,54 @@ Security.prototype.collectDependencies = function (callback) {
28121
parsedDependencies = JSON.parse(stdout).dependencies
29122

30123
if (!parsedDependencies) {
31-
return callback(new Error('`npm ls --json --production` returned with no dependencies'))
124+
callback(new Error('`npm ls --json --production` returned with no dependencies'))
125+
return
32126
}
33127
} catch (ex) {
34-
return callback(ex)
128+
callback(ex)
129+
return
35130
}
36131

37-
return callback(null, parsedDependencies)
132+
callback(null, parsedDependencies)
38133
})
39134
}
40135

41-
Security.prototype.sendDependencies = function () {
136+
Security.prototype.sendDependencies = function sendDependencies () {
42137
var _this = this
43138
this.collectDependencies(function (error, dependencies) {
44139
if (error) {
45140
debug('error collecting dependencies', error)
46141
return
47142
}
48143

49-
_this.collectorApi.sendDependencies(dependencies)
144+
_this.collectSnykFlags(function (_error, flags) {
145+
if (_error) {
146+
debug('error collecting snyk flags', _error)
147+
// send dependencies without patches
148+
_this.collectorApi.sendDependencies(dependencies)
149+
return
150+
}
151+
152+
forEach(dependencies, function (dependency, packageName) {
153+
addPatchesToDependency(dependency, packageName, flags)
154+
})
155+
156+
_this.collectorApi.sendDependencies(dependencies)
157+
})
50158
})
159+
160+
function addPatchesToDependency (dependency, packageName, flags) {
161+
if (dependency.dependencies) {
162+
forEach(dependency.dependencies, function (subDependency, subPackageName) {
163+
addPatchesToDependency(subDependency, subPackageName, flags)
164+
})
165+
}
166+
167+
var patches = flags[packageName + '@' + dependency.version]
168+
if (patches) {
169+
dependency.patches = patches
170+
}
171+
}
51172
}
52173

53174
function create (options) {

0 commit comments

Comments
 (0)