Skip to content

Commit

Permalink
feat: add go struct definitions of OSV record
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Kedar <[email protected]>
  • Loading branch information
michaelkedar committed Feb 4, 2025
1 parent a5a512f commit 7c21232
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 0 deletions.
2 changes: 2 additions & 0 deletions bindings/go/osvschema/constants.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package osvschema

const SchemaVersion = "1.6.8"

type Ecosystem string

const (
Expand Down
170 changes: 170 additions & 0 deletions bindings/go/osvschema/vulnerability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package osvschema

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"`
Upstream []string `json:"upstream,omitempty" yaml:"upstream,omitempty"`
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Details string `json:"details,omitempty" yaml:"details,omitempty"`
Severity []Severity `json:"severity,omitempty" yaml:"severity,omitempty"`
Affected []Affected `json:"affected,omitempty" yaml:"affected,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
}

0 comments on commit 7c21232

Please sign in to comment.