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 / libyear) 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].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.
106 107 108 109 110 |
# File 'lib/still_active/suppressions.rb', line 106 def initialize(entries, warnings, today) @entries = entries @warnings = warnings @today = today end |
Instance Attribute Details
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
104 105 106 |
# File 'lib/still_active/suppressions.rb', line 104 def warnings @warnings end |
Class Method Details
.from(raw, today: Date.today) ⇒ Object
41 42 43 44 45 |
# File 'lib/still_active/suppressions.rb', line 41 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.
133 134 135 136 137 138 139 140 |
# File 'lib/still_active/suppressions.rb', line 133 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.
122 123 124 125 126 127 128 129 |
# File 'lib/still_active/suppressions.rb', line 122 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
112 113 114 |
# File 'lib/still_active/suppressions.rb', line 112 def suppressed?(gem:, signal:, advisory: nil, aliases: []) !match(gem:, signal:, advisory:, aliases:).nil? end |