gitlab-secret_detection 0.11.1 → 0.39.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,8 @@ module Gitlab
5
5
  module Core
6
6
  # All the possible statuses emitted by the scan operation
7
7
  class Status
8
+ # These values must stay in-sync with the GRPC::ScanResponse::Status values
9
+ UNSPECIFIED = 0 # to match the GRPC::Status values
8
10
  FOUND = 1 # When scan operation completes with one or more findings
9
11
  FOUND_WITH_ERRORS = 2 # When scan operation completes with one or more findings along with some errors
10
12
  SCAN_TIMEOUT = 3 # When the scan operation runs beyond given time out
@@ -13,6 +15,38 @@ module Gitlab
13
15
  INPUT_ERROR = 6 # When the scan operation fails due to invalid input
14
16
  NOT_FOUND = 7 # When scan operation completes with zero findings
15
17
  AUTH_ERROR = 8 # When authentication fails
18
+
19
+ # Maps values to constants
20
+ @values_map = {}
21
+
22
+ # Using class instance variables and singleton methods
23
+ class << self
24
+ attr_reader :values_map
25
+
26
+ # Register constants and their values in the map
27
+ def const_set(name, value)
28
+ const = super
29
+ @values_map[value] = name
30
+ const
31
+ end
32
+
33
+ # Look up a constant by its value
34
+ def find_by_value(value)
35
+ const_name = @values_map[value]
36
+ const_name ? const_get(const_name) : nil
37
+ end
38
+
39
+ # Get the name of a constant by its value
40
+ def name_by_value(value)
41
+ @values_map[value]
42
+ end
43
+ end
44
+
45
+ # Initialize the values map with existing constants
46
+ constants.each do |const_name|
47
+ const_value = const_get(const_name)
48
+ @values_map[const_value] = const_name
49
+ end
16
50
  end
17
51
  end
18
52
  end
@@ -17,10 +17,14 @@ module Gitlab
17
17
  # Time to wait for the response from the service
18
18
  REQUEST_TIMEOUT_SECONDS = 10 # 10 seconds
19
19
 
20
- def initialize(host, secure: false, compression: true)
20
+ # Total payload size limit allowed per scan request
21
+ MAX_PAYLOAD_SIZE_PER_REQUEST = 4_000_000 # 3.8MiB (0.2MiB buffer for other request props)
22
+
23
+ def initialize(host, secure: false, compression: true, logger: nil)
21
24
  @host = host
22
25
  @secure = secure
23
26
  @compression = compression
27
+ @logger = logger.nil? ? LOGGER : logger
24
28
  end
25
29
 
26
30
  # Triggers Secret Detection service's `/Scan` gRPC endpoint. To keep it consistent with SDS gem interface,
@@ -29,13 +33,27 @@ module Gitlab
29
33
  # +Gitlab::SecretDetection::Core::Response+ type by assiging a appropriate +status+ value to it.
30
34
  def run_scan(request:, auth_token:, extra_headers: {})
31
35
  with_rescued_errors do
36
+ payload_size = calculate_payload_size(request)
37
+ if payload_size >= MAX_PAYLOAD_SIZE_PER_REQUEST
38
+ @logger.info(
39
+ message: "Skipping to send Scan Request to Secret Detection server due to request size overlimit",
40
+ payload_size:
41
+ )
42
+
43
+ next Gitlab::SecretDetection::GRPC::ScanResponse.new(
44
+ results: [],
45
+ status: SecretDetection::Core::Status::INPUT_ERROR,
46
+ applied_exclusions: []
47
+ )
48
+ end
49
+
32
50
  grpc_response = stub.scan(
33
51
  request,
34
52
  metadata: build_metadata(auth_token, extra_headers),
35
53
  deadline: request_deadline
36
54
  )
37
55
 
38
- convert_to_core_response(grpc_response)
56
+ grpc_response
39
57
  end
40
58
  end
41
59
 
@@ -51,16 +69,28 @@ module Gitlab
51
69
  request_stream = Gitlab::SecretDetection::GRPC::StreamRequestEnumerator.new(requests)
52
70
  results = []
53
71
  with_rescued_errors do
