github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/alpine/cataloger_test.go (about) 1 package alpine 2 3 import ( 4 "testing" 5 6 "github.com/google/go-cmp/cmp" 7 "github.com/google/go-cmp/cmp/cmpopts" 8 9 "github.com/anchore/syft/syft/artifact" 10 "github.com/anchore/syft/syft/file" 11 "github.com/anchore/syft/syft/pkg" 12 "github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest" 13 ) 14 15 func TestApkDBCataloger(t *testing.T) { 16 dbLocation := file.NewLocation("lib/apk/db/installed") 17 18 bashPkg := pkg.Package{ 19 Name: "bash", 20 Version: "5.2.21-r0", 21 Type: pkg.ApkPkg, 22 FoundBy: "apk-db-cataloger", 23 Licenses: pkg.NewLicenseSet( 24 pkg.NewLicenseFromLocations("GPL-3.0-or-later", dbLocation), 25 ), 26 Locations: file.NewLocationSet(dbLocation), 27 Metadata: pkg.ApkDBEntry{ 28 Package: "bash", 29 OriginPackage: "bash", 30 Maintainer: "Natanael Copa <ncopa@alpinelinux.org>", 31 Version: "5.2.21-r0", 32 Architecture: "x86_64", 33 URL: "https://www.gnu.org/software/bash/bash.html", 34 Description: "The GNU Bourne Again shell", 35 Size: 448728, 36 InstalledSize: 1396736, 37 Dependencies: []string{ 38 "/bin/sh", "so:libc.musl-x86_64.so.1", "so:libreadline.so.8", 39 }, 40 Provides: []string{ 41 "cmd:bash=5.2.21-r0", 42 }, 43 // note: files not provided and not under test 44 }, 45 } 46 47 busyboxBinshPkg := pkg.Package{ 48 Name: "busybox-binsh", 49 Version: "1.36.1-r15", 50 Type: pkg.ApkPkg, 51 FoundBy: "apk-db-cataloger", 52 Licenses: pkg.NewLicenseSet( 53 pkg.NewLicenseFromLocations("GPL-2.0-only", dbLocation), 54 ), 55 Locations: file.NewLocationSet(dbLocation), 56 Metadata: pkg.ApkDBEntry{ 57 Package: "busybox-binsh", 58 OriginPackage: "busybox", 59 Maintainer: "Sören Tempel <soeren+alpine@soeren-tempel.net>", 60 Version: "1.36.1-r15", 61 Architecture: "x86_64", 62 URL: "https://busybox.net/", 63 Description: "busybox ash /bin/sh", 64 Size: 1543, 65 InstalledSize: 8192, 66 Dependencies: []string{ 67 "busybox=1.36.1-r15", 68 }, 69 Provides: []string{ 70 "/bin/sh", "cmd:sh=1.36.1-r15", 71 }, 72 // note: files not provided and not under test 73 }, 74 } 75 76 muslPkg := pkg.Package{ 77 Name: "musl", 78 Version: "1.2.4_git20230717-r4", 79 Type: pkg.ApkPkg, 80 FoundBy: "apk-db-cataloger", 81 Licenses: pkg.NewLicenseSet( 82 pkg.NewLicenseFromLocations("MIT", dbLocation), 83 ), 84 Locations: file.NewLocationSet(dbLocation), 85 Metadata: pkg.ApkDBEntry{ 86 Package: "musl", 87 OriginPackage: "musl", 88 Maintainer: "Timo Teräs <timo.teras@iki.fi>", 89 Version: "1.2.4_git20230717-r4", 90 Architecture: "x86_64", 91 URL: "https://musl.libc.org/", 92 Description: "the musl c library (libc) implementation", 93 Size: 407278, 94 InstalledSize: 667648, 95 Dependencies: []string{}, 96 Provides: []string{ 97 "so:libc.musl-x86_64.so.1=1", 98 }, 99 // note: files not provided and not under test 100 }, 101 } 102 103 readlinePkg := pkg.Package{ 104 Name: "readline", 105 Version: "8.2.1-r2", 106 Type: pkg.ApkPkg, 107 FoundBy: "apk-db-cataloger", 108 Licenses: pkg.NewLicenseSet( 109 pkg.NewLicenseFromLocations("GPL-2.0-or-later", dbLocation), 110 ), 111 Locations: file.NewLocationSet(dbLocation), 112 Metadata: pkg.ApkDBEntry{ 113 Package: "readline", 114 OriginPackage: "readline", 115 Maintainer: "Natanael Copa <ncopa@alpinelinux.org>", 116 Version: "8.2.1-r2", 117 Architecture: "x86_64", 118 URL: "https://tiswww.cwru.edu/php/chet/readline/rltop.html", 119 Description: "GNU readline library", 120 Size: 119878, 121 InstalledSize: 303104, 122 Dependencies: []string{ 123 "so:libc.musl-x86_64.so.1", "so:libncursesw.so.6", 124 }, 125 Provides: []string{ 126 "so:libreadline.so.8=8.2", 127 }, 128 // note: files not provided and not under test 129 }, 130 } 131 132 expectedPkgs := []pkg.Package{ 133 bashPkg, 134 busyboxBinshPkg, 135 muslPkg, 136 readlinePkg, 137 } 138 139 // # apk info --depends bash 140 // bash-5.2.21-r0 depends on: 141 // /bin/sh 142 // so:libc.musl-x86_64.so.1 143 // so:libreadline.so.8 144 // 145 // # apk info --who-owns /bin/sh 146 // /bin/sh is owned by busybox-binsh-1.36.1-r15 147 // 148 // # find / | grep musl 149 // /lib/ld-musl-x86_64.so.1 150 // /lib/libc.musl-x86_64.so.1 151 // 152 // # apk info --who-owns '/lib/libc.musl-x86_64.so.1' 153 // /lib/libc.musl-x86_64.so.1 is owned by musl-1.2.4_git20230717-r4 154 // 155 // # find / | grep libreadline 156 // /usr/lib/libreadline.so.8.2 157 // /usr/lib/libreadline.so.8 158 // 159 // # apk info --who-owns '/usr/lib/libreadline.so.8' 160 // /usr/lib/libreadline.so.8 is owned by readline-8.2.1-r2 161 162 expectedRelationships := []artifact.Relationship{ 163 { 164 From: busyboxBinshPkg, 165 To: bashPkg, 166 Type: artifact.DependencyOfRelationship, 167 }, 168 { 169 From: readlinePkg, 170 To: bashPkg, 171 Type: artifact.DependencyOfRelationship, 172 }, 173 { 174 From: muslPkg, 175 To: readlinePkg, 176 Type: artifact.DependencyOfRelationship, 177 }, 178 { 179 From: muslPkg, 180 To: bashPkg, 181 Type: artifact.DependencyOfRelationship, 182 }, 183 } 184 185 pkgtest.NewCatalogTester(). 186 FromDirectory(t, "test-fixtures/multiple-1"). 187 WithCompareOptions(cmpopts.IgnoreFields(pkg.ApkDBEntry{}, "Files", "GitCommit", "Checksum")). 188 Expects(expectedPkgs, expectedRelationships). 189 TestCataloger(t, NewDBCataloger()) 190 191 } 192 193 func TestCatalogerDependencyTree(t *testing.T) { 194 assertion := func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) { 195 expected := map[string][]string{ 196 "alpine-baselayout": {"busybox", "alpine-baselayout-data", "musl"}, 197 "apk-tools": {"ca-certificates-bundle", "musl", "libcrypto1.1", "libssl1.1", "zlib"}, 198 "busybox": {"musl"}, 199 "libc-utils": {"musl-utils"}, 200 "libcrypto1.1": {"musl"}, 201 "libssl1.1": {"musl", "libcrypto1.1"}, 202 "musl-utils": {"scanelf", "musl"}, 203 "scanelf": {"musl"}, 204 "ssl_client": {"musl", "libcrypto1.1", "libssl1.1"}, 205 "zlib": {"musl"}, 206 } 207 pkgsByID := make(map[artifact.ID]pkg.Package) 208 for _, p := range pkgs { 209 p.SetID() 210 pkgsByID[p.ID()] = p 211 } 212 213 actualDependencies := make(map[string][]string) 214 215 for _, r := range relationships { 216 switch r.Type { 217 case artifact.DependencyOfRelationship: 218 to := pkgsByID[r.To.ID()] 219 from := pkgsByID[r.From.ID()] 220 actualDependencies[to.Name] = append(actualDependencies[to.Name], from.Name) 221 default: 222 t.Fatalf("unexpected relationship type: %+v", r.Type) 223 } 224 } 225 226 if d := cmp.Diff(expected, actualDependencies); d != "" { 227 t.Fail() 228 t.Log(d) 229 } 230 } 231 232 pkgtest.NewCatalogTester(). 233 FromDirectory(t, "test-fixtures/multiple-2"). 234 ExpectsAssertion(assertion). 235 TestCataloger(t, NewDBCataloger()) 236 237 } 238 239 func TestCataloger_Globs(t *testing.T) { 240 tests := []struct { 241 name string 242 fixture string 243 expected []string 244 }{ 245 { 246 name: "obtain DB files", 247 fixture: "test-fixtures/glob-paths", 248 expected: []string{"lib/apk/db/installed"}, 249 }, 250 } 251 252 for _, test := range tests { 253 t.Run(test.name, func(t *testing.T) { 254 pkgtest.NewCatalogTester(). 255 FromDirectory(t, test.fixture). 256 ExpectsResolverContentQueries(test.expected). 257 IgnoreUnfulfilledPathResponses("etc/apk/repositories"). 258 TestCataloger(t, NewDBCataloger()) 259 }) 260 } 261 }