diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb new file mode 100644 index 00000000..8b5eeadf --- /dev/null +++ b/lib/salus/rules_evaluation.rb @@ -0,0 +1,62 @@ +module Salus + class RulesEvaluation + RULE_TYPE_ID = "id".freeze + RULE_TYPE_SEVERITY = "severity".freeze + ID_FIELD_MAPPING = { + "GoOSV" => :ID, + "GradleOSV" => :ID, + "PythonOSV" => :ID, + "MavenOSV" => :ID, + "BundleAudit" => :cve + }.freeze + + SEVERITY_FIELD_MAPPING = { + "GoOSV" => :Severity, + "GradleOSV" => :Severity, + "PythonOSV" => :Severity, + "MavenOSV" => :Severity + }.freeze + + def self.evaluate_default(results) + return true if results.empty? + + false + end + + def self.evaluate_by_type(config, results, scanner) + case config["rule"]["type"] + when RULE_TYPE_ID + evaluate_by_id(config["rule"], results, scanner) + when RULE_TYPE_SEVERITY + evaluate_by_severit(config["rule"], results, scanner) + else + evaluate_default(results) + end + end + + def self.evaluate_by_id(config, results, scanner) + matches = config["matches"] + keys = matches.map { |x| x["key"] } + ids = results.map { |x| x[ID_FIELD_MAPPING[scanner]] } + + return true unless (keys & ids).length.positive? && ids.length.positive? + + reutrn false + end + + def self.evaluate_by_severity(config, results, _scanner) + matches = config["matches"] + keys = matches.map { |x| x["key"] } + ids = results.map { |x| x[SEVERITY_FIELD_MAPPING[scanner]] } + return true unless (keys & ids).length.positive? && ids.length.positive? + + reutrn false + end + + def self.evaluate_rules(config, results, scanner) + return evaluate_by_type(config, results, scanner) if config.key?('rule') + + evaluate_default(results) + end + end +end diff --git a/lib/salus/scanners/bundle_audit.rb b/lib/salus/scanners/bundle_audit.rb index 6ebc94eb..b670da30 100644 --- a/lib/salus/scanners/bundle_audit.rb +++ b/lib/salus/scanners/bundle_audit.rb @@ -41,6 +41,8 @@ module Salus::Scanners class BundleAudit < Base class UnvalidGemVulnError < StandardError; end + CLASS_NAME = self.class.name.split("::").last.freeze + def self.scanner_type Salus::ScannerTypes::DEPENDENCY end @@ -75,7 +77,11 @@ def run report_info(:ignored_cves, ignore) report_info(:vulnerabilities, @vulns) - @vulns.empty? ? report_success : report_failure + if Salus::RulesEvaluation.evaluate_rules(@config, @vulns, CLASS_NAME) + report_success + else + report_failure + end end def run_scanner(scanner, ignore) diff --git a/lib/salus/scanners/osv/go_osv.rb b/lib/salus/scanners/osv/go_osv.rb index eb48dd21..6b8887e4 100644 --- a/lib/salus/scanners/osv/go_osv.rb +++ b/lib/salus/scanners/osv/go_osv.rb @@ -1,4 +1,5 @@ require 'salus/scanners/osv/base' +require 'salus/rules_evaluation' module Salus::Scanners::OSV class GoOSV < Base @@ -9,6 +10,7 @@ class SemVersion < Gem::Version; end DEFAULT_SEVERITY = "MODERATE".freeze GITHUB_DATABASE_STRING = "Github Advisory Database".freeze GO_OSV_ADVISORY_URL = "https://osv-vulnerabilities.storage.googleapis.com/Go/all.zip".freeze + CLASS_NAME = self.class.name.split("::").last.freeze def should_run? @repository.go_sum_present? @@ -46,7 +48,7 @@ def run # Match and Report scanner status vulnerabilities_found = match_vulnerable_dependencies(dependencies) results = group_vulnerable_dependencies(vulnerabilities_found) - return report_success if results.empty? + return report_success if Salus::RulesEvaluation.evaluate_rules(@config, results, CLASS_NAME) report_failure log(JSON.pretty_generate(results)) diff --git a/lib/salus/scanners/osv/gradle_osv.rb b/lib/salus/scanners/osv/gradle_osv.rb index 086af14b..5102109d 100644 --- a/lib/salus/scanners/osv/gradle_osv.rb +++ b/lib/salus/scanners/osv/gradle_osv.rb @@ -10,6 +10,7 @@ class SemVersion < Gem::Version; end DEFAULT_SEVERITY = "MODERATE".freeze GRADLE_OSV_ADVISORY_URL = "https://osv-vulnerabilities.storage.googleapis.com"\ "/Maven/all.zip".freeze + CLASS_NAME = self.class.name.split("::").last.freeze def should_run? @repository.build_gradle_present? @@ -41,7 +42,7 @@ def run # Match and Report scanner status vulnerabilities_found = match_vulnerable_dependencies(dependencies) results = group_vulnerable_dependencies(vulnerabilities_found) - return report_success if results.empty? + return report_success if Salus::RulesEvaluation.evaluate_rules(@config, results, CLASS_NAME) report_failure log(JSON.pretty_generate(results)) diff --git a/lib/salus/scanners/osv/maven_osv.rb b/lib/salus/scanners/osv/maven_osv.rb index ac96f59a..189f17ae 100644 --- a/lib/salus/scanners/osv/maven_osv.rb +++ b/lib/salus/scanners/osv/maven_osv.rb @@ -10,6 +10,7 @@ class SemVersion < Gem::Version; end GITHUB_DATABASE_STRING = "Github Advisory Database".freeze MAVEN_OSV_ADVISORY_URL = "https://osv-vulnerabilities.storage.googleapis.com/"\ "Maven/all.zip".freeze + CLASS_NAME = self.class.name.split("::").last.freeze def should_run? @repository.pom_xml_present? @@ -46,7 +47,7 @@ def run # Match and Report scanner status vulnerabilities_found = match_vulnerable_dependencies(parser.pom_xml_dependencies) results = group_vulnerable_dependencies(vulnerabilities_found) - return report_success if results.empty? + return report_success if Salus::RulesEvaluation.evaluate_rules(@config, results, CLASS_NAME) report_failure log(JSON.pretty_generate(results)) diff --git a/lib/salus/scanners/osv/python_osv.rb b/lib/salus/scanners/osv/python_osv.rb index 2859823e..67522f05 100644 --- a/lib/salus/scanners/osv/python_osv.rb +++ b/lib/salus/scanners/osv/python_osv.rb @@ -10,6 +10,7 @@ class SemDependency < Gem::Dependency; end GITHUB_DATABASE_STRING = "Github Advisory Database".freeze PYTHON_OSV_ADVISORY_URL = "https://osv-vulnerabilities.storage.googleapis.com/"\ "PyPI/all.zip".freeze + CLASS_NAME = self.class.name.split("::").last.freeze def should_run? @repository.requirements_txt_present? @@ -41,7 +42,7 @@ def run # Match and Report scanner status vulnerabilities_found = match_vulnerable_dependencies(dependencies) results = group_vulnerable_dependencies(vulnerabilities_found) - return report_success if results.empty? + return report_success if Salus::RulesEvaluation.evaluate_rules(@config, results, CLASS_NAME) report_failure log(JSON.pretty_generate(results)) diff --git a/spec/fixtures/processor/local_uri/expected_report.json b/spec/fixtures/processor/local_uri/expected_report.json index be2f7ad3..97f4151d 100644 --- a/spec/fixtures/processor/local_uri/expected_report.json +++ b/spec/fixtures/processor/local_uri/expected_report.json @@ -249,7 +249,7 @@ "passed": true, "running_time": 1.45, "scanner_name": "Trufflehog", - "version": "3.19.0", + "version": "3.21.0", "warn": { } } diff --git a/spec/fixtures/processor/remote_uri/expected_report.json b/spec/fixtures/processor/remote_uri/expected_report.json index c8591a8e..2858cd85 100644 --- a/spec/fixtures/processor/remote_uri/expected_report.json +++ b/spec/fixtures/processor/remote_uri/expected_report.json @@ -249,7 +249,7 @@ "passed": true, "running_time": 1.45, "scanner_name": "Trufflehog", - "version": "3.19.0", + "version": "3.21.0", "warn": { } }