gitlab-secret_detection 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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