72
+ has_oversized_request = requests.any? do |request|
73
+ payload_size = calculate_payload_size(request)
74
+ payload_size >= MAX_PAYLOAD_SIZE_PER_REQUEST
75
+ end
76
+
77
+ if has_oversized_request
78
+ @logger.info("Skipping to send Scan Request to Secret Detection server due to request size overlimit")
79
+ response = Gitlab::SecretDetection::GRPC::ScanResponse.new(
80
+ status: SecretDetection::Core::Status::INPUT_ERROR
81
+ )
82
+ next (block_given? ? response : [response])
83
+ end
84
+
54
85
  stub.scan_stream(
55
86
  request_stream.each_item,
56
87
  metadata: build_metadata(auth_token, extra_headers),
57
88
  deadline: request_deadline
58
89
  ).each do |grpc_response|
59
- response = convert_to_core_response(grpc_response)
60
90
  if block_given?
61
- yield response
91
+ yield grpc_response
62
92
  else
63
- results << response
93
+ results << grpc_response
64
94
  end
65
95
  end
66
96
  results
@@ -116,28 +146,29 @@ module Gitlab
116
146
  def with_rescued_errors
117
147
  yield
118
148
  rescue ::GRPC::Unauthenticated
119
- SecretDetection::Core::Response.new(SecretDetection::Core::Status::AUTH_ERROR)
149
+ SecretDetection::Core::Response.new(status: SecretDetection::Core::Status::AUTH_ERROR)
120
150
  rescue ::GRPC::InvalidArgument => e
121
151
  SecretDetection::Core::Response.new(
122
- SecretDetection::Core::Status::INPUT_ERROR, nil, { message: e.details, **e.metadata }
152
+ status: SecretDetection::Core::Status::INPUT_ERROR,
153
+ results: nil,
154
+ metadata: { message: e.details, **e.metadata }
155
+ )
156
+ rescue ::GRPC::ResourceExhausted => e
157
+ @logger.error(message: "Secret Detection Server resource exhausted: #{e.details}", **e.metadata)
158
+ SecretDetection::Core::Response.new(
159
+ status: SecretDetection::Core::Status::SCAN_ERROR,
160
+ metadata: { message: e.details, **e.metadata }
123
161
  )
124
162
  rescue ::GRPC::Unknown, ::GRPC::BadStatus => e
125
163
  SecretDetection::Core::Response.new(
126
- SecretDetection::Core::Status::SCAN_ERROR, nil, { message: e.details }
164
+ status: SecretDetection::Core::Status::SCAN_ERROR,
165
+ results: nil,
166
+ metadata: { message: e.details, **e.metadata }
127
167
  )
128
168
  end
129
169
 
130
- def convert_to_core_response(grpc_response)
131
- response = grpc_response.to_h
132
-
133
- SecretDetection::Core::Response.new(
134
- response[:status],
135
- response[:results],
136
- response[:metadata]
137
- )
138
- rescue StandardError => e
139
- logger.error("Failed to convert to core response: #{e}")
140
- SecretDetection::Core::Response.new(SecretDetection::Core::Status::SCAN_ERROR)
170
+ def calculate_payload_size(request)
171
+ request&.payloads&.reduce(0) { |total, p| total + p.data.size + p.id.size }
141
172
  end
142
173
  end
143
174
  end
@@ -5,7 +5,7 @@
5
5
  require 'google/protobuf'
6
6
 
7
7
 
