github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/debian/cataloger_test.go (about) 1 package debian 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/stretchr/testify/require" 9 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 TestDpkgCataloger(t *testing.T) { 16 tests := []struct { 17 name string 18 expected []pkg.Package 19 }{ 20 { 21 name: "image-dpkg", 22 expected: []pkg.Package{ 23 { 24 Name: "libpam-runtime", 25 Version: "1.1.8-3.6", 26 FoundBy: "dpkg-db-cataloger", 27 Licenses: pkg.NewLicenseSet( 28 pkg.NewLicenseFromLocations("GPL-1", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")), 29 pkg.NewLicenseFromLocations("GPL-2", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")), 30 pkg.NewLicenseFromLocations("LGPL-2.1", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")), 31 ), 32 Locations: file.NewLocationSet( 33 file.NewVirtualLocation("/var/lib/dpkg/status", "/var/lib/dpkg/status"), 34 file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.md5sums", "/var/lib/dpkg/info/libpam-runtime.md5sums"), 35 file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.conffiles", "/var/lib/dpkg/info/libpam-runtime.conffiles"), 36 file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright"), 37 ), 38 Type: pkg.DebPkg, 39 Metadata: pkg.DpkgDBEntry{ 40 Package: "libpam-runtime", 41 Source: "pam", 42 Version: "1.1.8-3.6", 43 Architecture: "all", 44 Maintainer: "Steve Langasek <vorlon@debian.org>", 45 InstalledSize: 1016, 46 Description: `Runtime support for the PAM library 47 Contains configuration files and directories required for 48 authentication to work on Debian systems. This package is required 49 on almost all installations.`, 50 Depends: []string{ 51 "debconf (>= 0.5) | debconf-2.0", 52 "debconf (>= 1.5.19) | cdebconf", 53 "libpam-modules (>= 1.0.1-6)", 54 }, 55 Files: []pkg.DpkgFileRecord{ 56 { 57 Path: "/etc/pam.conf", 58 Digest: &file.Digest{ 59 Algorithm: "md5", 60 Value: "87fc76f18e98ee7d3848f6b81b3391e5", 61 }, 62 IsConfigFile: true, 63 }, 64 { 65 Path: "/etc/pam.d/other", 66 Digest: &file.Digest{ 67 Algorithm: "md5", 68 Value: "31aa7f2181889ffb00b87df4126d1701", 69 }, 70 IsConfigFile: true, 71 }, 72 {Path: "/lib/x86_64-linux-gnu/libz.so.1.2.11", Digest: &file.Digest{ 73 Algorithm: "md5", 74 Value: "55f905631797551d4d936a34c7e73474", 75 }}, 76 {Path: "/usr/share/doc/zlib1g/changelog.Debian.gz", Digest: &file.Digest{ 77 Algorithm: "md5", 78 Value: "cede84bda30d2380217f97753c8ccf3a", 79 }}, 80 {Path: "/usr/share/doc/zlib1g/changelog.gz", Digest: &file.Digest{ 81 Algorithm: "md5", 82 Value: "f3c9dafa6da7992c47328b4464f6d122", 83 }}, 84 {Path: "/usr/share/doc/zlib1g/copyright", Digest: &file.Digest{ 85 Algorithm: "md5", 86 Value: "a4fae96070439a5209a62ae5b8017ab2", 87 }}, 88 }, 89 }, 90 }, 91 }, 92 }, 93 { 94 name: "image-distroless-deb", 95 expected: []pkg.Package{ 96 { 97 Name: "libsqlite3-0", 98 Version: "3.34.1-3", 99 FoundBy: "dpkg-db-cataloger", 100 Licenses: pkg.NewLicenseSet( 101 pkg.NewLicenseFromLocations("public-domain", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")), 102 pkg.NewLicenseFromLocations("GPL-2+", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")), 103 pkg.NewLicenseFromLocations("GPL-2", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")), 104 ), 105 Locations: file.NewLocationSet( 106 file.NewVirtualLocation("/var/lib/dpkg/status.d/libsqlite3-0", "/var/lib/dpkg/status.d/libsqlite3-0"), 107 file.NewVirtualLocation("/var/lib/dpkg/status.d/libsqlite3-0.md5sums", "/var/lib/dpkg/status.d/libsqlite3-0.md5sums"), 108 file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright"), 109 ), 110 Type: pkg.DebPkg, 111 Metadata: pkg.DpkgDBEntry{ 112 Package: "libsqlite3-0", 113 Source: "sqlite3", 114 Version: "3.34.1-3", 115 Architecture: "arm64", 116 Maintainer: "Laszlo Boszormenyi (GCS) <gcs@debian.org>", 117 InstalledSize: 1490, 118 Description: `SQLite 3 shared library 119 SQLite is a C library that implements an SQL database engine. 120 Programs that link with the SQLite library can have SQL database 121 access without running a separate RDBMS process.`, 122 Depends: []string{"libc6 (>= 2.29)"}, 123 Files: []pkg.DpkgFileRecord{ 124 {Path: "/usr/lib/aarch64-linux-gnu/libsqlite3.so.0.8.6", Digest: &file.Digest{ 125 Algorithm: "md5", 126 Value: "e11d70c96979a1328ae4e7e50542782b", 127 }}, 128 {Path: "/usr/share/doc/libsqlite3-0/README.Debian", Digest: &file.Digest{ 129 Algorithm: "md5", 130 Value: "9d8facc2fa9d2df52f1c7cb4e5fa4741", 131 }}, 132 {Path: "/usr/share/doc/libsqlite3-0/changelog.Debian.gz", Digest: &file.Digest{ 133 Algorithm: "md5", 134 Value: "a58942e742f5056be0595e6ba69a323f", 135 }}, 136 {Path: "/usr/share/doc/libsqlite3-0/changelog.gz", Digest: &file.Digest{ 137 Algorithm: "md5", 138 Value: "52317be84c3ca44b7888c6921131e37d", 139 }}, 140 {Path: "/usr/share/doc/libsqlite3-0/changelog.html.gz", Digest: &file.Digest{ 141 Algorithm: "md5", 142 Value: "a856310354e6c8768e85b39ae838dd0a", 143 }}, 144 {Path: "/usr/share/doc/libsqlite3-0/copyright", Digest: &file.Digest{ 145 Algorithm: "md5", 146 Value: "be64db3e095486e5e105652c51199358", 147 }}, 148 }, 149 }, 150 }, 151 }, 152 }, 153 } 154 155 for _, tt := range tests { 156 t.Run(tt.name, func(t *testing.T) { 157 c := NewDBCataloger() 158 pkgtest.NewCatalogTester(). 159 WithImageResolver(t, tt.name). 160 IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change 161 Expects(tt.expected, nil). 162 TestCataloger(t, c) 163 }) 164 } 165 } 166 167 func Test_CatalogerRelationships(t *testing.T) { 168 tests := []struct { 169 name string 170 fixture string 171 wantRelationships map[string][]string 172 }{ 173 { 174 name: "relationships for coreutils", 175 fixture: "test-fixtures/var/lib/dpkg/status.d/coreutils-relationships", 176 wantRelationships: map[string][]string{ 177 "coreutils": {"libacl1", "libattr1", "libc6", "libgmp10", "libselinux1"}, 178 "libacl1": {"libc6"}, 179 "libattr1": {"libc6"}, 180 "libc6": {"libgcc-s1"}, 181 "libgcc-s1": {"gcc-12-base", "libc6"}, 182 "libgmp10": {"libc6"}, 183 "libpcre2-8-0": {"libc6"}, 184 "libselinux1": {"libc6", "libpcre2-8-0"}, 185 }, 186 }, 187 { 188 name: "relationships from dpkg example docs", 189 fixture: "test-fixtures/var/lib/dpkg/status.d/doc-examples", 190 wantRelationships: map[string][]string{ 191 "made-up-package-1": {"gnumach-dev", "hurd-dev", "kernel-headers-2.2.10"}, 192 "made-up-package-2": {"liblua5.1-dev", "libluajit5.1-dev"}, 193 "made-up-package-3": {"bar", "foo"}, 194 // note that the "made-up-package-4" depends on "made-up-package-5" but not via the direct 195 // package name, but through the "provides" virtual package name "virtual-package-5". 196 "made-up-package-4": {"made-up-package-5"}, 197 // note that though there is a "default-mta | mail-transport-agent | not-installed" 198 // dependency choice we raise up the packages that are installed for every choice. 199 // In this case that means that "default-mta" and "mail-transport-agent". 200 "mutt": {"default-mta", "libc6", "mail-transport-agent"}, 201 }, 202 }, 203 { 204 name: "relationships for libpam-runtime", 205 fixture: "test-fixtures/var/lib/dpkg/status.d/libpam-runtime", 206 wantRelationships: map[string][]string{ 207 "libpam-runtime": {"cdebconf", "debconf-2.0", "debconf1", "debconf2", "libpam-modules"}, 208 }, 209 }, 210 } 211 for _, tt := range tests { 212 t.Run(tt.name, func(t *testing.T) { 213 pkgs, relationships, err := NewDBCataloger().Catalog(context.Background(), file.NewMockResolverForPaths(tt.fixture)) 214 require.NotEmpty(t, pkgs) 215 require.NotEmpty(t, relationships) 216 require.NoError(t, err) 217 218 if d := cmp.Diff(tt.wantRelationships, abstractRelationships(t, relationships)); d != "" { 219 t.Errorf("unexpected relationships (-want +got):\n%s", d) 220 } 221 }) 222 } 223 } 224 225 func TestCataloger_Globs(t *testing.T) { 226 tests := []struct { 227 name string 228 fixture string 229 expected []string 230 }{ 231 { 232 name: "obtain db status files", 233 fixture: "test-fixtures/glob-paths", 234 expected: []string{ 235 "var/lib/dpkg/status", 236 "var/lib/dpkg/status.d/pkg-1.0", 237 "usr/lib/opkg/status", 238 "usr/lib/opkg/info/pkg-1.0.control", 239 }, 240 }, 241 } 242 243 for _, test := range tests { 244 t.Run(test.name, func(t *testing.T) { 245 pkgtest.NewCatalogTester(). 246 FromDirectory(t, test.fixture). 247 ExpectsResolverContentQueries(test.expected). 248 TestCataloger(t, NewDBCataloger()) 249 }) 250 } 251 }