| // Copyright 2024 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. |
| |
| // File copied from github.com/google/osv-scanner@v1.8.0/pkg/models/vulnerability.go |
| package genericosv |
| |
| import ( |
| "encoding/json" |
| "time" |
| ) |
| |
| // Package identifies the affected code library or command provided by the |
| // package. |
| // |
| // See: https://ossf.github.io/osv-schema/#affectedpackage-field |
| type Package struct { |
| Ecosystem Ecosystem `json:"ecosystem" yaml:"ecosystem"` |
| Name string `json:"name" yaml:"name"` |
| Purl string `json:"purl,omitempty" yaml:"purl,omitempty"` |
| } |
| |
| // Event describes a single version that either: |
| // |
| // - Introduces a vulnerability: {"introduced": string} |
| // - Fixes a vulnerability: {"fixed": string} |
| // - Describes the last known affected version: {"last_affected": string} |
| // - Sets an upper limit on the range being described: {"limit": string} |
| // |
| // Event instances form part of a “timeline” of status changes for the affected |
| // package described by the Affected struct. |
| // |
| // See: https://ossf.github.io/osv-schema/#affectedrangesevents-fields |
| type Event struct { |
| Introduced string `json:"introduced,omitempty" yaml:"introduced,omitempty"` |
| Fixed string `json:"fixed,omitempty" yaml:"fixed,omitempty"` |
| LastAffected string `json:"last_affected,omitempty" yaml:"last_affected,omitempty"` |
| Limit string `json:"limit,omitempty" yaml:"limit,omitempty"` |
| } |
| |
| // Range describes the affected range of given version for a specific package. |
| // |
| // See: https://ossf.github.io/osv-schema/#affectedranges-field |
| type Range struct { |
| Type RangeType `json:"type" yaml:"type"` |
| Events []Event `json:"events" yaml:"events"` |
| Repo string `json:"repo,omitempty" yaml:"repo,omitempty"` |
| DatabaseSpecific map[string]interface{} `json:"database_specific,omitempty" yaml:"database_specific,omitempty"` |
| } |
| |
| // Severity is used to describe the severity of a vulnerability for an affected |
| // package using one or more quantitative scoring methods. |
| // |
| // See: https://ossf.github.io/osv-schema/#severity-field |
| type Severity struct { |
| Type SeverityType `json:"type" yaml:"type"` |
| Score string `json:"score" yaml:"score"` |
| } |
| |
| // Affected describes an affected package version, meaning one instance that |
| // contains the vulnerability. |
| // |
| // See: https://ossf.github.io/osv-schema/#affected-fields |
| type Affected struct { |
| Package Package `json:"package,omitempty" yaml:"package,omitempty"` |
| Severity []Severity `json:"severity,omitempty" yaml:"severity,omitempty"` |
| Ranges []Range `json:"ranges,omitempty" yaml:"ranges,omitempty"` |
| Versions []string `json:"versions,omitempty" yaml:"versions,omitempty"` |
| DatabaseSpecific map[string]interface{} `json:"database_specific,omitempty" yaml:"database_specific,omitempty"` |
| EcosystemSpecific map[string]interface{} `json:"ecosystem_specific,omitempty" yaml:"ecosystem_specific,omitempty"` |
| } |
| |
| // MarshalJSON implements the json.Marshaler interface. |
| // |
| // This method ensures Package is only present if it is not equal to the zero value. |
| // This is achieved by embedding the Affected struct with a pointer to Package used |
| // to populate the "package" key in the JSON object. |
| func (a Affected) MarshalJSON() ([]byte, error) { |
| type rawAffected Affected // alias Affected to avoid recursion during Marshal |
| type wrapper struct { |
| Package *Package `json:"package,omitempty"` |
| rawAffected |
| } |
| raw := wrapper{rawAffected: rawAffected(a)} |
| if a.Package == (Package{}) { |
| raw.Package = nil |
| } else { |
| raw.Package = &(a.Package) |
| } |
| |
| return json.Marshal(raw) |
| } |
| |
| // Reference links to additional information, advisories, issue tracker entries, |
| // and so on about the vulnerability itself. |
| // |
| // See: https://ossf.github.io/osv-schema/#references-field |
| type Reference struct { |
| Type ReferenceType `json:"type" yaml:"type"` |
| URL string `json:"url" yaml:"url"` |
| } |
| |
| // Credit gives credit for the discovery, confirmation, patch, or other events |
| // in the life cycle of a vulnerability. |
| // |
| // See: https://ossf.github.io/osv-schema/#credits-fields |
| type Credit struct { |
| Name string `json:"name" yaml:"name"` |
| Type CreditType `json:"type,omitempty" yaml:"type,omitempty"` |
| Contact []string `json:"contact,omitempty" yaml:"contact,omitempty"` |
| } |
| |
| // Vulnerability is the core Open Source Vulnerability (OSV) data type. |
| // |
| // The full documentation for the schema is available at |
| // https://ossf.github.io/osv-schema. |
| type Vulnerability struct { |
| SchemaVersion string `json:"schema_version,omitempty" yaml:"schema_version,omitempty"` |
| ID string `json:"id" yaml:"id"` |
| Modified time.Time `json:"modified" yaml:"modified"` |
| Published time.Time `json:"published,omitempty" yaml:"published,omitempty"` |
| Withdrawn time.Time `json:"withdrawn,omitempty" yaml:"withdrawn,omitempty"` |
| Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"` |
| Related []string `json:"related,omitempty" yaml:"related,omitempty"` |
| Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` |
| Details string `json:"details,omitempty" yaml:"details,omitempty"` |
| Affected []Affected `json:"affected,omitempty" yaml:"affected,omitempty"` |
| // TODO(tatianabradley): There is a bug in Severity unmarshal. |
| // We don't use this field, so it is ignored until we fix this. |
| Severity []Severity `json:"-,omitempty" yaml:"-,omitempty"` |
| References []Reference `json:"references,omitempty" yaml:"references,omitempty"` |
| Credits []Credit `json:"credits,omitempty" yaml:"credits,omitempty"` |
| DatabaseSpecific map[string]interface{} `json:"database_specific,omitempty" yaml:"database_specific,omitempty"` |
| } |
| |
| // MarshalJSON implements the json.Marshaler interface. |
| // |
| // This method ensures times all times are formatted correctly according to the schema. |
| func (v Vulnerability) MarshalJSON() ([]byte, error) { |
| type rawVulnerability Vulnerability // alias Vulnerability to avoid recursion during Marshal |
| type wrapper struct { |
| Modified string `json:"modified"` |
| Published string `json:"published,omitempty"` |
| Withdrawn string `json:"withdrawn,omitempty"` |
| rawVulnerability |
| } |
| raw := wrapper{rawVulnerability: rawVulnerability(v)} |
| raw.Modified = v.Modified.UTC().Format(time.RFC3339) |
| if !v.Published.IsZero() { |
| raw.Published = v.Published.UTC().Format(time.RFC3339) |
| } |
| if !v.Withdrawn.IsZero() { |
| raw.Withdrawn = v.Withdrawn.UTC().Format(time.RFC3339) |
| } |
| |
| return json.Marshal(raw) |
| } |
| |
| // MarshalYAML implements the yaml.Marshaler interface. |
| // |
| // This method ensures times all times are formatted correctly. |
| func (v Vulnerability) MarshalYAML() (interface{}, error) { |
| type rawVulnerability Vulnerability // alias Vulnerability to avoid recursion during Marshal |
| raw := rawVulnerability(v) |
| if !v.Modified.IsZero() { |
| raw.Modified = v.Modified.UTC() |
| } |
| if !v.Published.IsZero() { |
| raw.Published = v.Published.UTC() |
| } |
| if !v.Withdrawn.IsZero() { |
| raw.Withdrawn = v.Withdrawn.UTC() |
| } |
| |
| return raw, nil |
| } |