still_active 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3351319b0427ef0043ecb5a150350499a25b7cb3228814184d3908d09497bc5
4
- data.tar.gz: ffbc01c085040a9ed570095f133407dce101e4aa9a22689bfe423bc32996cdb3
3
+ metadata.gz: 1b366f37d158cbf7b8e13c552ead6eefec0ec98270b9f8c511505d39a6299631
4
+ data.tar.gz: efb7a1a7cb3b12a9a8ec8e8aed8b955ec600ef8a35f455d2fe9185611a41ce6a
5
5
  SHA512:
6
- metadata.gz: 14f7e5c50c8df5291bd1239496f5016d11a2336bf6517a58887ab1a1ac3857dbb7cc3de99767f95f986b0620e3c07b448b081ce41dbb86b1d1c102ed404c3b56
7
- data.tar.gz: 58624fb08295567a415a9e58a1cefda2e0663144133bd38b6b8563588eb3958971ed52fef07884b4c03ad16fb97b685f661d3a45a240d09d116cd199d699985a
6
+ metadata.gz: 1dac0f642b896d150070c5d63172cf1102d6a978b6605d45a6e44b80ee548c9ec77e3f3922c1c6865cefee2a2ae576e2059bbee919bf69399709ad09a69b3963
7
+ data.tar.gz: f76ad2676b526b1819d97051f31da33d690f032d5eb23f352074e6d086668fc9223a460402220f73698023dfd0de10ae2288a222fb88fd2c3981b9a9c11d5b89
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [3.1.0] - 2026-09-07
6
+
7
+ ### Changed
8
+
9
+ - **`cvss-suite` is now a REQUIRED runtime dependency** (`>= 5.0`), no longer opt-in. Its 5.0 release dropped the constraints that kept it optional through 3.0 (a Ruby 2.6 floor, a `bigdecimal` cap, an exact `bundler` pin), so it now passes the same audit still_active runs on your own lockfile. It resolves automatically on `gem install`; the Ruby floor is unchanged. The `cvss-suite` input on the GitHub Action becomes a no-op.
10
+ - **CVSS-4-only advisories are always scored now**, and the number is the **base score** (what NVD and GHSA publish), not cvss-suite's `overall_score`, which folds threat metrics into the vector when present. Under `--fail-if-vulnerable=<severity>` an advisory that used to fail closed as unscored gets a real number, so a previously red run can go green when that number sits below your threshold. The GHSA label still floors the band, so a HIGH never demotes.
11
+
5
12
  ## [3.0.0] - 2026-08-21
6
13
 
7
14
  The maintenance lens goes cross-ecosystem. In one line each:
data/README.md CHANGED
@@ -219,7 +219,7 @@ Full semantics, thresholds, and transitive behaviour: [`docs/configuration.md`](
219
219
 
220
220
  ## Data sources
221
221
 
222
- Release dates and licenses from [RubyGems](https://rubygems.org) / [GitHub Packages](https://docs.github.com/en/packages) / [Artifactory](https://jfrog.com/artifactory/); repo activity from the [GitHub](https://docs.github.com/en/rest) / [GitLab](https://docs.gitlab.com/ee/api/) / [Codeberg](https://forgejo.org/docs/latest/user/api-usage/) API, or [ecosyste.ms](https://ecosyste.ms) tokenless ([CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)); OpenSSF Scorecard and CVSS from [deps.dev](https://deps.dev); advisory severities and fixed-version ranges from [OSV](https://osv.dev) (CVSS-4 scoring needs the optional [`cvss-suite`](https://rubygems.org/gems/cvss-suite)); extra advisories from [ruby-advisory-db](https://github.com/rubysec/ruby-advisory-db); runtime EOL from [endoflife.date](https://endoflife.date).
222
+ Release dates and licenses from [RubyGems](https://rubygems.org) / [GitHub Packages](https://docs.github.com/en/packages) / [Artifactory](https://jfrog.com/artifactory/); repo activity from the [GitHub](https://docs.github.com/en/rest) / [GitLab](https://docs.gitlab.com/ee/api/) / [Codeberg](https://forgejo.org/docs/latest/user/api-usage/) API, or [ecosyste.ms](https://ecosyste.ms) tokenless ([CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)); OpenSSF Scorecard and CVSS from [deps.dev](https://deps.dev); advisory severities and fixed-version ranges from [OSV](https://osv.dev), scored with [`cvss-suite`](https://rubygems.org/gems/cvss-suite) when deps.dev has no number (CVSS 4.0); extra advisories from [ruby-advisory-db](https://github.com/rubysec/ruby-advisory-db); runtime EOL from [endoflife.date](https://endoflife.date).
223
223
 
224
224
  ## Development
225
225
 
@@ -1,63 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cvss_suite"
4
+
3
5
  module StillActive
4
- # Computes a CVSS score from a vector string, across v2/v3/v4. deps.dev stores only
5
- # CVSS 3.x, so a CVSS-4-only advisory (the flagship protobuf case) arrives with no
6
- # numeric score; OSV carries the v4 vector, and this turns it into the number the
6
+ # Computes a CVSS base score from a vector string, across v2/v3/v4. deps.dev stores
7
+ # only CVSS 3.x, so a CVSS-4-only advisory (the flagship protobuf case) arrives with
8
+ # no numeric score; OSV carries the v4 vector, and this turns it into the number the
7
9
  # SARIF security-severity and CycloneDX rating want.
8
10
  #
9
- # cvss-suite is an OPTIONAL, undeclared dependency: it over-constrains its own deps
10
- # (an exact `bundler` pin, a `bigdecimal ~> 3.1` cap), the poison-pill pattern
11
- # still_active itself flags, so hard-requiring it would force that liability on every
12
- # user and trip our own audit. CvssHelper soft-requires it; install cvss-suite (or run
13
- # the distribution that bundles it) to light it up.
14
- #
15
- # Returns cvss-suite's `overall_score`: for the base-only vectors OSV publishes that
16
- # IS the base score, but a vector carrying threat/environmental metrics would fold
17
- # those in -- which is why the severity band floors at the authoritative GHSA label
18
- # (VulnerabilityHelper.advisory_severity) and this number never lowers it: the label
19
- # drives gating and SARIF level, the number only sharpens display. Fails safe: an
20
- # absent gem or an absent/unparseable vector yields nil, never a crash.
11
+ # Returns the BASE score, not cvss-suite's overall_score: a vector carrying threat or
12
+ # environmental metrics folds those into overall_score (E:U alone turns a 9.3 into
13
+ # an 8.1), while NVD and GHSA publish the base score. The severity band still floors
14
+ # at the authoritative GHSA label (VulnerabilityHelper.advisory_severity) because
15
+ # labels are assigned by people and can sit off the FIRST band edge; the label drives
16
+ # gating and SARIF level, the number sharpens display. Fails safe: an absent or
17
+ # unparseable vector yields nil, never a crash.
21
18
  module CvssHelper
22
19
  extend self
23
20
 
24
21
  def score(vector)
25
- return unless available?
26
22
  return if vector.nil? || vector.to_s.empty?
27
23
 
28
- cvss = CvssSuite.new(vector.to_s)
29
- cvss.valid? ? cvss.overall_score : nil
30
- rescue => e
31
- # We only reach here with cvss-suite loaded (available?), so a raise is the
32
- # installed gem failing this call site -- an incompatible version, a renamed
33
- # `overall_score` -- not a bad vector, which cvss-suite reports via valid?.
34
- # Fail safe to nil (the number is display-only, never gates), but don't
35
- # swallow it: an opted-in-but-broken scorer that emitted nothing would read
36
- # as "no advisories are scored". Warn once per run (not per advisory),
37
- # matching OsvClient.enrich rather than staying silent.
38
- warn_scorer_failed(e)
24
+ CvssSuite.parse(vector.to_s).base_score
25
+ rescue CvssSuite::Error
39
26
  nil
40
27
  end
41
-
42
- # Memoized soft-require: true once cvss-suite loads, false when it isn't installed.
43
- def available?
44
- return @available unless @available.nil?
45
-
46
- @available = begin
47
- require "cvss_suite"
48
- true
49
- rescue LoadError
50
- false
51
- end
52
- end
53
-
54
- private
55
-
56
- def warn_scorer_failed(error)
57
- return if @warned
58
-
59
- @warned = true
60
- warn("warning: cvss-suite scoring failed: #{error.class} (#{error.message}); CVSS numbers unavailable this run, check your cvss-suite version")
61
- end
62
28
  end
63
29
  end
@@ -23,11 +23,10 @@ module StillActive
23
23
  # One advisory's severity label ("low".."critical"), or nil when genuinely unscored.
24
24
  # The authoritative GHSA/OSV label is a FLOOR: a real CVSS number sharpens precision
25
25
  # and can RAISE the band, but never lowers it below the label. This matters because
26
- # the OSV-derived score is cvss-suite's overall_score, which folds in any
27
- # threat/environmental metrics a vector carries (and can diverge from GHSA at a band
28
- # edge) -- on a fail-closed, no-false-positive tool a computed number must not
29
- # silently demote a GHSA-HIGH finding out of a severity gate. With only one of the
30
- # two present, that one stands.
26
+ # GHSA labels are assigned by people and can sit off the FIRST band edge of the
27
+ # computed base score -- on a fail-closed, no-false-positive tool a computed
28
+ # number must not silently demote a GHSA-HIGH finding out of a severity gate.
29
+ # With only one of the two present, that one stands.
31
30
  def advisory_severity(vulnerability)
32
31
  from_score = (score = effective_score(vulnerability)) ? severity_label(score) : nil
33
32
  from_label = OSV_LABELS[vulnerability[:osv_severity].to_s.downcase]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StillActive
4
- VERSION = "3.0.0"
4
+ VERSION = "3.1.0"
5
5
  end
data/still_active.gemspec CHANGED
@@ -55,12 +55,12 @@ Gem::Specification.new do |spec|
55
55
  # carry an artificial floor.
56
56
  spec.add_runtime_dependency("async", ">= 2.2")
57
57
  spec.add_runtime_dependency("bundler", ">= 2.0")
58
- # cvss-suite (CVSS v4.0 base-score from an OSV vector, for the CVSS-4-only advisory
59
- # deps.dev can't score) is an OPTIONAL dependency, NOT declared here: it exact-pins
60
- # bundler and caps bigdecimal, the poison-pill pattern still_active flags, so we
61
- # won't force it on users or trip our own audit. CvssHelper soft-requires it; absent,
62
- # the OSV/GHSA severity label still carries gating + level and the number is skipped.
63
- # Install cvss-suite (or run the distribution that bundles it) to light up the number.
58
+ # CVSS base score from an OSV vector, for the CVSS-4-only advisory deps.dev can't
59
+ # score. 5.0 is the floor because it is the first release without the poison-pill
60
+ # constraints (a Ruby 2.6 floor, a bigdecimal cap, an exact bundler pin) that kept
61
+ # it optional through 3.0; 5.0 also adds base_score on CVSS 4.0, which is the API
62
+ # CvssHelper reads.
63
+ spec.add_runtime_dependency("cvss-suite", ">= 5.0")
64
64
  spec.add_runtime_dependency("faraday-retry")
65
65
  spec.add_runtime_dependency("gems")
66
66
  spec.add_runtime_dependency("octokit")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: still_active
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Floyd
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '2.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: cvss-suite
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '5.0'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: faraday-retry
42
56
  requirement: !ruby/object:Gem::Requirement