8
- descriptor_data = "\n\x16secret_detection.proto\x12\x17gitlab.secret_detection\"Z\n\tExclusion\x12>\n\x0e\x65xclusion_type\x18\x01 \x01(\x0e\x32&.gitlab.secret_detection.ExclusionType\x12\r\n\x05value\x18\x02 \x01(\t\"\xc0\x02\n\x0bScanRequest\x12>\n\x08payloads\x18\x01 \x03(\x0b\x32,.gitlab.secret_detection.ScanRequest.Payload\x12\x19\n\x0ctimeout_secs\x18\x02 \x01(\x02H\x00\x88\x01\x01\x12!\n\x14payload_timeout_secs\x18\x03 \x01(\x02H\x01\x88\x01\x01\x12\x36\n\nexclusions\x18\x04 \x03(\x0b\x32\".gitlab.secret_detection.Exclusion\x12\x0c\n\x04tags\x18\x05 \x03(\t\x1a\x43\n\x07Payload\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\x12\x13\n\x06offset\x18\x03 \x01(\x05H\x00\x88\x01\x01\x42\t\n\x07_offsetB\x0f\n\r_timeout_secsB\x17\n\x15_payload_timeout_secs\"\xa2\x04\n\x0cScanResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32-.gitlab.secret_detection.ScanResponse.Finding\x12\x0e\n\x06status\x18\x02 \x01(\x05\x12>\n\x12\x61pplied_exclusions\x18\x03 \x03(\x0b\x32\".gitlab.secret_detection.Exclusion\x1a\x9d\x01\n\x07\x46inding\x12\x12\n\npayload_id\x18\x01 \x01(\t\x12\x0e\n\x06status\x18\x02 \x01(\x05\x12\x11\n\x04type\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bline_number\x18\x05 \x01(\x05H\x02\x88\x01\x01\x42\x07\n\x05_typeB\x0e\n\x0c_descriptionB\x0e\n\x0c_line_number\"\xe1\x01\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x10\n\x0cSTATUS_FOUND\x10\x01\x12\x1c\n\x18STATUS_FOUND_WITH_ERRORS\x10\x02\x12\x17\n\x13STATUS_SCAN_TIMEOUT\x10\x03\x12\x1a\n\x16STATUS_PAYLOAD_TIMEOUT\x10\x04\x12\x15\n\x11STATUS_SCAN_ERROR\x10\x05\x12\x16\n\x12STATUS_INPUT_ERROR\x10\x06\x12\x14\n\x10STATUS_NOT_FOUND\x10\x07\x12\x15\n\x11STATUS_AUTH_ERROR\x10\x08*f\n\rExclusionType\x12\x1e\n\x1a\x45XCLUSION_TYPE_UNSPECIFIED\x10\x00\x12\x17\n\x13\x45XCLUSION_TYPE_RULE\x10\x01\x12\x1c\n\x18\x45XCLUSION_TYPE_RAW_VALUE\x10\x02\x32\xc1\x01\n\x07Scanner\x12U\n\x04Scan\x12$.gitlab.secret_detection.ScanRequest\x1a%.gitlab.secret_detection.ScanResponse\"\x00\x12_\n\nScanStream\x12$.gitlab.secret_detection.ScanRequest\x1a%.gitlab.secret_detection.ScanResponse\"\x00(\x01\x30\x01\x42 \xea\x02\x1dGitlab::SecretDetection::GRPCb\x06proto3"
8
+ descriptor_data = "\n\x16secret_detection.proto\x12\x17gitlab.secret_detection\"Z\n\tExclusion\x12>\n\x0e\x65xclusion_type\x18\x01 \x01(\x0e\x32&.gitlab.secret_detection.ExclusionType\x12\r\n\x05value\x18\x02 \x01(\t\"\xc0\x02\n\x0bScanRequest\x12>\n\x08payloads\x18\x01 \x03(\x0b\x32,.gitlab.secret_detection.ScanRequest.Payload\x12\x19\n\x0ctimeout_secs\x18\x02 \x01(\x02H\x00\x88\x01\x01\x12!\n\x14payload_timeout_secs\x18\x03 \x01(\x02H\x01\x88\x01\x01\x12\x36\n\nexclusions\x18\x04 \x03(\x0b\x32\".gitlab.secret_detection.Exclusion\x12\x0c\n\x04tags\x18\x05 \x03(\t\x1a\x43\n\x07Payload\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\t\x12\x13\n\x06offset\x18\x03 \x01(\x05H\x00\x88\x01\x01\x42\t\n\x07_offsetB\x0f\n\r_timeout_secsB\x17\n\x15_payload_timeout_secs\"\xa2\x04\n\x0cScanResponse\x12>\n\x07results\x18\x01 \x03(\x0b\x32-.gitlab.secret_detection.ScanResponse.Finding\x12\x0e\n\x06status\x18\x02 \x01(\x05\x12>\n\x12\x61pplied_exclusions\x18\x03 \x03(\x0b\x32\".gitlab.secret_detection.Exclusion\x1a\x9d\x01\n\x07\x46inding\x12\x12\n\npayload_id\x18\x01 \x01(\t\x12\x0e\n\x06status\x18\x02 \x01(\x05\x12\x11\n\x04type\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0bline_number\x18\x05 \x01(\x05H\x02\x88\x01\x01\x42\x07\n\x05_typeB\x0e\n\x0c_descriptionB\x0e\n\x0c_line_number\"\xe1\x01\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x10\n\x0cSTATUS_FOUND\x10\x01\x12\x1c\n\x18STATUS_FOUND_WITH_ERRORS\x10\x02\x12\x17\n\x13STATUS_SCAN_TIMEOUT\x10\x03\x12\x1a\n\x16STATUS_PAYLOAD_TIMEOUT\x10\x04\x12\x15\n\x11STATUS_SCAN_ERROR\x10\x05\x12\x16\n\x12STATUS_INPUT_ERROR\x10\x06\x12\x14\n\x10STATUS_NOT_FOUND\x10\x07\x12\x15\n\x11STATUS_AUTH_ERROR\x10\x08*\xa1\x01\n\rExclusionType\x12\x1e\n\x1a\x45XCLUSION_TYPE_UNSPECIFIED\x10\x00\x12\x17\n\x13\x45XCLUSION_TYPE_RULE\x10\x01\x12\x1c\n\x18\x45XCLUSION_TYPE_RAW_VALUE\x10\x02\x12\x17\n\x13\x45XCLUSION_TYPE_PATH\x10\x03\x12 \n\x1c\x45XCLUSION_TYPE_REGEX_PATTERN\x10\x04\x32\xc1\x01\n\x07Scanner\x12U\n\x04Scan\x12$.gitlab.secret_detection.ScanRequest\x1a%.gitlab.secret_detection.ScanResponse\"\x00\x12_\n\nScanStream\x12$.gitlab.secret_detection.ScanRequest\x1a%.gitlab.secret_detection.ScanResponse\"\x00(\x01\x30\x01\x42 \xea\x02\x1dGitlab::SecretDetection::GRPCb\x06proto3"
9
9
 
