| // Copyright 2023 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package govulncheck contains the JSON output structs for govulncheck. |
| // |
| // govulncheck supports streaming JSON by emitting a series of Message |
| // objects as it analyzes user code and discovers vulnerabilities. |
| // Streaming JSON is useful for displaying progress in real-time for |
| // large projects where govulncheck execution might take some time. |
| // |
| // govulncheck JSON emits configuration used to perform the analysis, |
| // a user-friendly message about what is being analyzed, and the |
| // vulnerability findings. Findings for the same vulnerability can |
| // can be emitted several times. For instance, govulncheck JSON will |
| // emit a finding when it sees that a vulnerable module is required |
| // before proceeding to check if the vulnerability is imported or called. |
| // Please see documentation on Message and related types for precise |
| // details on the stream encoding. |
| // |
| // There are no guarantees on the order of messages. The pattern of emitted |
| // messages can change in the future. Clients can follow code in handler.go |
| // for consuming the streaming JSON programmatically. |
| package govulncheck |
| |
| import ( |
| "time" |
| |
| "golang.org/x/vuln/internal/osv" |
| ) |
| |
| const ( |
| // ProtocolVersion is the current protocol version this file implements |
| ProtocolVersion = "v1.0.0" |
| ) |
| |
| // Message is an entry in the output stream. It will always have exactly one |
| // field filled in. |
| type Message struct { |
| Config *Config `json:"config,omitempty"` |
| Progress *Progress `json:"progress,omitempty"` |
| // OSV is emitted for every vulnerability in the current database |
| // that applies to user modules regardless of their version. If a |
| // module is being used at a vulnerable version, the corresponding |
| // OSV will be referenced in Findings depending on the type of usage |
| // and the desired scan level. |
| OSV *osv.Entry `json:"osv,omitempty"` |
| Finding *Finding `json:"finding,omitempty"` |
| } |
| |
| // Config must occur as the first message of a stream and informs the client |
| // about the information used to generate the findings. |
| // The only required field is the protocol version. |
| type Config struct { |
| // ProtocolVersion specifies the version of the JSON protocol. |
| ProtocolVersion string `json:"protocol_version"` |
| |
| // ScannerName is the name of the tool, for example, govulncheck. |
| // |
| // We expect this JSON format to be used by other tools that wrap |
| // govulncheck, which will have a different name. |
| ScannerName string `json:"scanner_name,omitempty"` |
| |
| // ScannerVersion is the version of the tool. |
| ScannerVersion string `json:"scanner_version,omitempty"` |
| |
| // DB is the database used by the tool, for example, |
| // vuln.go.dev. |
| DB string `json:"db,omitempty"` |
| |
| // LastModified is the last modified time of the data source. |
| DBLastModified *time.Time `json:"db_last_modified,omitempty"` |
| |
| // GoVersion is the version of Go used for analyzing standard library |
| // vulnerabilities. |
| GoVersion string `json:"go_version,omitempty"` |
| |
| // ScanLevel instructs govulncheck to analyze at a specific level of detail. |
| // Valid values include module, package and symbol. |
| ScanLevel ScanLevel `json:"scan_level,omitempty"` |
| |
| // ScanMode instructs govulncheck how to interpret the input and |
| // what to do with it. Valid values are source, binary, query, |
| // and extract. |
| ScanMode ScanMode `json:"scan_mode,omitempty"` |
| } |
| |
| // Progress messages are informational only, intended to allow users to monitor |
| // the progress of a long running scan. |
| // A stream must remain fully valid and able to be interpreted with all progress |
| // messages removed. |
| type Progress struct { |
| // A time stamp for the message. |
| Timestamp *time.Time `json:"time,omitempty"` |
| |
| // Message is the progress message. |
| Message string `json:"message,omitempty"` |
| } |
| |
| // Finding contains information on a discovered vulnerability. Each vulnerability |
| // will likely have multiple findings in JSON mode. This is because govulncheck |
| // emits findings as it does work, and therefore could emit one module level, |
| // one package level, and potentially multiple symbol level findings depending |
| // on scan level. |
| // Multiple symbol level findings can be emitted when multiple symbols of the |
| // same vuln are called or govulncheck decides to show multiple traces for the |
| // same symbol. |
| type Finding struct { |
| // OSV is the id of the detected vulnerability. |
| OSV string `json:"osv,omitempty"` |
| |
| // FixedVersion is the module version where the vulnerability was |
| // fixed. This is empty if a fix is not available. |
| // |
| // If there are multiple fixed versions in the OSV report, this will |
| // be the fixed version in the latest range event for the OSV report. |
| // |
| // For example, if the range events are |
| // {introduced: 0, fixed: 1.0.0} and {introduced: 1.1.0}, the fixed version |
| // will be empty. |
| // |
| // For the stdlib, we will show the fixed version closest to the |
| // Go version that is used. For example, if a fix is available in 1.17.5 and |
| // 1.18.5, and the GOVERSION is 1.17.3, 1.17.5 will be returned as the |
| // fixed version. |
| FixedVersion string `json:"fixed_version,omitempty"` |
| |
| // Trace contains an entry for each frame in the trace. |
| // |
| // Frames are sorted starting from the imported vulnerable symbol |
| // until the entry point. The first frame in Frames should match |
| // Symbol. |
| // |
| // In binary mode, trace will contain a single-frame with no position |
| // information. |
| // |
| // For module level source findings, the trace will contain a single-frame |
| // with no symbol, position, or package information. For package level source |
| // findings, the trace will contain a single-frame with no symbol or position |
| // information. |
| Trace []*Frame `json:"trace,omitempty"` |
| } |
| |
| // Frame represents an entry in a finding trace. |
| type Frame struct { |
| // Module is the module path of the module containing this symbol. |
| // |
| // Importable packages in the standard library will have the path "stdlib". |
| Module string `json:"module"` |
| |
| // Version is the module version from the build graph. |
| Version string `json:"version,omitempty"` |
| |
| // Package is the import path. |
| Package string `json:"package,omitempty"` |
| |
| // Function is the function name. |
| Function string `json:"function,omitempty"` |
| |
| // Receiver is the receiver type if the called symbol is a method. |
| // |
| // The client can create the final symbol name by |
| // prepending Receiver to FuncName. |
| Receiver string `json:"receiver,omitempty"` |
| |
| // Position describes an arbitrary source position |
| // including the file, line, and column location. |
| // A Position is valid if the line number is > 0. |
| // |
| // The filenames are relative to the directory of |
| // the enclosing module and always use "/" for |
| // portability. |
| Position *Position `json:"position,omitempty"` |
| } |
| |
| // Position represents arbitrary source position. |
| type Position struct { |
| Filename string `json:"filename,omitempty"` // filename, if any |
| Offset int `json:"offset"` // byte offset, starting at 0 |
| Line int `json:"line"` // line number, starting at 1 |
| Column int `json:"column"` // column number, starting at 1 (byte count) |
| } |
| |
| // ScanLevel represents the detail level at which a scan occurred. |
| // This can be necessary to correctly interpret the findings, for instance if |
| // a scan is at symbol level and a finding does not have a symbol it means the |
| // vulnerability was imported but not called. If the scan however was at |
| // "package" level, that determination cannot be made. |
| type ScanLevel string |
| |
| const ( |
| ScanLevelModule = "module" |
| ScanLevelPackage = "package" |
| ScanLevelSymbol = "symbol" |
| ) |
| |
| // WantSymbols can be used to check whether the scan level is one that is able |
| // to generate symbol-level findings. |
| func (l ScanLevel) WantSymbols() bool { return l == ScanLevelSymbol } |
| |
| // WantPackages can be used to check whether the scan level is one that is able |
| // to generate package-level findings. |
| func (l ScanLevel) WantPackages() bool { return l == ScanLevelPackage || l == ScanLevelSymbol } |
| |
| // ScanMode represents the mode in which a scan occurred. This can |
| // be necessary to correctly to interpret findings. For instance, |
| // a binary can be checked for vulnerabilities or the user just wants |
| // to extract minimal data necessary for the vulnerability check. |
| type ScanMode string |
| |
| const ( |
| ScanModeSource = "source" |
| ScanModeBinary = "binary" |
| ScanModeConvert = "convert" |
| ScanModeQuery = "query" |
| ScanModeExtract = "extract" // currently, only binary extraction is supported |
| ) |