Module: Ibex::Impact::Severity
- Defined in:
- lib/ibex/impact/severity.rb,
sig/ibex/impact/severity.rbs
Overview
Severity ranking and CI gate evaluation for impact findings.
Constant Summary collapse
- LEVELS =
%w[info low medium high critical].freeze
- FAIL_ON =
%w[ new_conflict nullable_change first_change follow_change action_arity unreachable ].freeze
- RANK =
LEVELS.each_with_index.to_h.freeze
- GATE_TO_KIND =
{ "nullable_change" => "nullable", "first_change" => "first", "follow_change" => "follow" }.freeze
Class Method Summary collapse
- .action_gate?(report, gates) ⇒ Boolean
- .conflict_gate?(report, gates) ⇒ Boolean
- .fails?(report, gates) ⇒ Boolean
- .level_for_kind(kind) ⇒ Object
- .max(left, right) ⇒ Object
- .symbols(changes, actions) ⇒ Object
- .unreachable_gate?(report, gates) ⇒ Boolean
- .validate_gates(gates) ⇒ Object
Instance Method Summary collapse
- #self?.action_gate? ⇒ Boolean
- #self?.conflict_gate? ⇒ Boolean
- #self?.fails? ⇒ Boolean
- #self?.level_for_kind ⇒ String
- #self?.max ⇒ String
- #self?.symbols ⇒ Hash[String, String]
- #self?.unreachable_gate? ⇒ Boolean
- #self?.validate_gates ⇒ Array[String]
Class Method Details
.action_gate?(report, gates) ⇒ Boolean
123 124 125 126 127 128 |
# File 'lib/ibex/impact/severity.rb', line 123 def action_gate?(report, gates) return false unless gates.include?("action_arity") action_records = report.fetch(:actions, []) #: Array[Hash[Symbol, Object?]] action_records.any? { |item| item[:severity] == "high" } end |
.conflict_gate?(report, gates) ⇒ Boolean
109 110 111 |
# File 'lib/ibex/impact/severity.rb', line 109 def conflict_gate?(report, gates) gates.include?("new_conflict") && report.dig(:automaton, :conflicts, :added)&.any? end |
.fails?(report, gates) ⇒ Boolean
94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/ibex/impact/severity.rb', line 94 def fails?(report, gates) return false if gates.empty? return true if conflict_gate?(report, gates) return true if unreachable_gate?(report, gates) return true if action_gate?(report, gates) symbol_records = report.fetch(:symbols, []) #: Array[Hash[Symbol, Object?]] gates.any? do |gate| kind = GATE_TO_KIND[gate] kind && symbol_records.any? { |item| item[:kinds].is_a?(Array) && item[:kinds].include?(kind) } end end |
.level_for_kind(kind) ⇒ Object
86 87 88 89 90 91 |
# File 'lib/ibex/impact/severity.rb', line 86 def level_for_kind(kind) return "high" if %w[first follow nullable].include?(kind) return "medium" if %w[reference precedence].include?(kind) "low" end |
.max(left, right) ⇒ Object
65 66 67 |
# File 'lib/ibex/impact/severity.rb', line 65 def max(left, right) RANK.fetch(left) >= RANK.fetch(right) ? left : right end |
.symbols(changes, actions) ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/ibex/impact/severity.rb', line 70 def symbols(changes, actions) levels = Hash.new("info") #: Hash[String, String] changes.each do |name, kinds| kinds.each do |kind| level = level_for_kind(kind) levels[name] = max(levels[name], level) end end actions.each do |finding| name = finding.fetch(:production).split(" -> ").first levels[name] = max(levels[name], finding.fetch(:severity)) end levels end |
.unreachable_gate?(report, gates) ⇒ Boolean
114 115 116 117 118 119 120 |
# File 'lib/ibex/impact/severity.rb', line 114 def unreachable_gate?(report, gates) return false unless gates.include?("unreachable") states = report.dig(:automaton, :unreachable) || [] nonterminals = report.dig(:automaton, :unreachable_nonterminals) || [] states.any? || nonterminals.any? end |
.validate_gates(gates) ⇒ Object
131 132 133 134 135 136 |
# File 'lib/ibex/impact/severity.rb', line 131 def validate_gates(gates) unknown = gates - FAIL_ON raise OptionParser::InvalidArgument, "unknown --fail-on value #{unknown.first.inspect}" unless unknown.empty? gates.uniq end |
Instance Method Details
#self?.action_gate? ⇒ Boolean
49 |
# File 'sig/ibex/impact/severity.rbs', line 49
def self?.action_gate?: (Hash[Symbol, Object?], Array[String]) -> bool
|
#self?.conflict_gate? ⇒ Boolean
43 |
# File 'sig/ibex/impact/severity.rbs', line 43
def self?.conflict_gate?: (Hash[Symbol, Object?], Array[String]) -> bool
|
#self?.fails? ⇒ Boolean
40 |
# File 'sig/ibex/impact/severity.rbs', line 40
def self?.fails?: (Hash[Symbol, Object?] report, Array[String] gates) -> bool
|
#self?.level_for_kind ⇒ String
37 |
# File 'sig/ibex/impact/severity.rbs', line 37
def self?.level_for_kind: (String) -> String
|
#self?.max ⇒ String
31 |
# File 'sig/ibex/impact/severity.rbs', line 31
def self?.max: (String left, String right) -> String
|
#self?.symbols ⇒ Hash[String, String]
34 |
# File 'sig/ibex/impact/severity.rbs', line 34
def self?.symbols: (Hash[String, Array[String]], Array[Hash[Symbol, String]]) -> Hash[String, String]
|
#self?.unreachable_gate? ⇒ Boolean
46 |
# File 'sig/ibex/impact/severity.rbs', line 46
def self?.unreachable_gate?: (Hash[Symbol, Object?], Array[String]) -> bool
|
#self?.validate_gates ⇒ Array[String]
52 |
# File 'sig/ibex/impact/severity.rbs', line 52
def self?.validate_gates: (Array[String] gates) -> Array[String]
|