github.com/google/osv-scalibr@v0.4.1/binary/proto/package_vuln_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 proto_test 16 17 import ( 18 "errors" 19 "testing" 20 21 "github.com/google/go-cmp/cmp" 22 "github.com/google/go-cmp/cmp/cmpopts" 23 "github.com/google/go-cpy/cpy" 24 "github.com/google/osv-scalibr/binary/proto" 25 "github.com/google/osv-scalibr/extractor" 26 "github.com/google/osv-scalibr/inventory" 27 "github.com/google/osv-scalibr/inventory/vex" 28 "google.golang.org/protobuf/testing/protocmp" 29 30 spb "github.com/google/osv-scalibr/binary/proto/scan_result_go_proto" 31 osvpb "github.com/ossf/osv-schema/bindings/go/osvschema" 32 ) 33 34 var ( 35 idToPkg = map[string]*extractor.Package{ 36 "1": purlDPKGAnnotationPackage, 37 } 38 pkgToID = func() map[*extractor.Package]string { 39 m := make(map[*extractor.Package]string) 40 for id, pkg := range idToPkg { 41 m[pkg] = id 42 } 43 return m 44 }() 45 46 pkgVulnStruct1 = &inventory.PackageVuln{ 47 Vulnerability: &osvpb.Vulnerability{}, 48 Package: purlDPKGAnnotationPackage, 49 Plugins: []string{"cve/cve-1234-finder", "cve/cve-1234-enricher"}, 50 ExploitabilitySignals: []*vex.FindingExploitabilitySignal{{ 51 Plugin: "some-plugin", 52 Justification: vex.ComponentNotPresent, 53 }}, 54 } 55 pkgVulnProto1 = &spb.PackageVuln{ 56 Vuln: &osvpb.Vulnerability{}, 57 PackageId: "1", 58 Plugins: []string{"cve/cve-1234-finder", "cve/cve-1234-enricher"}, 59 ExploitabilitySignals: []*spb.FindingExploitabilitySignal{ 60 { 61 Plugin: "some-plugin", 62 Justification: spb.VexJustification_COMPONENT_NOT_PRESENT, 63 }, 64 }, 65 } 66 ) 67 68 func TestPackageVulnSetup(t *testing.T) { 69 if len(pkgToID) != len(idToPkg) { 70 t.Fatalf("pkgToID and idToPkg have different lengths: %d != %d", len(pkgToID), len(idToPkg)) 71 } 72 for pkg, id := range pkgToID { 73 otherPkg, ok := idToPkg[id] 74 if !ok { 75 t.Fatalf("package with ID %q not found in idToPkg map", id) 76 } 77 if pkg != otherPkg { 78 t.Fatalf("package with ID %q has different pointer value %v", id, otherPkg) 79 } 80 } 81 } 82 83 func TestPackageVulnToProto(t *testing.T) { 84 copier := cpy.New( 85 cpy.IgnoreAllUnexported(), 86 ) 87 88 testCases := []struct { 89 desc string 90 pkgVuln *inventory.PackageVuln 91 want *spb.PackageVuln 92 wantErr error 93 }{ 94 { 95 desc: "nil", 96 pkgVuln: nil, 97 want: nil, 98 }, 99 { 100 desc: "success", 101 pkgVuln: pkgVulnStruct1, 102 want: pkgVulnProto1, 103 }, 104 { 105 desc: "missing_package", 106 pkgVuln: func(p *inventory.PackageVuln) *inventory.PackageVuln { 107 p = copier.Copy(p).(*inventory.PackageVuln) 108 p.Package = nil 109 return p 110 }(pkgVulnStruct1), 111 want: func(p *spb.PackageVuln) *spb.PackageVuln { 112 p = copier.Copy(p).(*spb.PackageVuln) 113 p.PackageId = "" 114 return p 115 }(pkgVulnProto1), 116 }, 117 } 118 119 for _, tc := range testCases { 120 t.Run(tc.desc, func(t *testing.T) { 121 got, err := proto.PackageVulnToProto(tc.pkgVuln, pkgToID) 122 if !errors.Is(err, tc.wantErr) { 123 t.Fatalf("PackageVulnToProto(%v, %v) returned error %v, want error %v", tc.pkgVuln, pkgToID, err, tc.wantErr) 124 } 125 126 if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { 127 t.Fatalf("PackageVulnToProto(%+v, %+v) returned diff (-want +got):\n%s", tc.pkgVuln, pkgToID, diff) 128 } 129 }) 130 } 131 } 132 133 func TestPackageVulnToStruct(t *testing.T) { 134 copier := cpy.New( 135 cpy.IgnoreAllUnexported(), 136 ) 137 138 testCases := []struct { 139 desc string 140 pkgVuln *spb.PackageVuln 141 idToPkg map[string]*extractor.Package 142 want *inventory.PackageVuln 143 wantErr error 144 }{ 145 { 146 desc: "nil", 147 pkgVuln: nil, 148 want: nil, 149 }, 150 { 151 desc: "success", 152 pkgVuln: pkgVulnProto1, 153 idToPkg: idToPkg, 154 want: pkgVulnStruct1, 155 }, 156 { 157 desc: "missing_package_ID", 158 pkgVuln: func(p *spb.PackageVuln) *spb.PackageVuln { 159 p = copier.Copy(p).(*spb.PackageVuln) 160 p.PackageId = "" 161 return p 162 }(pkgVulnProto1), 163 idToPkg: idToPkg, 164 want: nil, 165 wantErr: cmpopts.AnyError, 166 }, 167 } 168 169 for _, tc := range testCases { 170 t.Run(tc.desc, func(t *testing.T) { 171 got, err := proto.PackageVulnToStruct(tc.pkgVuln, tc.idToPkg) 172 if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" { 173 t.Fatalf("PackageVulnToStruct(%v, %v) returned error %v, want error %v", tc.pkgVuln, tc.idToPkg, err, tc.wantErr) 174 } 175 if diff := cmp.Diff(tc.want, got, protocmp.Transform()); diff != "" { 176 t.Fatalf("PackageVulnToStruct(%v, %v) returned diff (-want +got):\n%s", tc.pkgVuln, tc.idToPkg, diff) 177 } 178 }) 179 } 180 }