owasp-pipeline 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pipeline/filters/zap_consdensing_filter.rb +76 -0
- data/lib/pipeline/options.rb +7 -0
- data/lib/pipeline/tasks/base_task.rb +16 -0
- data/lib/pipeline/tasks/brakeman.rb +0 -2
- data/lib/pipeline/tasks/bundle-audit.rb +42 -40
- data/lib/pipeline/tasks/checkmarx.rb +0 -1
- data/lib/pipeline/tasks/dawnscanner.rb +0 -1
- data/lib/pipeline/tasks/eslint.rb +0 -2
- data/lib/pipeline/tasks/fim.rb +0 -1
- data/lib/pipeline/tasks/findsecbugs.rb +13 -4
- data/lib/pipeline/tasks/npm.rb +58 -0
- data/lib/pipeline/tasks/nsp.rb +23 -18
- data/lib/pipeline/tasks/pmd.rb +0 -1
- data/lib/pipeline/tasks/retirejs.rb +13 -15
- data/lib/pipeline/tasks/snyk.rb +81 -0
- data/lib/pipeline/tasks/zap.rb +6 -3
- data/lib/pipeline/tasks.rb +5 -5
- data/lib/pipeline/version.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0a8269dc146b2c043c1f82f86a181b69e1bf35e
|
4
|
+
data.tar.gz: e1f15cfe853e2d53b8e894033a9b665f4813ff26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6ff7447583d96ca3b88da5d54f0c85663879017c3e6d4cc4119e5d1969bfd36e356ab5db1e5aaea5bda4df181a95f39f826acac174d72bd53226058b609c741
|
7
|
+
data.tar.gz: 7d811611176d44b8f9d7c3a7955c049430142907f1fb453771724c102617a6a2b49bb9589e6d40e5ba2b880abe08dca874f0039aaadb7ed169fd5e0032ea21a8
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'pipeline/filters/base_filter'
|
2
|
+
|
3
|
+
class Pipeline::ZAPCondensingFilter < Pipeline::BaseFilter
|
4
|
+
|
5
|
+
Pipeline::Filters.add self
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@name = "ZAP Condensing Filter"
|
9
|
+
@description = "Consolidate N ZAP warnings to one per issue type."
|
10
|
+
end
|
11
|
+
|
12
|
+
def filter tracker
|
13
|
+
Pipeline.debug "Have #{tracker.findings.count} items pre ZAP filter."
|
14
|
+
tracker.findings.each do |finding|
|
15
|
+
if zap? finding
|
16
|
+
if xframe? finding
|
17
|
+
record tracker,finding
|
18
|
+
elsif xcontenttypeoptions? finding
|
19
|
+
record tracker, finding
|
20
|
+
elsif dirbrowsing? finding
|
21
|
+
record tracker, finding
|
22
|
+
elsif xxssprotection? finding
|
23
|
+
record tracker, finding
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
Pipeline.debug "Have #{tracker.findings.count} items post ZAP filter."
|
28
|
+
end
|
29
|
+
|
30
|
+
def zap? finding
|
31
|
+
if finding.source =~ /\AZAP/
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
|
37
|
+
def xframe? finding
|
38
|
+
if finding.description == "X-Frame-Options header is not included in the HTTP response to protect against 'ClickJacking' attacks."
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
|
44
|
+
def xcontenttypeoptions? finding
|
45
|
+
if finding.description == "The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing."
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
def dirbrowsing? finding
|
52
|
+
if finding.description == "It is possible to view the directory listing. Directory listing may reveal hidden scripts, include files , backup source files etc which be accessed to read sensitive information."
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
def xxssprotection? finding
|
59
|
+
if finding.description == "Web Browser XSS Protection is not enabled, or is disabled by the configuration of the 'X-XSS-Protection' HTTP response header on the web server"
|
60
|
+
return true
|
61
|
+
end
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Is it always true that the findings will be on the same site?
|
66
|
+
# For now, we can assume that.
|
67
|
+
# Note that this may not be an efficient way to to do this, but it seems to work as a first pass.
|
68
|
+
def record tracker, finding
|
69
|
+
tracker.findings.delete_if do |to_delete|
|
70
|
+
to_delete.description == finding.description
|
71
|
+
end
|
72
|
+
finding.detail << "\n\t** Consolidated ** - Potentially identified in > 1 spot." # Make sure to note that there were
|
73
|
+
tracker.findings.push finding
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
data/lib/pipeline/options.rb
CHANGED
@@ -99,6 +99,13 @@ module Pipeline::Options
|
|
99
99
|
options[:npm_registry] = url
|
100
100
|
end
|
101
101
|
|
102
|
+
opts.on "--exclude path1,path2,path3,etc", Array, "A list of paths to ignore when running recursive tasks (npm, retirejs, snyk, etc)" do |paths|
|
103
|
+
paths.each do |path|
|
104
|
+
options[:exclude_dirs] ||= Set.new
|
105
|
+
options[:exclude_dirs] << path
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
102
109
|
opts.separator ""
|
103
110
|
opts.separator "Output options:"
|
104
111
|
|
@@ -43,6 +43,22 @@ class Pipeline::BaseTask
|
|
43
43
|
@stage
|
44
44
|
end
|
45
45
|
|
46
|
+
def directories_with? file, exclude_dirs = []
|
47
|
+
exclude_dirs = @tracker.options[:exclude_dirs] if exclude_dirs == [] and @tracker.options[:exclude_dirs]
|
48
|
+
results = []
|
49
|
+
|
50
|
+
Find.find(@trigger.path) do |path|
|
51
|
+
if FileTest.directory? path
|
52
|
+
Find.prune if exclude_dirs.include? File.basename(path) or exclude_dirs.include? File.basename(path) + '/'
|
53
|
+
next
|
54
|
+
end
|
55
|
+
|
56
|
+
Find.prune unless File.basename(path) == file
|
57
|
+
|
58
|
+
results << File.dirname(path)
|
59
|
+
end
|
60
|
+
return results
|
61
|
+
end
|
46
62
|
|
47
63
|
def run
|
48
64
|
end
|
@@ -17,7 +17,6 @@ class Pipeline::Brakeman < Pipeline::BaseTask
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def run
|
20
|
-
# Pipeline.notify "#{@name}"
|
21
20
|
rootpath = @trigger.path
|
22
21
|
@result=runsystem(true, "brakeman", "-A", "-q", "-f", "json", "#{rootpath}")
|
23
22
|
end
|
@@ -57,4 +56,3 @@ class Pipeline::Brakeman < Pipeline::BaseTask
|
|
57
56
|
end
|
58
57
|
|
59
58
|
end
|
60
|
-
|
@@ -13,14 +13,15 @@ class Pipeline::BundleAudit < Pipeline::BaseTask
|
|
13
13
|
@description = "Dependency Checker analysis for Ruby"
|
14
14
|
@stage = :code
|
15
15
|
@labels << "code" << "ruby"
|
16
|
+
@results = {}
|
16
17
|
end
|
17
18
|
|
18
19
|
def run
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
directories_with?('Gemfile.lock').each do |dir|
|
21
|
+
Pipeline.notify "#{@name} scanning: #{dir}"
|
22
|
+
Dir.chdir(dir) do
|
23
|
+
@results[dir] = runsystem(true, "bundle-audit", "check")
|
24
|
+
end
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
@@ -46,43 +47,45 @@ class Pipeline::BundleAudit < Pipeline::BaseTask
|
|
46
47
|
|
47
48
|
private
|
48
49
|
def get_warnings
|
49
|
-
|
50
|
-
|
50
|
+
@results.each do |dir, result|
|
51
|
+
detail, jem, source, sev, hash = '','',{},'',''
|
52
|
+
result.each_line do | line |
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
if /\S/ !~ line
|
55
|
+
# Signal section is over. Reset variables and report.
|
56
|
+
if detail != ''
|
57
|
+
report "Gem #{jem} has known security issues.", detail, source, sev, fingerprint(hash)
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
+
detail, jem, source, sev, hash = '','', {},'',''
|
61
|
+
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
63
|
+
name, value = line.chomp.split(':')
|
64
|
+
case name
|
65
|
+
when 'Name'
|
66
|
+
jem << value
|
67
|
+
hash << value
|
68
|
+
when 'Version'
|
69
|
+
jem << value
|
70
|
+
hash << value
|
71
|
+
when 'Advisory'
|
72
|
+
source = { :scanner => @name, :file => "#{relative_path(dir, @trigger.path)}/Gemfile.lock", :line => nil, :code => nil }
|
73
|
+
hash << value
|
74
|
+
when 'Criticality'
|
75
|
+
sev = severity(value)
|
76
|
+
hash << sev
|
77
|
+
when 'URL'
|
78
|
+
detail += line.chomp.split('URL:').last
|
79
|
+
when 'Title'
|
80
|
+
detail += ",#{value}"
|
81
|
+
when 'Solution'
|
82
|
+
detail += ": #{value}"
|
83
|
+
when 'Insecure Source URI found'
|
84
|
+
report "Insecure GEM Source", "#{line.chomp} - use git or https", {:scanner => @name, :file => 'Gemfile.lock', :line => nil, :code => nil}, severity('high'), fingerprint("bundlerauditgemsource#{line.chomp}")
|
85
|
+
else
|
86
|
+
if line =~ /\S/ and line !~ /Unpatched versions found/
|
87
|
+
Pipeline.debug "Not sure how to handle line: #{line}"
|
88
|
+
end
|
86
89
|
end
|
87
90
|
end
|
88
91
|
end
|
@@ -90,4 +93,3 @@ class Pipeline::BundleAudit < Pipeline::BaseTask
|
|
90
93
|
|
91
94
|
|
92
95
|
end
|
93
|
-
|
@@ -16,7 +16,6 @@ class Pipeline::ESLint < Pipeline::BaseTask
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def run
|
19
|
-
Pipeline.notify "#{@name}"
|
20
19
|
rootpath = @trigger.path
|
21
20
|
currentpath = File.expand_path File.dirname(__FILE__)
|
22
21
|
Pipeline.debug "ESLint Config Path: #{currentpath}"
|
@@ -68,4 +67,3 @@ class Pipeline::ESLint < Pipeline::BaseTask
|
|
68
67
|
end
|
69
68
|
|
70
69
|
end
|
71
|
-
|
data/lib/pipeline/tasks/fim.rb
CHANGED
@@ -20,14 +20,23 @@ class Pipeline::FindSecurityBugs < Pipeline::BaseTask
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def run
|
23
|
-
Pipeline.notify "#{@name}"
|
24
23
|
@results_file = Tempfile.new(['findsecbugs','xml'])
|
25
24
|
|
26
|
-
|
27
|
-
|
25
|
+
unless File.exist?("#{@trigger.path}/.git/config")
|
26
|
+
Dir.chdir(@trigger.path) do
|
27
|
+
system("git", "init")
|
28
|
+
system("git", "add", "*")
|
29
|
+
system("git", "commit", "-am", "fake commit for mvn compile")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
directories_with?('pom.xml').each do |dir|
|
34
|
+
Dir.chdir(dir) do
|
35
|
+
runsystem(true, "mvn", "compile", "-fn")
|
36
|
+
end
|
28
37
|
end
|
29
38
|
|
30
|
-
Dir.chdir(
|
39
|
+
Dir.chdir(@tracker.options[:findsecbugs_path]) do
|
31
40
|
runsystem(true, "/bin/sh", "#{@tracker.options[:findsecbugs_path]}/findsecbugs.sh", "-effort:max", "-quiet", "-xml:withMessages", "-output", "#{@results_file.path}", "#{@trigger.path}")
|
32
41
|
@results = Nokogiri::XML(File.read(@results_file)).xpath '//BugInstance'
|
33
42
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'pipeline/tasks/base_task'
|
2
|
+
require 'pipeline/util'
|
3
|
+
require 'find'
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
class Pipeline::Npm < Pipeline::BaseTask
|
7
|
+
|
8
|
+
Pipeline::Tasks.add self
|
9
|
+
include Pipeline::Util
|
10
|
+
|
11
|
+
def initialize(trigger, tracker)
|
12
|
+
super(trigger, tracker)
|
13
|
+
@name = "NPM"
|
14
|
+
@description = "Node Package Manager"
|
15
|
+
@stage = :file
|
16
|
+
@labels << "file" << "javascript"
|
17
|
+
@results = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
exclude_dirs = ['node_modules','bower_components']
|
22
|
+
exclude_dirs = exclude_dirs.concat(@tracker.options[:exclude_dirs]).uniq if @tracker.options[:exclude_dirs]
|
23
|
+
directories_with?('package.json', exclude_dirs).each do |dir|
|
24
|
+
Pipeline.notify "#{@name} scanning: #{dir}"
|
25
|
+
Dir.chdir(dir) do
|
26
|
+
if @tracker.options.has_key?(:npm_registry)
|
27
|
+
registry = "--registry #{@tracker.options[:npm_registry]}"
|
28
|
+
else
|
29
|
+
registry = nil
|
30
|
+
end
|
31
|
+
@command = "npm install --ignore-scripts #{registry}"
|
32
|
+
@results << system(@command)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def analyze
|
38
|
+
begin
|
39
|
+
if @results.include? false
|
40
|
+
Pipeline.warn 'Error installing javascript dependencies with #{@command}'
|
41
|
+
end
|
42
|
+
rescue Exception => e
|
43
|
+
Pipeline.warn e.message
|
44
|
+
Pipeline.warn e.backtrace
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def supported?
|
49
|
+
supported = find_executable0('npm')
|
50
|
+
unless supported
|
51
|
+
Pipeline.notify "Install npm: https://nodejs.org/en/download/"
|
52
|
+
return false
|
53
|
+
else
|
54
|
+
return true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/lib/pipeline/tasks/nsp.rb
CHANGED
@@ -12,31 +12,37 @@ class Pipeline::NodeSecurityProject < Pipeline::BaseTask
|
|
12
12
|
@description = "Node Security Project"
|
13
13
|
@stage = :code
|
14
14
|
@labels << "code"
|
15
|
+
@results = []
|
15
16
|
end
|
16
17
|
|
17
18
|
def run
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
exclude_dirs = ['node_modules','bower_components']
|
20
|
+
exclude_dirs = exclude_dirs.concat(@tracker.options[:exclude_dirs]).uniq if @tracker.options[:exclude_dirs]
|
21
|
+
directories_with?('package.json', exclude_dirs).each do |dir|
|
22
|
+
Pipeline.notify "#{@name} scanning: #{dir}"
|
23
|
+
Dir.chdir(dir) do
|
24
|
+
@results << JSON.parse(`nsp check --output json 2>&1`)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
25
29
|
def analyze
|
26
30
|
begin
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
@results.each do |dir_result|
|
32
|
+
# This block iterates through each package name found and selects the unique nsp advisories
|
33
|
+
# regardless of version, and builds a pipeline finding hash for each unique package/advisory combo.
|
34
|
+
dir_result.uniq {|finding| finding['module']}.each do |package|
|
35
|
+
dir_result.select {|f| f['module'] == package['module']}.uniq {|m| m['advisory']}.each do |unique_finding|
|
36
|
+
description = "#{unique_finding['module']} - #{unique_finding['title']}"
|
37
|
+
detail = "Upgrade to versions: #{unique_finding['patched_versions']}\n#{unique_finding['advisory']}"
|
38
|
+
source = {
|
39
|
+
:scanner => 'NodeSecurityProject',
|
40
|
+
:file => "#{unique_finding['module']} - #{unique_finding['vulnerable_versions']}",
|
41
|
+
:line => nil,
|
42
|
+
:code => nil
|
43
|
+
}
|
44
|
+
report description, detail, source, 'medium', fingerprint("#{description}#{detail}#{source}")
|
45
|
+
end
|
40
46
|
end
|
41
47
|
end
|
42
48
|
rescue Exception => e
|
@@ -56,4 +62,3 @@ class Pipeline::NodeSecurityProject < Pipeline::BaseTask
|
|
56
62
|
end
|
57
63
|
|
58
64
|
end
|
59
|
-
|
data/lib/pipeline/tasks/pmd.rb
CHANGED
@@ -17,7 +17,6 @@ class Pipeline::PMD < Pipeline::BaseTask
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def run
|
20
|
-
Pipeline.notify "#{@name}"
|
21
20
|
@tracker.options[:pmd_checks] ||= "java-basic,java-sunsecure"
|
22
21
|
Dir.chdir @tracker.options[:pmd_path] do
|
23
22
|
@results = Nokogiri::XML(`bin/run.sh pmd -d #{@trigger.path} -f xml -R #{@tracker.options[:pmd_checks]}`).xpath('//file')
|
@@ -3,6 +3,7 @@ require 'json'
|
|
3
3
|
require 'pipeline/util'
|
4
4
|
require 'jsonpath'
|
5
5
|
require 'pathname'
|
6
|
+
require 'pry'
|
6
7
|
|
7
8
|
class Pipeline::RetireJS < Pipeline::BaseTask
|
8
9
|
|
@@ -15,28 +16,26 @@ class Pipeline::RetireJS < Pipeline::BaseTask
|
|
15
16
|
@description = "Dependency analysis for JavaScript"
|
16
17
|
@stage = :code
|
17
18
|
@labels << "code" << "javascript"
|
19
|
+
@results = []
|
18
20
|
end
|
19
21
|
|
20
22
|
def run
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
else
|
27
|
-
registry = nil
|
28
|
-
end
|
29
|
-
@result = `npm install --ignore-scripts #{registry}` # Need this even though it is slow to get full dependency analysis.
|
23
|
+
exclude_dirs = ['node_modules','bower_components']
|
24
|
+
exclude_dirs = exclude_dirs.concat(@tracker.options[:exclude_dirs]).uniq if @tracker.options[:exclude_dirs]
|
25
|
+
directories_with?('package.json', exclude_dirs).each do |dir|
|
26
|
+
Pipeline.notify "#{@name} scanning: #{dir}"
|
27
|
+
@results << `retire -c --outputformat json --path #{dir} 2>&1`
|
30
28
|
end
|
31
|
-
@result = `retire -c --outputformat json --path #{rootpath} 2>&1`
|
32
29
|
end
|
33
30
|
|
34
31
|
def analyze
|
35
32
|
begin
|
36
|
-
|
33
|
+
@results.each do |result|
|
34
|
+
vulnerabilities = parse_retire_json(JSON.parse(result))
|
37
35
|
|
38
|
-
|
39
|
-
|
36
|
+
vulnerabilities.each do |vuln|
|
37
|
+
report "Package #{vuln[:package]} has known security issues", vuln[:detail], vuln[:source], vuln[:severity], fingerprint("#{vuln[:package]}#{vuln[:source]}#{vuln[:severity]}")
|
38
|
+
end
|
40
39
|
end
|
41
40
|
rescue Exception => e
|
42
41
|
Pipeline.warn e.message
|
@@ -84,7 +83,7 @@ class Pipeline::RetireJS < Pipeline::BaseTask
|
|
84
83
|
result.select { |r| !r['file'].nil? }.each do |file_result|
|
85
84
|
JsonPath.on(file_result, '$..component').uniq.each do |comp|
|
86
85
|
JsonPath.on(file_result, "$..results[?(@.component == \'#{comp}\')].version").uniq.each do |version|
|
87
|
-
source_path =
|
86
|
+
source_path = relative_path(file_result['file'], @trigger.path)
|
88
87
|
vulnerabilities.select { |v| v[:package] == "#{comp}-#{version}" }.first[:source] = { :scanner => @name, :file => source_path.to_s, :line => nil, :code => nil }
|
89
88
|
end
|
90
89
|
end
|
@@ -103,4 +102,3 @@ class Pipeline::RetireJS < Pipeline::BaseTask
|
|
103
102
|
end
|
104
103
|
|
105
104
|
end
|
106
|
-
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'pipeline/tasks/base_task'
|
2
|
+
require 'pipeline/util'
|
3
|
+
require 'redcarpet'
|
4
|
+
|
5
|
+
class Pipeline::Snyk < Pipeline::BaseTask
|
6
|
+
|
7
|
+
Pipeline::Tasks.add self
|
8
|
+
include Pipeline::Util
|
9
|
+
|
10
|
+
def initialize(trigger, tracker)
|
11
|
+
super(trigger, tracker)
|
12
|
+
@name = "Snyk"
|
13
|
+
@description = "Snyk.io JS dependency checker"
|
14
|
+
@stage = :code
|
15
|
+
@labels << "code" << "javascript"
|
16
|
+
@results = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
exclude_dirs = ['node_modules','bower_components']
|
21
|
+
exclude_dirs = exclude_dirs.concat(@tracker.options[:exclude_dirs]).uniq if @tracker.options[:exclude_dirs]
|
22
|
+
directories_with?('package.json', exclude_dirs).each do |dir|
|
23
|
+
Pipeline.notify "#{@name} scanning: #{dir}"
|
24
|
+
Dir.chdir(dir) do
|
25
|
+
@results << JSON.parse(runsystem(true, "snyk", "test", "--json"))["vulnerabilities"]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def analyze
|
31
|
+
begin
|
32
|
+
markdown = Redcarpet::Markdown.new Redcarpet::Render::HTML.new(link_attributes: {target: "_blank"}), autolink: true, tables: true
|
33
|
+
|
34
|
+
@results.each do |dir_result|
|
35
|
+
# We build a single finding for each uniq result ID, adding the unique info (upgrade path and files) as a list
|
36
|
+
dir_result.uniq {|r| r['id']}.each do |result|
|
37
|
+
description = "#{result['name']}@#{result['version']} - #{result['title']}"
|
38
|
+
|
39
|
+
# Use Redcarpet to render the Markdown details to something pretty for web display
|
40
|
+
detail = markdown.render(result['description']).gsub('h2>','strong>').gsub('h3>', 'strong>')
|
41
|
+
upgrade_paths = [ "Upgrade Path:\n" ]
|
42
|
+
files = []
|
43
|
+
|
44
|
+
# Pull the list of files and upgrade paths from all results matching this ID
|
45
|
+
# This uses the same form as the retirejs task so it all looks nice together
|
46
|
+
dir_result.select{|r| r['id'] == result['id']}.each do |res|
|
47
|
+
res['upgradePath'].each_with_index do |upgrade, i|
|
48
|
+
upgrade_paths << "#{res['from'][i]} -> #{upgrade}"
|
49
|
+
end
|
50
|
+
files << res['from'].join('->')
|
51
|
+
end
|
52
|
+
|
53
|
+
source = {
|
54
|
+
:scanner => @name,
|
55
|
+
:file => files.join('<br>'),
|
56
|
+
:line => nil,
|
57
|
+
:code => upgrade_paths.uniq.join("\n"),
|
58
|
+
}
|
59
|
+
sev = severity(result['severity'])
|
60
|
+
fprint = fingerprint("#{description}#{detail}#{source}#{sev}")
|
61
|
+
|
62
|
+
report description, detail, source, sev, fprint
|
63
|
+
end
|
64
|
+
end
|
65
|
+
rescue Exception => e
|
66
|
+
Pipeline.warn e.message
|
67
|
+
Pipeline.warn e.backtrace
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def supported?
|
72
|
+
supported = find_executable0('snyk')
|
73
|
+
unless supported
|
74
|
+
Pipeline.notify "Install Snyk: 'npm install -g snyk'"
|
75
|
+
return false
|
76
|
+
else
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/lib/pipeline/tasks/zap.rb
CHANGED
@@ -24,7 +24,10 @@ class Pipeline::Zap < Pipeline::BaseTask
|
|
24
24
|
context = SecureRandom.uuid
|
25
25
|
|
26
26
|
Pipeline.debug "Running ZAP on: #{rootpath} from #{base} with #{context}"
|
27
|
-
|
27
|
+
|
28
|
+
# Create a new session so that the findings will be new.
|
29
|
+
Curl.get("#{base}/JSON/core/action/newSession/?zapapiformat=JSON&apikey=#{apikey}&name=&overwrite=")
|
30
|
+
|
28
31
|
# Set up Context
|
29
32
|
Curl.get("#{base}/JSON/context/action/newContext/?&apikey=#{apikey}&contextName=#{context}")
|
30
33
|
Curl.get("#{base}/JSON/context/action/includeInContext/?apikey=#{apikey}&contextName=#{context}®ex=#{rootpath}.*")
|
@@ -85,10 +88,10 @@ class Pipeline::Zap < Pipeline::BaseTask
|
|
85
88
|
def supported?
|
86
89
|
base = "#{@tracker.options[:zap_host]}:#{@tracker.options[:zap_port]}"
|
87
90
|
supported=JSON.parse(Curl.get("#{base}/JSON/core/view/version/").body_str)
|
88
|
-
if supported["version"]
|
91
|
+
if supported["version"] =~ /2.(4|5).\d+/
|
89
92
|
return true
|
90
93
|
else
|
91
|
-
Pipeline.notify "Install ZAP from owasp.org and ensure that the configuration to connect is correct."
|
94
|
+
Pipeline.notify "Install ZAP from owasp.org and ensure that the configuration to connect is correct. Supported versions = 2.4.0 and up - got #{supported['version']}"
|
92
95
|
return false
|
93
96
|
end
|
94
97
|
end
|
data/lib/pipeline/tasks.rb
CHANGED
@@ -60,8 +60,8 @@ class Pipeline::Tasks
|
|
60
60
|
|
61
61
|
#Run or don't run task based on options
|
62
62
|
#Now case-insensitive specifiers: nodesecurityproject = Pipeline::NodeSecurityProject
|
63
|
-
|
64
|
-
if tracker.options[:skip_tasks]
|
63
|
+
|
64
|
+
if tracker.options[:skip_tasks]
|
65
65
|
skip_tasks = tracker.options[:skip_tasks].map {|task| task.downcase}
|
66
66
|
end
|
67
67
|
if (tracker.options[:run_tasks])
|
@@ -73,9 +73,9 @@ class Pipeline::Tasks
|
|
73
73
|
|
74
74
|
task = c.new(trigger, tracker)
|
75
75
|
begin
|
76
|
-
if task.supported? and task.stage == stage
|
77
|
-
if task.labels.intersect? tracker.options[:labels] or # Only run tasks with labels
|
78
|
-
( run_tasks and run_tasks.include? task_name.downcase ) # or that are explicitly requested.
|
76
|
+
if task.supported? and task.stage == stage
|
77
|
+
if task.labels.intersect? tracker.options[:labels] or # Only run tasks with labels
|
78
|
+
( run_tasks and run_tasks.include? task_name.downcase ) # or that are explicitly requested.
|
79
79
|
Pipeline.notify "#{stage} - #{task_name} - #{task.labels}"
|
80
80
|
task.run
|
81
81
|
task.analyze
|
data/lib/pipeline/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: owasp-pipeline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Konda
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-04-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: terminal-table
|
@@ -166,6 +166,20 @@ dependencies:
|
|
166
166
|
- - ">="
|
167
167
|
- !ruby/object:Gem::Version
|
168
168
|
version: 1.6.0
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
name: redcarpet
|
171
|
+
requirement: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
type: :runtime
|
177
|
+
prerelease: false
|
178
|
+
version_requirements: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
169
183
|
- !ruby/object:Gem::Dependency
|
170
184
|
name: pry
|
171
185
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +225,7 @@ files:
|
|
211
225
|
- lib/pipeline/filters/base_filter.rb
|
212
226
|
- lib/pipeline/filters/jira_one_time_filter.rb
|
213
227
|
- lib/pipeline/filters/remove_all_filter.rb
|
228
|
+
- lib/pipeline/filters/zap_consdensing_filter.rb
|
214
229
|
- lib/pipeline/finding.rb
|
215
230
|
- lib/pipeline/mounters.rb
|
216
231
|
- lib/pipeline/mounters/base_mounter.rb
|
@@ -237,6 +252,7 @@ files:
|
|
237
252
|
- lib/pipeline/tasks/eslint.rb
|
238
253
|
- lib/pipeline/tasks/fim.rb
|
239
254
|
- lib/pipeline/tasks/findsecbugs.rb
|
255
|
+
- lib/pipeline/tasks/npm.rb
|
240
256
|
- lib/pipeline/tasks/nsp.rb
|
241
257
|
- lib/pipeline/tasks/owasp-dep-check.rb
|
242
258
|
- lib/pipeline/tasks/patterns.json
|
@@ -245,6 +261,7 @@ files:
|
|
245
261
|
- lib/pipeline/tasks/scanjs-eslintrc
|
246
262
|
- lib/pipeline/tasks/scanjs.rb
|
247
263
|
- lib/pipeline/tasks/sfl.rb
|
264
|
+
- lib/pipeline/tasks/snyk.rb
|
248
265
|
- lib/pipeline/tasks/test.rb
|
249
266
|
- lib/pipeline/tasks/zap.rb
|
250
267
|
- lib/pipeline/tracker.rb
|