Class: Gitlab::SecretDetection::Core::Scanner
- Inherits:
-
Object
- Object
- Gitlab::SecretDetection::Core::Scanner
- Defined in:
- lib/gitlab/secret_detection/core/scanner.rb
Overview
Scan is responsible for running Secret Detection scan operation
Constant Summary collapse
- DEFAULT_SCAN_TIMEOUT_SECS =
default time limit(in seconds) for running the scan operation per invocation
180- DEFAULT_PAYLOAD_TIMEOUT_SECS =
default time limit(in seconds) for running the scan operation on a single payload
30- MAX_PROCS_PER_REQUEST =
Max no of child processes to spawn per request ref: https://gitlab.com/gitlab-org/gitlab/-/issues/430160
5- MIN_CHUNK_SIZE_PER_PROC_BYTES =
Minimum cumulative size of the payloads required to spawn and run the scan within a new subprocess.
2_097_152- RUN_IN_SUBPROCESS =
Whether to run scan in subprocesses or not. Default is false.
ENV.fetch('GITLAB_SD_RUN_IN_SUBPROCESS', false)
- DEFAULT_MAX_FINDINGS_LIMIT =
Default limit for max findings to be returned in the scan
999
Instance Method Summary collapse
-
#initialize(rules:, logger: Logger.new($stdout)) ⇒ Scanner
constructor
Initializes the instance with logger along with following operations: 1.
-
#secrets_scan(payloads, timeout: DEFAULT_SCAN_TIMEOUT_SECS, payload_timeout: DEFAULT_PAYLOAD_TIMEOUT_SECS, exclusions: {}, tags: [], subprocess: RUN_IN_SUBPROCESS, max_findings_limit: DEFAULT_MAX_FINDINGS_LIMIT) ⇒ Object
Runs Secret Detection scan on the list of given payloads.
Constructor Details
#initialize(rules:, logger: Logger.new($stdout)) ⇒ Scanner
Initializes the instance with logger along with following operations:
- Filter the parsed ruleset down to rules applicable to push protection based on
their structured
scanningCapabilitiesfield. - Extract keywords from the applicable rules to use for matching keywords before regex operation.
- Build and Compile rule regex patterns obtained from the applicable rules.
Raises
RulesetCompilationErrorin case the regex pattern compilation fails.
35 36 37 38 39 40 41 |
# File 'lib/gitlab/secret_detection/core/scanner.rb', line 35 def initialize(rules:, logger: Logger.new($stdout)) @logger = logger @rules = select_push_protection_rules(rules) @keywords = create_keywords(@rules) @keyword_matcher = build_keyword_matcher(@rules) @pattern_matcher = build_pattern_matcher(@rules) end |
Instance Method Details
#secrets_scan(payloads, timeout: DEFAULT_SCAN_TIMEOUT_SECS, payload_timeout: DEFAULT_PAYLOAD_TIMEOUT_SECS, exclusions: {}, tags: [], subprocess: RUN_IN_SUBPROCESS, max_findings_limit: DEFAULT_MAX_FINDINGS_LIMIT) ⇒ Object
Runs Secret Detection scan on the list of given payloads. Both the total scan duration and
the duration for each payload is time bound via timeout and payload_timeout respectively.
payloadsArray of payloads where each payload should have
idanddataproperties.timeoutNo of seconds(accepts floating point for smaller time values) to limit the total scan duration
payload_timeoutNo of seconds(accepts floating point for smaller time values) to limit the scan duration on each payload
exclusionsHash with keys: :raw_value, :rule and values of arrays of either GRPC::Exclusion objects (when used as a standalone service) or Security::ProjectSecurityExclusion objects (when used as gem). :raw_value - Exclusions in the :raw array are the raw values to ignore. :rule - Exclusions in the :rule array are the rules to exclude from the ruleset used for the scan. Each rule is represented by its ID. For example:
gitlab_personal_access_tokenfor representing Gitlab Personal Access Token. By default, no rule is excluded from the ruleset.tagsDeprecated and ignored. Rules are selected via their structured
scanningCapabilitiesfield instead of tags. The argument is kept only for backward compatibility with existing callers and will be removed.max_findings_limitInteger to limit the number of findings to be returned in the scan. Defaults to 999 (+DEFAULT_MAX_FINDINGS_LIMIT+).
NOTE: Running the scan in fork mode primarily focuses on reducing the memory consumption of the scan by offloading regex operations on large payloads to sub-processes. However, it does not assure the improvement in the overall latency of the scan, specifically in the case of smaller payloads, where the overhead of forking a new process adds to the overall latency of the scan instead. More reference on Subprocess-based execution is found here: https://gitlab.com/gitlab-org/gitlab/-/issues/430160.
Returns an instance of Gitlab::SecretDetection::Core::Response by following below structure: { status: One of the Core::Status values results: [SecretDetection::Finding] }
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 |
# File 'lib/gitlab/secret_detection/core/scanner.rb', line 76 def secrets_scan( payloads, timeout: DEFAULT_SCAN_TIMEOUT_SECS, payload_timeout: DEFAULT_PAYLOAD_TIMEOUT_SECS, exclusions: {}, tags: [], subprocess: RUN_IN_SUBPROCESS, max_findings_limit: DEFAULT_MAX_FINDINGS_LIMIT ) return Core::Response.new(status: Core::Status::INPUT_ERROR) unless validate_scan_input(payloads) # assign defaults since grpc passing zero timeout value to `Timeout.timeout(..)` makes it effectively useless. timeout = DEFAULT_SCAN_TIMEOUT_SECS unless timeout.positive? payload_timeout = DEFAULT_PAYLOAD_TIMEOUT_SECS unless payload_timeout.positive? unless .nil? || .empty? || @tags_deprecation_warned @tags_deprecation_warned = true logger.warn( message: "The `tags` argument is deprecated and ignored. Rules are selected via their " \ "`scanningCapabilities` field instead.", given_tags: ) end Timeout.timeout(timeout) do matched_payloads = filter_by_keywords(keyword_matcher, payloads) next Core::Response.new(status: Core::Status::NOT_FOUND) if matched_payloads.empty? scan_args = { payloads: matched_payloads, payload_timeout:, pattern_matcher:, rules:, exclusions:, max_findings_limit: }.freeze logger.info( message: "Scan input parameters for running Secret Detection scan", timeout:, payload_timeout:, given_total_payloads: payloads.length, scannable_payloads_post_keyword_filter: matched_payloads.length, active_rules: rules.length, run_in_subprocess: subprocess, max_findings_limit:, given_exclusions: format_exclusions_hash(exclusions) ) secrets, applied_exclusions = subprocess ? run_scan_within_subprocess(**scan_args) : run_scan(**scan_args) scan_status = overall_scan_status(secrets) logger.info( message: "Secret Detection scan completed with #{secrets.length} secrets detected in the given payloads", detected_secrets_metadata: (secrets), applied_exclusions: format_exclusions_arr(applied_exclusions) ) Core::Response.new(status: scan_status, results: secrets, applied_exclusions:) end rescue Timeout::Error => e logger.error "Secret detection operation timed out: #{e}" Core::Response.new(status: Core::Status::SCAN_TIMEOUT) end |