From 2c1b9298be0ec69815089fe4a7d1afaaf830a16f Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 12:45:08 -0800 Subject: [PATCH 01/10] Allow Pass/Fail Customization --- lib/salus/auto_fix/yarn_audit_v1.rb | 3 ++- lib/salus/rules_evaluation.rb | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 lib/salus/rules_evaluation.rb diff --git a/lib/salus/auto_fix/yarn_audit_v1.rb b/lib/salus/auto_fix/yarn_audit_v1.rb index 456336de..6cee220d 100644 --- a/lib/salus/auto_fix/yarn_audit_v1.rb +++ b/lib/salus/auto_fix/yarn_audit_v1.rb @@ -67,7 +67,8 @@ def update_package_definition(blocks, parts) group_updates.each do |updates, versions| updates = updates.last vulnerable_package_info = get_package_info(updates) - list_of_versions_available = vulnerable_package_info["data"]["versions"] + list_of_versions_available = vulnerable_package_info.dig("data", "version") + # list_of_versions_available = vulnerable_package_info["data"]["versions"] version_to_update_to = Salus::SemanticVersion.select_upgrade_version( versions.first[:patch], list_of_versions_available ) diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb new file mode 100644 index 00000000..318c0323 --- /dev/null +++ b/lib/salus/rules_evaluation.rb @@ -0,0 +1,14 @@ +module Salus + class RulesEvaluation + RULE_TYPES = { + 'id' => 'id', + 'severity' => 'severity', + }.freeze + + end + + def evaluate(config, results) + return true + end + end + \ No newline at end of file From d2cb3f4c0534d8de553c2deda7c36abde09908ae Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 12:49:42 -0800 Subject: [PATCH 02/10] Invoke rules eval --- lib/salus/rules_evaluation.rb | 5 ++++- lib/salus/scanners/osv/gradle_osv.rb | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index 318c0323..45de12b9 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -8,7 +8,10 @@ class RulesEvaluation end def evaluate(config, results) - return true + if results.empty? + return true + end + return false end end \ No newline at end of file diff --git a/lib/salus/scanners/osv/gradle_osv.rb b/lib/salus/scanners/osv/gradle_osv.rb index 086af14b..ceec207e 100644 --- a/lib/salus/scanners/osv/gradle_osv.rb +++ b/lib/salus/scanners/osv/gradle_osv.rb @@ -1,5 +1,6 @@ require 'salus/scanners/osv/base' + module Salus::Scanners::OSV class GradleOSV < Base class SemVersion < Gem::Version; end @@ -41,9 +42,9 @@ 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(@config, results) - report_failure + # report_failure log(JSON.pretty_generate(results)) end From 1b83b5b578ba3b4da865c9ea2d382f82125d5492 Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 13:07:33 -0800 Subject: [PATCH 03/10] cleanup --- lib/salus/rules_evaluation.rb | 34 +++++++++++++++++++--------- lib/salus/scanners/osv/gradle_osv.rb | 1 - 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index 45de12b9..3200527c 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -1,17 +1,29 @@ module Salus - class RulesEvaluation - RULE_TYPES = { - 'id' => 'id', - 'severity' => 'severity', - }.freeze - + class RulesEvaluation + RULE_TYPE_ID = "id".freeze + RULE_TYPE_SEVERITY = "severity".freeze + + def evaluate_default(results) + return true if results.empty? + + false end - def evaluate(config, results) - if results.empty? - return true + def evaluate_by_type(config, _results) + case config.fetch("rule", "key") + when "id" + true + when "severity" + true + else + false end - return false + end + + def evaluate(config, results) + return evaluate_by_type(config, results) if config.key?('rule') + + evaluate_default(results) end end - \ No newline at end of file +end diff --git a/lib/salus/scanners/osv/gradle_osv.rb b/lib/salus/scanners/osv/gradle_osv.rb index ceec207e..dd471244 100644 --- a/lib/salus/scanners/osv/gradle_osv.rb +++ b/lib/salus/scanners/osv/gradle_osv.rb @@ -1,6 +1,5 @@ require 'salus/scanners/osv/base' - module Salus::Scanners::OSV class GradleOSV < Base class SemVersion < Gem::Version; end From 422ec56b6f451decf90a732c3d09d351c86db93f Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 13:27:25 -0800 Subject: [PATCH 04/10] remove call --- docs/scanners/go_osv.md | 5 +++++ lib/salus/auto_fix/yarn_audit_v1.rb | 3 +-- lib/salus/rules_evaluation.rb | 4 ++-- lib/salus/scanners/osv/gradle_osv.rb | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/scanners/go_osv.md b/docs/scanners/go_osv.md index 5b02817e..957cc14c 100644 --- a/docs/scanners/go_osv.md +++ b/docs/scanners/go_osv.md @@ -14,4 +14,9 @@ scanner_configs: changed_by: security-team notes: Currently no patch exists and determined that this vulnerability is not exploitable. expiration: "2022-12-31" + rule: + type: id + match: + - key: CVE-123 + - key: CVE-XYZ ``` diff --git a/lib/salus/auto_fix/yarn_audit_v1.rb b/lib/salus/auto_fix/yarn_audit_v1.rb index 6cee220d..456336de 100644 --- a/lib/salus/auto_fix/yarn_audit_v1.rb +++ b/lib/salus/auto_fix/yarn_audit_v1.rb @@ -67,8 +67,7 @@ def update_package_definition(blocks, parts) group_updates.each do |updates, versions| updates = updates.last vulnerable_package_info = get_package_info(updates) - list_of_versions_available = vulnerable_package_info.dig("data", "version") - # list_of_versions_available = vulnerable_package_info["data"]["versions"] + list_of_versions_available = vulnerable_package_info["data"]["versions"] version_to_update_to = Salus::SemanticVersion.select_upgrade_version( versions.first[:patch], list_of_versions_available ) diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index 3200527c..63d6346c 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -11,9 +11,9 @@ def evaluate_default(results) def evaluate_by_type(config, _results) case config.fetch("rule", "key") - when "id" + when RULE_TYPE_ID true - when "severity" + when RULE_TYPE_SEVERITY true else false diff --git a/lib/salus/scanners/osv/gradle_osv.rb b/lib/salus/scanners/osv/gradle_osv.rb index dd471244..cc4a7321 100644 --- a/lib/salus/scanners/osv/gradle_osv.rb +++ b/lib/salus/scanners/osv/gradle_osv.rb @@ -1,5 +1,6 @@ require 'salus/scanners/osv/base' + module Salus::Scanners::OSV class GradleOSV < Base class SemVersion < Gem::Version; end @@ -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 Salus::RulesEvaluation.evaluate(@config, results) + return report_success if results.empty? # report_failure log(JSON.pretty_generate(results)) From c92c74ced8d2c4c0ae9661a88767830a361dfbc5 Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 13:29:15 -0800 Subject: [PATCH 05/10] cleanup --- docs/scanners/go_osv.md | 5 ----- lib/salus/rules_evaluation.rb | 6 +++++- lib/salus/scanners/osv/gradle_osv.rb | 3 +-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/scanners/go_osv.md b/docs/scanners/go_osv.md index 957cc14c..5b02817e 100644 --- a/docs/scanners/go_osv.md +++ b/docs/scanners/go_osv.md @@ -14,9 +14,4 @@ scanner_configs: changed_by: security-team notes: Currently no patch exists and determined that this vulnerability is not exploitable. expiration: "2022-12-31" - rule: - type: id - match: - - key: CVE-123 - - key: CVE-XYZ ``` diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index 63d6346c..bcee8c7b 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -12,7 +12,7 @@ def evaluate_default(results) def evaluate_by_type(config, _results) case config.fetch("rule", "key") when RULE_TYPE_ID - true + evaluate_by_id when RULE_TYPE_SEVERITY true else @@ -20,6 +20,10 @@ def evaluate_by_type(config, _results) end end + def evaluate_by_id + true + end + def evaluate(config, results) return evaluate_by_type(config, results) if config.key?('rule') diff --git a/lib/salus/scanners/osv/gradle_osv.rb b/lib/salus/scanners/osv/gradle_osv.rb index cc4a7321..086af14b 100644 --- a/lib/salus/scanners/osv/gradle_osv.rb +++ b/lib/salus/scanners/osv/gradle_osv.rb @@ -1,6 +1,5 @@ require 'salus/scanners/osv/base' - module Salus::Scanners::OSV class GradleOSV < Base class SemVersion < Gem::Version; end @@ -44,7 +43,7 @@ def run results = group_vulnerable_dependencies(vulnerabilities_found) return report_success if results.empty? - # report_failure + report_failure log(JSON.pretty_generate(results)) end From a7d26c895cd07d0c9b66a8b4f5a6e8192317553c Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 14:31:11 -0800 Subject: [PATCH 06/10] Added logic --- lib/salus/rules_evaluation.rb | 32 +++++++++++++++++++++++--------- lib/salus/scanners/osv/go_osv.rb | 3 ++- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index bcee8c7b..84559bad 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -3,28 +3,42 @@ class RulesEvaluation RULE_TYPE_ID = "id".freeze RULE_TYPE_SEVERITY = "severity".freeze - def evaluate_default(results) + def self.evaluate_default(results) return true if results.empty? false end - def evaluate_by_type(config, _results) - case config.fetch("rule", "key") + def self.evaluate_by_type(config, results) + case config["rule"]["type"] when RULE_TYPE_ID - evaluate_by_id + evaluate_by_id(config["rule"], results) when RULE_TYPE_SEVERITY - true + evaluate_by_severity else - false + evaluate_default(results) end end - def evaluate_by_id - true + def self.evaluate_by_id(config, results) + matches = config["matches"] + keys = matches.map{ |x| x["key"] } + ids = results.map{ |x| x[:ID] } + return true unless (keys & ids).length.positive? + + reutrn false + end + + def self.evaluate_by_severity(config, results) + matches = config["matches"] + keys = matches.map{ |x| x["key"] } + ids = results.map{ |x| x[:Severity] } + return true unless (keys & ids).length.positive? + + reutrn false end - def evaluate(config, results) + def self.evaluate_rules(config, results) return evaluate_by_type(config, results) if config.key?('rule') evaluate_default(results) diff --git a/lib/salus/scanners/osv/go_osv.rb b/lib/salus/scanners/osv/go_osv.rb index eb48dd21..8862b113 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 @@ -46,7 +47,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) report_failure log(JSON.pretty_generate(results)) From 039f843cf743157991c44937c09dbefbb748efa4 Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 15:23:14 -0800 Subject: [PATCH 07/10] Update fixtures --- sample.txt | 1148 +++++++++++++++++ .../processor/local_uri/expected_report.json | 2 +- .../processor/remote_uri/expected_report.json | 2 +- spec/lib/salus/processor_spec.rb | 2 + 4 files changed, 1152 insertions(+), 2 deletions(-) create mode 100644 sample.txt diff --git a/sample.txt b/sample.txt new file mode 100644 index 00000000..24b4f53f --- /dev/null +++ b/sample.txt @@ -0,0 +1,1148 @@ + +Cyclonedx::ReportRubyGems + to_cyclonedx schema validation + succeeds if generated cyclonedx format is correct + succeeds if generated cyclonedx format is correct + succeeds if generated cyclonedx version is empty + succeeds if scan_reports contain duplicate reports + fails if generated cyclonedx report is not valid + to_cyclonedx spec version validation + cylonedx spec version 1.2 does not include properties field + cylonedx spec version 1.3 does include properties field + fails if provided cylonedx spec version is unsupported + +Cyclonedx::PackageUrl + purl format matches expected + purl format is correct with no special characters + purl format is correct with no version + purl format is correct with percent encoded strings + purl format removes leading and trailing / from namespace + +Cyclonedx::ReportGoDep + #run + should report all the deps using go.sum if available + should report all the deps in the Gopkg.lock if present + should report warning and send event if no Gopkg.lock/go.sumavailable and return empty build + +Cyclonedx::ReportGradleDeps + #run + should report all the deps in the build.gradle + should produce valid CycloneDX under normal conditions + +Cyclonedx::ReportNodeModules + #run + should report all the deps in the package.json if both\ + package-lock.json and yarn.lock files do not exist + should report all the deps in the package-lock.json if present + should report all the deps in the yarn.lock if present + should report all the deps in the bower.json if present + should produce valid CycloneDX for bower.json + should produce valid CycloneDX for including dev deps package-lock.json + should produce valid CycloneDX for excluding dev deps package-lock.json + +Cyclonedx::ReportPodfileLock + #run + should report all the deps in the Podfile.lock + should produce valid CycloneDX under normal conditions + should produce valid CycloneDX when an unparseable file is found + +Cyclonedx::ReportPomXml + #run + should report all the deps in the pom.xml + should produce valid CycloneDX under normal conditions + +Cyclonedx::ReportPythonModules + #run + should report all the deps in the unpinned requirements.txt + should report all the deps in the pinned requirements.txt + should report all the deps in the semi-pinned requirements.txt + +Cyclonedx::ReportRubyGems + #run + should report all the deps in the Gemfile if Gemfile.lock is absent in cyclonedx + should report all deps in Gemfile.lock in cyclonedx + should report all deps from multiple sources in Gemfile.lock in cyclonedx + +Cyclonedx::ReportRustCrates + #run + should report all the deps in the Cargo.lock if manifest is absent in cyclonedx + should calculate and report all the dependencies in the manifest if Cargo.lock is absent + should prefer the Cargo.lock over the manifest when both available + +Cyclonedx::ReportSwiftDeps + #run + should report all the deps in the Package.resolved + should produce valid CycloneDX under normal conditions + should produce valid CycloneDX when an unparseable file is found + +MergeUtil + deep_merge + should overwite arrays by default + should overwrite arrays when combine is false + should concat arrays when combine is true + +Salus::CLI + returns non-zero exit when invalid params are passed + +Salus::ConfigException + #initialize + should support initializing from a hash + should create an invalid exception if no params are passed + validation + should require the expected fields + active? + should return true if no expiration was given + should return true if empty expiration was given + should return false for past dates + should return true for current date + should return true for future dates + +Salus::Config + #initialize + should accept custom_info hashes + should accept custom_info strings + should deep merge config files + should replace arrays by default + should replace arrays when configured + should combine arrays when configured + should apply default scanner config for each scanner + should merge all NodeAudit related configuration + should merge arrays in all NodeAudit related configuration + no initialization file given + should use the default config file + project names + should not accept project names with invalid chars + should accept project names with valid chars + files given as source + should use the YAML files as config with ordered priority + bad files given as source + should ignore bad files + files point to envars that need to be interpolated + should replace references to envars with the envar values + #scanner_active? + should correctly answer if a scanner is active + #scanner_enforced? + should correctly answer if the current configuration has enforced scanning + +Salus::DiceCoefficient + should return 1.0 if two strings are same + should return 0.0 if two strings are completely different + should return higher value if two strings are very similar + should return lower value if two strings are less similar + +Salus::FileCopier + copy_files + should ignore existing files + should gracefully handle empty file list + should copy files not present + should clean up after itself + should attempt to clean up when exceptions are thrown + +Salus::Formatting + prettify_json_string + returns pretty json from valid json string + returns input string if json parse fails + +Salus::PathValidator + local_to_base? + should return false for files outside parent directory + should return false for folders outside parent directory + +Salus::PluginManager + apply_filter + applies the filter + does not apply filter from a different context + send_event + sends the event + +Salus::Processor + #initialize + explicit sources of config given files given + should load the config from the given file and URI sources and add them to the report + + +Failed to load file:///salus.yaml + + should expand the repo path provided + + +Failed to load file:///salus.yaml + + + +Failed to load file:///salus.yaml + + fetch_config_file should return nil if file content is not hash + + +Failed to load file:///namewithtypo.yaml + + should not use config files when they do not exist + implicitly look for file + should load the default config from the salus.yaml and add to report + #scan_project +Brakeman is scanning... +BundleAudit is scanning... +RepoNotEmpty is scanning... +RepoNotEmpty has finished +ReportRubyGems is scanning... +ReportRubyGems has finished +RubyPackageScanner is scanning... +RubyPackageScanner has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +Brakeman has finished +BundleAudit has finished +Trufflehog has finished + should scan the project given by a particular path +Brakeman is scanning... +NPMAudit is scanning... +Brakeman has finished +NPMAudit has finished + should override the configured active scanners when they're provided via command line +Brakeman is scanning... +NPMAudit is scanning... +Brakeman has finished +NPMAudit has finished + should scan the project using only scanners provided from the command line +Brakeman is scanning... +Brakeman is scanning... +NPMAudit is scanning... +Brakeman has finished +Brakeman has finished +NPMAudit has finished + should recurse when configured + #passed? +BundleAudit is scanning... +RepoNotEmpty is scanning... +RepoNotEmpty has finished +ReportRubyGems is scanning... +RubyPackageScanner is scanning... +RubyPackageScanner has finished +ReportRubyGems has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +BundleAudit has finished +Trufflehog has finished + should return false if the overall scan did not pass +BundleAudit is scanning... +RepoNotEmpty is scanning... +RubyPackageScanner is scanning... +RubyPackageScanner has finished +ReportRubyGems is scanning... +PatternSearch is scanning... +RepoNotEmpty has finished +PatternSearch has finished +ReportRubyGems has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +BundleAudit has finished +Trufflehog has finished + should return true if the overall scan passed + #export_report + remote URI +RepoNotEmpty is scanning... +RepoNotEmpty has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +Trufflehog has finished + should send the report to the remote URI (FAILED - 1) + Expect 0 report_uris for report_filter set to none + local URI +RepoNotEmpty is scanning... +RepoNotEmpty has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +Trufflehog has finished +Found { + "config": { + "active_scanners": [ + "Bandit", + "Brakeman", + "BundleAudit", + "CargoAudit", + "GoOSV", + "GoPackageScanner", + "GoVersionScanner", + "Gosec", + "GradleOSV", + "MavenOSV", + "NPMAudit", + "NPMPackageScanner", + "PatternSearch", + "PythonOSV", + "RepoNotEmpty", + "ReportGoDep", + "ReportGradleDeps", + "ReportNodeModules", + "ReportPodfileLock", + "ReportPomXml", + "ReportPythonModules", + "ReportRubyGems", + "ReportRustCrates", + "ReportSwiftDeps", + "RubyPackageScanner", + "RubyVersionScanner", + "Semgrep", + "Trufflehog", + "YarnAudit" + ], + "builds": { + "service_name": "buildkite", + "url": "http://example.com/builds/123" + }, + "enforced_scanners": [ + "Brakeman", + "BundleAudit", + "CargoAudit", + "Gosec", + "NPMAudit", + "PatternSearch", + "RepoNotEmpty", + "Semgrep", + "YarnAudit" + ], + "report_uris": [ + { + "format": "json", + "uri": "file:///home/spec/fixtures/processor/local_uri/salus_reports_folder/salus-report.json" + } + ], + "scanner_configs": { + "Bandit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Brakeman": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "BundleAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "CargoAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GoOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GoPackageScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GoVersionScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Gosec": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GradleOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "MavenOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "NPMAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "NPMPackageScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "NodeAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "PatternSearch": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "PythonOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "RepoNotEmpty": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportGoDep": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportGradleDeps": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportNodeModules": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportPodfileLock": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportPomXml": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportPythonModules": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportRubyGems": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportRustCrates": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportSwiftDeps": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "RubyPackageScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "RubyVersionScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Semgrep": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Trufflehog": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "YarnAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + } + }, + "sources": { + "configured": [ + "file:///salus.yaml" + ], + "valid": [ + "file:///salus.yaml" + ] + } + }, + "errors": [ + + ], + "passed": true, + "running_time": 0.52, + "scans": { + "PatternSearch": { + "errors": [ + + ], + "info": { + "hits": [ + + ], + "misses": [ + + ] + }, + "passed": true, + "running_time": 0.0, + "scanner_name": "PatternSearch", + "version": "0.9.0", + "warn": { + } + }, + "RepoNotEmpty": { + "errors": [ + + ], + "info": { + }, + "passed": true, + "running_time": 0.0, + "scanner_name": "RepoNotEmpty", + "version": "", + "warn": { + } + }, + "Semgrep": { + "errors": [ + + ], + "info": { + "hits": [ + + ], + "misses": [ + + ] + }, + "passed": true, + "running_time": 0.0, + "scanner_name": "Semgrep", + "version": "1.0.0", + "warn": { + } + }, + "Trufflehog": { + "errors": [ + + ], + "info": { + }, + "passed": true, + "running_time": 1.45, + "scanner_name": "Trufflehog", + "version": "3.19.0", + "warn": { + } + } + }, + "version": "2.26.0" +} +versus for { + "config": { + "active_scanners": [ + "Bandit", + "Brakeman", + "BundleAudit", + "CargoAudit", + "GoOSV", + "GoPackageScanner", + "GoVersionScanner", + "Gosec", + "GradleOSV", + "MavenOSV", + "NPMAudit", + "NPMPackageScanner", + "PatternSearch", + "PythonOSV", + "RepoNotEmpty", + "ReportGoDep", + "ReportGradleDeps", + "ReportNodeModules", + "ReportPodfileLock", + "ReportPomXml", + "ReportPythonModules", + "ReportRubyGems", + "ReportRustCrates", + "ReportSwiftDeps", + "RubyPackageScanner", + "RubyVersionScanner", + "Semgrep", + "Trufflehog", + "YarnAudit" + ], + "builds": { + "service_name": "buildkite", + "url": "http://example.com/builds/123" + }, + "enforced_scanners": [ + "Brakeman", + "BundleAudit", + "CargoAudit", + "Gosec", + "NPMAudit", + "PatternSearch", + "RepoNotEmpty", + "Semgrep", + "YarnAudit" + ], + "report_uris": [ + { + "format": "json", + "uri": "file:///home/spec/fixtures/processor/local_uri/salus_reports_folder/salus-report.json" + } + ], + "scanner_configs": { + "Bandit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Brakeman": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "BundleAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "CargoAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GoOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GoPackageScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GoVersionScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Gosec": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "GradleOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "MavenOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "NPMAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "NPMPackageScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "NodeAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "PatternSearch": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "PythonOSV": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "RepoNotEmpty": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportGoDep": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportGradleDeps": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportNodeModules": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportPodfileLock": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportPomXml": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportPythonModules": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportRubyGems": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportRustCrates": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "ReportSwiftDeps": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "RubyPackageScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "RubyVersionScanner": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Semgrep": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "Trufflehog": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + }, + "YarnAudit": { + "pass_on_raise": false, + "scanner_timeout_s": 0 + } + }, + "sources": { + "configured": [ + "file:///salus.yaml" + ], + "valid": [ + "file:///salus.yaml" + ] + } + }, + "errors": [ + + ], + "passed": true, + "running_time": 1.83, + "scans": { + "PatternSearch": { + "errors": [ + + ], + "info": { + "hits": [ + + ], + "misses": [ + + ] + }, + "passed": true, + "running_time": 0.0, + "scanner_name": "PatternSearch", + "version": "0.9.0", + "warn": { + } + }, + "RepoNotEmpty": { + "errors": [ + + ], + "info": { + }, + "passed": true, + "running_time": 0.03, + "scanner_name": "RepoNotEmpty", + "version": "", + "warn": { + } + }, + "Semgrep": { + "errors": [ + + ], + "info": { + "hits": [ + + ], + "misses": [ + + ] + }, + "passed": true, + "running_time": 0.0, + "scanner_name": "Semgrep", + "version": "1.0.0", + "warn": { + } + }, + "Trufflehog": { + "errors": [ + + ], + "info": { + }, + "passed": true, + "running_time": 1.67, + "scanner_name": "Trufflehog", + "version": "3.21.0", + "warn": { + } + } + }, + "version": "2.26.0" +} + should write the report to the local file system based on a path in the given repo (FAILED - 2) + multiple URIs +RepoNotEmpty is scanning... +RepoNotEmpty has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +Trufflehog has finished + should still send the 2nd report to the remote URI + Registering to reporting Scanners finished event +RepoNotEmpty is scanning... +RepoNotEmpty has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +Trufflehog has finished + should Recieve reporting_scanners_ran event + remote URI headers verbs +RepoNotEmpty is scanning... +RepoNotEmpty has finished +PatternSearch is scanning... +PatternSearch has finished +Trufflehog is scanning... +Semgrep is scanning... +Semgrep has finished +Trufflehog has finished + should send the report to the remote URI with correct headers and verb + +Salus::RepoSearcher + dependencies + should have access to ripgrep + matching_repos + should return project repo if not set to recurse + should not implicity include project repo when supplied with recursion settings + should support static directories + should fitler out unsafe directories + should allow relative references that resolve to repo path + should support dynamic directories via content and filename + should support dynamic directories via content only + should support dynamic directories via filename only + should filter out exclusions + should support temporal static files + +Salus::Repo + IMPORTANT_FILES runtime defined functions + should create a getter and presence check method for special files + should create a getter and search for files marked with wildcard + +Salus::Report + #to_s + should merge runs from the same scanner + #to_h and miscellaneous reporting methods + emits the expected reporting data via the #to_h method + should apply filters for to_h + should apply filters for to_sarif + does not include project_name/custom_info/config if not given + should merge multilpe scans from a given scanner, failing if any failed + #passed? + returns true if and only if all required scans passed + #export_report + HTTP report URI given + should make a call to send the report for http URI + should raise if there is an error with sending the report to a HTTP endpoint + HTTP report URI given with request parameters + should make a call to send the json report for http URI + should make a call to send the yaml report for http URI + should make a call to send the txt report for http URI + should make a call to send the sarif report for http URI + should make a call to send the sarif_diff_full report for http URI + local file report URI given + should save to the given directory for a local file uri + should raise if it tries to write a file report to a non-existent directory + x-scanner type + should get the correct x-scanner based on format + merge_reports + should merge reports from the same scanner when configured + should not merge reports from the same scanner by default + #satisfies_filter + runs all reports when `all` filter is provided + doesnt run any reports when `none` filter is provided + runs only `good-name` reports when `name:good-name` filter is provided + runs only yaml-formatted reports when `format:yaml` filter is provided + runs only reports with `name` keys when `name:*` filter is provided + #deep_sort + for salus outputs + should deepsort json output format + should deepsort sarif output + should deepsort YAML output + should deepsort cyclonedx output + +Salus::ScanReport + merge! + should combine fields + should apply the custom fail message + will raise when combine reports from different scanners + #to_s + not verbose and passed + includes all relevant important in string form + not verbose and failed + includes all relevant important in string form + verbose and passed + includes all relevant important in string form + not verbose + includes all relevant important in string form + +Salus::Scanners::Bandit + #should_run? + no requirements.txt nor setup.cfg + should return false + requirements.txt present but no setup.cfg + should return true + setup.cfg present but no requirements.txt + should return true + py files present but not requirements.txt/setup.cfg + should return true + #run + non-bandit project + should record 0 line of code scanned if no code + python project with insecure code + should record failure and record the STDOUT from bandit + python project with insecure code in a nested folder + should record failure and record the STDOUT from bandit + python project with no known vulnerabilities + should report a passing scan + python project with unknown skip + should report a failing scan + #config_options + when using aggregate + and aggregate by filename + and aggregate by vuln + when using configfile + if no configfile baseline - results include test_id B301 + and configfile says skip test_id B301 + when listing exceptions + should allow exception entries + should support expirations + when using profile + if no profile baseline - results test names include multiple items + and profile says include only one test name + when using tests + and tests only B301 + and test B105 and B301 + and test B105, B301, B403 + when using skip + and skip B301 + and skip B301, B403 + when using baseline file + if no baseline, then results include two files + and using main.py as baseline + when using ini file + ini file option should work + when using ignore nosec + if ignore nosec is false then report passes + and ignore nosec + when using exclude path + if not using exclude path baseline + and exclude main.py, then only main2.py will be scanned + and exclude both main.py and main2.py + when using confidence + and confidence level is MEDIUM + and confidence level is HIGH + using severity level + and severity level is LOW + and severity level is MEDIUM + and severity level is HIGH + #version_valid? + scanner version is valid + should return true + #supported_languages + should return supported languages + should return python + +Salus::Scanners::Base + run! + should catch exceptions from scanners and record the error + should catch exceptions and fail the build if pass_on_raise false + should catch exceptions and fail the build if pass_on_raise false + should time out when execution time exceeds configured timeout + #run + should raise an exception since this is an abstract function + #should_run? + should raise an exception since this is an abstract function + #run_shell + should execute a shell command and yield a ShellResult with appropriate values + #report_success + should log to the report that the scan passed + #report_failure + should log to the report that the scan failed + #report_info + should store some info indexed by scanner and info type + #report_stdout + should store the stdout of the scanner + #report_stderr + should store the stderr of the scanner + #build_options + should build the options correctly based on a hash + +Salus::Scanners::Brakeman + #run + runs cleanly against a project bundled with Bundler 2 + non-rails project + should record the STDERR of brakeman + brakeman configs + should error if no top-level app dir and no user defined app path + should respect the config for user defined app path if no top-level app dir + should respect brakeman.ignore files + should respect expirations from brakeman.ignore files + should support exceptions + should report an error if unable to create temporary ignore + should support expirations in exceptions + should support merging exceptions with brakeman.ignore files + should respect the config for user defined app path + should respect the config for all checks + should respect the config for running only a subset of checks + should respect the config excluding some checks + should respect the config supressing warning levels + should respect the config for ignoring files + should respect the config for only scanning certain files + brakeman warnings or errors + should fail if a potential vulnerability is detected in the repo + should fail if brakeman encounters a parse error + #should_run? + no Gemfile nor Rails gem + should return false + Gemfile present but no rails gem + should return false + Gemfile present with rails gem + should return true + Gemfile present with rails gem but no rails app + should return false + #version_valid? + scanner version is valid + should return true + #supported_languages + should return supported languages + should return ruby + +Bugsnag + #run + blank directory + bugsnag should receiev error + +Salus::Scanners::BundleAudit + #run + should check for updates to the CVE DB + runs cleanly against a project bundled with Bundler 2 + CVEs in Gemfile.lock + should record failure and record the STDOUT from bundle-audit + insecure sources in Gemfile + should record failure and report results + no CVEs in Gemfile.lock + should report success + no CVEs in Gemfile.lock when ignoring CVEs + should record success and report on the ignored CVEs + exceptions with expirations + should apply active exceptions + should not apply expired exceptions + should record success and report on the ignored CVEs + with local db + should report vulns from both local db and ruby advisory db + #should_run? + should return false if Gemfile.lock not present + should return true if Gemfile.lock is present + #version_valid? + scanner version is valid + should return true + #supported_languages + should return supported languages + should return ruby + #valid_local_db? + should detect valid/invalid local dbs + +Salus::Scanners::CargoAudit + #should_run? + should return false in the absence of Cargo.lock + should return true if Cargo.lock is present + #run + should pass when there are no vulnerabilities + should fail when there are missing dependencies + should fail when there are vulnerabilities + should elevate warnings as errors + should ignore warnings if disabled in the config + should honor exceptions in the config + should honor exception expirations + should send the audit log as json + should log pretty json + should report error if there were issues in running cargo audit + #version_valid? + scanner version is valid + should return true + #supported_languages + should return supported languages + should return rust + +Salus::Scanners::Gosec + #run + non-go project + should record the STDERR of gosec + go project with vulnerabilities + should record failure and record the STDOUT from gosec + go project with vulnerabilities in a nested folder + should record failure and record the STDOUT from gosec + go project with no known vulnerabilities + should report a passing scan + go project with malformed go + should report a failing scan + #run from multiple subdirs + go project with multiple sub-projects + should report failures in both sub-projects + #should_run? + behaves like when go file types are present + returns true + behaves like when go file types are present + returns true + behaves like when go file types are present + returns true + behaves like when go file types are present + returns true + when go file types are missing + returns false + #config_options + when using nosec + and nosec is set to true + disables nosec comments + and nosec is set to false + enables nosec comments + and nosec is not set to a boolean + warns when not provided a valid options + when using nosec-tag + and a valid tag + respects nosec-tag over nosec + and disabling nosec + respects nosec settings also + and an invalid tag + warns when not provided a valid option + when including rules + actually includes only the given rules + and when using nosec flag + only scans for included rules even if issue is whitelisted + when excluding rules + actually excludes only the given rules + and when using nosec flag + only scans for included rules even if issue is whitelisted + active exceptions + should honor active exceptions + expired exceptions + should ignore expired exceptions + when sorting by severity + is sorted in the report + when filtering by severity + is filtered by severity + when filtering by confidence + filtered by confidence + when the scan should be forced to pass + always passes + when scanning tests + scans for issues in test files + when excluding directories + and is a real directory 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": { } } diff --git a/spec/lib/salus/processor_spec.rb b/spec/lib/salus/processor_spec.rb index f7cbe5d5..1321970e 100644 --- a/spec/lib/salus/processor_spec.rb +++ b/spec/lib/salus/processor_spec.rb @@ -293,6 +293,8 @@ def remove_key(json_string, encoded = false) processor.scan_project processor.export_report + puts "Found #{expected_report}" + puts "versus for #{File.read(local_uri)}" expect(File.read(local_uri)).to match_report_json(expected_report, true) # remove report file that was generated from Salus execution From 89f9a911a0672e2662c7391054f4f6fa7b2c93d7 Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 15:25:53 -0800 Subject: [PATCH 08/10] minor nit --- lib/salus/rules_evaluation.rb | 8 +- sample.txt | 1148 --------------------------------- 2 files changed, 4 insertions(+), 1152 deletions(-) delete mode 100644 sample.txt diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index 84559bad..1e30e2f5 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -22,8 +22,8 @@ def self.evaluate_by_type(config, results) def self.evaluate_by_id(config, results) matches = config["matches"] - keys = matches.map{ |x| x["key"] } - ids = results.map{ |x| x[:ID] } + keys = matches.map { |x| x["key"] } + ids = results.map { |x| x[:ID] } return true unless (keys & ids).length.positive? reutrn false @@ -31,8 +31,8 @@ def self.evaluate_by_id(config, results) def self.evaluate_by_severity(config, results) matches = config["matches"] - keys = matches.map{ |x| x["key"] } - ids = results.map{ |x| x[:Severity] } + keys = matches.map { |x| x["key"] } + ids = results.map { |x| x[:Severity] } return true unless (keys & ids).length.positive? reutrn false diff --git a/sample.txt b/sample.txt deleted file mode 100644 index 24b4f53f..00000000 --- a/sample.txt +++ /dev/null @@ -1,1148 +0,0 @@ - -Cyclonedx::ReportRubyGems - to_cyclonedx schema validation - succeeds if generated cyclonedx format is correct - succeeds if generated cyclonedx format is correct - succeeds if generated cyclonedx version is empty - succeeds if scan_reports contain duplicate reports - fails if generated cyclonedx report is not valid - to_cyclonedx spec version validation - cylonedx spec version 1.2 does not include properties field - cylonedx spec version 1.3 does include properties field - fails if provided cylonedx spec version is unsupported - -Cyclonedx::PackageUrl - purl format matches expected - purl format is correct with no special characters - purl format is correct with no version - purl format is correct with percent encoded strings - purl format removes leading and trailing / from namespace - -Cyclonedx::ReportGoDep - #run - should report all the deps using go.sum if available - should report all the deps in the Gopkg.lock if present - should report warning and send event if no Gopkg.lock/go.sumavailable and return empty build - -Cyclonedx::ReportGradleDeps - #run - should report all the deps in the build.gradle - should produce valid CycloneDX under normal conditions - -Cyclonedx::ReportNodeModules - #run - should report all the deps in the package.json if both\ - package-lock.json and yarn.lock files do not exist - should report all the deps in the package-lock.json if present - should report all the deps in the yarn.lock if present - should report all the deps in the bower.json if present - should produce valid CycloneDX for bower.json - should produce valid CycloneDX for including dev deps package-lock.json - should produce valid CycloneDX for excluding dev deps package-lock.json - -Cyclonedx::ReportPodfileLock - #run - should report all the deps in the Podfile.lock - should produce valid CycloneDX under normal conditions - should produce valid CycloneDX when an unparseable file is found - -Cyclonedx::ReportPomXml - #run - should report all the deps in the pom.xml - should produce valid CycloneDX under normal conditions - -Cyclonedx::ReportPythonModules - #run - should report all the deps in the unpinned requirements.txt - should report all the deps in the pinned requirements.txt - should report all the deps in the semi-pinned requirements.txt - -Cyclonedx::ReportRubyGems - #run - should report all the deps in the Gemfile if Gemfile.lock is absent in cyclonedx - should report all deps in Gemfile.lock in cyclonedx - should report all deps from multiple sources in Gemfile.lock in cyclonedx - -Cyclonedx::ReportRustCrates - #run - should report all the deps in the Cargo.lock if manifest is absent in cyclonedx - should calculate and report all the dependencies in the manifest if Cargo.lock is absent - should prefer the Cargo.lock over the manifest when both available - -Cyclonedx::ReportSwiftDeps - #run - should report all the deps in the Package.resolved - should produce valid CycloneDX under normal conditions - should produce valid CycloneDX when an unparseable file is found - -MergeUtil - deep_merge - should overwite arrays by default - should overwrite arrays when combine is false - should concat arrays when combine is true - -Salus::CLI - returns non-zero exit when invalid params are passed - -Salus::ConfigException - #initialize - should support initializing from a hash - should create an invalid exception if no params are passed - validation - should require the expected fields - active? - should return true if no expiration was given - should return true if empty expiration was given - should return false for past dates - should return true for current date - should return true for future dates - -Salus::Config - #initialize - should accept custom_info hashes - should accept custom_info strings - should deep merge config files - should replace arrays by default - should replace arrays when configured - should combine arrays when configured - should apply default scanner config for each scanner - should merge all NodeAudit related configuration - should merge arrays in all NodeAudit related configuration - no initialization file given - should use the default config file - project names - should not accept project names with invalid chars - should accept project names with valid chars - files given as source - should use the YAML files as config with ordered priority - bad files given as source - should ignore bad files - files point to envars that need to be interpolated - should replace references to envars with the envar values - #scanner_active? - should correctly answer if a scanner is active - #scanner_enforced? - should correctly answer if the current configuration has enforced scanning - -Salus::DiceCoefficient - should return 1.0 if two strings are same - should return 0.0 if two strings are completely different - should return higher value if two strings are very similar - should return lower value if two strings are less similar - -Salus::FileCopier - copy_files - should ignore existing files - should gracefully handle empty file list - should copy files not present - should clean up after itself - should attempt to clean up when exceptions are thrown - -Salus::Formatting - prettify_json_string - returns pretty json from valid json string - returns input string if json parse fails - -Salus::PathValidator - local_to_base? - should return false for files outside parent directory - should return false for folders outside parent directory - -Salus::PluginManager - apply_filter - applies the filter - does not apply filter from a different context - send_event - sends the event - -Salus::Processor - #initialize - explicit sources of config given files given - should load the config from the given file and URI sources and add them to the report - - -Failed to load file:///salus.yaml - - should expand the repo path provided - - -Failed to load file:///salus.yaml - - - -Failed to load file:///salus.yaml - - fetch_config_file should return nil if file content is not hash - - -Failed to load file:///namewithtypo.yaml - - should not use config files when they do not exist - implicitly look for file - should load the default config from the salus.yaml and add to report - #scan_project -Brakeman is scanning... -BundleAudit is scanning... -RepoNotEmpty is scanning... -RepoNotEmpty has finished -ReportRubyGems is scanning... -ReportRubyGems has finished -RubyPackageScanner is scanning... -RubyPackageScanner has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -Brakeman has finished -BundleAudit has finished -Trufflehog has finished - should scan the project given by a particular path -Brakeman is scanning... -NPMAudit is scanning... -Brakeman has finished -NPMAudit has finished - should override the configured active scanners when they're provided via command line -Brakeman is scanning... -NPMAudit is scanning... -Brakeman has finished -NPMAudit has finished - should scan the project using only scanners provided from the command line -Brakeman is scanning... -Brakeman is scanning... -NPMAudit is scanning... -Brakeman has finished -Brakeman has finished -NPMAudit has finished - should recurse when configured - #passed? -BundleAudit is scanning... -RepoNotEmpty is scanning... -RepoNotEmpty has finished -ReportRubyGems is scanning... -RubyPackageScanner is scanning... -RubyPackageScanner has finished -ReportRubyGems has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -BundleAudit has finished -Trufflehog has finished - should return false if the overall scan did not pass -BundleAudit is scanning... -RepoNotEmpty is scanning... -RubyPackageScanner is scanning... -RubyPackageScanner has finished -ReportRubyGems is scanning... -PatternSearch is scanning... -RepoNotEmpty has finished -PatternSearch has finished -ReportRubyGems has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -BundleAudit has finished -Trufflehog has finished - should return true if the overall scan passed - #export_report - remote URI -RepoNotEmpty is scanning... -RepoNotEmpty has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -Trufflehog has finished - should send the report to the remote URI (FAILED - 1) - Expect 0 report_uris for report_filter set to none - local URI -RepoNotEmpty is scanning... -RepoNotEmpty has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -Trufflehog has finished -Found { - "config": { - "active_scanners": [ - "Bandit", - "Brakeman", - "BundleAudit", - "CargoAudit", - "GoOSV", - "GoPackageScanner", - "GoVersionScanner", - "Gosec", - "GradleOSV", - "MavenOSV", - "NPMAudit", - "NPMPackageScanner", - "PatternSearch", - "PythonOSV", - "RepoNotEmpty", - "ReportGoDep", - "ReportGradleDeps", - "ReportNodeModules", - "ReportPodfileLock", - "ReportPomXml", - "ReportPythonModules", - "ReportRubyGems", - "ReportRustCrates", - "ReportSwiftDeps", - "RubyPackageScanner", - "RubyVersionScanner", - "Semgrep", - "Trufflehog", - "YarnAudit" - ], - "builds": { - "service_name": "buildkite", - "url": "http://example.com/builds/123" - }, - "enforced_scanners": [ - "Brakeman", - "BundleAudit", - "CargoAudit", - "Gosec", - "NPMAudit", - "PatternSearch", - "RepoNotEmpty", - "Semgrep", - "YarnAudit" - ], - "report_uris": [ - { - "format": "json", - "uri": "file:///home/spec/fixtures/processor/local_uri/salus_reports_folder/salus-report.json" - } - ], - "scanner_configs": { - "Bandit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Brakeman": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "BundleAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "CargoAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GoOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GoPackageScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GoVersionScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Gosec": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GradleOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "MavenOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "NPMAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "NPMPackageScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "NodeAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "PatternSearch": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "PythonOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "RepoNotEmpty": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportGoDep": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportGradleDeps": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportNodeModules": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportPodfileLock": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportPomXml": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportPythonModules": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportRubyGems": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportRustCrates": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportSwiftDeps": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "RubyPackageScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "RubyVersionScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Semgrep": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Trufflehog": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "YarnAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - } - }, - "sources": { - "configured": [ - "file:///salus.yaml" - ], - "valid": [ - "file:///salus.yaml" - ] - } - }, - "errors": [ - - ], - "passed": true, - "running_time": 0.52, - "scans": { - "PatternSearch": { - "errors": [ - - ], - "info": { - "hits": [ - - ], - "misses": [ - - ] - }, - "passed": true, - "running_time": 0.0, - "scanner_name": "PatternSearch", - "version": "0.9.0", - "warn": { - } - }, - "RepoNotEmpty": { - "errors": [ - - ], - "info": { - }, - "passed": true, - "running_time": 0.0, - "scanner_name": "RepoNotEmpty", - "version": "", - "warn": { - } - }, - "Semgrep": { - "errors": [ - - ], - "info": { - "hits": [ - - ], - "misses": [ - - ] - }, - "passed": true, - "running_time": 0.0, - "scanner_name": "Semgrep", - "version": "1.0.0", - "warn": { - } - }, - "Trufflehog": { - "errors": [ - - ], - "info": { - }, - "passed": true, - "running_time": 1.45, - "scanner_name": "Trufflehog", - "version": "3.19.0", - "warn": { - } - } - }, - "version": "2.26.0" -} -versus for { - "config": { - "active_scanners": [ - "Bandit", - "Brakeman", - "BundleAudit", - "CargoAudit", - "GoOSV", - "GoPackageScanner", - "GoVersionScanner", - "Gosec", - "GradleOSV", - "MavenOSV", - "NPMAudit", - "NPMPackageScanner", - "PatternSearch", - "PythonOSV", - "RepoNotEmpty", - "ReportGoDep", - "ReportGradleDeps", - "ReportNodeModules", - "ReportPodfileLock", - "ReportPomXml", - "ReportPythonModules", - "ReportRubyGems", - "ReportRustCrates", - "ReportSwiftDeps", - "RubyPackageScanner", - "RubyVersionScanner", - "Semgrep", - "Trufflehog", - "YarnAudit" - ], - "builds": { - "service_name": "buildkite", - "url": "http://example.com/builds/123" - }, - "enforced_scanners": [ - "Brakeman", - "BundleAudit", - "CargoAudit", - "Gosec", - "NPMAudit", - "PatternSearch", - "RepoNotEmpty", - "Semgrep", - "YarnAudit" - ], - "report_uris": [ - { - "format": "json", - "uri": "file:///home/spec/fixtures/processor/local_uri/salus_reports_folder/salus-report.json" - } - ], - "scanner_configs": { - "Bandit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Brakeman": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "BundleAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "CargoAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GoOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GoPackageScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GoVersionScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Gosec": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "GradleOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "MavenOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "NPMAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "NPMPackageScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "NodeAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "PatternSearch": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "PythonOSV": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "RepoNotEmpty": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportGoDep": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportGradleDeps": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportNodeModules": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportPodfileLock": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportPomXml": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportPythonModules": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportRubyGems": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportRustCrates": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "ReportSwiftDeps": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "RubyPackageScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "RubyVersionScanner": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Semgrep": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "Trufflehog": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - }, - "YarnAudit": { - "pass_on_raise": false, - "scanner_timeout_s": 0 - } - }, - "sources": { - "configured": [ - "file:///salus.yaml" - ], - "valid": [ - "file:///salus.yaml" - ] - } - }, - "errors": [ - - ], - "passed": true, - "running_time": 1.83, - "scans": { - "PatternSearch": { - "errors": [ - - ], - "info": { - "hits": [ - - ], - "misses": [ - - ] - }, - "passed": true, - "running_time": 0.0, - "scanner_name": "PatternSearch", - "version": "0.9.0", - "warn": { - } - }, - "RepoNotEmpty": { - "errors": [ - - ], - "info": { - }, - "passed": true, - "running_time": 0.03, - "scanner_name": "RepoNotEmpty", - "version": "", - "warn": { - } - }, - "Semgrep": { - "errors": [ - - ], - "info": { - "hits": [ - - ], - "misses": [ - - ] - }, - "passed": true, - "running_time": 0.0, - "scanner_name": "Semgrep", - "version": "1.0.0", - "warn": { - } - }, - "Trufflehog": { - "errors": [ - - ], - "info": { - }, - "passed": true, - "running_time": 1.67, - "scanner_name": "Trufflehog", - "version": "3.21.0", - "warn": { - } - } - }, - "version": "2.26.0" -} - should write the report to the local file system based on a path in the given repo (FAILED - 2) - multiple URIs -RepoNotEmpty is scanning... -RepoNotEmpty has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -Trufflehog has finished - should still send the 2nd report to the remote URI - Registering to reporting Scanners finished event -RepoNotEmpty is scanning... -RepoNotEmpty has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -Trufflehog has finished - should Recieve reporting_scanners_ran event - remote URI headers verbs -RepoNotEmpty is scanning... -RepoNotEmpty has finished -PatternSearch is scanning... -PatternSearch has finished -Trufflehog is scanning... -Semgrep is scanning... -Semgrep has finished -Trufflehog has finished - should send the report to the remote URI with correct headers and verb - -Salus::RepoSearcher - dependencies - should have access to ripgrep - matching_repos - should return project repo if not set to recurse - should not implicity include project repo when supplied with recursion settings - should support static directories - should fitler out unsafe directories - should allow relative references that resolve to repo path - should support dynamic directories via content and filename - should support dynamic directories via content only - should support dynamic directories via filename only - should filter out exclusions - should support temporal static files - -Salus::Repo - IMPORTANT_FILES runtime defined functions - should create a getter and presence check method for special files - should create a getter and search for files marked with wildcard - -Salus::Report - #to_s - should merge runs from the same scanner - #to_h and miscellaneous reporting methods - emits the expected reporting data via the #to_h method - should apply filters for to_h - should apply filters for to_sarif - does not include project_name/custom_info/config if not given - should merge multilpe scans from a given scanner, failing if any failed - #passed? - returns true if and only if all required scans passed - #export_report - HTTP report URI given - should make a call to send the report for http URI - should raise if there is an error with sending the report to a HTTP endpoint - HTTP report URI given with request parameters - should make a call to send the json report for http URI - should make a call to send the yaml report for http URI - should make a call to send the txt report for http URI - should make a call to send the sarif report for http URI - should make a call to send the sarif_diff_full report for http URI - local file report URI given - should save to the given directory for a local file uri - should raise if it tries to write a file report to a non-existent directory - x-scanner type - should get the correct x-scanner based on format - merge_reports - should merge reports from the same scanner when configured - should not merge reports from the same scanner by default - #satisfies_filter - runs all reports when `all` filter is provided - doesnt run any reports when `none` filter is provided - runs only `good-name` reports when `name:good-name` filter is provided - runs only yaml-formatted reports when `format:yaml` filter is provided - runs only reports with `name` keys when `name:*` filter is provided - #deep_sort - for salus outputs - should deepsort json output format - should deepsort sarif output - should deepsort YAML output - should deepsort cyclonedx output - -Salus::ScanReport - merge! - should combine fields - should apply the custom fail message - will raise when combine reports from different scanners - #to_s - not verbose and passed - includes all relevant important in string form - not verbose and failed - includes all relevant important in string form - verbose and passed - includes all relevant important in string form - not verbose - includes all relevant important in string form - -Salus::Scanners::Bandit - #should_run? - no requirements.txt nor setup.cfg - should return false - requirements.txt present but no setup.cfg - should return true - setup.cfg present but no requirements.txt - should return true - py files present but not requirements.txt/setup.cfg - should return true - #run - non-bandit project - should record 0 line of code scanned if no code - python project with insecure code - should record failure and record the STDOUT from bandit - python project with insecure code in a nested folder - should record failure and record the STDOUT from bandit - python project with no known vulnerabilities - should report a passing scan - python project with unknown skip - should report a failing scan - #config_options - when using aggregate - and aggregate by filename - and aggregate by vuln - when using configfile - if no configfile baseline - results include test_id B301 - and configfile says skip test_id B301 - when listing exceptions - should allow exception entries - should support expirations - when using profile - if no profile baseline - results test names include multiple items - and profile says include only one test name - when using tests - and tests only B301 - and test B105 and B301 - and test B105, B301, B403 - when using skip - and skip B301 - and skip B301, B403 - when using baseline file - if no baseline, then results include two files - and using main.py as baseline - when using ini file - ini file option should work - when using ignore nosec - if ignore nosec is false then report passes - and ignore nosec - when using exclude path - if not using exclude path baseline - and exclude main.py, then only main2.py will be scanned - and exclude both main.py and main2.py - when using confidence - and confidence level is MEDIUM - and confidence level is HIGH - using severity level - and severity level is LOW - and severity level is MEDIUM - and severity level is HIGH - #version_valid? - scanner version is valid - should return true - #supported_languages - should return supported languages - should return python - -Salus::Scanners::Base - run! - should catch exceptions from scanners and record the error - should catch exceptions and fail the build if pass_on_raise false - should catch exceptions and fail the build if pass_on_raise false - should time out when execution time exceeds configured timeout - #run - should raise an exception since this is an abstract function - #should_run? - should raise an exception since this is an abstract function - #run_shell - should execute a shell command and yield a ShellResult with appropriate values - #report_success - should log to the report that the scan passed - #report_failure - should log to the report that the scan failed - #report_info - should store some info indexed by scanner and info type - #report_stdout - should store the stdout of the scanner - #report_stderr - should store the stderr of the scanner - #build_options - should build the options correctly based on a hash - -Salus::Scanners::Brakeman - #run - runs cleanly against a project bundled with Bundler 2 - non-rails project - should record the STDERR of brakeman - brakeman configs - should error if no top-level app dir and no user defined app path - should respect the config for user defined app path if no top-level app dir - should respect brakeman.ignore files - should respect expirations from brakeman.ignore files - should support exceptions - should report an error if unable to create temporary ignore - should support expirations in exceptions - should support merging exceptions with brakeman.ignore files - should respect the config for user defined app path - should respect the config for all checks - should respect the config for running only a subset of checks - should respect the config excluding some checks - should respect the config supressing warning levels - should respect the config for ignoring files - should respect the config for only scanning certain files - brakeman warnings or errors - should fail if a potential vulnerability is detected in the repo - should fail if brakeman encounters a parse error - #should_run? - no Gemfile nor Rails gem - should return false - Gemfile present but no rails gem - should return false - Gemfile present with rails gem - should return true - Gemfile present with rails gem but no rails app - should return false - #version_valid? - scanner version is valid - should return true - #supported_languages - should return supported languages - should return ruby - -Bugsnag - #run - blank directory - bugsnag should receiev error - -Salus::Scanners::BundleAudit - #run - should check for updates to the CVE DB - runs cleanly against a project bundled with Bundler 2 - CVEs in Gemfile.lock - should record failure and record the STDOUT from bundle-audit - insecure sources in Gemfile - should record failure and report results - no CVEs in Gemfile.lock - should report success - no CVEs in Gemfile.lock when ignoring CVEs - should record success and report on the ignored CVEs - exceptions with expirations - should apply active exceptions - should not apply expired exceptions - should record success and report on the ignored CVEs - with local db - should report vulns from both local db and ruby advisory db - #should_run? - should return false if Gemfile.lock not present - should return true if Gemfile.lock is present - #version_valid? - scanner version is valid - should return true - #supported_languages - should return supported languages - should return ruby - #valid_local_db? - should detect valid/invalid local dbs - -Salus::Scanners::CargoAudit - #should_run? - should return false in the absence of Cargo.lock - should return true if Cargo.lock is present - #run - should pass when there are no vulnerabilities - should fail when there are missing dependencies - should fail when there are vulnerabilities - should elevate warnings as errors - should ignore warnings if disabled in the config - should honor exceptions in the config - should honor exception expirations - should send the audit log as json - should log pretty json - should report error if there were issues in running cargo audit - #version_valid? - scanner version is valid - should return true - #supported_languages - should return supported languages - should return rust - -Salus::Scanners::Gosec - #run - non-go project - should record the STDERR of gosec - go project with vulnerabilities - should record failure and record the STDOUT from gosec - go project with vulnerabilities in a nested folder - should record failure and record the STDOUT from gosec - go project with no known vulnerabilities - should report a passing scan - go project with malformed go - should report a failing scan - #run from multiple subdirs - go project with multiple sub-projects - should report failures in both sub-projects - #should_run? - behaves like when go file types are present - returns true - behaves like when go file types are present - returns true - behaves like when go file types are present - returns true - behaves like when go file types are present - returns true - when go file types are missing - returns false - #config_options - when using nosec - and nosec is set to true - disables nosec comments - and nosec is set to false - enables nosec comments - and nosec is not set to a boolean - warns when not provided a valid options - when using nosec-tag - and a valid tag - respects nosec-tag over nosec - and disabling nosec - respects nosec settings also - and an invalid tag - warns when not provided a valid option - when including rules - actually includes only the given rules - and when using nosec flag - only scans for included rules even if issue is whitelisted - when excluding rules - actually excludes only the given rules - and when using nosec flag - only scans for included rules even if issue is whitelisted - active exceptions - should honor active exceptions - expired exceptions - should ignore expired exceptions - when sorting by severity - is sorted in the report - when filtering by severity - is filtered by severity - when filtering by confidence - filtered by confidence - when the scan should be forced to pass - always passes - when scanning tests - scans for issues in test files - when excluding directories - and is a real directory From 4708be8aaf1e02513324936def14047fd35e7f7c Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 20:04:34 -0800 Subject: [PATCH 09/10] Rules for osv scanners --- lib/salus/scanners/osv/gradle_osv.rb | 2 +- lib/salus/scanners/osv/maven_osv.rb | 2 +- lib/salus/scanners/osv/python_osv.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/salus/scanners/osv/gradle_osv.rb b/lib/salus/scanners/osv/gradle_osv.rb index 086af14b..31e0c69b 100644 --- a/lib/salus/scanners/osv/gradle_osv.rb +++ b/lib/salus/scanners/osv/gradle_osv.rb @@ -41,7 +41,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) 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..f9affb6e 100644 --- a/lib/salus/scanners/osv/maven_osv.rb +++ b/lib/salus/scanners/osv/maven_osv.rb @@ -46,7 +46,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) 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..fcacfeae 100644 --- a/lib/salus/scanners/osv/python_osv.rb +++ b/lib/salus/scanners/osv/python_osv.rb @@ -41,7 +41,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) report_failure log(JSON.pretty_generate(results)) From c0bfdcfccf72d240d7929d4915b9367fd4903d77 Mon Sep 17 00:00:00 2001 From: Maitray Shah Date: Wed, 21 Dec 2022 21:53:07 -0800 Subject: [PATCH 10/10] Update logic and add bundleaudit --- lib/salus/rules_evaluation.rb | 37 +++++++++++++++++++--------- lib/salus/scanners/bundle_audit.rb | 8 +++++- lib/salus/scanners/osv/go_osv.rb | 3 ++- lib/salus/scanners/osv/gradle_osv.rb | 3 ++- lib/salus/scanners/osv/maven_osv.rb | 3 ++- lib/salus/scanners/osv/python_osv.rb | 3 ++- spec/lib/salus/processor_spec.rb | 2 -- 7 files changed, 41 insertions(+), 18 deletions(-) diff --git a/lib/salus/rules_evaluation.rb b/lib/salus/rules_evaluation.rb index 1e30e2f5..8b5eeadf 100644 --- a/lib/salus/rules_evaluation.rb +++ b/lib/salus/rules_evaluation.rb @@ -2,6 +2,20 @@ 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? @@ -9,37 +23,38 @@ def self.evaluate_default(results) false end - def self.evaluate_by_type(config, results) + def self.evaluate_by_type(config, results, scanner) case config["rule"]["type"] when RULE_TYPE_ID - evaluate_by_id(config["rule"], results) + evaluate_by_id(config["rule"], results, scanner) when RULE_TYPE_SEVERITY - evaluate_by_severity + evaluate_by_severit(config["rule"], results, scanner) else evaluate_default(results) end end - def self.evaluate_by_id(config, results) + def self.evaluate_by_id(config, results, scanner) matches = config["matches"] keys = matches.map { |x| x["key"] } - ids = results.map { |x| x[:ID] } - return true unless (keys & ids).length.positive? + 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) + def self.evaluate_by_severity(config, results, _scanner) matches = config["matches"] keys = matches.map { |x| x["key"] } - ids = results.map { |x| x[:Severity] } - return true unless (keys & ids).length.positive? + 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) - return evaluate_by_type(config, results) if config.key?('rule') + def self.evaluate_rules(config, results, scanner) + return evaluate_by_type(config, results, scanner) if config.key?('rule') evaluate_default(results) 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 8862b113..6b8887e4 100644 --- a/lib/salus/scanners/osv/go_osv.rb +++ b/lib/salus/scanners/osv/go_osv.rb @@ -10,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? @@ -47,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 Salus::RulesEvaluation.evaluate_rules(@config, results) + 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 31e0c69b..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 Salus::RulesEvaluation.evaluate_rules(@config, results) + 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 f9affb6e..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 Salus::RulesEvaluation.evaluate_rules(@config, results) + 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 fcacfeae..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 Salus::RulesEvaluation.evaluate_rules(@config, results) + return report_success if Salus::RulesEvaluation.evaluate_rules(@config, results, CLASS_NAME) report_failure log(JSON.pretty_generate(results)) diff --git a/spec/lib/salus/processor_spec.rb b/spec/lib/salus/processor_spec.rb index 1321970e..f7cbe5d5 100644 --- a/spec/lib/salus/processor_spec.rb +++ b/spec/lib/salus/processor_spec.rb @@ -293,8 +293,6 @@ def remove_key(json_string, encoded = false) processor.scan_project processor.export_report - puts "Found #{expected_report}" - puts "versus for #{File.read(local_uri)}" expect(File.read(local_uri)).to match_report_json(expected_report, true) # remove report file that was generated from Salus execution