Class: SemgrepWebApp::ScaFinding

Inherits:
BaseModel
  • Object
show all
Defined in:
lib/semgrep_web_app/models/sca_finding.rb

Overview

A Supply Chain finding that Semgrep has identified in your organization

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseModel

#check_for_conflict, #process_additional_properties, #process_array, #process_basic_value, #process_hash, #to_hash, #to_json

Constructor Details

#initialize(categories: SKIP, confidence: SKIP, created_at: SKIP, epss_score: SKIP, external_ticket: SKIP, first_seen_scan_id: SKIP, fix_recommendations: SKIP, found_dependency: SKIP, id: SKIP, is_malicious: SKIP, line_of_code_url: SKIP, location: SKIP, match_based_id: SKIP, reachability: SKIP, reachable_condition: SKIP, ref: SKIP, relevant_since: SKIP, repository: SKIP, review_comments: SKIP, rule: SKIP, rule_message: SKIP, rule_name: SKIP, severity: SKIP, state: SKIP, state_updated_at: SKIP, status: SKIP, syntactic_id: SKIP, triage_comment: SKIP, triage_reason: SKIP, triage_state: SKIP, triaged_at: SKIP, usage: SKIP, vulnerability_identifier: SKIP, additional_properties: nil) ⇒ ScaFinding

Returns a new instance of ScaFinding.



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 244

def initialize(categories: SKIP, confidence: SKIP, created_at: SKIP,
               epss_score: SKIP, external_ticket: SKIP,
               first_seen_scan_id: SKIP, fix_recommendations: SKIP,
               found_dependency: SKIP, id: SKIP, is_malicious: SKIP,
               line_of_code_url: SKIP, location: SKIP, match_based_id: SKIP,
               reachability: SKIP, reachable_condition: SKIP, ref: SKIP,
               relevant_since: SKIP, repository: SKIP,
               review_comments: SKIP, rule: SKIP, rule_message: SKIP,
               rule_name: SKIP, severity: SKIP, state: SKIP,
               state_updated_at: SKIP, status: SKIP, syntactic_id: SKIP,
               triage_comment: SKIP, triage_reason: SKIP,
               triage_state: SKIP, triaged_at: SKIP, usage: SKIP,
               vulnerability_identifier: SKIP, additional_properties: nil)
  # Add additional model properties to the instance
  additional_properties = {} if additional_properties.nil?

  @categories = categories unless categories == SKIP
  @confidence = confidence unless confidence == SKIP
  @created_at = created_at unless created_at == SKIP
  @epss_score = epss_score unless epss_score == SKIP
  @external_ticket = external_ticket unless external_ticket == SKIP
  @first_seen_scan_id = first_seen_scan_id unless first_seen_scan_id == SKIP
  @fix_recommendations = fix_recommendations unless fix_recommendations == SKIP
  @found_dependency = found_dependency unless found_dependency == SKIP
  @id = id unless id == SKIP
  @is_malicious = is_malicious unless is_malicious == SKIP
  @line_of_code_url = line_of_code_url unless line_of_code_url == SKIP
  @location = location unless location == SKIP
  @match_based_id = match_based_id unless match_based_id == SKIP
  @reachability = reachability unless reachability == SKIP
  @reachable_condition = reachable_condition unless reachable_condition == SKIP
  @ref = ref unless ref == SKIP
  @relevant_since = relevant_since unless relevant_since == SKIP
  @repository = repository unless repository == SKIP
  @review_comments = review_comments unless review_comments == SKIP
  @rule = rule unless rule == SKIP
  @rule_message = rule_message unless rule_message == SKIP
  @rule_name = rule_name unless rule_name == SKIP
  @severity = severity unless severity == SKIP
  @state = state unless state == SKIP
  @state_updated_at = state_updated_at unless state_updated_at == SKIP
  @status = status unless status == SKIP
  @syntactic_id = syntactic_id unless syntactic_id == SKIP
  @triage_comment = triage_comment unless triage_comment == SKIP
  @triage_reason = triage_reason unless triage_reason == SKIP
  @triage_state = triage_state unless triage_state == SKIP
  @triaged_at = triaged_at unless triaged_at == SKIP
  @usage = usage unless usage == SKIP
  @vulnerability_identifier = vulnerability_identifier unless vulnerability_identifier == SKIP
  @additional_properties = additional_properties
