owasp-pipeline 0.8.3

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +23 -0
  3. data/FEATURES +19 -0
  4. data/README.md +101 -0
  5. data/bin/pipeline +67 -0
  6. data/lib/pipeline.rb +301 -0
  7. data/lib/pipeline/event.rb +14 -0
  8. data/lib/pipeline/filters.rb +41 -0
  9. data/lib/pipeline/filters/base_filter.rb +19 -0
  10. data/lib/pipeline/filters/jira_one_time_filter.rb +57 -0
  11. data/lib/pipeline/filters/remove_all_filter.rb +16 -0
  12. data/lib/pipeline/finding.rb +52 -0
  13. data/lib/pipeline/mounters.rb +55 -0
  14. data/lib/pipeline/mounters/base_mounter.rb +31 -0
  15. data/lib/pipeline/mounters/docker_mounter.rb +44 -0
  16. data/lib/pipeline/mounters/filesystem_mounter.rb +25 -0
  17. data/lib/pipeline/mounters/git_mounter.rb +52 -0
  18. data/lib/pipeline/mounters/iso_mounter.rb +42 -0
  19. data/lib/pipeline/mounters/url_mounter.rb +28 -0
  20. data/lib/pipeline/options.rb +240 -0
  21. data/lib/pipeline/reporters.rb +50 -0
  22. data/lib/pipeline/reporters/base_reporter.rb +21 -0
  23. data/lib/pipeline/reporters/csv_reporter.rb +19 -0
  24. data/lib/pipeline/reporters/jira_reporter.rb +61 -0
  25. data/lib/pipeline/reporters/json_reporter.rb +20 -0
  26. data/lib/pipeline/reporters/text_reporter.rb +19 -0
  27. data/lib/pipeline/scanner.rb +28 -0
  28. data/lib/pipeline/tasks.rb +124 -0
  29. data/lib/pipeline/tasks/av.rb +43 -0
  30. data/lib/pipeline/tasks/base_task.rb +64 -0
  31. data/lib/pipeline/tasks/brakeman.rb +60 -0
  32. data/lib/pipeline/tasks/bundle-audit.rb +93 -0
  33. data/lib/pipeline/tasks/checkmarx.rb +62 -0
  34. data/lib/pipeline/tasks/eslint.rb +71 -0
  35. data/lib/pipeline/tasks/fim.rb +61 -0
  36. data/lib/pipeline/tasks/nsp.rb +59 -0
  37. data/lib/pipeline/tasks/owasp-dep-check.rb +120 -0
  38. data/lib/pipeline/tasks/patterns.json +394 -0
  39. data/lib/pipeline/tasks/retirejs.rb +106 -0
  40. data/lib/pipeline/tasks/scanjs-eslintrc +106 -0
  41. data/lib/pipeline/tasks/scanjs.rb +32 -0
  42. data/lib/pipeline/tasks/sfl.rb +67 -0
  43. data/lib/pipeline/tasks/test.rb +47 -0
  44. data/lib/pipeline/tasks/zap.rb +84 -0
  45. data/lib/pipeline/tracker.rb +47 -0
  46. data/lib/pipeline/util.rb +39 -0
  47. data/lib/pipeline/version.rb +3 -0
  48. data/lib/zapjson.json +0 -0
  49. metadata +205 -0
