Class: RailVerdict::Finding

Inherits:
Object
  • Object
show all
Defined in:
lib/rail_verdict/contracts/finding.rb

Constant Summary collapse

SCHEMA_VERSION =
"1.0"
FINGERPRINT_PAYLOAD_SCHEMA =
"https://railverdict.dev/fingerprint-payload/v1"
LEGACY_FINGERPRINT_PAYLOAD_SCHEMA =
"https://railverdict.dev/fingerprint-payload/v0.1"
FINGERPRINT_PATTERN =
/\Asha256:[0-9a-f]{64}\z/
LOCATION_PATH_PATTERN =
%r{
  \A
  (?!/)
  (?!.*\\)
  (?!.*//)
  (?!(?:\.{1,2})(?:/|\z))
  (?!.* / (?:\.{1,2}) (?:/|\z))
  [^\u0000-\u001f/]+
  (?:/[^\u0000-\u001f/]+)*
  \z
}x
ORIGINS =
%w[deterministic runtime ai custom].freeze
SEVERITIES =
%w[info low medium high critical].freeze
CONFIDENCES =
%w[low medium high].freeze
STATES =
%w[observed introduced existing resolved changed moved suppressed waived].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fingerprint:, origin:, analyzer:, rule_id:, category:, severity:, confidence:, state:, evidence_ref:, location:, message:) ⇒ Finding

Returns a new instance of Finding.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rail_verdict/contracts/finding.rb', line 41

def initialize(fingerprint:, origin:, analyzer:, rule_id:, category:, severity:, confidence:,
               state:, evidence_ref:, location:, message:)
  @fingerprint = require_match(fingerprint, FINGERPRINT_PATTERN, "fingerprint")
  @origin = require_member(origin, ORIGINS, "origin")
  @analyzer = require_nonempty(analyzer, "analyzer", 256)
  @rule_id = require_nonempty(rule_id, "rule_id", 256)
  @category = require_nonempty(category, "category", 256)
  @severity = require_member(severity, SEVERITIES, "severity")
  @confidence = require_member(confidence, CONFIDENCES, "confidence")
  @state = require_member(state, STATES, "state")
  @evidence_ref = require_nonempty(evidence_ref, "evidence_ref", 512)
  @location = validate_location(location)
  @message = require_nonempty(message, "message", 4096)
  @id = Finding.id_for(@fingerprint).freeze
  @location.freeze
  @analyzer.freeze
  @rule_id.freeze
  @category.freeze
  @evidence_ref.freeze
  @message.freeze
  freeze
end

Instance Attribute Details

#analyzerObject (readonly)

Returns the value of attribute analyzer.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def analyzer
  @analyzer
end

#categoryObject (readonly)

Returns the value of attribute category.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def category
  @category
end

#confidenceObject (readonly)

Returns the value of attribute confidence.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def confidence
  @confidence
end

#evidence_refObject (readonly)

Returns the value of attribute evidence_ref.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def evidence_ref
  @evidence_ref
end

#fingerprintObject (readonly)

Returns the value of attribute fingerprint.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def fingerprint
  @fingerprint
end

#idObject (readonly)

Returns the value of attribute id.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def id
  @id
end

#locationObject (readonly)

Returns the value of attribute location.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def location
  @location
end

#messageObject (readonly)

Returns the value of attribute message.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def message
  @message
end

#originObject (readonly)

Returns the value of attribute origin.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def origin
  @origin
end

#rule_idObject (readonly)

Returns the value of attribute rule_id.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def rule_id
  @rule_id
end

#severityObject (readonly)

Returns the value of attribute severity.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def severity
  @severity
end

#stateObject (readonly)

Returns the value of attribute state.



29
30
31
# File 'lib/rail_verdict/contracts/finding.rb', line 29

def state
  @state
end

Class Method Details

.fingerprint_for(analyzer:, rule_id:, path:, message:) ⇒ Object



32
33
34
# File 'lib/rail_verdict/contracts/finding.rb', line 32

def self.fingerprint_for(analyzer:, rule_id:, path:, message:)
  Fingerprint.hexdigest(analyzer: analyzer, rule_id: rule_id, path: path, message: message)
end

.id_for(fingerprint) ⇒ Object



36
37
38
39
# File 'lib/rail_verdict/contracts/finding.rb', line 36

def self.id_for(fingerprint)
  hex = fingerprint.delete_prefix("sha256:")
  "rv:#{hex.slice(0, 20)}"
end

Instance Method Details

#schema_versionObject



64
65
66
# File 'lib/rail_verdict/contracts/finding.rb', line 64

def schema_version
  SCHEMA_VERSION
end

#sort_keyObject



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rail_verdict/contracts/finding.rb', line 68

def sort_key
  [
    location.fetch("path").to_s,
    location["start_line"] || -1,
    location["end_line"] || -1,
    analyzer,
    rule_id,
    fingerprint,
    id
  ]
end

#to_schema_hObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rail_verdict/contracts/finding.rb', line 80

def to_schema_h
  {
    "schema_version" => SCHEMA_VERSION,
    "id" => id,
    "fingerprint" => fingerprint,
    "origin" => origin,
    "analyzer" => analyzer,
    "rule_id" => rule_id,
    "category" => category,
    "severity" => severity,
    "confidence" => confidence,
    "state" => state,
    "evidence_ref" => evidence_ref,
    "location" => location,
    "message" => message
  }
end