forked from maThmatics/salus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsalus.rb
143 lines (118 loc) · 4.23 KB
/
salus.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
require 'active_support'
require 'active_support/core_ext'
require 'salus/bugsnag'
require 'salus/cli'
require 'salus/repo'
require 'salus/package_utils'
require 'salus/scanners'
require 'salus/config'
require 'salus/config_exception'
require 'salus/processor'
require 'salus/plugin_manager'
require 'sarif/sarif_report'
require 'cyclonedx/report'
require 'salus/report_request'
require 'salus/repo_searcher'
require 'salus/path_validator'
require 'salus/scanner_types'
module Salus
VERSION = '2.20.0'.freeze
DEFAULT_REPO_PATH = './repo'.freeze # This is inside the docker container at /home/repo.
DEFAULT_REPORT_FILTER = 'all'.freeze
NONE_REPORT_FILTER = 'none'.freeze
SafeYAML::OPTIONS[:default_mode] = :safe
EXIT_SUCCESS = 0
EXIT_FAILURE = 1
# report_error(:hard_error => true) will cause EXIT_HARD_ERROR
# meaning salus will always fail even if pass_on_raise=true
EXIT_HARD_ERROR = 2
FULL_SARIF_DIFF_FORMAT = 'sarif_diff_full'.freeze
URI_DELIMITER = ' '.freeze # space
class << self
include SalusBugsnag
attr_accessor :hard_error_encountered
# rubocop:disable Metrics/ParameterLists
def scan(
config: nil,
quiet: false,
verbose: false,
repo_path: DEFAULT_REPO_PATH,
use_colors: true,
filter_sarif: "",
sarif_diff_full: "",
git_diff: "",
ignore_config_id: "",
only: [],
reports: DEFAULT_REPORT_FILTER,
heartbeat: true
)
# rubocop:enable Metrics/ParameterLists
Salus::PluginManager.load_plugins
Salus::PluginManager.send_event(:salus_scan, method(__method__).parameters)
### Heartbeat ###
if !quiet && heartbeat
heartbeat_thr = heartbeat(60) # Print a heartbeat every 60s. [0s, 60s, 120s, ...]
end
### Configuration ###
# Config option would be: --config="<uri x> <uri y> etc"
configuration_directives = (ENV['SALUS_CONFIGURATION'] || config || '').split(URI_DELIMITER)
processor = Salus::Processor.new(configuration_directives, repo_path: repo_path,
filter_sarif: filter_sarif,
ignore_config_id: ignore_config_id,
cli_scanners_to_run: only, report_filter: reports)
unless sarif_diff_full.empty?
return process_sarif_full_diff(processor, sarif_diff_full, git_diff)
end
### Scan Project ###
# Scan project with Salus client.
processor.scan_project
### Reporting ###
# Print report to stdout.
puts processor.string_report(verbose: verbose, use_colors: use_colors) unless quiet
processor.report.report_uris.reject! { |u| u['format'] == FULL_SARIF_DIFF_FORMAT }
# Try to send Salus reports to remote server or local files.
processor.export_report
heartbeat_thr&.kill
# System exit with success or failure - useful for CI builds.
exit_status = if Salus.hard_error_encountered
EXIT_HARD_ERROR
else
processor.passed? ? EXIT_SUCCESS : EXIT_FAILURE
end
system_exit(exit_status)
end
def process_sarif_full_diff(processor, sarif_diff_full, git_diff)
begin
processor.create_full_sarif_diff(sarif_diff_full, git_diff)
rescue StandardError => e
puts "Failed to get sarif diff #{e.inspect}"
system_exit(EXIT_FAILURE)
end
processor.report.report_uris.select! { |u| u['format'] == FULL_SARIF_DIFF_FORMAT }
processor.export_report
if Sarif::BaseSarif.salus_passed?(processor.report.full_diff_sarif)
system_exit(EXIT_SUCCESS)
else
puts "- Sarif diff contains vulnerabilities"
system_exit(EXIT_FAILURE)
end
end
private
# This method is mapped directly to exit() to make testing easier
# since we can stub it. Otherwise our test process would actually
# just exit early.
def system_exit(status)
exit(status)
end
# This method spawns a thread in order to print a heartbeat
def heartbeat(time)
Thread.new do
loop do
puts "[INFORMATIONAL: #{Time.now}]: Salus is running."
sleep time
end
end
end
end
end
Salus.hard_error_encountered = false