owasp-pipeline 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c19bcf63e27cbc2579358e2f581943797d31b056
4
+ data.tar.gz: 4b1daacd45d7dcb1d5bad0643da0b9c9cf8e93ad
5
+ SHA512:
6
+ metadata.gz: cf4edf3934d7f2b596bc6baf3c1e85449100026b86aec1fcb690723a8f4cb2f48c2e3a974c7b79ec478384970501c1f8413ed7a4743f1e5087f922cb8571a06e
7
+ data.tar.gz: c7cdbd7eaf00185447d5fbb2ebf042f4c68cdfa15ef10547bd923b98d8373a736b69b3c48cc030728f05164502852e07a7eaad6a38f7660bd17e7db77c91b1f5
data/CHANGES ADDED
@@ -0,0 +1,23 @@
1
+ ## 0.6.0
2
+ * Docker image.
3
+ * JavaScript tools (retire.js, nodesecurity, eslint)
4
+ * Java tools (SonarCube, Findbugs)
5
+ ## 0.5.3
6
+ * Checkmarx
7
+ * JIRA Integration
8
+ * Search for secrets (a la gitrob)
9
+ * OWASP dependency-check
10
+ ## 0.1.0
11
+ * Structure for pipeline and initial tool series.
12
+ * gem packaging
13
+ * Finding / reporting
14
+ * docker mounting
15
+ * Support for task labels. Run with 'pipeline -l label' and only tasks that identify with that label will run.
16
+ * Move to only keep options in tracker.
17
+
18
+ ## FUTURE
19
+ * TODO: add scap
20
+ * TODO: Devtools: pmd, brakeman, dependency checker, codescan, scanjs, bandit, etc.
21
+ * TODO: Misc OS checks
22
+ * TODO: Active: ZAP, gauntlt
23
+ * TODO: .NET
data/FEATURES ADDED
@@ -0,0 +1,19 @@
1
+ # Capabilities
2
+ * AV
3
+ * FIM
4
+
5
+ FUTURE:
6
+ * oscap - https://www.redhat.com/archives/open-scap-list/2013-May/msg00007.html
7
+ * pmd
8
+ * brakeman
9
+ * dependency checker
10
+ * codescan
11
+
12
+ # Images
13
+ * Raw directory on file system.
14
+ * git
15
+ * docker
16
+
17
+ FUTURE:
18
+ * iso
19
+ * vmdk, vdi, ami
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ ![Pipeline Logo](https://upload.wikimedia.org/wikipedia/commons/3/37/The_Great_Wave_of_Kanagava.jpg)
2
+
3
+ # Pipeline
4
+
5
+ Pipeline is a framework for running a series of tools. Generally, it is intended as a backbone
6
+ for automating a security analysis pipeline of tools.
7
+
8
+ # Recommended Usage
9
+
10
+ For those wishing to run pipeline, we recommend using the docker image.
11
+ See the documentation for more info. [Pipeline Docker Documentation](./DOCKER.md)
12
+
13
+ For those interested in how to use Pipeline in a DevOps context, see
14
+ [Pipeline DevOps Integration Options](./DEVOPS.md)
15
+
16
+ # Installation
17
+
18
+ gem install pipeline
19
+
20
+ # Extending Pipeline
21
+
22
+ Pipeline is intended to be extended through added "tasks". To add a new tool,
23
+ copy an existing task and tweak to make it work for the tool in question.
24
+
25
+ # Usage
26
+
27
+ pipeline <options> <target>
28
+
29
+ ## Options
30
+
31
+ Common options include:
32
+ -d for debug
33
+ -f for format (takes "json", "csv", "jira")
34
+
35
+ For a full list of options, use `pipeline --help` or see the [OPTIONS.md](./OPTIONS.md) file.
36
+
37
+ ## Target
38
+
39
+ The target can be:
40
+ * Filesystem (which is analyzed in place)
41
+ * Git repo (which is cloned for analysis)
42
+ * Other types of images (.iso, docker, etc. are experimental)
43
+
44
+
45
+ # Dependencies
46
+
47
+ * clamav
48
+ * hashdeep
49
+ * rm (*nix)
50
+ * git
51
+ * mount (*nix)
52
+ * docker
53
+
54
+ # Development
55
+
56
+ To run the code, run the following from the root directory:
57
+ >ruby bin/pipeline <options> target
58
+
59
+ To build a gem, just run:
60
+ gem build pipeline.gemspec
61
+
62
+
63
+ # Integration
64
+
65
+ ## Git Hooks
66
+
67
+ First, grab the hook from the code.
68
+ ```
69
+ meditation:hooks mk$ cp /area53/owasp/pipeline/hooks/pre-commit .
70
+ ```
71
+
72
+ Then make it executable.
73
+ ```
74
+ meditation:hooks mk$ chmod +x pre-commit
75
+ ```
76
+
77
+ Make sure the shell you are committing in can see docker.
78
+ ```
79
+ meditation:hooks mk$ eval "$(docker-machine env default)"
80
+ ```
81
+
82
+ Now go test and make a change and commit a file.
83
+ The result should be that pipeline runs against your
84
+ code and will not allow commits unless the results
85
+ are clean. (Which is not necessarily a reasonable
86
+ expectation)
87
+
88
+
89
+ # Configuration files
90
+
91
+ For advanced usage scenarios, you can save your configuration and use it at runtime.
92
+
93
+ # Authors
94
+
95
+ Matt Konda
96
+ Alex Lock
97
+ Rafa Perez
98
+
99
+ # License
100
+
101
+ Apache 2: http://www.apache.org/licenses/LICENSE-2.0
data/bin/pipeline ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+ #Adjust path in case called directly and not through gem
3
+ $:.unshift "#{File.expand_path(File.dirname(__FILE__))}/../lib"
4
+
5
+ require 'pipeline'
6
+ require 'pipeline/options'
7
+ require 'pipeline/version'
8
+
9
+ #Parse options
10
+ begin
11
+ options, parser = Pipeline::Options.parse! ARGV
12
+ rescue OptionParser::ParseError => e
13
+ $stderr.puts e.message.capitalize
14
+ $stderr.puts "Please see `pipeline --help` for valid options"
15
+ exit -1
16
+ end
17
+
18
+ #Exit early for these options
19
+ if options[:list_checks] or options[:list_optional_checks]
20
+ Pipeline.list_checks options
21
+ exit
22
+ elsif options[:create_config]
23
+ Pipeline.dump_config options
24
+ exit
25
+ elsif options[:show_help]
26
+ puts parser
27
+ exit
28
+ elsif options[:show_version]
29
+ puts "Pipeline #{Pipeline::Version}"
30
+ exit
31
+ end
32
+
33
+ #Set application path according to the commandline arguments
34
+ unless options[:target]
35
+ if ARGV[-1].nil?
36
+ options[:target] = "."
37
+ else
38
+ options[:target] = ARGV[-1]
39
+ end
40
+ end
41
+
42
+ trap("INT") do
43
+ $stderr.puts "\nInterrupted - exiting."
44
+
45
+ if options[:debug]
46
+ $stderr.puts caller
47
+ end
48
+
49
+ exit!
50
+ end
51
+
52
+ if options[:quiet].nil?
53
+ options[:quiet] = :command_line
54
+ end
55
+
56
+ begin
57
+ #Run scan and output a report
58
+ tracker = Pipeline.run options.merge(:print_report => true, :quiet => options[:quiet])
59
+
60
+ #Return error code if --exit-on-warn is used and warnings were found
61
+ if options[:exit_on_warn] and not tracker.findings.empty?
62
+ exit Pipeline::Warnings_Found_Exit_Code
63
+ end
64
+ rescue Pipeline::NoTargetError => e
65
+ $stderr.puts e.message
66
+ exit 1
67
+ end
data/lib/pipeline.rb ADDED
@@ -0,0 +1,301 @@
1
+ require 'rubygems'
2
+ require 'yaml'
3
+ require 'set'
4
+ require 'tempfile'
5
+
6
+ module Pipeline
7
+
8
+ #This exit code is used when warnings are found and the --exit-on-warn
9
+ #option is set
10
+ Warnings_Found_Exit_Code = 3
11
+
12
+ @debug = false
13
+ @quiet = false
14
+ @loaded_dependencies = []
15
+
16
+ #Run Pipeline.
17
+ #
18
+ #Options:
19
+ #
20
+ # * :config_file - configuration file
21
+ # * :exit_on_warn - return false if warnings found, true otherwise. Not recommended for library use (default: false)
22
+ # * :output_files - files for output
23
+ # * :output_formats - formats for output (:to_s, :to_tabs, :to_csv, :to_html)
24
+ # * :parallel_checks - run checks in parallel (default: true)
25
+ # * :print_report - if no output file specified, print to stdout (default: false)
26
+ # * :quiet - suppress most messages (default: true)
27
+ def self.run options
28
+ options = set_options options
29
+
30
+ @quiet = !!options[:quiet]
31
+ @debug = !!options[:debug]
32
+
33
+ if @quiet
34
+ options[:report_progress] = false
35
+ end
36
+
37
+ scan options
38
+ end
39
+
40
+ #Sets up options for run, checks given application path
41
+ def self.set_options options
42
+ if options.is_a? String
43
+ options = { :target => options }
44
+ end
45
+
46
+ if options[:quiet] == :command_line
47
+ command_line = true
48
+ options.delete :quiet
49
+ end
50
+
51
+ options = default_options.merge(load_options(options[:config_file], options[:quiet])).merge(options)
52
+
53
+ if options[:quiet].nil? and not command_line
54
+ options[:quiet] = true
55
+ end
56
+
57
+ options[:output_format] = get_output_format options
58
+
59
+ if options[:appname].nil?
60
+ path = options[:target]
61
+ options[:appname] = File.split(path).last
62
+ end
63
+ options
64
+ end
65
+
66
+ CONFIG_FILES = [
67
+ File.expand_path("./config/pipeline.yml"),
68
+ File.expand_path("~/.pipeline/config.yml"),
69
+ File.expand_path("/etc/pipeline/config.yml")
70
+ ]
71
+
72
+ #Load options from YAML file
73
+ def self.load_options custom_location, quiet
74
+ #Load configuration file
75
+ if config = config_file(custom_location)
76
+ options = YAML.load_file config
77
+
78
+ if options
79
+ options.each { |k, v| options[k] = Set.new v if v.is_a? Array }
80
+
81
+ # notify if options[:quiet] and quiet is nil||false
82
+ notify "[Notice] Using configuration in #{config}" unless (options[:quiet] || quiet)
83
+ options
84
+ else
85
+ notify "[Notice] Empty configuration file: #{config}" unless quiet
86
+ {}
87
+ end
88
+ else
89
+ {}
90
+ end
91
+ end
92
+
93
+ def self.config_file custom_location = nil
94
+ supported_locations = [File.expand_path(custom_location || "")] + CONFIG_FILES
95
+ supported_locations.detect {|f| File.file?(f) }
96
+ end
97
+
98
+ #Default set of options
99
+ def self.default_options
100
+ {
101
+ :parallel_tasks => true,
102
+ :skip_tasks => Set.new(),
103
+ :exit_on_warn => true,
104
+ :output_format => :text,
105
+ :working_dir => "~/line/tmp/",
106
+ :zap_host => "http://localhost",
107
+ :zap_port => "9999",
108
+ :labels => Set.new() << "filesystem" << "code" # Defaults to run.
109
+ }
110
+ end
111
+
112
+ #Determine output formats based on options[:output_formats]
113
+ #or options[:output_files]
114
+ def self.get_output_format options
115
+ if options[:output_file]
116
+ get_format_from_output_file options[:output_file]
117
+ elsif options[:output_format]
118
+ get_format_from_output_format options[:output_format]
119
+ else
120
+ begin
121
+ require 'terminal-table'
122
+ return [:to_s]
123
+ rescue LoadError
124
+ return [:to_json]
125
+ end
126
+ end
127
+ end
128
+
129
+ def self.get_format_from_output_format output_format
130
+ case output_format
131
+ when :html, :to_html
132
+ [:to_html]
133
+ when :csv, :to_csv
134
+ [:to_csv]
135
+ when :pdf, :to_pdf
136
+ [:to_pdf]
137
+ when :tabs, :to_tabs
138
+ [:to_tabs]
139
+ when :json, :to_json
140
+ [:to_json]
141
+ when :jira, :to_jira
142
+ [:to_jira]
143
+ when :markdown, :to_markdown
144
+ [:to_markdown]
145
+ else
146
+ [:to_s]
147
+ end
148
+ end
149
+ private_class_method :get_format_from_output_format
150
+
151
+ def self.get_format_from_output_file output_file
152
+ case output_file
153
+ when /\.html$/i
154
+ :to_html
155
+ when /\.csv$/i
156
+ :to_csv
157
+ when /\.pdf$/i
158
+ :to_pdf
159
+ when /\.tabs$/i
160
+ :to_tabs
161
+ when /\.json$/i
162
+ :to_json
163
+ when /\.md$/i
164
+ :to_markdown
165
+ else
166
+ :to_s
167
+ end
168
+ end
169
+ private_class_method :get_format_from_output_file
170
+
171
+ #Output list of tasks (for `-k` option)
172
+ def self.list_checks options
173
+ require 'pipeline/scanner'
174
+
175
+ add_external_tasks options
176
+
177
+ if options[:list_optional_tasks]
178
+ $stderr.puts "Optional Tasks:"
179
+ tasks = Tasks.optional_tasks
180
+ else
181
+ $stderr.puts "Available tasks:"
182
+ tasks = Tasks.tasks
183
+ end
184
+
185
+ format_length = 30
186
+
187
+ $stderr.puts "-" * format_length
188
+ tasks.each do |task|
189
+ $stderr.printf("%-#{format_length}s\n", task.name)
190
+ end
191
+ end
192
+
193
+ #Output configuration to YAML
194
+ def self.dump_config options
195
+ if options[:create_config].is_a? String
196
+ file = options[:create_config]
197
+ else
198
+ file = nil
199
+ end
200
+
201
+ options.delete :create_config
202
+
203
+ options.each do |k,v|
204
+ if v.is_a? Set
205
+ options[k] = v.to_a
206
+ end
207
+ end
208
+
209
+ if file
210
+ File.open file, "w" do |f|
211
+ YAML.dump options, f
212
+ end
213
+ puts "Output configuration to #{file}"
214
+ else
215
+ puts YAML.dump(options)
216
+ end
217
+ exit
218
+ end
219
+
220
+ #Run a scan. Generally called from Pipeline.run instead of directly.
221
+ def self.scan options
222
+ #Load scanner
223
+ notify "Loading scanner..."
224
+
225
+ begin
226
+ require 'pipeline/scanner'
227
+ require 'pipeline/tracker'
228
+ require 'pipeline/mounters'
229
+ require 'pipeline/filters'
230
+ require 'pipeline/reporters'
231
+
232
+ rescue LoadError => e
233
+ $stderr.puts e.message
234
+ raise NoPipelineError, "Cannot find lib/ directory or load the key pipeline."
235
+ end
236
+
237
+ # debug "API: #{options[:jira_api_url.to_s]}"
238
+ # debug "Project: #{options[:jira_project.to_s]}"
239
+ # debug "Cookie: #{options[:jira_cookie.to_s]}"
240
+
241
+ add_external_tasks options
242
+
243
+ tracker = Tracker.new options
244
+ debug "Mounting ... #{options[:target]}"
245
+ # Make the target accessible.
246
+ target = Pipeline::Mounters.mount tracker
247
+
248
+ #Start scanning
249
+ scanner = Scanner.new
250
+ notify "Processing target...#{options[:target]}"
251
+ scanner.process target, tracker
252
+
253
+ # Filter the results (Don't report anything that has been reported before)
254
+ Pipeline::Filters.filter tracker
255
+
256
+ # Generate Report
257
+ notify "Generating report...#{options[:output_format]}"
258
+ Pipeline::Reporters.run_report tracker
259
+
260
+ tracker
261
+ end
262
+
263
+ def self.error message
264
+ $stderr.puts message
265
+ end
266
+
267
+ def self.warn message
268
+ $stderr.puts message unless @quiet
269
+ end
270
+
271
+ def self.notify message
272
+ $stderr.puts message #unless @debug
273
+ end
274
+
275
+ def self.debug message
276
+ $stderr.puts message if @debug
277
+ end
278
+
279
+ def self.load_pipeline_dependency name
280
+ return if @loaded_dependencies.include? name
281
+
282
+ begin
283
+ require name
284
+ rescue LoadError => e
285
+ $stderr.puts e.message
286
+ $stderr.puts "Please install the appropriate dependency."
287
+ exit! -1
288
+ end
289
+ end
290
+
291
+ def self.add_external_tasks options
292
+ options[:additional_tasks_path].each do |path|
293
+ Pipeline::Tasks.initialize_tasks path
294
+ end if options[:additional_tasks_path]
295
+ end
296
+
297
+ class DependencyError < RuntimeError; end
298
+ class NoPipelineError < RuntimeError; end
299
+ class NoTargetError < RuntimeError; end
300
+ class JiraConfigError < RuntimeError; end
301
+ end