diff --git a/docs/release-notes.md b/docs/release-notes.md index fd775774..ff99e6c5 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,7 +9,10 @@ of `zizmor`. ## Next (UNRELEASED) -Nothing yet! +### Improvements 🌱 + +* SARIF outputs are now slightly more aligned with GitHub Code Scanning + expectations (#528) ## v1.3.1 diff --git a/src/finding/mod.rs b/src/finding/mod.rs index b9a3b6b2..326ff298 100644 --- a/src/finding/mod.rs +++ b/src/finding/mod.rs @@ -393,6 +393,18 @@ pub(crate) struct Finding<'w> { pub(crate) ignored: bool, } +impl Finding<'_> { + /// A basic Markdown representation of the finding's metadata. + pub(crate) fn to_markdown(&self) -> String { + format!( + "`{ident}`: {desc}\n\nDocs: <{url}>", + ident = self.ident, + desc = self.desc, + url = self.url + ) + } +} + pub(crate) struct FindingBuilder<'w> { ident: &'static str, desc: &'static str, diff --git a/src/sarif.rs b/src/sarif.rs index 6fa5f2d5..b1e5530d 100644 --- a/src/sarif.rs +++ b/src/sarif.rs @@ -4,8 +4,8 @@ use std::collections::HashSet; use serde_sarif::sarif::{ ArtifactContent, ArtifactLocation, Location as SarifLocation, LogicalLocation, Message, - PhysicalLocation, PropertyBag, Region, ReportingDescriptor, Result as SarifResult, ResultKind, - ResultLevel, Run, Sarif, Tool, ToolComponent, + MultiformatMessageString, PhysicalLocation, PropertyBag, Region, ReportingDescriptor, + Result as SarifResult, ResultKind, ResultLevel, Run, Sarif, Tool, ToolComponent, }; use crate::finding::{Finding, Location, Severity}; @@ -78,6 +78,12 @@ fn build_rule(finding: &Finding) -> ReportingDescriptor { ReportingDescriptor::builder() .id(finding.ident) .help_uri(finding.url) + .help( + MultiformatMessageString::builder() + .text(finding.desc) + .markdown(finding.to_markdown()) + .build(), + ) .build() } @@ -86,12 +92,25 @@ fn build_results(findings: &[Finding]) -> Vec { } fn build_result(finding: &Finding<'_>) -> SarifResult { + // NOTE: Safe unwrap because FindingBuilder::build ensures a primary location. + let primary = finding + .locations + .iter() + .find(|l| l.symbolic.primary) + .unwrap(); + SarifResult::builder() - .message(finding.desc) .rule_id(finding.ident) - .locations(build_locations( - finding.locations.iter().filter(|l| l.symbolic.primary), - )) + // NOTE: We use the primary location's annotation for the result's message. + // This is conceptually incorrect since the location's annotation should + // only be on the location itself. However, GitHub's SARIF viewer does not + // render location-level messages, so we use the primary location's message + // to ensure something reasonable is presented. + // This ends up being OK since the only other thing we'd put here + // is the finding's description, which is already in the rule's help message. + // See https://github.com/woodruffw/zizmor/issues/526 for context. + .message(&primary.symbolic.annotation) + .locations(build_locations(std::iter::once(primary))) .related_locations(build_locations( finding.locations.iter().filter(|l| !l.symbolic.primary), ))