| // Copyright 2024 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import ( | |
| "context" | |
| "fmt" | |
| vlog "golang.org/x/vulndb/cmd/vulnreport/log" | |
| "golang.org/x/vulndb/internal/cve5" | |
| "golang.org/x/vulndb/internal/genericosv" | |
| "golang.org/x/vulndb/internal/pkgsite" | |
| "golang.org/x/vulndb/internal/report" | |
| "golang.org/x/vulndb/internal/triage" | |
| ) | |
| type triager interface { | |
| triage(context.Context, string) error | |
| } | |
| type cveTriager struct { | |
| report.Fetcher | |
| pc *pkgsite.Client | |
| } | |
| func (t *cveTriager) triage(ctx context.Context, id string) error { | |
| cve, err := fetchAs[*cve5.CVERecord](ctx, t, id) | |
| if err != nil { | |
| return err | |
| } | |
| result, err := triage.RefersToGoModule(ctx, cve, t.pc) | |
| if err != nil { | |
| return err | |
| } | |
| printResult(id, result) | |
| return nil | |
| } | |
| type ghsaTriager struct { | |
| report.Fetcher | |
| } | |
| func (t *ghsaTriager) triage(ctx context.Context, id string) error { | |
| ghsa, err := fetchAs[*genericosv.Entry](ctx, t, id) | |
| if err != nil { | |
| return err | |
| } | |
| result := triage.ContainsGoModule(ghsa) | |
| printResult(id, result) | |
| return nil | |
| } | |
| func printResult(id string, result *triage.Result) { | |
| if result == nil { | |
| vlog.Infof("%s does not appear to be a Go vulnerability", id) | |
| return | |
| } | |
| vlog.Outf("%s is likely a Go vulnerability", id) | |
| if result.ModulePath != "" { | |
| vlog.Outf("Module: %s", result.ModulePath) | |
| } | |
| if result.PackagePath != "" { | |
| vlog.Outf("Package: %s", result.PackagePath) | |
| } | |
| if result.Reason != "" { | |
| vlog.Outf("Reason: %s", result.Reason) | |
| } | |
| } | |
| func fetchAs[T any](ctx context.Context, f report.Fetcher, id string) (T, error) { | |
| var zero T | |
| src, err := f.Fetch(ctx, id) | |
| if err != nil { | |
| return zero, err | |
| } | |
| v, ok := src.(T) | |
| if !ok { | |
| return zero, fmt.Errorf("%s cannot be cast as %T", src, zero) | |
| } | |
| return v, nil | |
| } | |
| func triageCVEs(ctx context.Context, cves []string) { | |
| if len(cves) == 0 { | |
| return | |
| } | |
| t := &cveTriager{Fetcher: cve5.NewFetcher(), pc: pkgsite.Default()} | |
| triageBatch(ctx, t, cves) | |
| } | |
| func triageGHSAs(ctx context.Context, ghsas []string) { | |
| if len(ghsas) == 0 { | |
| return | |
| } | |
| t := &ghsaTriager{Fetcher: genericosv.NewFetcher()} | |
| triageBatch(ctx, t, ghsas) | |
| } | |
| func triageBatch(ctx context.Context, t triager, ids []string) { | |
| for _, id := range ids { | |
| if err := t.triage(ctx, id); err != nil { | |
| vlog.Err(err) | |
| } | |
| } | |
| } |