end

Instance Attribute Details

#categoriesArray[String]

The categories of the finding as classified by the associated rule metadata

Returns:

  • (Array[String])


15
16
17
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 15

def categories
  @categories
end

#confidenceConfidence1

Confidence of the finding, derived from the rule that triggered it

Returns:



19
20
21
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 19

def confidence
  @confidence
end

#created_atString

The timestamp when this finding was created

Returns:

  • (String)


23
24
25
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 23

def created_at
  @created_at
end

#epss_scoreEpssScore

The score assigned by FIRST.org's Exploitation Probability Scoring System

Returns:



27
28
29
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 27

def epss_score
  @epss_score
end

#external_ticketExternalTicket

External ticket associated with finding

Returns:



31
32
33
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 31

def external_ticket
  @external_ticket
end

#first_seen_scan_idInteger

Unique ID of the Semgrep scan that first identified this finding

Returns:

  • (Integer)


35
36
37
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 35

def first_seen_scan_id
  @first_seen_scan_id
end

#fix_recommendationsArray[FixRecommendation]

Recommendations for fixing the vulnerability

Returns:



39
40
41
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 39

def fix_recommendations
  @fix_recommendations
end

#found_dependencyFoundDependency

Information about the vulnerable package that was found in the codebase

Returns:



43
44
45
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 43

def found_dependency
  @found_dependency
end

#idInteger

Unique ID of this finding

Returns:

  • (Integer)


47
48
49
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 47

def id
  @id
end

#is_maliciousTrueClass | FalseClass

True if the finding is from a malicious dependency

Returns:

  • (TrueClass | FalseClass)


51
52
53
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 51

def is_malicious
  @is_malicious
end

#line_of_code_urlString

The source URL including file and line number

Returns:

  • (String)


55
56
57
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 55

def line_of_code_url
  @line_of_code_url
end

#locationFindingLocation

Location of the record in a file, as reported by Semgrep. If null, then the information does not exist or lacks integrity (older or broken scans)

Returns:



60
61
62
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 60

def location
  @location
end

#match_based_idString

ID calculated based on a finding's file path, rule identifier and pattern, and index

Returns:

  • (String)


65
66
67
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 65

def match_based_id
  @match_based_id
end

#reachabilityReachability

Indicates whether the vulnerable code is reachable

Returns:



69
70
71
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 69

def reachability
  @reachability
end

#reachable_conditionString

Description of the condition under which the vulnerability becomes reachable. Applies to conditionally reachable findings

Returns:

  • (String)


74
75
76
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 74

def reachable_condition
  @reachable_condition
end

#refString

External reference to the source of this finding (e.g. PR)

Returns:

  • (String)


78
79
80
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 78

def ref
  @ref
end

#relevant_sinceString

The timestamp when this finding was detected by Semgrep (the first time, or when reintroduced)

Returns:

  • (String)


83
84
85
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 83

def relevant_since
  @relevant_since
end

#repositoryFindingRepository

Which repository this finding was identified in

Returns:



87
88
89
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 87

def repository
  @repository
end

#review_commentsArray[ReviewComment]

List of external review comment information associated with a finding

Returns:



91
92
93
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 91

def review_comments
  @review_comments
end

#ruleFindingRule

Rule that applies to this finding

Returns:



95
96
97
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 95

def rule
  @rule
end

#rule_messageString

Deprecated in favor of rule.message. Rule message at the time of finding identification. Older findings may not have a value for this field

Returns:

  • (String)


100
101
102
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 100

def rule_message
  @rule_message
end

#rule_nameString

Deprecated in favor of rule.name

Returns:

  • (String)


104
105
106
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 104

def rule_name
  @rule_name
end

#severitySeverity1

Severity of the finding, derived from the rule that triggered it. Low is equivalent to INFO, Medium to WARNING, and High to ERROR

Returns:



109
110
111
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 109

def severity
  @severity
end

#stateState

The finding's resolution state. Managed only by changes detected at scan time, the state is combined with triage_state to ultimately determine a final status which is exposed in the UI and API

Returns:



115
116
117
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 115

def state
  @state
end

#state_updated_atString

When this issue's state (resolution state) was last updated, as distinct from when the issue was triaged (triaged_at)

Returns:

  • (String)


120
121
122
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 120

def state_updated_at
  @state_updated_at
