gitlab-secret_detection 0.12.0 → 0.13.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23eb987781013adea0ee3eaf3a52f3b7c89e09268a7dfff504d0346efbfeb8e2
4
- data.tar.gz: 9a301fcbdb3b9a2bb76e4dd978a8d574a654a2a65ed4ec3c4f3fd962dfe67c3d
3
+ metadata.gz: f72d7d8262749305fdf1811df74637af4f7ba4bbf693fc41d2cdb34d1ca25238
4
+ data.tar.gz: 6896b4eb32dc734640c0dc125dd75e79b765f27aa618f73fec81c83c0c20df93
5
5
  SHA512:
6
- metadata.gz: 9f2ff05eb818ffeed0a1d1736d59de48822dd8f2d2fb8f56526dd6aa2e36c901eb1592a8372f0999c72c2f8ee6e8fc0b8ac7bf37021f10e2f405aebb2b890a5b
7
- data.tar.gz: 38cdab69b370d7f82784d7e861784cda7a6867341bab08f238ee54aa427c61b5056fced813ab9c9161f8a5b14d8493cc6be29e10779187f76b61980586757b23
6
+ metadata.gz: 2d35dfa136b9524f851a6ed20885aa6d50b9334f12166fd9d131ff523ed38bed1264bad953fd6fa58e63fe2c5f9c62be129d3be231258eef25990803b9b67d4e
7
+ data.tar.gz: 331a74ba7a779f275717c769c0f63785d7e74d25b07da5d07f44c08a1a0c7f343eec3ba7fd8285d549d298fac4d93bdc3f2bc122ea7cb30bd567e4c75e43efdb
@@ -7,14 +7,16 @@ module Gitlab
7
7
  #
8
8
  # +status+:: One of values from Gitlab::SecretDetection::Core::Status indicating the scan operation's status
9
9
  # +results+:: Array of Gitlab::SecretDetection::Core::Finding values. Default value is nil.
10
- # +metadata+:: Hash object containing additional meta information about the response. It is currently used
11
10
  # to embed more information on error.
11
+ # +applied_exclusions+:: Array of Exclusions that were applied during this scan.
12
+ # +metadata+:: Hash object containing additional meta information about the response. It is currently used
12
13
  class Response
13
- attr_reader :status, :results, :metadata
14
+ attr_reader :status, :results, :applied_exclusions, :metadata
14
15
 
15
- def initialize(status, results = [], metadata = {})
16
+ def initialize(status:, results: [], applied_exclusions: [], metadata: {})
16
17
  @status = status
17
18
  @results = results
19
+ @applied_exclusions = applied_exclusions
18
20
  @metadata = metadata
19
21
  end
20
22
 
@@ -25,15 +27,21 @@ module Gitlab
25
27
  def to_h
26
28
  {
27
29
  status:,
28
- metadata:,
29
- results: results&.map(&:to_h)
30
+ results: results&.map(&:to_h),
31
+ applied_exclusions:,
32
+ metadata:
30
33
  }
31
34
  end
32
35
 
33
36
  protected
34
37
 
35
38
  def state
36
- [status, metadata, results]
39
+ [
40
+ status,
41
+ results,
42
+ applied_exclusions,
43
+ metadata
44
+ ]
37
45
  end
38
46
  end
39
47
  end
@@ -90,7 +90,7 @@ module Gitlab
90
90
  subprocess: RUN_IN_SUBPROCESS
91
91
  )
92
92
 
93
- return Core::Response.new(Core::Status::INPUT_ERROR) unless validate_scan_input(payloads)
93
+ return Core::Response.new(status: Core::Status::INPUT_ERROR) unless validate_scan_input(payloads)
94
94
 
95
95
  # assign defaults since grpc passing zero timeout value to `Timeout.timeout(..)` makes it effectively useless.
96
96
  timeout = DEFAULT_SCAN_TIMEOUT_SECS unless timeout.positive?
@@ -102,24 +102,26 @@ module Gitlab
102
102
 
103
103
  matched_payloads = filter_by_keywords(keyword_matcher, payloads)
104
104
 
105
- next Core::Response.new(Core::Status::NOT_FOUND) if matched_payloads.empty?
105
+ next Core::Response.new(status: Core::Status::NOT_FOUND) if matched_payloads.empty?
106
106
 
107
107
  scan_args = {
108
- payloads: matched_payloads, payload_timeout:,
108
+ payloads: matched_payloads,
109
+ payload_timeout:,
109
110
  pattern_matcher: build_pattern_matcher(tags:),
110
- raw_value_exclusions:, rule_exclusions:
111
+ raw_value_exclusions:,
112
+ rule_exclusions:
111
113
  }
