github.com/google/osv-scalibr@v0.4.1/detector/govulncheck/binary/binary_test.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 binary_test 16 17 import ( 18 "os" 19 "path/filepath" 20 "runtime" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto" 25 "github.com/google/osv-scalibr/detector/govulncheck/binary" 26 "github.com/google/osv-scalibr/extractor" 27 "github.com/google/osv-scalibr/extractor/filesystem/language/golang/gobinary" 28 scalibrfs "github.com/google/osv-scalibr/fs" 29 "github.com/google/osv-scalibr/inventory" 30 "github.com/google/osv-scalibr/packageindex" 31 "github.com/google/osv-scalibr/purl" 32 osvpb "github.com/ossf/osv-schema/bindings/go/osvschema" 33 "google.golang.org/protobuf/testing/protocmp" 34 "google.golang.org/protobuf/types/known/timestamppb" 35 ) 36 37 const binaryName = "semaphore-demo-go" 38 39 func TestScan(t *testing.T) { 40 wd, err := os.Getwd() 41 if err != nil { 42 t.Fatalf("os.Getwd(): %v", err) 43 } 44 // Govulncheck expects the path to be file:///c:/something 45 if runtime.GOOS == "windows" { 46 wd = "/" + wd 47 } 48 det := binary.New(&cpb.PluginConfig{ 49 PluginSpecific: []*cpb.PluginSpecificConfig{ 50 {Config: &cpb.PluginSpecificConfig_Govulncheck{Govulncheck: &cpb.GovulncheckConfig{ 51 OfflineVulnDbPath: filepath.ToSlash(filepath.Join(wd, "testdata", "vulndb")), 52 }}}, 53 }, 54 }) 55 px := setupPackageIndex([]string{binaryName}) 56 findings, err := det.Scan(t.Context(), scalibrfs.RealFSScanRoot("."), px) 57 if err != nil { 58 t.Fatalf("detector.Scan(%v): %v", px, err) 59 } 60 // There are two vulns in the test vulndb defined for two 61 // module dependencies of the test binary. Both dependencies 62 // are used at a vulnerable version. However, for only one 63 // there is a vulnerable symbol present in the binary. 64 if len(findings.PackageVulns) != 1 { 65 t.Fatalf("detector.Scan(%v): expected 1 finding, got: %v", px, findings.PackageVulns) 66 } 67 got := findings.PackageVulns[0] 68 want := &inventory.PackageVuln{ 69 Vulnerability: &osvpb.Vulnerability{ 70 Id: "GO-2022-1144", 71 Modified: ×tamppb.Timestamp{}, 72 Published: ×tamppb.Timestamp{}, 73 Withdrawn: ×tamppb.Timestamp{}, 74 Aliases: []string{"CVE-2022-41717", "GHSA-xrjj-mj9h-534m"}, 75 Summary: "Excessive memory growth in net/http and golang.org/x/net/http2", 76 Details: "An attacker can cause excessive memory growth in a Go server accepting HTTP/2 requests.\n\n" + 77 "HTTP/2 server connections contain a cache of HTTP header keys sent by the client. While the total " + 78 "number of entries in this cache is capped, an attacker sending very large keys can cause the " + 79 "server to allocate approximately 64 MiB per open connection.", 80 Affected: []*osvpb.Affected{ 81 { 82 Package: &osvpb.Package{Ecosystem: "Go", Name: "stdlib"}, 83 }, 84 }, 85 References: []*osvpb.Reference{ 86 {Type: osvpb.Reference_REPORT, Url: "https://go.dev/issue/56350"}, 87 {Type: osvpb.Reference_FIX, Url: "https://go.dev/cl/455717"}, 88 {Type: osvpb.Reference_FIX, Url: "https://go.dev/cl/455635"}, 89 { 90 Type: osvpb.Reference_WEB, 91 Url: "https://groups.google.com/g/golang-announce/c/L_3rmdT0BMU/m/yZDrXjIiBQAJ", 92 }, 93 }, 94 Credits: []*osvpb.Credit{{Name: "Josselin Costanzi"}}, 95 }, 96 } 97 98 // Remove some fields that might change between govulncheck versions. 99 got.Vulnerability.SchemaVersion = "" 100 got.Vulnerability.Modified = ×tamppb.Timestamp{} 101 got.Vulnerability.Published = ×tamppb.Timestamp{} 102 got.Vulnerability.Withdrawn = ×tamppb.Timestamp{} 103 got.Vulnerability.Affected = []*osvpb.Affected{got.Vulnerability.Affected[0]} 104 got.Vulnerability.Affected[0].Ranges = nil 105 got.Vulnerability.Affected[0].EcosystemSpecific = nil 106 got.Vulnerability.DatabaseSpecific = nil 107 108 if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" { 109 t.Errorf("detector.Scan(%v): unexpected findings (-want +got):\n%s", px, diff) 110 } 111 } 112 113 func TestScanErrorInGovulncheck(t *testing.T) { 114 wd, err := os.Getwd() 115 if err != nil { 116 t.Fatalf("os.Getwd(): %v", err) 117 } 118 // Govulncheck expects the path to be file:///c:/something 119 if runtime.GOOS == "windows" { 120 wd = "/" + wd 121 } 122 det := binary.New(&cpb.PluginConfig{ 123 PluginSpecific: []*cpb.PluginSpecificConfig{ 124 {Config: &cpb.PluginSpecificConfig_Govulncheck{Govulncheck: &cpb.GovulncheckConfig{ 125 OfflineVulnDbPath: filepath.ToSlash(filepath.Join(wd, "testdata", "vulndb")), 126 }}}, 127 }, 128 }) 129 px := setupPackageIndex([]string{"nonexistent", binaryName}) 130 result, err := det.Scan(t.Context(), scalibrfs.RealFSScanRoot("."), px) 131 if err == nil { 132 t.Fatalf("detector.Scan(%v): Expected an error, got none", px) 133 } 134 if len(result.PackageVulns) == 0 { 135 t.Fatalf("detector.Scan(%v): Expected scan results, got none", px) 136 } 137 } 138 139 func setupPackageIndex(names []string) *packageindex.PackageIndex { 140 var pkgs []*extractor.Package 141 for _, n := range names { 142 pkgs = append(pkgs, &extractor.Package{ 143 Name: n, 144 Version: "1.2.3", 145 PURLType: purl.TypeGolang, 146 Locations: []string{filepath.Join("testdata", n)}, 147 Plugins: []string{gobinary.Name}, 148 }) 149 } 150 px, _ := packageindex.New(pkgs) 151 return px 152 }