10
10
  pool = Google::Protobuf::DescriptorPool.generated_pool
11
11
  pool.add_serialized_file(descriptor_data)
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sentry-ruby'
4
+
5
+ require_relative '../../../../lib/gitlab/secret_detection/core/ruleset'
6
+
7
+ module Gitlab
8
+ module SecretDetection
9
+ module GRPC
10
+ module IntegratedErrorTracking
11
+ extend self
12
+
13
+ def track_exception(exception, args = {})
14
+ unless Sentry.initialized?
15
+ logger.warn(message: "Cannot track exception in Error Tracking as Sentry is not initialized")
16
+ return
17
+ end
18
+
19
+ args[:ruleset_version] = ruleset_version
20
+
21
+ Sentry.capture_exception(exception, **args)
22
+ end
23
+
24
+ def setup(logger: Logger.new($stdout))
25
+ if Sentry.initialized?
26
+ logger.warn(message: "Sentry is already initialized, skipping re-setup")
27
+ return
28
+ end
29
+
30
+ logger.info(message: "Initializing Sentry SDK for Integrated Error Tracking..")
31
+
32
+ unless can_setup_sentry?
33
+ logger.warn(message: "Integrated Error Tracking not available, skipping Sentry SDK initialization")
34
+ return false
35
+ end
36
+
37
+ Sentry.init do |config|
38
+ config.dsn = ENV.fetch('SD_TRACKING_DSN')
39
+ config.environment = ENV.fetch('SD_ENV')
40
+ config.release = Gitlab::SecretDetection::Gem::VERSION
41
+ config.send_default_pii = true
42
+ config.send_modules = false
43
+ config.traces_sample_rate = 0.2 if ENV.fetch('ENABLE_SENTRY_PERFORMANCE_MONITORING', 'false') == 'true'
44
+ end
45
+
46
+ Sentry.set_context('ruleset', { version: ruleset_version })
47
+
48
+ true
49
+ rescue StandardError => e
50
+ logger.error(message: "Failed to initialize Sentry SDK for Integrated Error Tracking: #{e}")
51
+ raise e
52
+ end
53
+
54
+ def ruleset_version
55
+ @ruleset_version ||= Gitlab::SecretDetection::Core::Ruleset.new.extract_ruleset_version || 'unknown'
56
+ end
57
+
58
+ def can_setup_sentry?
59
+ ENV.fetch('SD_ENV', '') == 'production' && ENV.fetch('SD_TRACKING_DSN', '') != ''
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -32,6 +32,7 @@ module Gitlab
32
32
  module GRPC
