Skip to content

Commit

Permalink
internal/{ghsa,report}: move ghsaToReport to ghsa package
Browse files Browse the repository at this point in the history
Change-Id: I8bbb9482dddf3b1c58bcaff037c7d60fcb1539e7
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/583655
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Commit-Queue: Tatiana Bradley <tatianabradley@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
  • Loading branch information
tatianab committed May 15, 2024
1 parent 685ac19 commit 57274b4
Show file tree
Hide file tree
Showing 54 changed files with 755 additions and 764 deletions.
2 changes: 1 addition & 1 deletion all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func TestLintReports(t *testing.T) {
}
}
if r.CVEMetadata != nil {
generated, err := r.ToCVE5()
generated, err := cveschema5.FromReport(r)
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/cve/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ func addMissing(yamlFile string, missing []string) error {
if err := r.Write(yamlFile); err != nil {
return err
}
cve, err := r.ToCVE5()
cve, err := cveschema5.FromReport(r)
if err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/vulnreport/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"time"

"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/internal/cveclient"
"golang.org/x/vulndb/internal/genai"
"golang.org/x/vulndb/internal/genericosv"
"golang.org/x/vulndb/internal/ghsa"
Expand Down Expand Up @@ -209,12 +210,12 @@ func fetch(ctx context.Context, alias string, gc *ghsa.Client) report.Source {
switch {
case idstr.IsGHSA(alias):
if *graphQL {
f = report.LegacyGHSAFetcher(gc)
f = gc
} else {
f = genericosv.NewFetcher()
}
case idstr.IsCVE(alias):
f = report.CVE5Fetcher()
f = cveclient.NewFetcher()
default:
log.Warnf("alias %s is not supported, creating basic report", alias)
return report.Original()
Expand Down
3 changes: 2 additions & 1 deletion cmd/vulnreport/cve.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"context"

"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/internal/cveschema5"
"golang.org/x/vulndb/internal/database"
"golang.org/x/vulndb/internal/report"
)
Expand Down Expand Up @@ -44,7 +45,7 @@ func (c *cveCmd) run(ctx context.Context, filename string) (err error) {
// writeCVE converts a report to JSON CVE5 record and writes it to
// data/cve/v5.
func writeCVE(r *report.Report) error {
cve, err := r.ToCVE5()
cve, err := cveschema5.FromReport(r)
if err != nil {
return err
}
Expand Down
19 changes: 18 additions & 1 deletion internal/cveclient/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

package cveclient

import "golang.org/x/vulndb/internal/cveschema5"
import (
"context"

"golang.org/x/vulndb/internal/cveschema5"
"golang.org/x/vulndb/internal/report"
)

// Fetch returns the CVE record associated with the ID.
// It is intended one-off (non-batch) requests, and
Expand All @@ -15,3 +20,15 @@ func Fetch(id string) (*cveschema5.CVERecord, error) {
})
return c.RetrieveRecord(id)
}

type cve5Fetcher struct{}

var _ report.Fetcher = &cve5Fetcher{}

func NewFetcher() report.Fetcher {
return &cve5Fetcher{}
}

func (*cve5Fetcher) Fetch(ctx context.Context, id string) (report.Source, error) {
return Fetch(id)
}
36 changes: 21 additions & 15 deletions internal/cvelistrepo/cvelistrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,46 +112,52 @@ func blobReader(repo *git.Repository, hash plumbing.Hash) (io.Reader, error) {
return blob.Reader()
}

type CVE any

// FetchCVE fetches the CVE file for cveID from the CVElist repo and returns
// the parsed info.
func FetchCVE(ctx context.Context, repo *git.Repository, cveID string, cve CVE) (err error) {
func FetchCVE[T any](ctx context.Context, repo *git.Repository, cveID string) (_ T, err error) {
defer derrors.Wrap(&err, "FetchCVE(repo, commit, %s)", cveID)
var zero T

ref, err := repo.Reference(plumbing.HEAD, true)
if err != nil {
return err
return zero, err
}
ch := ref.Hash()
commit, err := repo.CommitObject(ch)
if err != nil {
return err
return zero, err
}
files, err := Files(repo, commit)
if err != nil {
return err
return zero, err
}
for _, f := range files {
if strings.Contains(f.Filename, cveID) {
if err := Parse(repo, f, cve); err != nil {
return err
cve, err := Parse[T](repo, f)
if err != nil {
return zero, err
}
return nil
return cve, nil
}
}
return fmt.Errorf("%s not found", cveID)
return zero, fmt.Errorf("%s not found", cveID)
}

// Parse unmarshals the contents of f into v.
func Parse(repo *git.Repository, f File, v any) error {
// Parse unmarshals the contents of f.
func Parse[T any](repo *git.Repository, f File) (T, error) {
var zero T
b, err := f.ReadAll(repo)
if err != nil {
return err
return zero, err
}
if len(b) == 0 {
return fmt.Errorf("%s is empty", f.Filename)
return zero, fmt.Errorf("%s is empty", f.Filename)
}
v := new(T)
if err := json.Unmarshal(b, v); err != nil {
return zero, err
}
return json.Unmarshal(b, v)
return *v, nil
}

func (f *File) ReadAll(repo *git.Repository) ([]byte, error) {
Expand Down
140 changes: 53 additions & 87 deletions internal/cvelistrepo/cvelistrepo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"golang.org/x/vulndb/internal/cveschema5"
"golang.org/x/vulndb/internal/gitrepo"
"golang.org/x/vulndb/internal/idstr"
"golang.org/x/vulndb/internal/report"
)

var update = flag.Bool("update", false, "update the .txtar files with real CVE data (this takes a while)")
Expand All @@ -37,10 +38,10 @@ func TestMain(m *testing.M) {
flag.Parse()
if *update {
ctx := context.Background()
if err := WriteTxtarRepo(ctx, URLv4, v4txtar, cveIDs); err != nil {
if err := writeTxtarRepo(ctx, URLv4, v4txtar, cveIDs); err != nil {
fail(err)
}
if err := WriteTxtarRepo(ctx, URLv5, v5txtar, cveIDs); err != nil {
if err := writeTxtarRepo(ctx, URLv5, v5txtar, cveIDs); err != nil {
fail(err)
}
}
Expand Down Expand Up @@ -101,96 +102,61 @@ func TestFiles(t *testing.T) {
}

func TestFetchCVE(t *testing.T) {
for _, tc := range []struct {
name string
txtarFile string
newCVE func() CVE
}{
{
name: "v4",
txtarFile: v4txtar,
newCVE: func() CVE { return new(cveschema.CVE) },
},
{
name: "v5",
txtarFile: v5txtar,
newCVE: func() CVE { return new(cveschema5.CVERecord) },
},
} {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
repo, _, err := gitrepo.TxtarRepoAndHead(tc.txtarFile)
if err != nil {
t.Fatal(err)
}

for _, id := range cveIDs {
t.Run(id, func(t *testing.T) {
cve := tc.newCVE()
if err := FetchCVE(ctx, repo, id, cve); err != nil {
t.Fatal(err)
}
if got, want := cveID(cve), id; got != want {
t.Errorf("FetchCVE(%s) ID = %s, want %s", id, got, want)
}
})
}
})
}
testFetchCVE[*cveschema.CVE](t, "v4", v4txtar)
testFetchCVE[*cveschema5.CVERecord](t, "v5", v5txtar)
}

func cveID(cve CVE) string {
switch c := cve.(type) {
case *cveschema5.CVERecord:
return c.Metadata.ID
case *cveschema.CVE:
return c.Metadata.ID
default:
return "invalid"
}
func testFetchCVE[S report.Source](t *testing.T, name, txtarFile string) {
t.Run(name, func(t *testing.T) {
ctx := context.Background()
repo, _, err := gitrepo.TxtarRepoAndHead(txtarFile)
if err != nil {
t.Fatal(err)
}

for _, id := range cveIDs {
t.Run(id, func(t *testing.T) {
cve, err := FetchCVE[S](ctx, repo, id)
if err != nil {
t.Fatal(err)
}
if got, want := cve.SourceID(), id; got != want {
t.Errorf("FetchCVE(%s) ID = %s, want %s", id, got, want)
}
})
}
})
}

func TestParse(t *testing.T) {
for _, tc := range []struct {
name string
txtarFile string
newCVE func() CVE
}{
{
name: "v4",
txtarFile: v4txtar,
newCVE: func() CVE { return new(cveschema.CVE) },
},
{
name: "v5",
txtarFile: v5txtar,
newCVE: func() CVE { return new(cveschema5.CVERecord) },
},
} {
t.Run(tc.name, func(t *testing.T) {
repo, commit, err := gitrepo.TxtarRepoAndHead(tc.txtarFile)
if err != nil {
t.Fatal(err)
}
testParse[*cveschema.CVE](t, "v4", v4txtar)
testParse[*cveschema5.CVERecord](t, "v5", v5txtar)
}

files, err := Files(repo, commit)
if err != nil {
t.Fatal(err)
}
func testParse[S report.Source](t *testing.T, name, txtarFile string) {
t.Run(name, func(t *testing.T) {
repo, commit, err := gitrepo.TxtarRepoAndHead(txtarFile)
if err != nil {
t.Fatal(err)
}

for _, file := range files {
t.Run(file.Filename, func(t *testing.T) {
cve := tc.newCVE()
if err := Parse(repo, file, cve); err != nil {
t.Fatal(err)
}
want := idstr.FindCVE(file.Filename)
if got := cveID(cve); got != want {
t.Errorf("ParseCVE(%s) ID = %s, want %s", file.Filename, got, want)
t.Log(cve)
}
})
}
})
}
files, err := Files(repo, commit)
if err != nil {
t.Fatal(err)
}

for _, file := range files {
t.Run(file.Filename, func(t *testing.T) {
cve, err := Parse[S](repo, file)
if err != nil {
t.Fatal(err)
}
want := idstr.FindCVE(file.Filename)
if got := cve.SourceID(); got != want {
t.Errorf("ParseCVE(%s) ID = %s, want %s", file.Filename, got, want)
t.Log(cve)
}
})
}
})
}

0 comments on commit 57274b4

Please sign in to comment.