end

#statusStatus

The finding's status as exposed in the UI. Status is a derived property combining information from the finding state and triage_state. The triage_state can be used to override the scan state if the finding is still detected

Returns:



127
128
129
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 127

def status
  @status
end

#syntactic_idString

ID calculated based on a finding's file path, rule identifier and matched code, and index. Prefer match_based_id

Returns:

  • (String)


132
133
134
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 132

def syntactic_id
  @syntactic_id
end

#triage_commentString

The detailed comment provided during triage

Returns:

  • (String)


136
137
138
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 136

def triage_comment
  @triage_comment
end

#triage_reasonTriageReason

Reason provided when this issue was triaged

Returns:



140
141
142
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 140

def triage_reason
  @triage_reason
end

#triage_stateTriageState

The finding's triage state. Note: "reviewing" and "fixing" are only in private beta. Set by the user and used along with state to generate the final "status" viewable in the UI

Returns:



146
147
148
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 146

def triage_state
  @triage_state
end

#triaged_atString

When the finding was triaged

Returns:

  • (String)


150
151
152
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 150

def triaged_at
  @triaged_at
end

#usageUsage

Usage of the vulnerable package in the codebase. Applies to reachable findings

Returns:



155
156
157
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 155

def usage
  @usage
end

#vulnerability_identifierString

Identifier of the vulnerability in the vulnerability database

Returns:

  • (String)


159
160
161
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 159

def vulnerability_identifier
  @vulnerability_identifier
end

Class Method Details

.from_hash(hash) ⇒ Object

Creates an instance of the object from a hash.



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 297

def self.from_hash(hash)
  return nil unless hash

  # Extract variables from the hash.
  categories = hash.key?('categories') ? hash['categories'] : SKIP
  confidence = hash.key?('confidence') ? hash['confidence'] : SKIP
  created_at = hash.key?('created_at') ? hash['created_at'] : SKIP
  epss_score = EpssScore.from_hash(hash['epss_score']) if hash['epss_score']
  external_ticket = ExternalTicket.from_hash(hash['external_ticket']) if
    hash['external_ticket']
  first_seen_scan_id =
    hash.key?('first_seen_scan_id') ? hash['first_seen_scan_id'] : SKIP
  # Parameter is an array, so we need to iterate through it
  fix_recommendations = nil
  unless hash['fix_recommendations'].nil?
    fix_recommendations = []
    hash['fix_recommendations'].each do |structure|
      fix_recommendations << (FixRecommendation.from_hash(structure) if structure)
    end
  end

  fix_recommendations = SKIP unless hash.key?('fix_recommendations')
  found_dependency = FoundDependency.from_hash(hash['found_dependency']) if
    hash['found_dependency']
  id = hash.key?('id') ? hash['id'] : SKIP
  is_malicious = hash.key?('is_malicious') ? hash['is_malicious'] : SKIP
  line_of_code_url =
    hash.key?('line_of_code_url') ? hash['line_of_code_url'] : SKIP
  location = FindingLocation.from_hash(hash['location']) if hash['location']
  match_based_id =
    hash.key?('match_based_id') ? hash['match_based_id'] : SKIP
  reachability = hash.key?('reachability') ? hash['reachability'] : SKIP
  reachable_condition =
    hash.key?('reachable_condition') ? hash['reachable_condition'] : SKIP
  ref = hash.key?('ref') ? hash['ref'] : SKIP
  relevant_since =
    hash.key?('relevant_since') ? hash['relevant_since'] : SKIP
  repository = FindingRepository.from_hash(hash['repository']) if hash['repository']
  # Parameter is an array, so we need to iterate through it
  review_comments = nil
  unless hash['review_comments'].nil?
    review_comments = []
    hash['review_comments'].each do |structure|
      review_comments << (ReviewComment.from_hash(structure) if structure)
    end
  end

  review_comments = SKIP unless hash.key?('review_comments')
  rule = FindingRule.from_hash(hash['rule']) if hash['rule']
  rule_message = hash.key?('rule_message') ? hash['rule_message'] : SKIP
  rule_name = hash.key?('rule_name') ? hash['rule_name'] : SKIP
  severity = hash.key?('severity') ? hash['severity'] : SKIP
  state = hash.key?('state') ? hash['state'] : SKIP
  state_updated_at =
    hash.key?('state_updated_at') ? hash['state_updated_at'] : SKIP
  status = hash.key?('status') ? hash['status'] : SKIP
  syntactic_id = hash.key?('syntactic_id') ? hash['syntactic_id'] : SKIP
  triage_comment =
    hash.key?('triage_comment') ? hash['triage_comment'] : SKIP
  triage_reason = hash.key?('triage_reason') ? hash['triage_reason'] : SKIP
  triage_state = hash.key?('triage_state') ? hash['triage_state'] : SKIP
  triaged_at = hash.key?('triaged_at') ? hash['triaged_at'] : SKIP
  usage = Usage.from_hash(hash['usage']) if hash['usage']
  vulnerability_identifier =
    hash.key?('vulnerability_identifier') ? hash['vulnerability_identifier'] : SKIP

  # Create a new hash for additional properties, removing known properties.
  new_hash = hash.reject { |k, _| names.value?(k) }

  additional_properties = APIHelper.get_additional_properties(
    new_hash, proc { |value| value }
  )

  # Create object from extracted values.
  ScaFinding.new(categories: categories,
                 confidence: confidence,
                 created_at: created_at,
                 epss_score: epss_score,
                 external_ticket: external_ticket,
                 first_seen_scan_id: first_seen_scan_id,
                 fix_recommendations: fix_recommendations,
                 found_dependency: found_dependency,
                 id: id,
                 is_malicious: is_malicious,
                 line_of_code_url: line_of_code_url,
                 location: location,
                 match_based_id: match_based_id,
                 reachability: reachability,
                 reachable_condition: reachable_condition,
                 ref: ref,
                 relevant_since: relevant_since,
                 repository: repository,
                 review_comments: review_comments,
                 rule: rule,
                 rule_message: rule_message,
                 rule_name: rule_name,
                 severity: severity,
                 state: state,
                 state_updated_at: state_updated_at,
                 status: status,
                 syntactic_id: syntactic_id,
                 triage_comment: triage_comment,
                 triage_reason: triage_reason,
                 triage_state: triage_state,
                 triaged_at: triaged_at,
                 usage: usage,
                 vulnerability_identifier: vulnerability_identifier,
                 additional_properties: additional_properties)
