v1.5 — ecosystem integrations (license, dual-source vulns, CycloneDX, Dependabot context)#26
Merged
Merged
Conversation
Reuses the per-version `licenses` field already present in the RubyGems versions payload we fetch — no extra request — and exposes it as a `License` column (terminal + markdown) and an additive `license` JSON field. Comma-joined for multi-license gems; nil/"-" for git/path sources with no RubyGems metadata. Read-only metadata only: license policy (allow/deny gating) stays the domain of license_finder. schema_version stays 1 (additive field). First of the v1.5 ecosystem-integration commits; unblocks the CycloneDX renderer, which maps this into component.licenses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
still_active reads vulnerabilities from deps.dev; bundler-audit reads rubysec/ruby-advisory-db. The two diverge on Ruby-specific advisories the rubysec maintainers curate before they reach OSV. Users running both saw different counts with no explanation. When bundler-audit is installed with a current advisory checkout, we now read its advisories through its own Database loader (we're a consumer — no YAML parsing or range matching of our own) and merge them with deps.dev, deduplicating on shared identifiers. Each advisory carries a `source` (deps.dev / ruby-advisory-db / merged); deps.dev wins on CVSS/title/vector, ruby-advisory-db fills gaps. Opt-in by composition: no bundler-audit, no second source — falls back silently to deps.dev with a hint to run `bundle audit update`. A malformed advisory in the checkout is surfaced with a warning, not swallowed as []: a silent empty result there would hide a real vulnerability, the exact gap this feature closes. Verified against bundler-audit 0.9.3 (CVSS in #to_h; Database.new raises ArgumentError when the checkout is absent) and dogfooded against the real ruby-advisory-db. schema_version stays 1 (source is additive); SA003 unchanged. bundler-audit is a dev dependency only — detected at runtime, never a runtime dep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
In --baseline (and terminal/markdown/JSON) runs, a bot-authored update is
now recognized and the report leads with a narrative ("Dependabot bump:
rack 2.0.0 -> 2.0.6") so reviewers see intent, not just a list. JSON gains
an additive top-level `pr_context` ({ bot, bumps: [{ gem, from, to }] }).
Detection cascade: GITHUB_ACTOR -> dependabot/|renovate/ branch prefix ->
commit subject. The subject patterns are deliberately conservative because
false positives are worse than misses: Dependabot's `bump X from Y to Z`
skeleton is safe unprefixed, but the Renovate `update X to vN` pattern
requires a v-prefixed version so it can't fire on ordinary "Update README
to mention SARIF" commits. Git probes rescue SystemCallError so a
missing/unlaunchable git only costs the narrative, never the run.
schema_version stays 1 (pr_context additive); SARIF unaffected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Makes still_active's data portable: --cyclonedx[=PATH] emits a CycloneDX SBOM so the dep graph plus our signals flow into Trivy / Dependency-Track / Snyk / GitHub's dependency-submission API instead of being walled in our own JSON. Defaults to 1.6 — the version mainstream consumers actually ingest today (cyclonedx-core-java/Dependency-Track and cyclonedx-go/Trivy both cap at 1.6 as of 2026); --cyclonedx-version=1.7 opts into the latest. Our emitted subset is identical across both, so only the specVersion string changes, and a consumer that only knows 1.6 would reject a 1.7-stamped doc — hence the conservative default. Native fields carry name/version/purl/licenses/vulnerabilities; maintenance signals with no CycloneDX home (archived, OpenSSF, libyear, last commit, yanked) ride in still_active:-namespaced properties. serialNumber is derived from the component set, so two SBOMs of the same lockfile are byte-identical apart from the generation timestamp (injectable, so tests are deterministic). Separate output format — the schema_version:1 JSON envelope is untouched. Stdlib only (json/digest/time); no new runtime deps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the v1.5 features (license column, dual-source vulns, CycloneDX, Dependabot/Renovate context) across the README and bumps the version. Adds an "Alongside dependency-review-action" section: a comparison matrix and a dual-job workflow. GitHub's first-party action gates CVEs/licenses server-side but surfaces no maintenance signals and is GitHub-only — so the recipe runs both, letting still_active add the maintenance lens. Records on paper the "complementary, not a replacement" positioning the gem is built on. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
VersionHelper joins multiple licenses with ", " for terminal/markdown
display ("Hippocratic-2.1, MIT"); the CycloneDX renderer was feeding that
joined string straight into license.id, which must be a single SPDX
identifier. A joined value is neither a valid id nor a valid SPDX
expression, so SBOM validators and Dependency-Track's license matcher
reject or drop it — undercutting the "feeds Trivy/Dependency-Track" claim.
Split back into one license entry per id. Surfaced by a full-branch review
(every test used single-license gems, so it slipped through); confirmed
fixed against vcr (Hippocratic-2.1, MIT) and debug (Ruby, BSD-2-Clause).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…extracting bumps Dependabot's commit-message.prefix / prefix-development / include:scope (and Renovate's commitMessagePrefix) change the subject prefix, so a configured "chore(deps): bump …" or "deps: bump …" previously fell back to the generic "Dependabot dependency update" narrative even though the bot was detected. Separate the two concerns: detection patterns stay anchored and conservative (they must never false-positive on a human commit), while extraction now uses unanchored skeleton patterns. Extraction only runs after a bot is already confirmed via GITHUB_ACTOR/branch/anchored-subject, so ignoring the prefix there can't widen detection — the human-commit false-positive guards still pass. Detection was already prefix-independent in CI (it keys off GITHUB_ACTOR and the branch); this fixes the narrative for custom-prefix configs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
--baseline, --sarif, and --cyclonedx are mutually exclusive and resolved by precedence (baseline > sarif > cyclonedx > terminal/markdown/json). Combining them previously dropped the losers silently. Now a stderr warning names the mode that wins and the ones ignored, and a separate warning fires when --cyclonedx-version is set without --cyclonedx (no effect otherwise). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n 1.5.0 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…CTOR Research (dependabot/fetch-metadata) confirms the authoritative signal is the PR author in the GitHub event payload (pull_request.user.login), not GITHUB_ACTOR. GITHUB_ACTOR reflects who triggered *this* run, so it flips to a human who re-runs the workflow or pushes to the bot's branch, while the PR author does not. Make pull_request.user.login the primary signal, keeping GITHUB_ACTOR/branch/subject as fallbacks. pr_author_login never raises: a missing/unreadable/malformed-or-wrong-shape payload falls through to the weaker signals (rescue includes TypeError so a top-level array or non-Hash pull_request/user can't crash the audit over a cosmetic narrative — detect runs unguarded in CLI#run). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Verified against the docs: the dependency-submission API ingests a proprietary snapshot format, not CycloneDX directly (submission goes through SPDX/Anchore converter actions). Our --cyclonedx output doesn't feed it, so the claim was false. Trivy / Dependency-Track / Snyk are confirmed direct consumers (Snyk's `sbom test` takes CycloneDX 1.4-1.6 and requires the purl we emit), so they stay. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ource The diff workflow runs `bundle exec still_active`, so bundler-audit (a dev dependency) is on the load path — but its advisory DB ships separately and wasn't fetched, leaving the v1.5 dual-source merge dormant. Add a `bundle-audit update` step so our own CI actually exercises the deps.dev + ruby-advisory-db merge. Best-effort: on failure still_active falls back to deps.dev only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| metrics (~> 0.12) | ||
| traces (~> 0.18) | ||
| bigdecimal (4.1.2) | ||
| bundler-audit (0.9.3) |
still_active diff0 regressions · 1 added · 0 removed · 1 bumped · 0 signal-changes Added
Version bumps
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v1.5 — ecosystem integrations
Five features that make still_active compose with the rest of the Ruby supply-chain ecosystem rather than duplicate it. Each shipped as its own commit, TDD'd, individually reviewed, and dogfooded against real data.
Features
Licensecolumn in terminal/markdown, additivelicensefield in JSON.bundler-auditis installed (with a currentbundle audit updatecheckout), advisories fromrubysec/ruby-advisory-dbare merged with deps.dev, deduped on shared identifiers, each tagged with itssource(deps.dev/ruby-advisory-db/merged). Closes the "why do bundler-audit and still_active disagree?" gap.pr_context. Detected primarily via the event-payload PR author (pull_request.user.login, same authoritative signaldependabot/fetch-metadatauses), with conservative fallbacks. Bump extraction tolerates customcommit-message.prefix/scope configs.--cyclonedx): default 1.6 (the version Trivy/Dependency-Track/Snyk ingest today),--cyclonedx-version=1.7to opt in. Native fields for name/version/purl/licenses/vulnerabilities; maintenance signals instill_active:-namespaced properties; deterministic content-derived serialNumber.dependency-review-actioninterop: comparison matrix + dual-job workflow recipe in the README.Plus: a warning when mutually-exclusive output flags are combined, and a CI step so our own PR-diff workflow exercises the dual-source merge.
Invariants held
schema_versionstays1(all new fields additive); SARIF rule IDsSA001–SA007unchanged.bundler-auditis dev-only, detected at runtime.Verification
pr_contextin JSON.dependency-submission API) that didn't survive verification — both fixed.See
CHANGELOG.mdfor the full 1.5.0 entry.🤖 Generated with Claude Code