owasp-pipeline 0.8.5 → 0.8.6
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.
- 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
|