src

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

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 )