Expand description
SARIF 2.1.0 output (FR-008, US-002) for GitHub code scanning and other SARIF consumers.
Each distinct SARIF rule id becomes one tool.driver.rules entry, and each
CheckFinding becomes one run.results entry with its Range translated to a
SARIF physical location region. A rule id is CheckFinding::code when the finding is
Category::Vulnerable and code passes deps_core::osv::is_valid_osv_id
(is_advisory_finding), falling back to its Category wire token otherwise (issue
#1075, spec 062 review S3: FR-008 says “each existing diagnostic code becomes a SARIF rule
id”; issue #1077 review #2: code is never trusted as a rule id/name verbatim without that
validity check). A vulnerability finding’s code is its OSV advisory id
(RUSTSEC-.../GHSA-...), so distinct advisories now produce distinct rules instead of
collapsing into one shared vulnerable rule. code is deliberately not used for the
other coded categories (Unsatisfiable/License/Deprecated/MutableRefPin): their
diagnostic-code constants are already 1:1 with a Category (no finer granularity to gain),
and MutableRefPin alone has two internal code constants (GitHub Actions’ and GitLab CI’s)
that would otherwise fragment one category into two rules for zero benefit (issue #1077
S1 review). Outdated/Yanked/Other findings, and the “+N more advisories” overflow
line, carry no code at all and always use the category token.
Rule metadata (issue #1077): every rule gets a shortDescription from
Category::description. An advisory rule additionally gets:
helpUri, preferringCheckFinding::advisory_url— the authoritativehttps://osv.dev/vulnerability/{id}page OSV itself gave the diagnostic — and falling back todeps_core::osv::validated_osv_url(the same validated-construction pathdeps-core’s own OSV client uses fordeps_core::osv::Advisory::url) only when that is unavailable;fullDescription, built from the finding’s own message, which already embeds the advisory’s OSV-provided summary (push_vulnerability_diagnostics);properties["security-severity"], fromsecurity_severity_score, whenCheckFinding::advisory_severitynames a graded bucket.
A category-only rule gets none of the three: it has no natural per-rule URL, no single-advisory description, and no per-advisory severity to report.
Each result also carries a partialFingerprints entry (collect_result_contexts, issue
#1077) derived from (manifest path, percent-encoded dependency identity, percent-encoded
rule id, an occurrence ordinal) — deliberately excluding the finding’s range, so an
unrelated line shift elsewhere in the manifest does not change it and make GitHub treat an
existing alert as new. See that function’s doc for why percent-encoding and the ordinal are
both necessary (issue #1077 S2 review: a raw | join can collide across components, and
same-manifest/same-dependency/same-rule findings — e.g. one package declared in both
[dependencies] and [dev-dependencies] — would otherwise collapse onto one fingerprint).
run.automationDetails.id (automation_id, issue #1077) disambiguates repeated SARIF
uploads for the same commit — see that function’s doc for the category/run-id split GitHub
expects it to follow.