Documentation
¶
Overview ¶
Package export builds deterministic SARIF 2.1.0 + OpenVEX documents from stored findings. Templated from data – no LLM in the report path.
Index ¶
- func MarshalSARIF(findings []finding.Finding, version string, opts SARIFOptions) ([]byte, error)
- type CSAFDoc
- type CSAFDocument
- type CSAFEngine
- type CSAFFlag
- type CSAFGenerator
- type CSAFProductName
- type CSAFProductStatus
- type CSAFProductTree
- type CSAFPublisher
- type CSAFRevision
- type CSAFTracking
- type CSAFVulnID
- type CSAFVulnerability
- type ReachabilityEvidence
- type ReachabilityLabel
- type SARIFArtifactLocation
- type SARIFCodeFlow
- type SARIFConfig
- type SARIFDriver
- type SARIFLocation
- type SARIFLog
- type SARIFLogicalLocation
- type SARIFMultiformatText
- type SARIFOptions
- type SARIFPhysicalLocation
- type SARIFRegion
- type SARIFResult
- type SARIFRule
- type SARIFRuleMeta
- type SARIFRun
- type SARIFSuppression
- type SARIFText
- type SARIFThreadFlow
- type SARIFThreadFlowLocation
- type SARIFTool
- type Service
- func (s *Service) CSAFVEX(ctx context.Context, engagementID shared.ID) (*CSAFDoc, error)
- func (s *Service) OpenVEX(ctx context.Context, engagementID shared.ID, supersedes string) (*VEXDoc, error)
- func (s *Service) SARIF(ctx context.Context, engagementID shared.ID) (*SARIFLog, error)
- func (s *Service) SetAIGateExemptions(reader ports.AIGateExemptionReader)
- func (s *Service) SetJudgments(j judgmentReader)
- type VEXDoc
- type VEXDocRef
- type VEXProduct
- type VEXStatement
- type VEXVuln
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MarshalSARIF ¶
MarshalSARIF renders findings as an indented SARIF 2.1.0 log – the artifact a code-scanning uploader (e.g. GitHub `codeql-action/upload-sarif`) consumes. It is deterministic and templated purely from stored findings: no clock, no LLM (golden rule 5). version is the synapse driver version recorded on the run's tool driver. opts carries optional per-finding resolvers: Manifest gives SCA findings a physical location (a repo-relative manifest path), Fix adds the remediating version, and AIGateExemption explains policy-authorized external suppression without removing the result. All are nil-safe; pass the zero SARIFOptions to enrich nothing.
Types ¶
type CSAFDoc ¶ added in v0.2.0
type CSAFDoc struct {
Document CSAFDocument `json:"document"`
// product_tree and vulnerabilities are omitted when empty rather than emitted as `[]`, which CSAF
// rejects (its arrays must be non-empty when present).
ProductTree *CSAFProductTree `json:"product_tree,omitempty"`
Vulnerabilities []CSAFVulnerability `json:"vulnerabilities,omitempty"`
}
type CSAFDocument ¶ added in v0.2.0
type CSAFDocument struct {
Category string `json:"category"`
CSAFVersion string `json:"csaf_version"`
Publisher CSAFPublisher `json:"publisher"`
Title string `json:"title"`
Tracking CSAFTracking `json:"tracking"`
}
type CSAFEngine ¶ added in v0.2.0
type CSAFGenerator ¶ added in v0.2.0
type CSAFGenerator struct {
Engine CSAFEngine `json:"engine"`
}
type CSAFProductName ¶ added in v0.2.0
type CSAFProductStatus ¶ added in v0.2.0
type CSAFProductTree ¶ added in v0.2.0
type CSAFProductTree struct {
FullProductNames []CSAFProductName `json:"full_product_names"`
}
type CSAFPublisher ¶ added in v0.2.0
type CSAFRevision ¶ added in v0.2.0
type CSAFTracking ¶ added in v0.2.0
type CSAFTracking struct {
ID string `json:"id"`
Status string `json:"status"`
Version string `json:"version"`
InitialReleaseDate string `json:"initial_release_date"`
CurrentReleaseDate string `json:"current_release_date"`
Generator CSAFGenerator `json:"generator"`
RevisionHistory []CSAFRevision `json:"revision_history"`
}
type CSAFVulnID ¶ added in v0.2.0
type CSAFVulnerability ¶ added in v0.2.0
type CSAFVulnerability struct {
CVE string `json:"cve,omitempty"`
IDs []CSAFVulnID `json:"ids,omitempty"`
Flags []CSAFFlag `json:"flags,omitempty"`
ProductStatus CSAFProductStatus `json:"product_status"`
}
type ReachabilityEvidence ¶ added in v0.2.0
type ReachabilityEvidence struct {
Source string `json:"source"` // always "reachability"
Label ReachabilityLabel `json:"label"`
Tier judgment.ReachabilityTier `json:"tier,omitempty"`
Path []string `json:"path,omitempty"`
}
ReachabilityEvidence is the tagged evidence item a finding renders for its reachability posture, adopting the Snyk evidence[] contract (source-tagged evidence beside the dependency path). Source is always "reachability"; Label is the derived four-state label; Tier is the proving tier when a judgment decided it; Path is the call/exploit path from the winning claim (empty when none / not reachable).
func DeriveReachabilityEvidence ¶ added in v0.2.0
func DeriveReachabilityEvidence(judgments []judgment.Judgment, findingID string) *ReachabilityEvidence
DeriveReachabilityEvidence derives a finding's reachability evidence from its PUBLISHABLE, finding-scoped reachability judgments (the same publishability gate the VEX path uses). It selects the winning claim with the shared state-aware ordering (judgment.ReachabilityClaim.Supersedes, EPIC #1042 A-CORE), so an unproven negative never shadows a reachable, then maps it to a derived label:
- a winning REACHABLE claim -> reachable (with its call path);
- a winning proven not_reachable (SuppressesFinding) -> present_unreached;
- a winning inconclusive claim, or NO reachability judgment at all -> no_analysis.
It never mints conditionally_reachable (reserved for the conditional engine). It ALWAYS returns a non-nil evidence item so every finding carries an explicit reachability posture (no_analysis when nothing conclusive ran), never a silently-absent one. Deriving at the surface keeps the domain verdict enum unchanged.
type ReachabilityLabel ¶ added in v0.2.0
type ReachabilityLabel string
ReachabilityLabel is the closed, user-visible reachability vocabulary rendered as a tagged evidence item (EPIC #1042, 0.2). It is DERIVED at the surface from a finding's reachability judgments; it is not a domain verdict and does not change the ReachabilityState enum (which stays reachable|not_reachable| unknown). The wire values match the reachbench label vocabulary so the benchmark and the public export speak one contract, and the OpenAPI enum is the authoritative public schema.
const ( // LabelReachable: a PUBLISHABLE reachable judgment (any tier) is the winning claim. The vulnerable code // is reached; the call/exploit path is carried alongside. LabelReachable ReachabilityLabel = "reachable" // LabelConditionallyReachable: reachable only under a precondition (a taint label / guard). Reserved for // the conditional-reachability engine; not emitted until that lands. LabelConditionallyReachable ReachabilityLabel = "conditionally_reachable" // LabelPresentUnreached: a SOUND proof of non-reachability (SuppressesFinding). The vulnerable code is // present in a matched dependency but proven not reached. LabelPresentUnreached ReachabilityLabel = "present_unreached" // LabelNoAnalysis: no conclusive reachability analysis for this finding, either because no reachability // judgment exists or the strongest one is inconclusive (unknown / unproven). Distinct from // present_unreached: absence of analysis is never reported as a proven-unreached result. LabelNoAnalysis ReachabilityLabel = "no_analysis" )
type SARIFArtifactLocation ¶
type SARIFArtifactLocation struct {
URI string `json:"uri"` // repo-relative path (GitHub matches it against the PR diff)
}
type SARIFCodeFlow ¶ added in v0.2.0
type SARIFCodeFlow struct {
ThreadFlows []SARIFThreadFlow `json:"threadFlows"`
}
type SARIFConfig ¶
type SARIFConfig struct {
Level string `json:"level"`
}
type SARIFDriver ¶
type SARIFLocation ¶
type SARIFLocation struct {
// A first-party finding (SAST/secret/misconfig) has a source file:line -> physicalLocation, so a
// code-scanning UI annotates the exact line. An SCA finding is about a dependency, not a source
// line -> logicalLocation module. Exactly one is set per location.
PhysicalLocation *SARIFPhysicalLocation `json:"physicalLocation,omitempty"`
LogicalLocations []SARIFLogicalLocation `json:"logicalLocations,omitempty"`
}
type SARIFLogicalLocation ¶
type SARIFMultiformatText ¶ added in v0.2.2
type SARIFMultiformatText struct {
Text string `json:"text"`
Markdown string `json:"markdown,omitempty"`
}
SARIFMultiformatText is SARIF's multiformatMessageString. GitHub renders the markdown variant.
type SARIFOptions ¶
type SARIFOptions struct {
// Manifest returns the repo-relative manifest/lockfile that declares a dependency finding's
// component, so the result gets a physical location a code-scanning UI can annotate. "" when unknown.
Manifest func(finding.Finding) string
// Fix returns the version that remediates a dependency finding. "" when there is no fix or it is unknown.
Fix func(finding.Finding) string
// AIGateExemption returns policy metadata only when the finding's exemption has already passed the
// server-owned authorization re-check. SARIF renders it as an external accepted suppression while
// retaining the result. Advisory or review-required opinions must return false.
AIGateExemption func(finding.Finding) (ports.AIGateExemption, bool)
// RuleMeta returns the catalog entry for a rule id. Without it a result carries only an id, a title
// and a level, which is what made the output hard to act on: no rule link, no rationale, no fix.
// Returning false leaves the rule with just the fields derived from the finding.
RuleMeta func(ruleID string) (SARIFRuleMeta, bool)
}
SARIFOptions carries optional per-finding resolvers. Every field is nil-safe.
type SARIFPhysicalLocation ¶
type SARIFPhysicalLocation struct {
ArtifactLocation SARIFArtifactLocation `json:"artifactLocation"`
Region *SARIFRegion `json:"region,omitempty"`
}
type SARIFRegion ¶
type SARIFResult ¶
type SARIFResult struct {
RuleID string `json:"ruleId"`
Level string `json:"level"`
Message SARIFText `json:"message"`
Locations []SARIFLocation `json:"locations,omitempty"`
CodeFlows []SARIFCodeFlow `json:"codeFlows,omitempty"`
Suppressions []SARIFSuppression `json:"suppressions,omitempty"`
Properties map[string]any `json:"properties,omitempty"`
}
type SARIFRule ¶
type SARIFRule struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
ShortDescription SARIFText `json:"shortDescription"`
FullDescription *SARIFText `json:"fullDescription,omitempty"`
// Help is what a code-scanning UI shows when a reader opens the alert, so the remediation goes here
// rather than only in the message.
Help *SARIFMultiformatText `json:"help,omitempty"`
HelpURI string `json:"helpUri,omitempty"`
DefaultConfiguration *SARIFConfig `json:"defaultConfiguration,omitempty"`
Properties map[string]any `json:"properties,omitempty"`
}
type SARIFRuleMeta ¶ added in v0.2.2
type SARIFRuleMeta struct {
Name string // catalog name, when it is more precise than the finding title
Description string // what the rule checks -> fullDescription
Rationale string // why it matters -> help
Remediation string // how to fix it -> help
HelpURI string // a page that resolves today -> helpUri
Tags []string // language / category tags -> properties.tags
CWE []string
OWASP []string
Precision string // "high" | "medium" | "low", when the catalog states it
}
SARIFRuleMeta is the published catalog metadata for one rule. It fills in the fields that tell a reader what the rule checks, why it matters, and how to fix it, which a bare id and title do not.
type SARIFRun ¶
type SARIFRun struct {
Tool SARIFTool `json:"tool"`
Results []SARIFResult `json:"results"`
}
type SARIFSuppression ¶ added in v0.1.8
type SARIFThreadFlow ¶ added in v0.2.0
type SARIFThreadFlow struct {
Locations []SARIFThreadFlowLocation `json:"locations"`
}
type SARIFThreadFlowLocation ¶ added in v0.2.0
type SARIFThreadFlowLocation struct {
Location SARIFLocation `json:"location"`
}
type SARIFTool ¶
type SARIFTool struct {
Driver SARIFDriver `json:"driver"`
}
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service renders an engagement's findings as SARIF or OpenVEX.
func NewService ¶
NewService wires the export use case.
func (*Service) CSAFVEX ¶ added in v0.2.0
CSAFVEX returns the same publishable findings as a CSAF 2.0 VEX document, the enterprise-standard companion to OpenVEX. It asserts exactly what OpenVEX asserts, reshaped into CSAF's product-tree + per-vulnerability product-status model.
func (*Service) OpenVEX ¶
func (s *Service) OpenVEX(ctx context.Context, engagementID shared.ID, supersedes string) (*VEXDoc, error)
OpenVEX returns the engagement's vulnerability findings as an OpenVEX 0.2 document. It reads through the publishability gate – consistent with SARIF and the report path – so an unproven exploitation finding is never asserted in a VEX statement. supersedes, when non-empty, is the @id of a prior document this one replaces (the caller who re-exports knows it); the document's own @id is content-addressed, so an unchanged re-export is idempotent.
func (*Service) SARIF ¶
SARIF returns the engagement's findings as a SARIF 2.1.0 log. It reads through the publishability gate so an unproven exploitation finding never ships in the exported log.
func (*Service) SetAIGateExemptions ¶ added in v0.1.8
func (s *Service) SetAIGateExemptions(reader ports.AIGateExemptionReader)
SetAIGateExemptions wires the latest-scan policy projection used to annotate retained SARIF results. nil keeps legacy exports unannotated.
func (*Service) SetJudgments ¶
func (s *Service) SetJudgments(j judgmentReader)
SetJudgments wires the reachability-judgment reader so OpenVEX picks the not_affected justification by reachability tier. nil ⇒ the default justification.
type VEXDoc ¶
type VEXDoc struct {
Context string `json:"@context"`
ID string `json:"@id"`
Author string `json:"author"`
Timestamp string `json:"timestamp"`
Version int `json:"version"`
Tooling string `json:"tooling,omitempty"`
Supersedes []VEXDocRef `json:"supersedes,omitempty"`
Statements []VEXStatement `json:"statements"`
}
type VEXDocRef ¶ added in v0.2.0
type VEXDocRef struct {
ID string `json:"@id"`
}
VEXDocRef references a prior document this one supersedes.
type VEXProduct ¶
type VEXProduct struct {
ID string `json:"@id"`
}
type VEXStatement ¶
type VEXStatement struct {
Vulnerability VEXVuln `json:"vulnerability"`
Products []VEXProduct `json:"products"`
Status string `json:"status"`
Justification string `json:"justification,omitempty"`
// Timestamp is the per-statement assertion time (when the finding's status was last evaluated). Per the
// OpenVEX spec a statement without one inherits the document timestamp; emitting it explicitly lets a
// consumer age each assertion independently.
Timestamp string `json:"timestamp,omitempty"`
}