govulncheck.go (9384B)
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 govulncheck contains the JSON output structs for govulncheck. 6 // 7 // govulncheck supports streaming JSON by emitting a series of Message 8 // objects as it analyzes user code and discovers vulnerabilities. 9 // Streaming JSON is useful for displaying progress in real-time for 10 // large projects where govulncheck execution might take some time. 11 // 12 // govulncheck JSON emits configuration used to perform the analysis, 13 // a user-friendly message about what is being analyzed, and the 14 // vulnerability findings. Findings for the same vulnerability can 15 // can be emitted several times. For instance, govulncheck JSON will 16 // emit a finding when it sees that a vulnerable module is required 17 // before proceeding to check if the vulnerability is imported or called. 18 // Please see documentation on Message and related types for precise 19 // details on the stream encoding. 20 // 21 // There are no guarantees on the order of messages. The pattern of emitted 22 // messages can change in the future. Clients can follow code in handler.go 23 // for consuming the streaming JSON programmatically. 24 package govulncheck 25 26 import ( 27 "time" 28 29 "golang.org/x/vuln/internal/osv" 30 ) 31 32 const ( 33 // ProtocolVersion is the current protocol version this file implements 34 ProtocolVersion = "v1.0.0" 35 ) 36 37 // Message is an entry in the output stream. It will always have exactly one 38 // field filled in. 39 type Message struct { 40 Config *Config `json:"config,omitempty"` 41 Progress *Progress `json:"progress,omitempty"` 42 SBOM *SBOM `json:"SBOM,omitempty"` 43 // OSV is emitted for every vulnerability in the current database 44 // that applies to user modules regardless of their version. If a 45 // module is being used at a vulnerable version, the corresponding 46 // OSV will be referenced in Findings depending on the type of usage 47 // and the desired scan level. 48 OSV *osv.Entry `json:"osv,omitempty"` 49 Finding *Finding `json:"finding,omitempty"` 50 } 51 52 // Config must occur as the first message of a stream and informs the client 53 // about the information used to generate the findings. 54 // The only required field is the protocol version. 55 type Config struct { 56 // ProtocolVersion specifies the version of the JSON protocol. 57 ProtocolVersion string `json:"protocol_version"` 58 59 // ScannerName is the name of the tool, for example, govulncheck. 60 // 61 // We expect this JSON format to be used by other tools that wrap 62 // govulncheck, which will have a different name. 63 ScannerName string `json:"scanner_name,omitempty"` 64 65 // ScannerVersion is the version of the tool. 66 ScannerVersion string `json:"scanner_version,omitempty"` 67 68 // DB is the database used by the tool, for example, 69 // vuln.go.dev. 70 DB string `json:"db,omitempty"` 71 72 // LastModified is the last modified time of the data source. 73 DBLastModified *time.Time `json:"db_last_modified,omitempty"` 74 75 // GoVersion is the version of Go used for analyzing standard library 76 // vulnerabilities. 77 GoVersion string `json:"go_version,omitempty"` 78 79 // ScanLevel instructs govulncheck to analyze at a specific level of detail. 80 // Valid values include module, package and symbol. 81 ScanLevel ScanLevel `json:"scan_level,omitempty"` 82 83 // ScanMode instructs govulncheck how to interpret the input and 84 // what to do with it. Valid values are source, binary, query, 85 // and extract. 86 ScanMode ScanMode `json:"scan_mode,omitempty"` 87 } 88 89 // SBOM contains minimal information about the artifacts govulncheck is scanning. 90 type SBOM struct { 91 // The go version used by govulncheck when scanning, which also defines 92 // the version of the standard library used for detecting vulns. 93 GoVersion string `json:"go_version,omitempty"` 94 95 // The set of modules included in the scan. 96 Modules []*Module `json:"modules,omitempty"` 97 98 // The roots of the scan, as package paths. 99 // For binaries, this will be the main package. 100 // For source code, this will be the packages matching the provided package patterns. 101 Roots []string `json:"roots,omitempty"` 102 } 103 104 type Module struct { 105 // The full module path. 106 Path string `json:"path,omitempty"` 107 108 // The version of the module. 109 Version string `json:"version,omitempty"` 110 } 111 112 // Progress messages are informational only, intended to allow users to monitor 113 // the progress of a long running scan. 114 // A stream must remain fully valid and able to be interpreted with all progress 115 // messages removed. 116 type Progress struct { 117 // A time stamp for the message. 118 Timestamp *time.Time `json:"time,omitempty"` 119 120 // Message is the progress message. 121 Message string `json:"message,omitempty"` 122 } 123 124 // Finding contains information on a discovered vulnerability. Each vulnerability 125 // will likely have multiple findings in JSON mode. This is because govulncheck 126 // emits findings as it does work, and therefore could emit one module level, 127 // one package level, and potentially multiple symbol level findings depending 128 // on scan level. 129 // Multiple symbol level findings can be emitted when multiple symbols of the 130 // same vuln are called or govulncheck decides to show multiple traces for the 131 // same symbol. 132 type Finding struct { 133 // OSV is the id of the detected vulnerability. 134 OSV string `json:"osv,omitempty"` 135 136 // FixedVersion is the module version where the vulnerability was 137 // fixed. This is empty if a fix is not available. 138 // 139 // If there are multiple fixed versions in the OSV report, this will 140 // be the fixed version in the latest range event for the OSV report. 141 // 142 // For example, if the range events are 143 // {introduced: 0, fixed: 1.0.0} and {introduced: 1.1.0}, the fixed version 144 // will be empty. 145 // 146 // For the stdlib, we will show the fixed version closest to the 147 // Go version that is used. For example, if a fix is available in 1.17.5 and 148 // 1.18.5, and the GOVERSION is 1.17.3, 1.17.5 will be returned as the 149 // fixed version. 150 FixedVersion string `json:"fixed_version,omitempty"` 151 152 // Trace contains an entry for each frame in the trace. 153 // 154 // Frames are sorted starting from the imported vulnerable symbol 155 // until the entry point. The first frame in Frames should match 156 // Symbol. 157 // 158 // In binary mode, trace will contain a single-frame with no position 159 // information. 160 // 161 // For module level source findings, the trace will contain a single-frame 162 // with no symbol, position, or package information. For package level source 163 // findings, the trace will contain a single-frame with no symbol or position 164 // information. 165 Trace []*Frame `json:"trace,omitempty"` 166 } 167 168 // Frame represents an entry in a finding trace. 169 type Frame struct { 170 // Module is the module path of the module containing this symbol. 171 // 172 // Importable packages in the standard library will have the path "stdlib". 173 Module string `json:"module"` 174 175 // Version is the module version from the build graph. 176 Version string `json:"version,omitempty"` 177 178 // Package is the import path. 179 Package string `json:"package,omitempty"` 180 181 // Function is the function name. 182 Function string `json:"function,omitempty"` 183 184 // Receiver is the receiver type if the called symbol is a method. 185 // 186 // The client can create the final symbol name by 187 // prepending Receiver to FuncName. 188 Receiver string `json:"receiver,omitempty"` 189 190 // Position describes an arbitrary source position 191 // including the file, line, and column location. 192 // A Position is valid if the line number is > 0. 193 // 194 // The filenames are relative to the directory of 195 // the enclosing module and always use "/" for 196 // portability. 197 Position *Position `json:"position,omitempty"` 198 } 199 200 // Position represents arbitrary source position. 201 type Position struct { 202 Filename string `json:"filename,omitempty"` // filename, if any 203 Offset int `json:"offset"` // byte offset, starting at 0 204 Line int `json:"line"` // line number, starting at 1 205 Column int `json:"column"` // column number, starting at 1 (byte count) 206 } 207 208 // ScanLevel represents the detail level at which a scan occurred. 209 // This can be necessary to correctly interpret the findings, for instance if 210 // a scan is at symbol level and a finding does not have a symbol it means the 211 // vulnerability was imported but not called. If the scan however was at 212 // "package" level, that determination cannot be made. 213 type ScanLevel string 214 215 const ( 216 ScanLevelModule = "module" 217 ScanLevelPackage = "package" 218 ScanLevelSymbol = "symbol" 219 ) 220 221 // WantSymbols can be used to check whether the scan level is one that is able 222 // to generate symbol-level findings. 223 func (l ScanLevel) WantSymbols() bool { return l == ScanLevelSymbol } 224 225 // WantPackages can be used to check whether the scan level is one that is able 226 // to generate package-level findings. 227 func (l ScanLevel) WantPackages() bool { return l == ScanLevelPackage || l == ScanLevelSymbol } 228 229 // ScanMode represents the mode in which a scan occurred. This can 230 // be necessary to correctly to interpret findings. For instance, 231 // a binary can be checked for vulnerabilities or the user just wants 232 // to extract minimal data necessary for the vulnerability check. 233 type ScanMode string 234 235 const ( 236 ScanModeSource = "source" 237 ScanModeBinary = "binary" 238 ScanModeConvert = "convert" 239 ScanModeQuery = "query" 240 ScanModeExtract = "extract" // currently, only binary extraction is supported 241 )