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 =

Signature:

  • Array[String]

Returns:

  • (Array[String])
%w[info low medium high critical].freeze
FAIL_ON =

Returns:

  • (Array[String])
%w[
  new_conflict nullable_change first_change follow_change action_arity unreachable
].freeze
RANK =

Signature:

  • Array[String]

Returns:

  • (Hash[String, Integer])
LEVELS.each_with_index.to_h.freeze
GATE_TO_KIND =

Signature:

  • Hash[String, Integer]

Returns:

  • (Hash[String, String])
{
  "nullable_change" => "nullable", "first_change" => "first", "follow_change" => "follow"
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.action_gate?(report, gates) ⇒ Boolean

RBS:

  • (Hash[Symbol, Object?], Array[String]) -> bool

Returns:

  • (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

RBS:

  • (Hash[Symbol, Object?], Array[String]) -> bool

Returns:

  • (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

RBS:

  • (Hash[Symbol, Object?] report, Array[String] gates) -> bool

Returns:

  • (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

RBS:

  • (String) -> String



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

RBS:

  • (String left, String right) -> String



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

RBS:

  • (Hash[String, Array[String]], Array[Hash[Symbol, String]]) -> Hash[String, String]



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

RBS:

  • (Hash[Symbol, Object?], Array[String]) -> bool

Returns:

  • (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

RBS:

  • (Array[String] gates) -> Array[String]

Raises:

  • (OptionParser::InvalidArgument)


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

RBS:

  • (Hash[Symbol, Object?], Array[String]) -> bool

Parameters:

  • (Hash[Symbol, Object?])
  • (Array[String])

Returns:

  • (Boolean)


49
# File 'sig/ibex/impact/severity.rbs', line 49

def self?.action_gate?: (Hash[Symbol, Object?], Array[String]) -> bool

#self?.conflict_gate?Boolean

RBS:

  • (Hash[Symbol, Object?], Array[String]) -> bool

Parameters:

  • (Hash[Symbol, Object?])
  • (Array[String])

Returns:

  • (Boolean)


43
# File 'sig/ibex/impact/severity.rbs', line 43

def self?.conflict_gate?: (Hash[Symbol, Object?], Array[String]) -> bool

#self?.fails?Boolean

RBS:

  • (Hash[Symbol, Object?] report, Array[String] gates) -> bool

Parameters:

  • report (Hash[Symbol, Object?])
  • gates (Array[String])

Returns:

  • (Boolean)


40
# File 'sig/ibex/impact/severity.rbs', line 40

def self?.fails?: (Hash[Symbol, Object?] report, Array[String] gates) -> bool

#self?.level_for_kindString

RBS:

  • (String) -> String

Parameters:

  • (String)

Returns:

  • (String)


37
# File 'sig/ibex/impact/severity.rbs', line 37

def self?.level_for_kind: (String) -> String

#self?.maxString

RBS:

  • (String left, String right) -> String

Parameters:

  • left (String)
  • right (String)

Returns:

  • (String)


31
# File 'sig/ibex/impact/severity.rbs', line 31

def self?.max: (String left, String right) -> String

#self?.symbolsHash[String, String]

RBS:

  • (Hash[String, Array[String]], Array[Hash[Symbol, String]]) -> Hash[String, String]

Parameters:

  • (Hash[String, Array[String]])
  • (Array[Hash[Symbol, String]])

Returns:

  • (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

RBS:

  • (Hash[Symbol, Object?], Array[String]) -> bool

Parameters:

  • (Hash[Symbol, Object?])
  • (Array[String])

Returns:

  • (Boolean)


46
# File 'sig/ibex/impact/severity.rbs', line 46

def self?.unreachable_gate?: (Hash[Symbol, Object?], Array[String]) -> bool

#self?.validate_gatesArray[String]

RBS:

  • (Array[String] gates) -> Array[String]

Parameters:

  • gates (Array[String])

Returns:

  • (Array[String])


52
# File 'sig/ibex/impact/severity.rbs', line 52

def self?.validate_gates: (Array[String] gates) -> Array[String]