src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

sarif.go (8547B)


      1 // Copyright 2023 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Package sarif defines Static Analysis Results Interchange Format
      6 // (SARIF) types supported by govulncheck.
      7 //
      8 // The implementation covers the subset of the specification available
      9 // at https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=sarif.
     10 //
     11 // The sarif encoding models govulncheck findings as Results. Each
     12 // Result encodes findings for a unique OSV entry at the most precise
     13 // detected level only. CodeFlows summarize call stacks, similar to govulncheck
     14 // textual output, while Stacks contain call stack information verbatim.
     15 //
     16 // The result Levels are defined by the govulncheck.ScanLevel and the most
     17 // precise level at which the finding was detected. Result error is produced
     18 // when the finding level matches the user desired level of scan precision;
     19 // all other finding levels are then classified as progressively weaker.
     20 // For instance, if the user specified symbol scan level and govulncheck
     21 // detected a use of a vulnerable symbol, then the Result will have error
     22 // Level. If the symbol was not used but its package was imported, then the
     23 // Result Level is warning, and so on.
     24 //
     25 // Each Result is attached to the first line of the go.mod file. Other
     26 // ArtifactLocations are paths relative to their enclosing modules.
     27 // Similar to JSON output format, this makes govulncheck sarif locations
     28 // portable.
     29 //
     30 // The relative paths in PhysicalLocations also come with a URIBaseID offset.
     31 // Paths for the source module analyzed, the Go standard library, and third-party
     32 // dependencies are relative to %SRCROOT%, %GOROOT%, and %GOMODCACHE% offsets,
     33 // resp. We note that the URIBaseID offsets are not explicitly defined in
     34 // the sarif output. It is the clients responsibility to set them to resolve
     35 // paths at their local machines.
     36 //
     37 // All paths use "/" delimiter for portability.
     38 //
     39 // Properties field of a Tool.Driver is a govulncheck.Config used for the
     40 // invocation of govulncheck producing the Results. Properties field of
     41 // a Rule contains information on CVE and GHSA aliases for the corresponding
     42 // rule OSV. Clients can use this information to, say, suppress and filter
     43 // vulnerabilities.
     44 //
     45 // Please see the definition of types below for more information.
     46 package sarif
     47 
     48 import "golang.org/x/vuln/internal/govulncheck"
     49 
     50 // Log is the top-level SARIF object encoded in UTF-8.
     51 type Log struct {
     52 	// Version should always be "2.1.0"
     53 	Version string `json:"version,omitempty"`
     54 
     55 	// Schema should always be "https://json.schemastore.org/sarif-2.1.0.json"
     56 	Schema string `json:"$schema,omitempty"`
     57 
     58 	// Runs describes executions of static analysis tools. For govulncheck,
     59 	// there will be only one run object.
     60 	Runs []Run `json:"runs,omitempty"`
     61 }
     62 
     63 // Run summarizes results of a single invocation of a static analysis tool,
     64 // in this case govulncheck.
     65 type Run struct {
     66 	Tool Tool `json:"tool,omitempty"`
     67 	// Results contain govulncheck findings. There should be exactly one
     68 	// Result per a detected use of an OSV.
     69 	Results []Result `json:"results"`
     70 }
     71 
     72 // Tool captures information about govulncheck analysis that was run.
     73 type Tool struct {
     74 	Driver Driver `json:"driver,omitempty"`
     75 }
     76 
     77 // Driver provides details about the govulncheck binary being executed.
     78 type Driver struct {
     79 	// Name is "govulncheck"
     80 	Name string `json:"name,omitempty"`
     81 	// Version is the govulncheck version
     82 	Version string `json:"semanticVersion,omitempty"`
     83 	// InformationURI points to the description of govulncheck tool
     84 	InformationURI string `json:"informationUri,omitempty"`
     85 	// Properties are govulncheck run metadata, such as vuln db, Go version, etc.
     86 	Properties govulncheck.Config `json:"properties,omitempty"`
     87 
     88 	Rules []Rule `json:"rules"`
     89 }
     90 
     91 // Rule corresponds to the static analysis rule/analyzer that
     92 // produces findings. For govulncheck, rules are OSVs.
     93 type Rule struct {
     94 	// ID is OSV.ID
     95 	ID               string      `json:"id,omitempty"`
     96 	ShortDescription Description `json:"shortDescription,omitempty"`
     97 	FullDescription  Description `json:"fullDescription,omitempty"`
     98 	Help             Description `json:"help,omitempty"`
     99 	HelpURI          string      `json:"helpUri,omitempty"`
    100 	// Properties contain OSV.Aliases (CVEs and GHSAs) as tags.
    101 	// Consumers of govulncheck SARIF can use these tags to filter
    102 	// results.
    103 	Properties RuleTags `json:"properties,omitempty"`
    104 }
    105 
    106 // RuleTags defines properties.tags.
    107 type RuleTags struct {
    108 	Tags []string `json:"tags"`
    109 }
    110 
    111 // Description is a text in its raw or markdown form.
    112 type Description struct {
    113 	Text     string `json:"text,omitempty"`
    114 	Markdown string `json:"markdown,omitempty"`
    115 }
    116 
    117 // Result is a set of govulncheck findings for an OSV. For call stack
    118 // mode, it will contain call stacks for the OSV. There is exactly
    119 // one Result per detected OSV. Only findings at the most precise
    120 // detected level appear in the Result. For instance, if there are
    121 // symbol findings for an OSV, those findings will be in the Result,
    122 // but not the package and module level findings for the same OSV.
    123 type Result struct {
    124 	// RuleID is the Rule.ID/OSV producing the finding.
    125 	RuleID string `json:"ruleId,omitempty"`
    126 	// Level is one of "error", "warning", and "note".
    127 	Level string `json:"level,omitempty"`
    128 	// Message explains the overall findings.
    129 	Message Description `json:"message,omitempty"`
    130 	// Locations to which the findings are associated. Always
    131 	// a single location pointing to the first line of the go.mod
    132 	// file. The path to the file is "go.mod".
    133 	Locations []Location `json:"locations,omitempty"`
    134 	// CodeFlows summarize call stacks produced by govulncheck.
    135 	CodeFlows []CodeFlow `json:"codeFlows,omitempty"`
    136 	// Stacks encode call stacks produced by govulncheck.
    137 	Stacks []Stack `json:"stacks,omitempty"`
    138 }
    139 
    140 // CodeFlow summarizes a detected offending flow of information in terms of
    141 // code locations. More precisely, it can contain several related information
    142 // flows, keeping them together. In govulncheck, those can be all call stacks
    143 // for, say, a particular symbol or package.
    144 type CodeFlow struct {
    145 	// ThreadFlows is effectively a set of related information flows.
    146 	ThreadFlows []ThreadFlow `json:"threadFlows"`
    147 	Message     Description  `json:"message,omitempty"`
    148 }
    149 
    150 // ThreadFlow encodes an information flow as a sequence of locations.
    151 // For govulncheck, it can encode a call stack.
    152 type ThreadFlow struct {
    153 	Locations []ThreadFlowLocation `json:"locations,omitempty"`
    154 }
    155 
    156 type ThreadFlowLocation struct {
    157 	// Module is module information in the form <module-path>@<version>.
    158 	// <version> can be empty when the module version is not known as
    159 	// with, say, the source module analyzed.
    160 	Module string `json:"module,omitempty"`
    161 	// Location also contains a Message field.
    162 	Location Location `json:"location,omitempty"`
    163 }
    164 
    165 // Stack is a sequence of frames and can encode a govulncheck call stack.
    166 type Stack struct {
    167 	Message Description `json:"message,omitempty"`
    168 	Frames  []Frame     `json:"frames"`
    169 }
    170 
    171 // Frame is effectively a module location. It can also contain thread and
    172 // parameter info, but those are not needed for govulncheck.
    173 type Frame struct {
    174 	// Module is module information in the form <module-path>@<version>.
    175 	// <version> can be empty when the module version is not known as
    176 	// with, say, the source module analyzed.
    177 	Module   string   `json:"module,omitempty"`
    178 	Location Location `json:"location,omitempty"`
    179 }
    180 
    181 // Location is currently a physical location annotated with a message.
    182 type Location struct {
    183 	PhysicalLocation PhysicalLocation `json:"physicalLocation,omitempty"`
    184 	Message          Description      `json:"message,omitempty"`
    185 }
    186 
    187 type PhysicalLocation struct {
    188 	ArtifactLocation ArtifactLocation `json:"artifactLocation,omitempty"`
    189 	Region           Region           `json:"region,omitempty"`
    190 }
    191 
    192 const (
    193 	SrcRootID    = "%SRCROOT%"
    194 	GoRootID     = "%GOROOT%"
    195 	GoModCacheID = "%GOMODCACHE%"
    196 )
    197 
    198 // ArtifactLocation is a path to an offending file.
    199 type ArtifactLocation struct {
    200 	// URI is a path relative to URIBaseID.
    201 	URI string `json:"uri,omitempty"`
    202 	// URIBaseID is offset for URI, one of %SRCROOT%, %GOROOT%,
    203 	// and %GOMODCACHE%.
    204 	URIBaseID string `json:"uriBaseId,omitempty"`
    205 }
    206 
    207 // Region is a target region within a file.
    208 type Region struct {
    209 	StartLine   int `json:"startLine,omitempty"`
    210 	StartColumn int `json:"startColumn,omitempty"`
    211 	EndLine     int `json:"endLine,omitempty"`
    212 	EndColumn   int `json:"endColumn,omitempty"`
    213 }