end

.namesObject

A mapping from model property names to API property names.



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 162

def self.names
  @_hash = {} if @_hash.nil?
  @_hash['categories'] = 'categories'
  @_hash['confidence'] = 'confidence'
  @_hash['created_at'] = 'created_at'
  @_hash['epss_score'] = 'epss_score'
  @_hash['external_ticket'] = 'external_ticket'
  @_hash['first_seen_scan_id'] = 'first_seen_scan_id'
  @_hash['fix_recommendations'] = 'fix_recommendations'
  @_hash['found_dependency'] = 'found_dependency'
  @_hash['id'] = 'id'
  @_hash['is_malicious'] = 'is_malicious'
  @_hash['line_of_code_url'] = 'line_of_code_url'
  @_hash['location'] = 'location'
  @_hash['match_based_id'] = 'match_based_id'
  @_hash['reachability'] = 'reachability'
  @_hash['reachable_condition'] = 'reachable_condition'
  @_hash['ref'] = 'ref'
  @_hash['relevant_since'] = 'relevant_since'
  @_hash['repository'] = 'repository'
  @_hash['review_comments'] = 'review_comments'
  @_hash['rule'] = 'rule'
  @_hash['rule_message'] = 'rule_message'
  @_hash['rule_name'] = 'rule_name'
  @_hash['severity'] = 'severity'
  @_hash['state'] = 'state'
  @_hash['state_updated_at'] = 'state_updated_at'
  @_hash['status'] = 'status'
  @_hash['syntactic_id'] = 'syntactic_id'
  @_hash['triage_comment'] = 'triage_comment'
  @_hash['triage_reason'] = 'triage_reason'
  @_hash['triage_state'] = 'triage_state'
  @_hash['triaged_at'] = 'triaged_at'
  @_hash['usage'] = 'usage'
  @_hash['vulnerability_identifier'] = 'vulnerability_identifier'
  @_hash
end

.nullablesObject

An array for nullable fields



240
241
242
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 240

def self.nullables
  []
end

.optionalsObject

An array for optional fields



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 201

