github.com/google/osv-scalibr@v0.4.1/guidedremediation/internal/resolution/vulnerabilities_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 resolution_test 16 17 import ( 18 "testing" 19 20 "deps.dev/util/resolve" 21 "deps.dev/util/resolve/dep" 22 "deps.dev/util/resolve/schema" 23 "github.com/google/go-cmp/cmp" 24 "github.com/google/go-cmp/cmp/cmpopts" 25 "github.com/google/osv-scalibr/guidedremediation/internal/manifest" 26 "github.com/google/osv-scalibr/guidedremediation/internal/manifest/npm" 27 "github.com/google/osv-scalibr/guidedremediation/internal/resolution" 28 "github.com/google/osv-scalibr/guidedremediation/internal/vulnenrichertest" 29 ) 30 31 func TestFindVulnerabilities(t *testing.T) { 32 aliasType := func(knownAs string) dep.Type { 33 var typ dep.Type 34 typ.AddAttr(dep.KnownAs, knownAs) 35 return typ 36 } 37 m := mockManifest{ 38 name: "test", 39 version: "1.0.0", 40 system: resolve.NPM, 41 requirements: []mockManifestRequirements{ 42 { 43 name: "alice", 44 version: "^1.0.0", 45 }, 46 { 47 name: "alice", 48 version: "^2.0.0", 49 typ: aliasType("charlie"), 50 }, 51 { 52 name: "bob", 53 version: "*", 54 }, 55 }, 56 } 57 m.groups = map[manifest.RequirementKey][]string{ 58 npm.MakeRequirementKey(m.Requirements()[0]): {"dev"}, 59 npm.MakeRequirementKey(m.Requirements()[2]): {"dev"}, 60 } 61 62 g, err := schema.ParseResolve(` 63 test 1.0.0 64 alice@^1.0.0 1.0.0 65 $c@^2.0.1 66 KnownAs charlie | alice@^2.0.0 2.0.1 67 bob@* 1.0.0 68 c: charlie@^2.0.0 2.0.1 69 `, resolve.NPM) 70 if err != nil { 71 t.Fatal(err) 72 } 73 const ( 74 // Parsing the above graph should map packages to these nodes. 75 testNode resolve.NodeID = 0 76 aliceV1Node resolve.NodeID = 1 77 aliceV2Node resolve.NodeID = 2 78 bobNode resolve.NodeID = 3 79 charlieNode resolve.NodeID = 4 80 ) 81 82 vulnEnricher := vulnenrichertest.NewMockVulnerabilityEnricher(t, "testdata/vulnerabilities.json") 83 type vuln struct { 84 ID string 85 Nodes []resolve.NodeID 86 } 87 want := []vuln{ 88 { 89 ID: "VULN-000", 90 Nodes: []resolve.NodeID{ 91 aliceV1Node, 92 aliceV2Node, 93 }, 94 }, 95 { 96 ID: "VULN-001", 97 Nodes: []resolve.NodeID{ 98 aliceV1Node, 99 }, 100 }, 101 { 102 ID: "VULN-002", 103 Nodes: []resolve.NodeID{ 104 charlieNode, 105 }, 106 }, 107 { 108 ID: "VULN-003", 109 Nodes: []resolve.NodeID{ 110 bobNode, 111 charlieNode, 112 }, 113 }, 114 } 115 116 vulns, err := resolution.FindVulnerabilities(t.Context(), vulnEnricher, m.Groups(), g) 117 if err != nil { 118 t.Fatal(err) 119 } 120 got := make([]vuln, len(vulns)) 121 for i, v := range vulns { 122 got[i].ID = v.OSV.Id 123 for _, sg := range v.Subgraphs { 124 got[i].Nodes = append(got[i].Nodes, sg.Dependency) 125 } 126 } 127 128 cmpOpts := []cmp.Option{ 129 cmpopts.SortSlices(func(a, b vuln) bool { return a.ID < b.ID }), 130 cmpopts.SortSlices(func(a, b resolve.NodeID) bool { return a < b }), 131 } 132 133 if diff := cmp.Diff(want, got, cmpOpts...); diff != "" { 134 t.Errorf("FindVulnerabilities() mismatch (-want +got):\n%s", diff) 135 } 136 }