33
33
  class ScannerService < Scanner::Service
34
34
  include SDLogger
35
+ include IntegratedErrorTracking
35
36
 
36
37
  # Maximum timeout value that can be given as the input. This guards
37
38
  # against the misuse of timeouts.
@@ -45,46 +46,63 @@ module Gitlab
45
46
  }.freeze
46
47
 
47
48
  # Implementation for /Scan RPC method
48
- def scan(request, _call)
49
- scan_request_action(request)
49
+ def scan(request, call)
50
+ scan_request_action(request, call)
50
51
  end
51
52
 
52
53
  # Implementation for /ScanStream RPC method
53
- def scan_stream(requests, _call)
54
- request_action = ->(r) { scan_request_action(r) }
54
+ def scan_stream(requests, call)
55
+ request_action = ->(r) { scan_request_action(r, call) }
55
56
  StreamEnumerator.new(requests, request_action).each_item
56
57
  end
57
58
 
58
59
  private
59
60
 
60
- def scan_request_action(request)
61
+ def scan_request_action(request, call)
62
+ if request.nil?
63
+ logger.error(
64
+ message: "FATAL: Secret Detection gRPC scan request is `nil`",
65
+ deadline: call.deadline,
66
+ cancelled: call.cancelled?
67
+ )
68
+ return Gitlab::SecretDetection::GRPC::ScanResponse.new(
69
+ results: [],
70
+ status: Gitlab::SecretDetection::GRPC::ScanResponse::Status::STATUS_INPUT_ERROR,
71
+ applied_exclusions: []
72
+ )
73
+ end
74
+
75
+ logger.info(message: "Secret Detection gRPC scan request received")
76
+
61
77
  validate_request(request)
62
78
 
63
79
  payloads = request.payloads.to_a
80
+ exclusions = { raw_value: [], rule: [], path: [] }
64
81
 
65
- raw_value_exclusions = []
66
- rule_exclusions = []
67
-
68
- request.exclusions&.each do |exclusion|
69
- case exclusion.type
82
+ request.exclusions.each do |exclusion|
83
+ case exclusion.exclusion_type
70
84
  when :EXCLUSION_TYPE_RAW_VALUE
71
- raw_value_exclusions << exclusion.value
85
+ exclusions[:raw_value] << exclusion
72
86
  when :EXCLUSION_TYPE_RULE
73
- rule_exclusions << exclusion.value
87
+ exclusions[:rule] << exclusion
88
+ when :EXCLUSION_TYPE_PATH
89
+ exclusions[:path] << exclusion
90
+ else
91
+ logger.warn("Unknown exclusion type #{exclusion.exclusion_type}")
74
92
  end
75
93
  end
76
94
 
77
95
  begin
78
96
  result = scanner.secrets_scan(
79
97
  payloads,
80
- raw_value_exclusions:,
81
- rule_exclusions:,
98
+ exclusions:,
82
99
  tags: request.tags.to_a,
83
100
  timeout: request.timeout_secs,
84
101
  payload_timeout: request.payload_timeout_secs
85
102
  )
86
103
  rescue StandardError => e
87
- logger.error("Failed to run the scan: #{e}")
104
+ logger.error(message: "Failed to run the secret detection scan", exception: e.message)
105
+ track_exception(e)
88
106
  raise ::GRPC::Unknown, e.message
89
107
  end
90
108
 
@@ -94,7 +112,8 @@ module Gitlab
94
112
 
