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