@@ -0,0 +1,28 @@
1
+ require 'pipeline/mounters/base_mounter'
2
+
3
+ class Pipeline::URLMounter < Pipeline::BaseMounter
4
+ Pipeline::Mounters.add self
5
+
6
+ def initialize trigger, options
7
+ super(trigger)
8
+ @options = options
9
+ @name = "URL"
10
+ @description = "Mount a url - typically for a live attack."
11
+ end
12
+
13
+ def mount target
14
+ return target
15
+ end
16
+
17
+ def supports? target
18
+ start = target.slice(0,4)
19
+ last = target.slice(-4,target.length)
20
+ if last === ".git"
21
+ return false
22
+ elsif start === "http"
23
+ return true
24
+ else
25
+ return false
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,240 @@
1
+ require 'optparse'
2
+ require 'set'
3
+
4
+ #Parses command line arguments for Brakeman
5
+ module Pipeline::Options
6
+
7
+ class << self
8
+
9
+ #Parse argument array
10
+ def parse args
11
+ get_options args
12
+ end
13
+
14
+ #Parse arguments and remove them from the array as they are matched
15
+ def parse! args
16
+ get_options args, true
17
+ end
18
+
19
+ #Return hash of options and the parser
20
+ def get_options args, destructive = false
21
+ options = {}
22
+
23
+ parser = OptionParser.new do |opts|
24
+ opts.banner = "Usage: pipeline [options] image/root/path"
25
+
26
+ opts.separator ""
27
+ opts.separator "Pipeline is a swiss army knife of security analysis tools."
28
+ opts.separator "It has built in support for static analysis, AV, fim, and "
29
+ opts.separator "is being extended to be used for analyzing all kinds of "
30
+ opts.separator "projects, images or file systems."
31
+ opts.separator ""
32
+ opts.separator "Pipeline also features filters to perform deduplication "
33
+ opts.separator "and the abilty to handle false positives."
34
+ opts.separator ""
35
+ opts.separator "See also the docker image."
36
+ opts.separator ""
37
+
38
+ opts.separator "Control options:"
39
+
40
+ opts.on "-n", "--no-threads", "Run checks sequentially" do
41
+ options[:parallel_checks] = false
42
+ end
43
+
44
+ opts.on "--[no-]progress", "Show progress reports" do |progress|
45
+ options[:report_progress] = progress
46
+ end
47
+
48
+ opts.on "-T", "--target PATH", "Specify target" do |target|
49
+ options[:target] = path
50
+ end
51
+
52
+ opts.on "-q", "--[no-]quiet", "Suppress informational messages" do |quiet|
53
+ options[:quiet] = quiet
54
+ end
55
+
56
+ opts.on( "-z", "--exit-on-warn", "Exit code is non-zero if warnings found") do
57
+ options[:exit_on_warn] = true
58
+ end
59
+
60
+ opts.separator ""
61
+ opts.separator "Scanning options:"
62
+
63
+ opts.on "-A", "--run-all-checks", "Run all default and optional checks" do
64
+ options[:run_all_checks] = true
65
+ end
66
+
67
+ opts.on "-t", "--test Check1,Check2,etc", Array, "Only run the specified checks" do |checks|
68
+ options[:run_tasks] ||= Set.new
69
+ options[:run_tasks].merge checks
70
+ end
71
+
72
+ opts.on "-x", "--except Check1,Check2,etc", Array, "Skip the specified checks" do |skip|
73
+ skip.each do |s|
74
+
75
+ options[:skip_checks] ||= Set.new
76
+ options[:skip_checks] << s
77
+ end
78
+ end
79
+
80
+ opts.on "-a", "--appname NAME", "Override the inferred application name." do |appname|
81
+ options[:appname] = appname
82
+ end
83
+
84
+ opts.on "-r", "--revision REV", "Specify a revision of software to pass on to checkmarx" do |revision|
85
+ options[:revision] = revision
86
+ end
87
+
88
+ opts.on "-l", "--labels Label1,Label2,etc", Array, "Run the checks with the supplied labels" do |labels|
89
+ options[:labels] ||= Set.new
90
+ options[:labels].merge labels
91
+ end
92
+
93
+ opts.on "--add-checks-path path1,path2,etc", Array, "A directory containing additional out-of-tree checks to run" do |paths|
94
+ options[:additional_checks_path] ||= Set.new
95
+ options[:additional_checks_path].merge paths.map {|p| File.expand_path p}
96
+ end
97
+
98
+ opts.on "--npm-registry URL", "Use a custom npm registry when installing dependencies for javascript scanners" do |url|
99
+ options[:npm_registry] = url
100
+ end
101
+
102
+ opts.separator ""
103
+ opts.separator "Output options:"
104
+
105
+ opts.on "-d", "--debug", "Lots of output" do
106
+ options[:debug] = true
107
+ end
108
+
109
+ opts.on "-f",
110
+ "--format TYPE",
111
+ [:text, :html, :csv, :tabs, :json, :jira, :markdown],
112
+ "Specify output formats. Default is text" do |type|
113
+ options[:output_format] = type
114
+ end
115
+
116
+ opts.on "--css-file CSSFile", "Specify CSS to use for HTML output" do |file|
117
+ options[:html_style] = File.expand_path file
118
+ end
119
+
120
+ opts.on "-i IGNOREFILE", "--ignore-config IGNOREFILE", "Use configuration to ignore warnings" do |file|
121
+ options[:ignore_file] = file
122
+ end
123
+
124
+ opts.on "-I", "--interactive-ignore", "Interactively ignore warnings" do
125
+ options[:interactive_ignore] = true
126
+ end
127
+
128
+ opts.on "-o", "--output FILE", "Specify file for output. Defaults to stdout." do |file|
129
+ options[:output_file] = file
130
+ end
131
+
132
+ opts.on "--summary", "Only output summary of warnings" do
133
+ options[:summary_only] = true
134
+ end
135
+
136
+ opts.separator ""
137
+ opts.separator "JIRA options:"
138
+
139
+ opts.on "--jira-project PROJECT", "Specify the jira project to create issues in. If issue looks like APPS-13, this should be APPS." do |project|
140
+ options[:jira_project] = project
141
+ end
142
+
143
+ opts.on "--jira-api-url URL", "Specify the jira rest api endpoint. Eg. domain.com/jira/jira/rest/api/2/." do |url|
144
+ options[:jira_api_url] = url
145
+ end
146
+
147
+ opts.on "--jira-cookie COOKIE", "Specify the session cookie to get to Jira." do |cookie|
148
+ options[:jira_cookie] = cookie
149
+ end
150
+
151
+ opts.on "--jira-component COMPONENT", "Specify the JIRA component to use." do |component|
152
+ options[:jira_component] = component
153
+ end
154
+
155
+ opts.separator ""
156
+ opts.separator "ZAP options:"
157
+
158
+ opts.on "--zap-api-token token", "Specify the ZAP API token to use when connecting to the API" do |token|
159
+ options[:zap_api_token] = token
160
+ end
161
+
162
+ opts.on "--zap-host HOST", "Specify the host ZAP is running on." do |host|
163
+ options[:zap_host] = host
164
+ end
165
+
166
+ opts.on "--zap-port PORT", "Specify the port ZAP is running on." do |port|
167
+ options[:zap_port] = port
168
+ end
169
+
170
+ opts.separator ""
171
+ opts.separator "Checkmarx options:"
172
+
173
+ opts.on "--checkmarx-user USER", "Specify the Checkmarx user to use when connecting to the API" do |user|
174
+ options[:checkmarx_user] = user
175
+ end
176
+
177
+ opts.on "--checkmarx-password PASSWORD", "Specify password for the Checkmarx API user" do |password|
178
+ options[:checkmarx_password] = password
179
+ end
180
+
181
+ opts.on "--checkmarx-server server", "Specify the API server to use for Checkmarx scans" do |server|
182
+ options[:checkmarx_server] = server
183
+ end
184
+
185
+ opts.on "--checkmarx-log logfile", "Specify the log file to use for Checkmarx scans" do |logfile|
186
+ options[:checkmarx_log] = logfile
187
+ end
188
+
189
+ opts.on "--checkmarx-project project", "Specify the full path of the Checkmarx project for this scan" do |project|
190
+ options[:checkmarx_project] = project
191
+ end
192
+
193
+ opts.separator ""
194
+ opts.separator "Configuration files:"
195
+
196
+ opts.on "-c", "--config-file FILE", "Use specified configuration file" do |file|
197
+ options[:config_file] = File.expand_path(file)
198
+ end
199
+
200
+ opts.on "-C", "--create-config [FILE]", "Output configuration file based on options" do |file|
201
+ if file
202
+ options[:create_config] = file
203
+ else
204
+ options[:create_config] = true
205
+ end
206
+ end
207
+
208
+ opts.separator ""
209
+
210
+ opts.on "-k", "--checks", "List all available vulnerability checks" do
211
+ options[:list_checks] = true
212
+ end
213
+
214
+ opts.on "--optional-checks", "List optional checks" do
215
+ options[:list_optional_checks] = true
216
+ end
217
+
218
+ opts.on "-v", "--version", "Show Pipeline version" do
219
+ options[:show_version] = true
220
+ end
221
+
222
+ opts.on_tail "-h", "--help", "Display this message" do
223
+ options[:show_help] = true
224
+ end
225
+ end
226
+
227
+ if destructive
228
+ parser.parse! args
229
+ else
230
+ parser.parse args
231
+ end
232
+
233
+ if options[:previous_results_json] and options[:output_files]
234
+ options[:comparison_output_file] = options[:output_files].shift
235
+ end
236
+
237
+ return options, parser
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,50 @@
1
+ class Pipeline::Reporters
2
+ @reporters = []
3
+
4
+ #Add a task. This will call +_klass_.new+ when running tests
5
+ def self.add klass
6
+ @reporters << klass unless @reporters.include? klass
7
+ end
8
+
9
+ def self.reporters
10
+ @reporters
11
+ end
12
+
13
+ def self.initialize_reporters reporters_directory = ""
14
+ #Load all files in task_directory
15
+ Dir.glob(File.join(reporters_directory, "*.rb")).sort.each do |f|
16
+ require f
17
+ end
18
+ end
19
+
20
+ #No need to use this directly.
21
+ def initialize options = { }
22
+ end
23
+
24
+ #Run all the tasks on the given Tracker.
25
+ #Returns a new instance of tasks with the results.
26
+ def self.run_report(tracker)
27
+ @reporters.each do |c|
28
+ reporter = c.new()
29
+ if tracker.options[:output_format].first == reporter.format
30
+ begin
31
+ output = reporter.run_report(tracker)
32
+ if tracker.options[:output_file]
33
+ file = File.open(tracker.options[:output_file], 'w'){ |f| f.write(output)}
34
+ else
35
+ Pipeline.notify output
36
+ end
37
+ rescue => e
38
+ Pipeline.error e.message
39
+ tracker.error e
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ #Load all files in reporters/ directory
48
+ Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/reporters/*.rb").sort.each do |f|
49
+ require f.match(/(pipeline\/reporters\/.*)\.rb$/)[0]
50
+ end
@@ -0,0 +1,21 @@
1
+ require 'pipeline/finding'
2
+
3
+ class Pipeline::BaseReporter
4
+ attr_accessor :name, :format
5
+
6
+ def initialize()
7
+ end
8
+
9
+ def run_report(tracker)
10
+ Pipeline.notify "Running base reoprt..."
11
+ output = ""
12
+ tracker.findings.each do |finding|
13
+ output += out(finding)
14
+ end
15
+ output
16
+ end
17
+
18
+ def out(finding)
19
+ end
20
+
21
+ end
@@ -0,0 +1,19 @@
1
+ require 'pipeline/finding'
2
+ require 'pipeline/reporters/base_reporter'
3
+
4
+ class Pipeline::CSVReporter < Pipeline::BaseReporter
5
+
6
+ Pipeline::Reporters.add self
7
+
8
+ attr_accessor :name, :format
9
+
10
+ def initialize()
11
+ @name = "CSVReporter"
12
+ @format = :to_csv
13
+ end
14
+
15
+ def out(finding)
16
+ finding.to_csv
17
+ end
18
+
19
+ end
@@ -0,0 +1,61 @@
1
+ require 'pipeline/finding'
2
+ require 'pipeline/reporters/base_reporter'
3
+ require 'json'
4
+ require 'curb'
5
+
6
+ class Pipeline::JiraReporter < Pipeline::BaseReporter
7
+
8
+ Pipeline::Reporters.add self
9
+
10
+ attr_accessor :name, :format
11
+
12
+ def initialize()
13
+ @name = "JiraReporter"
14
+ @format = :to_jira
15
+ end
16
+
17
+ def run_report(tracker)
18
+ @project = tracker.options[:jira_project.to_s]
19
+ @api = tracker.options[:jira_api_url.to_s]
20
+ @cookie = tracker.options[:jira_cookie.to_s]
21
+ @component = tracker.options[:jira_component.to_s]
22
+
23
+ tracker.findings.each do |finding|
24
+ report finding
25
+ end
26
+ "Results are in JIRA"
27
+ end
28
+
29
+ def report(finding)
30
+ json = get_jira_json(finding)
31
+ http = Curl.post("#{@api}/issue/", json.to_s) do |http|
32
+ http.headers['Content-Type'] = "application/json"
33
+ http.headers['Cookie'] = @cookie
34
+ end
35
+ if http.response_code != 201 # Created ...
36
+ Pipeline.error "Problem with HTTP #{http.response_code} - #{http.body_str}"
37
+ end
38
+ end
39
+
40
+ private
41
+ def get_jira_json(finding)
42
+ json = {
43
+ "fields": {
44
+ "project":
45
+ {
46
+ "key": "#{@project}"
47
+ },
48
+ "summary": "#{finding.appname} - #{finding.description}",
49
+ "description": "#{finding.to_string}\n\nFINGERPRINT: #{finding.fingerprint}",
50
+ "issuetype": {
51
+ "name": "Task"
52
+ },
53
+ "labels":["Pipeline","#{finding.appname}"],
54
+ "components": [ { "name": "#{@component}" } ]
55
+ }
56
+ }.to_json
57
+ json
58
+ end
59
+ end
60
+
61
+
@@ -0,0 +1,20 @@
1
+ require 'pipeline/finding'
2
+ require 'pipeline/reporters/base_reporter'
3
+
4
+ require 'json'
5
+
6
+ class Pipeline::JSONReporter < Pipeline::BaseReporter
7
+
8
+ Pipeline::Reporters.add self
9
+
10
+ attr_accessor :name, :format
11
+
12
+ def initialize()
13
+ @name = "JSONReporter"
14
+ @format = :to_json
15
+ end
16
+
17
+ def out(finding)
18
+ finding.to_json
19
+ end
20
+ end