112
114
 
113
- secrets = subprocess ? run_scan_within_subprocess(**scan_args) : run_scan(**scan_args)
115
+ secrets, applied_exclusions = subprocess ? run_scan_within_subprocess(**scan_args) : run_scan(**scan_args)
114
116
 
115
117
  scan_status = overall_scan_status(secrets)
116
118
 
117
- Core::Response.new(scan_status, secrets)
119
+ Core::Response.new(status: scan_status, results: secrets, applied_exclusions:)
118
120
  end
119
121
  rescue Timeout::Error => e
120
122
  logger.error "Secret detection operation timed out: #{e}"
121
123
 
122
- Core::Response.new(Core::Status::SCAN_TIMEOUT)
124
+ Core::Response.new(status: Core::Status::SCAN_TIMEOUT)
123
125
  end
124
126
 
125
127
  private
@@ -208,25 +210,42 @@ module Gitlab
208
210
  # literal values to exclude from the input before the scan, also SD rules to exclude during
209
211
  # the scan when performed on the payloads.
210
212
  def run_scan(
211
- payloads:, payload_timeout:, pattern_matcher:, raw_value_exclusions: [], rule_exclusions: [])
212
- payloads.flat_map do |payload|
213
+ payloads:,
214
+ payload_timeout:,
215
+ pattern_matcher:,
216
+ raw_value_exclusions: [],
217
+ rule_exclusions: []
218
+ )
219
+ all_applied_exclusions = Set.new
220
+
221
+ all_findings = payloads.flat_map do |payload|
213
222
  Timeout.timeout(payload_timeout) do
214
- find_secrets_in_payload(
223
+ findings, applied_exclusions = find_secrets_in_payload(
215
224
  payload:,
216
225
  pattern_matcher:,
217
- raw_value_exclusions:, rule_exclusions:
226
+ raw_value_exclusions:,
227
+ rule_exclusions:
218
228
  )
229
+ all_applied_exclusions.merge(applied_exclusions)
230
+ findings
219
231
  end
220
232
  rescue Timeout::Error => e
221
233
  logger.error "Secret Detection scan timed out on the payload(id:#{payload.id}): #{e}"
234
+
222
235
  Core::Finding.new(payload.id,
223
236
  Core::Status::PAYLOAD_TIMEOUT)
224
237
  end
238
+ [all_findings.freeze, all_applied_exclusions.to_a.freeze]
225
239
  end
226
240
 
227
241
  def run_scan_within_subprocess(
228
- payloads:, payload_timeout:, pattern_matcher:, raw_value_exclusions: [],
229
- rule_exclusions: [])
242
+ payloads:,
243
+ payload_timeout:,
244
+ pattern_matcher:,
245
+ raw_value_exclusions: [],
246
+ rule_exclusions: []
247
+ )
248
+ all_applied_exclusions = Set.new
230
249
  payload_sizes = payloads.map(&:size)
231
250
  grouped_payload_indices = group_by_chunk_size(payload_sizes)
232
251
 
@@ -239,19 +258,22 @@ module Gitlab
239
258
  ) do |grouped_payload|
240
259
  grouped_payload.flat_map do |payload|
241
260
  Timeout.timeout(payload_timeout) do
