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 }