golang.org/x/tools/gopls@v0.15.3/internal/vulncheck/vulntest/report.go (about)

     1  // Copyright 2022 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  //go:build go1.18
     6  // +build go1.18
     7  
     8  package vulntest
     9  
    10  import (
    11  	"fmt"
    12  	"io"
    13  	"os"
    14  	"strings"
    15  	"time"
    16  
    17  	"golang.org/x/mod/semver"
    18  	"golang.org/x/tools/gopls/internal/vulncheck/osv"
    19  	"gopkg.in/yaml.v3"
    20  )
    21  
    22  //
    23  // The following was selectively copied from golang.org/x/vulndb/internal/report
    24  //
    25  
    26  // readReport reads a Report in YAML format.
    27  func readReport(in io.Reader) (*Report, error) {
    28  	d := yaml.NewDecoder(in)
    29  	// Require that all fields in the file are in the struct.
    30  	// This corresponds to v2's UnmarshalStrict.
    31  	d.KnownFields(true)
    32  	var r Report
    33  	if err := d.Decode(&r); err != nil {
    34  		return nil, fmt.Errorf("yaml.Decode: %v", err)
    35  	}
    36  	return &r, nil
    37  }
    38  
    39  // Report represents a vulnerability report in the vulndb.
    40  // See https://go.googlesource.com/vulndb/+/refs/heads/master/doc/format.md
    41  type Report struct {
    42  	ID string `yaml:",omitempty"`
    43  
    44  	Modules []*Module `yaml:",omitempty"`
    45  
    46  	// Summary is a short phrase describing the vulnerability.
    47  	Summary string `yaml:",omitempty"`
    48  
    49  	// Description is the CVE description from an existing CVE. If we are
    50  	// assigning a CVE ID ourselves, use CVEMetadata.Description instead.
    51  	Description string     `yaml:",omitempty"`
    52  	Published   time.Time  `yaml:",omitempty"`
    53  	Withdrawn   *time.Time `yaml:",omitempty"`
    54  
    55  	References []*Reference `yaml:",omitempty"`
    56  }
    57  
    58  // Write writes r to filename in YAML format.
    59  func (r *Report) Write(filename string) (err error) {
    60  	f, err := os.Create(filename)
    61  	if err != nil {
    62  		return err
    63  	}
    64  	err = r.encode(f)
    65  	err2 := f.Close()
    66  	if err == nil {
    67  		err = err2
    68  	}
    69  	return err
    70  }
    71  
    72  // ToString encodes r to a YAML string.
    73  func (r *Report) ToString() (string, error) {
    74  	var b strings.Builder
    75  	if err := r.encode(&b); err != nil {
    76  		return "", err
    77  	}
    78  	return b.String(), nil
    79  }
    80  
    81  func (r *Report) encode(w io.Writer) error {
    82  	e := yaml.NewEncoder(w)
    83  	defer e.Close()
    84  	e.SetIndent(4)
    85  	return e.Encode(r)
    86  }
    87  
    88  type VersionRange struct {
    89  	Introduced Version `yaml:"introduced,omitempty"`
    90  	Fixed      Version `yaml:"fixed,omitempty"`
    91  }
    92  
    93  type Module struct {
    94  	Module   string         `yaml:",omitempty"`
    95  	Versions []VersionRange `yaml:",omitempty"`
    96  	Packages []*Package     `yaml:",omitempty"`
    97  }
    98  
    99  type Package struct {
   100  	Package string   `yaml:",omitempty"`
   101  	GOOS    []string `yaml:"goos,omitempty"`
   102  	GOARCH  []string `yaml:"goarch,omitempty"`
   103  	// Symbols originally identified as vulnerable.
   104  	Symbols []string `yaml:",omitempty"`
   105  	// Additional vulnerable symbols, computed from Symbols via static analysis
   106  	// or other technique.
   107  	DerivedSymbols []string `yaml:"derived_symbols,omitempty"`
   108  }
   109  
   110  // Version is an SemVer 2.0.0 semantic version with no leading "v" prefix,
   111  // as used by OSV.
   112  type Version string
   113  
   114  // V returns the version with a "v" prefix.
   115  func (v Version) V() string {
   116  	return "v" + string(v)
   117  }
   118  
   119  // IsValid reports whether v is a valid semantic version string.
   120  func (v Version) IsValid() bool {
   121  	return semver.IsValid(v.V())
   122  }
   123  
   124  // Before reports whether v < v2.
   125  func (v Version) Before(v2 Version) bool {
   126  	return semver.Compare(v.V(), v2.V()) < 0
   127  }
   128  
   129  // Canonical returns the canonical formatting of the version.
   130  func (v Version) Canonical() string {
   131  	return strings.TrimPrefix(semver.Canonical(v.V()), "v")
   132  }
   133  
   134  // Reference type is a reference (link) type.
   135  type ReferenceType string
   136  
   137  const (
   138  	ReferenceTypeAdvisory = ReferenceType("ADVISORY")
   139  	ReferenceTypeArticle  = ReferenceType("ARTICLE")
   140  	ReferenceTypeReport   = ReferenceType("REPORT")
   141  	ReferenceTypeFix      = ReferenceType("FIX")
   142  	ReferenceTypePackage  = ReferenceType("PACKAGE")
   143  	ReferenceTypeEvidence = ReferenceType("EVIDENCE")
   144  	ReferenceTypeWeb      = ReferenceType("WEB")
   145  )
   146  
   147  // ReferenceTypes is the set of reference types defined in OSV.
   148  var ReferenceTypes = []ReferenceType{
   149  	ReferenceTypeAdvisory,
   150  	ReferenceTypeArticle,
   151  	ReferenceTypeReport,
   152  	ReferenceTypeFix,
   153  	ReferenceTypePackage,
   154  	ReferenceTypeEvidence,
   155  	ReferenceTypeWeb,
   156  }
   157  
   158  // A Reference is a link to some external resource.
   159  //
   160  // For ease of typing, References are represented in the YAML as a
   161  // single-element mapping of type to URL.
   162  type Reference osv.Reference
   163  
   164  func (r *Reference) MarshalYAML() (interface{}, error) {
   165  	return map[string]string{
   166  		strings.ToLower(string(r.Type)): r.URL,
   167  	}, nil
   168  }
   169  
   170  func (r *Reference) UnmarshalYAML(n *yaml.Node) (err error) {
   171  	if n.Kind != yaml.MappingNode || len(n.Content) != 2 || n.Content[0].Kind != yaml.ScalarNode || n.Content[1].Kind != yaml.ScalarNode {
   172  		return &yaml.TypeError{Errors: []string{
   173  			fmt.Sprintf("line %d: report.Reference must contain a mapping with one value", n.Line),
   174  		}}
   175  	}
   176  	r.Type = osv.ReferenceType(strings.ToUpper(n.Content[0].Value))
   177  	r.URL = n.Content[1].Value
   178  	return nil
   179  }