ci/internal/cve/record.go (42 lines of code) (raw):
//go:generate npx quicktype -o internal/cve/record_gen.go --package cve --top-level Record --just-types-and-package --omit-empty --field-tags json --src-lang schema CVE_Record_bundled.schema.json
package cve
import (
"encoding/json"
"errors"
"io"
"log/slog"
"strings"
)
const expectedDataTypeValue = "CVE_RECORD"
// ErrNotCVERecord is an error returned when data is not a CVE record.
var ErrNotCVERecord = errors.New("not a CVE record")
// RecordFromReader loads a CVE record from given reader expected to contain
// a CVE JSON record following the v5 format.
// Returns [ErrNotCVERecord] if the reader does not contain a CVE record.
func RecordFromReader(r io.Reader) (*Record, error) {
var record Record
if err := json.NewDecoder(r).Decode(&record); err != nil {
return nil, ErrNotCVERecord
}
if record.DataType != expectedDataTypeValue {
return nil, ErrNotCVERecord
}
if !strings.HasPrefix(record.DataVersion, "5.") {
return nil, ErrNotCVERecord
}
return &record, nil
}
// RecordVersion determines the version of a CVE record from the given reader.
// Returns [ErrNotCVERecord] if the reader does not contain a CVE record.
func RecordVersion(r io.Reader) (string, error) {
s := struct {
DataType string `json:"dataType"`
DataVersion string `json:"dataVersion"`
}{}
if err := json.NewDecoder(r).Decode(&s); err != nil {
return "", ErrNotCVERecord
}
if s.DataType != expectedDataTypeValue {
return "", ErrNotCVERecord
}
if s.DataVersion == "" {
return "", ErrNotCVERecord
}
return s.DataVersion, nil
}
// LogValue satisfies the [slog.LogValuer] interface.
func (r *Record) LogValue() slog.Value {
return slog.StringValue(r.CveMetadata.CveID)
}