95
113
  Gitlab::SecretDetection::GRPC::ScanResponse.new(
96
114
  results: findings,
97
- status: result.status
115
+ status: result.status,
116
+ applied_exclusions: result.applied_exclusions
98
117
  )
99
118
  end
100
119
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'grpc/integrated_error_tracking'
3
4
  require_relative 'grpc/scanner_service'
4
5
  require_relative 'grpc/client/stream_request_enumerator'
5
6
  require_relative 'grpc/client/grpc_client'
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gitlab
4
+ module SecretDetection
5
+ module Utils
6
+ class Masker
7
+ DEFAULT_VISIBLE_CHAR_COUNT = 3
8
+ DEFAULT_MASK_CHAR_COUNT = 5
9
+ DEFAULT_MASK_CHAR = '*'
10
+
11
+ class << self
12
+ def mask_secret(
13
+ raw_secret_value,
14
+ mask_char: DEFAULT_MASK_CHAR,
15
+ visible_chars_count: DEFAULT_VISIBLE_CHAR_COUNT,
16
+ mask_chars_count: DEFAULT_MASK_CHAR_COUNT
17
+ )
18
+ return '' if raw_secret_value.nil? || raw_secret_value.empty?
19
+ return raw_secret_value if raw_secret_value.length <= visible_chars_count # Too short to mask
20
+
21
+ chars = raw_secret_value.chars
22
+ position = 0
23
+
24
+ while position < chars.length
25
+ # Show 'visible_chars_count' characters
26
+ position += visible_chars_count
27
+
28
+ # Mask next 'mask_chars' characters if available
29
+ mask_chars_count.times do
30
+ break if position >= chars.length
31
+
32
+ chars[position] = mask_char
33
+ position += 1
34
+ end
35
+ end
36
+
37
+ chars.join
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'utils/certificate'
4
4
  require_relative 'utils/memoize'
5
+ require_relative 'utils/masker'
5
6
 
6
7
  module Gitlab
7
8
  module SecretDetection
@@ -3,23 +3,9 @@
3
3
  module Gitlab
4
4
  module SecretDetection
5
5
  class Gem
6
- DEFAULT_VERSION = "0.0.1"
7
-
8
- SEMVER_REGEX = /^\d+\.\d+\.\d+(?:-[a-zA-Z0-9\-\.]+)?(?:\+[a-zA-Z0-9\-\.]+)?$/
9
-
10
- def self.get_release_version
11
- release_version = ENV.fetch("SD_GEM_RELEASE_VERSION", "")
12
-
13
- if release_version.empty?
14
- raise LoadError("Missing SD_GEM_RELEASE_VERSION environment variable.") unless local_env?
15
-
16
- "#{DEFAULT_VERSION}-debug"
17
- elsif release_version.match?(SEMVER_REGEX)
18
- release_version
19
- else
20
- "#{DEFAULT_VERSION}-#{release_version}"
21
- end
22
- end
6
+ # Ensure to maintain the same version in CHANGELOG file.
7
+ # More details available under 'Release Process' section in the README.md file.
8
+ VERSION = "0.39.2"
23
9
 
24
10
  # SD_ENV env var is used to determine which environment the
25
11
  # server is running. This var is defined in `.runway/env-<env>.yml` files.
@@ -17,6 +17,8 @@ enum ExclusionType {
17
17
  EXCLUSION_TYPE_UNSPECIFIED = 0;
18
18
  EXCLUSION_TYPE_RULE = 1; // Rule ID to exclude
19
19
  EXCLUSION_TYPE_RAW_VALUE = 2; // Raw value to exclude
20
+ EXCLUSION_TYPE_PATH = 3; // Specific file path to exclude
21
+ EXCLUSION_TYPE_REGEX_PATTERN = 4; // Regular expression to exclude
20
22
  }
21
23
 
22
24
  /* Request arg for triggering Scan/ScanStream method */
@@ -39,6 +41,7 @@ message ScanRequest {
39
41
  }
40
42
 
41
43
  /* Response from Scan/ScanStream method */
44
+ /* Any changes to these definitions must be matched by changes in the Core classes that correspond to them */
42
45
  message ScanResponse {
43
46
  // Represents a secret finding identified within a payload
44
47
  message Finding {