242
- find_secrets_in_payload(
261
+ findings, applied_exclusions = find_secrets_in_payload(
243
262
  payload:,
244
263
  pattern_matcher:,
245
264
  raw_value_exclusions:, rule_exclusions:
246
265
  )
266
+ all_applied_exclusions.merge(applied_exclusions)
267
+ findings
247
268
  end
248
269
  rescue Timeout::Error => e
249
270
  logger.error "Secret Detection scan timed out on the payload(id:#{payload.id}): #{e}"
271
+
250
272
  Core::Finding.new(payload.id, Core::Status::PAYLOAD_TIMEOUT)
251
273
  end
252
274
  end
253
275
 
254
- found_secrets.freeze
276
+ [found_secrets.freeze, all_applied_exclusions.to_a.freeze]
255
277
  end
256
278
 
257
279
  # Finds secrets in the given payload guarded with a timeout as a circuit breaker. It accepts
@@ -259,6 +281,7 @@ module Gitlab
259
281
  # the scan.
260
282
  def find_secrets_in_payload(payload:, pattern_matcher:, raw_value_exclusions: [], rule_exclusions: [])
261
283
  findings = []
284
+ applied_exclusions = Set.new
262
285
 
263
286
  payload_offset = payload.respond_to?(:offset) ? payload.offset : 0
264
287
 
@@ -268,6 +291,7 @@ module Gitlab
268
291
  unless raw_value_exclusions.empty?
269
292
  raw_value_exclusions.each do |value|
270
293
  line.gsub!(value, '') # replace input that doesn't contain allowed value in it
294
+ applied_exclusions << value # TODO we need the id of the exclusion
271
295
  end
272
296
  end
273
297
 
@@ -284,19 +308,30 @@ module Gitlab
284
308
  matches.each do |match_idx|
285
309
  rule = rules[match_idx]
286
310
 
287
- next if rule_exclusions.include?(rule[:id])
311
+ next if applied_rule_exclusion?(rule[:id], rule_exclusions, applied_exclusions)
288
312
 
289
313
  title = rule[:title].nil? ? rule[:description] : rule[:title]
290
- findings << Core::Finding.new(payload.id, Core::Status::FOUND, line_no, rule[:id],
291
- title)
314
+
315
+ findings << Core::Finding.new(
316
+ payload.id,
317
+ Core::Status::FOUND,
318
+ line_no,
319
+ rule[:id],
320
+ title
321
+ )
292
322
  end
293
323
  end
294
324
 
295
- findings.freeze
325
+ [findings.freeze, applied_exclusions]
296
326
  rescue StandardError => e
297
327
  logger.error "Secret Detection scan failed on the payload(id:#{payload.id}): #{e}"
298
328
 
299
- Core::Finding.new(payload.id, Core::Status::SCAN_ERROR)
329
+ [[Core::Finding.new(payload.id, Core::Status::SCAN_ERROR)], []]
330
+ end
331
+
332
+ def applied_rule_exclusion?(type, rule_exclusions, applied_exclusions)
333
+ applied_exclusion = rule_exclusions&.find { |rule_exclusion| rule_exclusion == type }
334
+ applied_exclusion && (applied_exclusions << applied_exclusion)
300
335
  end
301
336
 
302
337
  # Validates the given payloads by verifying the type and
@@ -17,10 +17,11 @@ 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
+ def initialize(host, secure: false, compression: true, logger: nil)
21
21
  @host = host
22
22
  @secure = secure
23
23
  @compression = compression
24
+ @logger = logger.nil? ? LOGGER : logger
24
25
  end
25
26
 
26
27
  # Triggers Secret Detection service's `/Scan` gRPC endpoint. To keep it consistent with SDS gem interface,
@@ -116,14 +117,18 @@ module Gitlab
116
117
  def with_rescued_errors
117
118
  yield
118
119
  rescue ::GRPC::Unauthenticated
119
- SecretDetection::Core::Response.new(SecretDetection::Core::Status::AUTH_ERROR)
120
+ SecretDetection::Core::Response.new(status: SecretDetection::Core::Status::AUTH_ERROR)
120
121
  rescue ::GRPC::InvalidArgument => e
121
122
  SecretDetection::Core::Response.new(
122
- SecretDetection::Core::Status::INPUT_ERROR, nil, { message: e.details, **e.metadata }
123
+ status: SecretDetection::Core::Status::INPUT_ERROR,
124
+ results: nil,
125
+ metadata: { message: e.details, **e.metadata }
123
126
  )
124
127
  rescue ::GRPC::Unknown, ::GRPC::BadStatus => e
125
128
  SecretDetection::Core::Response.new(
126
- SecretDetection::Core::Status::SCAN_ERROR, nil, { message: e.details }
129
+ status: SecretDetection::Core::Status::SCAN_ERROR,
130
+ results: nil,
131
+ metadata: { message: e.details }
127
132
  )
128
133
  end
129
134
 
@@ -131,13 +136,13 @@ module Gitlab
131
136
  response = grpc_response.to_h
132
137
 
133
138
  SecretDetection::Core::Response.new(
134
- response[:status],
135
- response[:results],
136
- response[:metadata]
139
+ status: response[:status],
140
+ results: response[:results],
141
+ metadata: response[:metadata]
137
142
  )
138
143
  rescue StandardError => e
139
- logger.error("Failed to convert to core response: #{e}")
140
- SecretDetection::Core::Response.new(SecretDetection::Core::Status::SCAN_ERROR)
144
+ @logger.error("Failed to convert to core response: #{e}")
145
+ SecretDetection::Core::Response.new(status: SecretDetection::Core::Status::SCAN_ERROR)
141
146
  end
142
147
  end
143
148
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-secret_detection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - group::secret detection