github.com/google/osv-scalibr@v0.4.1/enricher/govulncheck/source/gvcreal.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package source 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "os" 22 "os/exec" 23 24 "github.com/google/osv-scalibr/enricher/govulncheck/source/internal" 25 "github.com/google/osv-scalibr/enricher/govulncheck/source/internal/url" 26 vulnpb "github.com/ossf/osv-schema/bindings/go/osvschema" 27 "golang.org/x/vuln/scan" 28 "google.golang.org/protobuf/encoding/protojson" 29 ) 30 31 // realGovulncheckClient is the real implementation of govulncheckClient. 32 type realGovulncheckClient struct{} 33 34 func (r *realGovulncheckClient) RunGovulncheck(ctx context.Context, absModDir string, vulns []*vulnpb.Vulnerability, goVersion string) (map[string][]*internal.Finding, error) { 35 // Create a temporary directory containing all the vulnerabilities that 36 // are passed in to check against govulncheck. 37 // 38 // This enables OSV scanner to supply the OSV vulnerabilities to run 39 // against govulncheck and manage the database separately from vuln.go.dev. 40 dbdir, err := os.MkdirTemp("", "") 41 if err != nil { 42 return nil, err 43 } 44 defer func() { 45 rerr := os.RemoveAll(dbdir) 46 if err == nil { 47 err = rerr 48 } 49 }() 50 51 for _, vuln := range vulns { 52 dat, err := protojson.Marshal(vuln) 53 if err != nil { 54 return nil, err 55 } 56 if err := os.WriteFile(fmt.Sprintf("%s/%s.json", dbdir, vuln.GetId()), dat, 0600); err != nil { 57 return nil, err 58 } 59 } 60 61 // this only errors if the file path is not absolute, 62 // which paths from os.MkdirTemp should always be 63 dbdirURL, err := url.FromFilePath(dbdir) 64 if err != nil { 65 return nil, err 66 } 67 68 // Run govulncheck on the module at moddir and vulnerability database that 69 // was just created. 70 cmd := scan.Command(ctx, "-db", dbdirURL.String(), "-C", absModDir, "-json", "-mode", "source", "./...") 71 var b bytes.Buffer 72 cmd.Stdout = &b 73 cmd.Env = append(os.Environ(), "GOVERSION=go"+goVersion) 74 if err := cmd.Start(); err != nil { 75 return nil, err 76 } 77 if err := cmd.Wait(); err != nil { 78 return nil, err 79 } 80 81 // Group the output of govulncheck based on the OSV ID. 82 h := &osvHandler{ 83 idToFindings: map[string][]*internal.Finding{}, 84 } 85 if err := handleJSON(bytes.NewReader(b.Bytes()), h); err != nil { 86 return nil, err 87 } 88 89 return h.idToFindings, nil 90 } 91 92 func (r *realGovulncheckClient) GoToolchainAvailable(ctx context.Context) bool { 93 cmd := exec.CommandContext(ctx, "go", "version") 94 _, err := cmd.Output() 95 96 return err == nil 97 }