query.go (1893B)
1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package scan 6 7 import ( 8 "context" 9 "fmt" 10 "regexp" 11 12 "golang.org/x/vuln/internal/client" 13 "golang.org/x/vuln/internal/govulncheck" 14 isem "golang.org/x/vuln/internal/semver" 15 ) 16 17 // runQuery reports vulnerabilities that apply to the queries in the config. 18 func runQuery(ctx context.Context, handler govulncheck.Handler, cfg *config, c *client.Client) error { 19 reqs := make([]*client.ModuleRequest, len(cfg.patterns)) 20 for i, query := range cfg.patterns { 21 mod, ver, err := parseModuleQuery(query) 22 if err != nil { 23 return err 24 } 25 if err := handler.Progress(queryProgressMessage(mod, ver)); err != nil { 26 return err 27 } 28 reqs[i] = &client.ModuleRequest{ 29 Path: mod, Version: ver, 30 } 31 } 32 33 resps, err := c.ByModules(ctx, reqs) 34 if err != nil { 35 return err 36 } 37 38 ids := make(map[string]bool) 39 for _, resp := range resps { 40 for _, entry := range resp.Entries { 41 if _, ok := ids[entry.ID]; !ok { 42 err := handler.OSV(entry) 43 if err != nil { 44 return err 45 } 46 ids[entry.ID] = true 47 } 48 } 49 } 50 51 return nil 52 } 53 54 func queryProgressMessage(module, version string) *govulncheck.Progress { 55 return &govulncheck.Progress{ 56 Message: fmt.Sprintf("Looking up vulnerabilities in %s at %s...", module, version), 57 } 58 } 59 60 var modQueryRegex = regexp.MustCompile(`(.+)@(.+)`) 61 62 func parseModuleQuery(pattern string) (_ string, _ string, err error) { 63 matches := modQueryRegex.FindStringSubmatch(pattern) 64 // matches should be [module@version, module, version] 65 if len(matches) != 3 { 66 return "", "", fmt.Errorf("invalid query %s: must be of the form module@version", pattern) 67 } 68 mod, ver := matches[1], matches[2] 69 if !isem.Valid(ver) { 70 return "", "", fmt.Errorf("version %s is not valid semver", ver) 71 } 72 73 return mod, ver, nil 74 }