From c59adea16d3e0f38e6d2a769b6de232b0e735212 Mon Sep 17 00:00:00 2001 From: Dustin Ingram Date: Mon, 18 May 2026 15:29:33 +0000 Subject: [PATCH] fix(vulnfeeds): output standard OSV YAML instead of wrapped format yaml.v2 treats the anonymous *osvschema.Vulnerability field in the vulns.Vulnerability wrapper struct as a named 'Vulnerability' key. This caused new advisories to be written with a top-level 'vulnerability:' field after a recent bugfix initialized the pointer. This commit updates ToYAML, FromYAML, and FromJSON to encode and decode the inner osvschema.Vulnerability struct directly, restoring the standard OSV output format while maintaining the fix for nil pointer panics. --- vulnfeeds/cmd/pypi/main_test.go | 29 +++++++++++++---------------- vulnfeeds/vulns/vulns.go | 14 +++++++------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/vulnfeeds/cmd/pypi/main_test.go b/vulnfeeds/cmd/pypi/main_test.go index a009d487da0..69cfc838ca0 100644 --- a/vulnfeeds/cmd/pypi/main_test.go +++ b/vulnfeeds/cmd/pypi/main_test.go @@ -25,14 +25,13 @@ func TestLoadExisting(t *testing.T) { // 1. Write a valid vulnerability YAML validYaml := ` -vulnerability: - id: PYSEC-2021-123 - affected: - - package: - name: foo-pkg - ecosystem: PyPI - aliases: - - CVE-2021-12345 +id: PYSEC-2021-123 +affected: + - package: + name: foo-pkg + ecosystem: PyPI +aliases: + - CVE-2021-12345 ` if err := os.WriteFile(filepath.Join(tmpDir, "valid.yaml"), []byte(validYaml), 0600); err != nil { t.Fatalf("failed to write valid YAML: %v", err) @@ -40,10 +39,9 @@ vulnerability: // 2. Write a vulnerability YAML with empty/missing affected block missingAffectedYaml := ` -vulnerability: - id: PYSEC-2021-456 - aliases: - - CVE-2021-67890 +id: PYSEC-2021-456 +aliases: + - CVE-2021-67890 ` if err := os.WriteFile(filepath.Join(tmpDir, "missing_affected.yaml"), []byte(missingAffectedYaml), 0600); err != nil { t.Fatalf("failed to write YAML with missing affected: %v", err) @@ -51,10 +49,9 @@ vulnerability: // 3. Write a vulnerability YAML with affected block but missing package missingPackageYaml := ` -vulnerability: - id: PYSEC-2021-789 - affected: - - {} +id: PYSEC-2021-789 +affected: + - {} ` if err := os.WriteFile(filepath.Join(tmpDir, "missing_package.yaml"), []byte(missingPackageYaml), 0600); err != nil { t.Fatalf("failed to write YAML with missing package: %v", err) diff --git a/vulnfeeds/vulns/vulns.go b/vulnfeeds/vulns/vulns.go index f0ac4419de2..bc877159d29 100644 --- a/vulnfeeds/vulns/vulns.go +++ b/vulnfeeds/vulns/vulns.go @@ -403,7 +403,7 @@ func (v *Vulnerability) ToJSON(w io.Writer) error { // ToYAML serializes the Vulnerability to YAML. func (v *Vulnerability) ToYAML(w io.Writer) error { encoder := yaml.NewEncoder(w) - return encoder.Encode(v) + return encoder.Encode(v.Vulnerability) } // ClassifyReferenceLink infers the OSV schema's reference type for a given URL. @@ -769,25 +769,25 @@ func GetCPEs(cpeApplicability []models.CPE, metrics *models.ConversionMetrics) [ // FromYAML deserializes a Vulnerability from a YAML reader. func FromYAML(r io.Reader) (*Vulnerability, error) { decoder := yaml.NewDecoder(r) - vuln := Vulnerability{Vulnerability: &osvschema.Vulnerability{}} - err := decoder.Decode(&vuln) + inner := &osvschema.Vulnerability{} + err := decoder.Decode(inner) if err != nil { return nil, err } - return &vuln, nil + return &Vulnerability{Vulnerability: inner}, nil } // FromJSON deserializes a Vulnerability from a JSON reader. func FromJSON(r io.Reader) (*Vulnerability, error) { decoder := json.NewDecoder(r) - vuln := Vulnerability{Vulnerability: &osvschema.Vulnerability{}} - err := decoder.Decode(&vuln) + inner := &osvschema.Vulnerability{} + err := decoder.Decode(inner) if err != nil { return nil, err } - return &vuln, nil + return &Vulnerability{Vulnerability: inner}, nil } // CheckQuality will return true if field text is not a filler text or otherwise empty