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
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