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].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.
107 108 109 110 111 |
# File 'lib/still_active/suppressions.rb', line 107 def initialize(entries, warnings, today) @entries = entries @warnings = warnings @today = today end |
Instance Attribute Details
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
105 106 107 |
# File 'lib/still_active/suppressions.rb', line 105 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.
134 135 136 137 138 139 140 141 |
# File 'lib/still_active/suppressions.rb', line 134 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.
123 124 125 126 127 128 129 130 |
# File 'lib/still_active/suppressions.rb', line 123 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
113 114 115 |
# File 'lib/still_active/suppressions.rb', line 113 def suppressed?(gem:, signal:, advisory: nil, aliases: []) !match(gem:, signal:, advisory:, aliases:).nil? end |