Skip to content

Commit

Permalink
cmd/cve: add option to automatically preserve CVE refs
Browse files Browse the repository at this point in the history
In the "cve publish" command, allow the user to choose to automatically
update a report & its CVE record with missing CVE references.

Change-Id: I2a3e45aa896e6bd69cc8b9697a227ca7aaf4144a
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/547496
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Damien Neil <[email protected]>
  • Loading branch information
tatianab committed Dec 6, 2023
1 parent bcb698b commit 7a77555
Showing 1 changed file with 62 additions and 16 deletions.
78 changes: 62 additions & 16 deletions cmd/cve/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (
"github.com/google/go-cmp/cmp"
"golang.org/x/vulndb/internal/cveclient"
"golang.org/x/vulndb/internal/cveschema5"
"golang.org/x/vulndb/internal/database"
"golang.org/x/vulndb/internal/report"
)

var (
Expand Down Expand Up @@ -310,8 +312,8 @@ func publish(c *cveclient.Client, filename string) (err error) {
}

var (
publish func(string, *cveschema5.Containers) (*cveschema5.CVERecord, error)
action string
publishFunc func(string, *cveschema5.Containers) (*cveschema5.CVERecord, error)
action string
)
switch state := assigned.State; state {
case cveschema5.StatePublished:
Expand All @@ -324,16 +326,27 @@ func publish(c *cveclient.Client, filename string) (err error) {
fmt.Printf("publish would update record with diff (-existing, +new):\n%s\n", diff)
// The CVE program sometimes adds references to CVEs, so we need
// to make sure we don't accidentally delete them.
handleDeleted(existing, toPublish, filename)
if updated := handleDeleted(existing, toPublish, filename); updated {
// If we updated the CVE, check if any changes remain.
_, toPublish, err = cveschema5.ReadForPublish(filename)
if err != nil {
return err
}
if diff := cmp.Diff(existing.Containers, *toPublish); diff == "" {
fmt.Println("after adding missing refs, updating record would now have no effect")
return nil
}
fmt.Printf("after adding missing refs, publish would now update record with diff (-existing, +new):\n%s\n", diff)
}
} else {
fmt.Println("updating record would have no effect, skipping")
return nil
}
publish = c.UpdateRecord
publishFunc = c.UpdateRecord
action = "update"
case cveschema5.StateReserved:
fmt.Printf("publish would create new record for %s\n", cveID)
publish = c.CreateRecord
publishFunc = c.CreateRecord
action = "create"
default:
return fmt.Errorf("publishing a %s record is not supported", state)
Expand All @@ -347,7 +360,7 @@ func publish(c *cveclient.Client, filename string) (err error) {
return nil
}

_, err = publish(cveID, toPublish)
_, err = publishFunc(cveID, toPublish)
if err != nil {
return err
}
Expand All @@ -357,17 +370,19 @@ func publish(c *cveclient.Client, filename string) (err error) {
return nil
}

func handleDeleted(existing *cveschema5.CVERecord, toPublish *cveschema5.Containers, filename string) {
func handleDeleted(existing *cveschema5.CVERecord, toPublish *cveschema5.Containers, filename string) bool {
deleted := findDeleted(existing.Containers.CNAContainer.References, toPublish.CNAContainer.References)
if len(deleted) > 0 {
goID := strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
yamlReportFile := fmt.Sprintf("data/reports/%s.yaml", goID)
// To preserve an externally-added reference, add it to
// cve_metadata.references. An example is GO-2022-0476.
// This warning may be spurious if a reference is deleted from
// a YAML report - in this case it should be ignored.
fmt.Printf(
`!! WARNING !!
if len(deleted) == 0 {
return false
}
goID := strings.TrimSuffix(filepath.Base(filename), filepath.Ext(filename))
yamlReportFile := fmt.Sprintf("data/reports/%s.yaml", goID)
// To preserve an externally-added reference, add it to
// cve_metadata.references. An example is GO-2022-0476.
// This warning may be spurious if a reference is deleted from
// a YAML report - in this case it should be ignored.
fmt.Printf(
`!! WARNING !!
updating record would delete %[1]d reference(s) that may have been added by the CVE program;
to preserve these references, add references to %[2]s and run "vulnreport fix %[2]s":
Expand All @@ -379,7 +394,38 @@ cve_metadata:
only update now if this warning is spurious (i.e., the records were deleted on purpose)
`, len(deleted), yamlReportFile, strings.Join(deleted, "\n - "))

reader := bufio.NewReader(os.Stdin)
fmt.Printf("try to auto-add missing refs? (y/N)\n")
text, _ := reader.ReadString('\n')
if text != "y\n" {
return false
}

cveFile := fmt.Sprintf("data/cve/%s.json", goID)
if err := addMissing(yamlReportFile, cveFile, deleted); err != nil {
fmt.Println("ERROR: could not add missing refs: ", err)
return false
}

fmt.Printf("successfully added %d missing refs\n", len(deleted))
return true
}

func addMissing(yamlFile, cveFile string, missing []string) error {
r, err := report.Read(yamlFile)
if err != nil {
return err
}
r.CVEMetadata.References = append(r.CVEMetadata.References, missing...)
if err := r.Write(yamlFile); err != nil {
return err
}
cve, err := r.ToCVE5()
if err != nil {
return err
}
return database.WriteJSON(r.CVEFilename(), cve, true)
}

// findDeleted returns a list of URLs in oldRefs that are not in newRefs.
Expand Down

0 comments on commit 7a77555

Please sign in to comment.