def self.optionals
  %w[
    categories
    confidence
    created_at
    epss_score
    external_ticket
    first_seen_scan_id
    fix_recommendations
    found_dependency
    id
    is_malicious
    line_of_code_url
    location
    match_based_id
    reachability
    reachable_condition
    ref
    relevant_since
    repository
    review_comments
    rule
    rule_message
    rule_name
    severity
    state
    state_updated_at
    status
    syntactic_id
    triage_comment
    triage_reason
    triage_state
    triaged_at
    usage
    vulnerability_identifier
  ]
end

.validate(value) ⇒ Object

Validates an instance of the object from a given value.

Parameters:

  • The (ScaFinding | Hash)

    value against the validation is performed.



409
410
411
412
413
414
415
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 409

def self.validate(value)
  return true if value.instance_of? self

  return false unless value.instance_of? Hash

  true
end

Instance Method Details

#inspectObject

Provides a debugging-friendly string with detailed object information.



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 437

def inspect
  class_name = self.class.name.split('::').last
  "<#{class_name} categories: #{@categories.inspect}, confidence: #{@confidence.inspect},"\
  " created_at: #{@created_at.inspect}, epss_score: #{@epss_score.inspect}, external_ticket:"\
  " #{@external_ticket.inspect}, first_seen_scan_id: #{@first_seen_scan_id.inspect},"\
  " fix_recommendations: #{@fix_recommendations.inspect}, found_dependency:"\
  " #{@found_dependency.inspect}, id: #{@id.inspect}, is_malicious: #{@is_malicious.inspect},"\
  " line_of_code_url: #{@line_of_code_url.inspect}, location: #{@location.inspect},"\
  " match_based_id: #{@match_based_id.inspect}, reachability: #{@reachability.inspect},"\
  " reachable_condition: #{@reachable_condition.inspect}, ref: #{@ref.inspect},"\
  " relevant_since: #{@relevant_since.inspect}, repository: #{@repository.inspect},"\
  " review_comments: #{@review_comments.inspect}, rule: #{@rule.inspect}, rule_message:"\
  " #{@rule_message.inspect}, rule_name: #{@rule_name.inspect}, severity:"\
  " #{@severity.inspect}, state: #{@state.inspect}, state_updated_at:"\
  " #{@state_updated_at.inspect}, status: #{@status.inspect}, syntactic_id:"\
  " #{@syntactic_id.inspect}, triage_comment: #{@triage_comment.inspect}, triage_reason:"\
  " #{@triage_reason.inspect}, triage_state: #{@triage_state.inspect}, triaged_at:"\
  " #{@triaged_at.inspect}, usage: #{@usage.inspect}, vulnerability_identifier:"\
  " #{@vulnerability_identifier.inspect}, additional_properties: #{@additional_properties}>"
end

#to_sObject

Provides a human-readable string representation of the object.



418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# File 'lib/semgrep_web_app/models/sca_finding.rb', line 418

def to_s
  class_name = self.class.name.split('::').last
  "<#{class_name} categories: #{@categories}, confidence: #{@confidence}, created_at:"\
  " #{@created_at}, epss_score: #{@epss_score}, external_ticket: #{@external_ticket},"\
  " first_seen_scan_id: #{@first_seen_scan_id}, fix_recommendations: #{@fix_recommendations},"\
  " found_dependency: #{@found_dependency}, id: #{@id}, is_malicious: #{@is_malicious},"\
  " line_of_code_url: #{@line_of_code_url}, location: #{@location}, match_based_id:"\
  " #{@match_based_id}, reachability: #{@reachability}, reachable_condition:"\
  " #{@reachable_condition}, ref: #{@ref}, relevant_since: #{@relevant_since}, repository:"\
  " #{@repository}, review_comments: #{@review_comments}, rule: #{@rule}, rule_message:"\
  " #{@rule_message}, rule_name: #{@rule_name}, severity: #{@severity}, state: #{@state},"\
  " state_updated_at: #{@state_updated_at}, status: #{@status}, syntactic_id:"\
  " #{@syntactic_id}, triage_comment: #{@triage_comment}, triage_reason: #{@triage_reason},"\
  " triage_state: #{@triage_state}, triaged_at: #{@triaged_at}, usage: #{@usage},"\
  " vulnerability_identifier: #{@vulnerability_identifier}, additional_properties:"\
  " #{@additional_properties}>"
end