Class: StillActive::Suppressions
- Inherits:
-
Object
- Object
- StillActive::Suppressions
- Defined in:
- lib/still_active/suppressions.rb
Overview
Granular, auditable suppression of individual findings, loaded from the
ignore: block of a committed .still_active.yml. Each entry silences one
signal (activity / vulnerability / libyear / poison) or one advisory for one
gem, optionally until an expiry date, replacing the all-or-nothing whole-gem
--ignore. A bare gem
name (or a gem-only mapping) keeps the old whole-gem behaviour so --ignore
can union into the same list.
Two guardrails keep suppression from hiding live risk: a lapsed entry stops applying so the finding re-surfaces, and a vulnerability suppression must name an explicit advisory id, so a newly disclosed CVE on the same gem is never pre-silenced.
Defined Under Namespace
Classes: Entry
Constant Summary collapse
- GATEABLE_SIGNALS =
[:activity, :vulnerability, :libyear, :poison, :language_ceiling, :deprecated].freeze
Instance Attribute Summary collapse
-
#warnings ⇒ Object
readonly
Returns the value of attribute warnings.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(entries, warnings, today) ⇒ Suppressions
constructor
A new instance of Suppressions.
-
#match(gem:, signal:, advisory: nil, aliases: []) ⇒ Object
The first live entry covering this finding, or nil.
-
#stale_gem_warnings(present_gems) ⇒ Object
Warnings for live entries that name a gem absent from the audited set: they can never match, so they are dead config (a typo, or a gem removed since the suppression was written).
- #suppressed?(gem:, signal:, advisory: nil, aliases: []) ⇒ Boolean
Constructor Details
#initialize(entries, warnings, today) ⇒ Suppressions
Returns a new instance of Suppressions.
109 110 111 112 113 |
# File 'lib/still_active/suppressions.rb', line 109 def initialize(entries, warnings, today) @entries = entries @warnings = warnings @today = today end |
Instance Attribute Details
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
107 108 109 |
# File 'lib/still_active/suppressions.rb', line 107 def warnings @warnings end |
Class Method Details
.from(raw, today: Date.today) ⇒ Object
42 43 44 45 46 |
# File 'lib/still_active/suppressions.rb', line 42 def from(raw, today: Date.today) warnings = [] entries = Array(raw).filter_map { |item| parse_entry(item, warnings) } new(entries, warnings, today) end |
Instance Method Details
#match(gem:, signal:, advisory: nil, aliases: []) ⇒ Object
The first live entry covering this finding, or nil. Used by SARIF to carry the suppression's reason as the native suppressions justification.
136 137 138 139 140 141 142 143 |
# File 'lib/still_active/suppressions.rb', line 136 def match(gem:, signal:, advisory: nil, aliases: []) @entries.find do |entry| next false if entry.expired?(@today) next false unless entry.gem.nil? || entry.gem == gem entry.covers?(signal:, advisory:, aliases:) end end |
#stale_gem_warnings(present_gems) ⇒ Object
Warnings for live entries that name a gem absent from the audited set: they
can never match, so they are dead config (a typo, or a gem removed since
the suppression was written). This is the presence axis of suppression rot;
expired? already covers the time axis, so an expired entry isn't
re-reported here, and a gem-agnostic advisory entry (gem nil) is skipped
since it applies across the whole graph.
125 126 127 128 129 130 131 132 |
# File 'lib/still_active/suppressions.rb', line 125 def stale_gem_warnings(present_gems) @entries.filter_map do |entry| next if entry.expired?(@today) next unless entry.gem && !present_gems.include?(entry.gem) "suppression for #{entry.gem} never applies: it is not in the audited dependencies (typo, or removed since it was suppressed?)" end end |
#suppressed?(gem:, signal:, advisory: nil, aliases: []) ⇒ Boolean
115 116 117 |
# File 'lib/still_active/suppressions.rb', line 115 def suppressed?(gem:, signal:, advisory: nil, aliases: []) !match(gem:, signal:, advisory:, aliases:).nil? end |