diff --git a/syft/cataloger/apkdb/parse_apk_db.go b/syft/cataloger/apkdb/parse_apk_db.go index 3ce1f921d..7f317c324 100644 --- a/syft/cataloger/apkdb/parse_apk_db.go +++ b/syft/cataloger/apkdb/parse_apk_db.go @@ -89,7 +89,16 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) { switch key { case "F": - lastFile = "/" + value + currentFile := "/" + value + + newFileRecord := pkg.ApkFileRecord{ + Path: currentFile, + } + files = append(files, newFileRecord) + fileRecord = &files[len(files)-1] + + // future aux references are relative to previous "F" records + lastFile = currentFile continue case "R": newFileRecord := pkg.ApkFileRecord{ @@ -97,7 +106,7 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) { } files = append(files, newFileRecord) fileRecord = &files[len(files)-1] - case "a": + case "a", "M": ownershipFields := strings.Split(value, ":") if len(ownershipFields) < 3 { log.Errorf("unexpected APK ownership field: %q", value) @@ -108,7 +117,7 @@ func parseApkDBEntry(reader io.Reader) (*pkg.ApkMetadata, error) { continue } fileRecord.OwnerUID = ownershipFields[0] - fileRecord.OwnerGUI = ownershipFields[1] + fileRecord.OwnerGID = ownershipFields[1] fileRecord.Permissions = ownershipFields[2] // note: there are more optional fields available that we are not capturing, e.g.: // "0:0:755:Q1JaDEHQHBbizhEzoWK1YxuraNU/4=" diff --git a/syft/cataloger/apkdb/parse_apk_db_test.go b/syft/cataloger/apkdb/parse_apk_db_test.go index c8846ac24..99ffb2d2b 100644 --- a/syft/cataloger/apkdb/parse_apk_db_test.go +++ b/syft/cataloger/apkdb/parse_apk_db_test.go @@ -19,10 +19,25 @@ func TestExtraFileAttributes(t *testing.T) { name: "test extra file attributes (checksum) are ignored", expected: pkg.ApkMetadata{ Files: []pkg.ApkFileRecord{ + { + Path: "/usr", + }, + { + Path: "/usr/lib", + }, + { + Path: "/usr/lib/jvm", + }, + { + Path: "/usr/lib/jvm/java-1.8-openjdk", + }, + { + Path: "/usr/lib/jvm/java-1.8-openjdk/bin", + }, { Path: "/usr/lib/jvm/java-1.8-openjdk/bin/policytool", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1M0C9qfC/+kdRiOodeihG2GMRtkE=", }, @@ -60,13 +75,13 @@ func TestExtraFileAttributes(t *testing.T) { } } -func TestSinglePackage(t *testing.T) { +func TestSinglePackageDetails(t *testing.T) { tests := []struct { - name string + fixture string expected pkg.ApkMetadata }{ { - name: "Test Single Package", + fixture: "test-fixtures/single", expected: pkg.ApkMetadata{ Package: "musl-utils", OriginPackage: "musl", @@ -82,51 +97,428 @@ func TestSinglePackage(t *testing.T) { PullChecksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=", GitCommitOfAport: "4024cc3b29ad4c65544ad068b8f59172b5494306", Files: []pkg.ApkFileRecord{ + { + Path: "/sbin", + }, { Path: "/sbin/ldconfig", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1Kja2+POZKxEkUOZqwSjC6kmaED4=", }, + { + Path: "/usr", + }, + { + Path: "/usr/bin", + }, { Path: "/usr/bin/iconv", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1CVmFbdY+Hv6/jAHl1gec2Kbx1EY=", }, { Path: "/usr/bin/ldd", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1yFAhGggmL7ERgbIA7KQxyTzf3ks=", }, { Path: "/usr/bin/getconf", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1dAdYK8M/INibRQF5B3Rw7cmNDDA=", }, { Path: "/usr/bin/getent", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1eR2Dz/WylabgbWMTkd2+hGmEya4=", }, }, }, }, + { + fixture: "test-fixtures/base", + expected: pkg.ApkMetadata{ + Package: "alpine-baselayout", + OriginPackage: "alpine-baselayout", + Version: "3.2.0-r6", + Description: "Alpine base dir structure and init scripts", + Maintainer: "Natanael Copa ", + License: "GPL-2.0-only", + Architecture: "x86_64", + URL: "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout", + Size: 19917, + InstalledSize: 409600, + PullDependencies: "/bin/sh so:libc.musl-x86_64.so.1", + PullChecksum: "Q1myMNfd7u5v5UTgNHeq1e31qTjZU=", + GitCommitOfAport: "e1c51734fa96fa4bac92e9f14a474324c67916fc", + Files: []pkg.ApkFileRecord{ + { + Path: "/dev", + }, + { + Path: "/dev/pts", + }, + { + Path: "/dev/shm", + }, + { + Path: "/etc", + }, + { + Path: "/etc/fstab", + Checksum: "Q11Q7hNe8QpDS531guqCdrXBzoA/o=", + }, + { + Path: "/etc/group", + Checksum: "Q1oJ16xWudgKOrXIEquEDzlF2Lsm4=", + }, + { + Path: "/etc/hostname", + Checksum: "Q16nVwYVXP/tChvUPdukVD2ifXOmc=", + }, + { + Path: "/etc/hosts", + Checksum: "Q1BD6zJKZTRWyqGnPi4tSfd3krsMU=", + }, + { + Path: "/etc/inittab", + Checksum: "Q1TsthbhW7QzWRe1E/NKwTOuD4pHc=", + }, + { + Path: "/etc/modules", + Checksum: "Q1toogjUipHGcMgECgPJX64SwUT1M=", + }, + { + Path: "/etc/motd", + Checksum: "Q1XmduVVNURHQ27TvYp1Lr5TMtFcA=", + }, + { + Path: "/etc/mtab", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "777", + Checksum: "Q1kiljhXXH1LlQroHsEJIkPZg2eiw=", + }, + { + Path: "/etc/passwd", + Checksum: "Q1TchuuLUfur0izvfZQZxgN/LJhB8=", + }, + { + Path: "/etc/profile", + Checksum: "Q1KpFb8kl5LvwXWlY3e58FNsjrI34=", + }, + { + Path: "/etc/protocols", + Checksum: "Q13FqXUnvuOpMDrH/6rehxuYAEE34=", + }, + { + Path: "/etc/services", + Checksum: "Q1C6HJNgQvLWqt5VY+n7MZJ1rsDuY=", + }, + { + Path: "/etc/shadow", + OwnerUID: "0", + OwnerGID: "42", + Permissions: "640", + Checksum: "Q1ltrPIAW2zHeDiajsex2Bdmq3uqA=", + }, + { + Path: "/etc/shells", + Checksum: "Q1ojm2YdpCJ6B/apGDaZ/Sdb2xJkA=", + }, + { + Path: "/etc/sysctl.conf", + Checksum: "Q14upz3tfnNxZkIEsUhWn7Xoiw96g=", + }, + { + Path: "/etc/apk", + }, + { + Path: "/etc/conf.d", + }, + { + Path: "/etc/crontabs", + }, + { + Path: "/etc/crontabs/root", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "600", + Checksum: "Q1vfk1apUWI4yLJGhhNRd0kJixfvY=", + }, + { + Path: "/etc/init.d", + }, + { + Path: "/etc/modprobe.d", + }, + { + Path: "/etc/modprobe.d/aliases.conf", + Checksum: "Q1WUbh6TBYNVK7e4Y+uUvLs/7viqk=", + }, + { + Path: "/etc/modprobe.d/blacklist.conf", + Checksum: "Q1xxYGU6S6TLQvb7ervPrWWwAWqMg=", + }, + { + Path: "/etc/modprobe.d/i386.conf", + Checksum: "Q1pnay/njn6ol9cCssL7KiZZ8etlc=", + }, + { + Path: "/etc/modprobe.d/kms.conf", + Checksum: "Q1ynbLn3GYDpvajba/ldp1niayeog=", + }, + { + Path: "/etc/modules-load.d", + }, + { + Path: "/etc/network", + }, + { + Path: "/etc/network/if-down.d", + }, + { + Path: "/etc/network/if-post-down.d", + }, + { + Path: "/etc/network/if-pre-up.d", + }, + { + Path: "/etc/network/if-up.d", + }, + { + Path: "/etc/opt", + }, + { + Path: "/etc/periodic", + }, + { + Path: "/etc/periodic/15min", + }, + { + Path: "/etc/periodic/daily", + }, + { + Path: "/etc/periodic/hourly", + }, + { + Path: "/etc/periodic/monthly", + }, + { + Path: "/etc/periodic/weekly", + }, + { + Path: "/etc/profile.d", + }, + { + Path: "/etc/profile.d/color_prompt", + Checksum: "Q10wL23GuSCVfumMRgakabUI6EsSk=", + }, + { + Path: "/etc/profile.d/locale", + Checksum: "Q1R4bIEpnKxxOSrlnZy9AoawqZ5DU=", + }, + { + Path: "/etc/sysctl.d", + }, + { + Path: "/home", + }, + { + Path: "/lib", + }, + { + Path: "/lib/firmware", + }, + { + Path: "/lib/mdev", + }, + { + Path: "/lib/modules-load.d", + }, + { + Path: "/lib/sysctl.d", + }, + { + Path: "/lib/sysctl.d/00-alpine.conf", + Checksum: "Q1HpElzW1xEgmKfERtTy7oommnq6c=", + }, + { + Path: "/media", + }, + { + Path: "/media/cdrom", + }, + { + Path: "/media/floppy", + }, + { + Path: "/media/usb", + }, + { + Path: "/mnt", + }, + { + Path: "/opt", + }, + { + Path: "/proc", + }, + { + Path: "/root", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "700", + }, + { + Path: "/run", + }, + { + Path: "/sbin", + }, + { + Path: "/sbin/mkmntdirs", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "755", + Checksum: "Q1YeuSmC7iDbEWrusPzA/zUQF6YSg=", + }, + { + Path: "/srv", + }, + { + Path: "/sys", + }, + { + Path: "/tmp", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "1777", + }, + { + Path: "/usr", + }, + { + Path: "/usr/lib", + }, + { + Path: "/usr/lib/modules-load.d", + }, + { + Path: "/usr/local", + }, + { + Path: "/usr/local/bin", + }, + { + Path: "/usr/local/lib", + }, + { + Path: "/usr/local/share", + }, + { + Path: "/usr/sbin", + }, + { + Path: "/usr/share", + }, + { + Path: "/usr/share/man", + }, + { + Path: "/usr/share/misc", + }, + { + Path: "/var", + }, + { + Path: "/var/run", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "777", + Checksum: "Q11/SNZz/8cK2dSKK+cJpVrZIuF4Q=", + }, + { + Path: "/var/cache", + }, + { + Path: "/var/cache/misc", + }, + { + Path: "/var/empty", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "555", + }, + { + Path: "/var/lib", + }, + { + Path: "/var/lib/misc", + }, + { + Path: "/var/local", + }, + { + Path: "/var/lock", + }, + { + Path: "/var/lock/subsys", + }, + { + Path: "/var/log", + }, + { + Path: "/var/mail", + }, + { + Path: "/var/opt", + }, + { + Path: "/var/spool", + }, + { + Path: "/var/spool/mail", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "777", + Checksum: "Q1dzbdazYZA2nTzSIG3YyNw7d4Juc=", + }, + { + Path: "/var/spool/cron", + }, + { + Path: "/var/spool/cron/crontabs", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "777", + Checksum: "Q1OFZt+ZMp7j0Gny0rqSKuWJyqYmA=", + }, + { + Path: "/var/tmp", + OwnerUID: "0", + OwnerGID: "0", + Permissions: "1777", + }, + }, + }, + }, } for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - file, err := os.Open("test-fixtures/single") + t.Run(test.fixture, func(t *testing.T) { + file, err := os.Open(test.fixture) if err != nil { - t.Fatal("Unable to read test_fixtures/single: ", err) + t.Fatal("Unable to read fixture: ", err) } defer func() { err := file.Close() @@ -203,38 +595,47 @@ func TestMultiplePackages(t *testing.T) { PullChecksum: "Q1bTtF5526tETKfL+lnigzIDvm+2o=", GitCommitOfAport: "4024cc3b29ad4c65544ad068b8f59172b5494306", Files: []pkg.ApkFileRecord{ + { + Path: "/sbin", + }, { Path: "/sbin/ldconfig", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1Kja2+POZKxEkUOZqwSjC6kmaED4=", }, + { + Path: "/usr", + }, + { + Path: "/usr/bin", + }, { Path: "/usr/bin/iconv", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1CVmFbdY+Hv6/jAHl1gec2Kbx1EY=", }, { Path: "/usr/bin/ldd", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1yFAhGggmL7ERgbIA7KQxyTzf3ks=", }, { Path: "/usr/bin/getconf", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1dAdYK8M/INibRQF5B3Rw7cmNDDA=", }, { Path: "/usr/bin/getent", OwnerUID: "0", - OwnerGUI: "0", + OwnerGID: "0", Permissions: "755", Checksum: "Q1eR2Dz/WylabgbWMTkd2+hGmEya4=", }, diff --git a/syft/cataloger/apkdb/test-fixtures/base b/syft/cataloger/apkdb/test-fixtures/base new file mode 100644 index 000000000..6fc37e44f --- /dev/null +++ b/syft/cataloger/apkdb/test-fixtures/base @@ -0,0 +1,149 @@ +C:Q1myMNfd7u5v5UTgNHeq1e31qTjZU= +P:alpine-baselayout +V:3.2.0-r6 +A:x86_64 +S:19917 +I:409600 +T:Alpine base dir structure and init scripts +U:https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout +L:GPL-2.0-only +o:alpine-baselayout +m:Natanael Copa +t:1590679557 +c:e1c51734fa96fa4bac92e9f14a474324c67916fc +D:/bin/sh so:libc.musl-x86_64.so.1 +p:cmd:mkmntdirs +F:dev +F:dev/pts +F:dev/shm +F:etc +R:fstab +Z:Q11Q7hNe8QpDS531guqCdrXBzoA/o= +R:group +Z:Q1oJ16xWudgKOrXIEquEDzlF2Lsm4= +R:hostname +Z:Q16nVwYVXP/tChvUPdukVD2ifXOmc= +R:hosts +Z:Q1BD6zJKZTRWyqGnPi4tSfd3krsMU= +R:inittab +Z:Q1TsthbhW7QzWRe1E/NKwTOuD4pHc= +R:modules +Z:Q1toogjUipHGcMgECgPJX64SwUT1M= +R:motd +Z:Q1XmduVVNURHQ27TvYp1Lr5TMtFcA= +R:mtab +a:0:0:777 +Z:Q1kiljhXXH1LlQroHsEJIkPZg2eiw= +R:passwd +Z:Q1TchuuLUfur0izvfZQZxgN/LJhB8= +R:profile +Z:Q1KpFb8kl5LvwXWlY3e58FNsjrI34= +R:protocols +Z:Q13FqXUnvuOpMDrH/6rehxuYAEE34= +R:services +Z:Q1C6HJNgQvLWqt5VY+n7MZJ1rsDuY= +R:shadow +a:0:42:640 +Z:Q1ltrPIAW2zHeDiajsex2Bdmq3uqA= +R:shells +Z:Q1ojm2YdpCJ6B/apGDaZ/Sdb2xJkA= +R:sysctl.conf +Z:Q14upz3tfnNxZkIEsUhWn7Xoiw96g= +F:etc/apk +F:etc/conf.d +F:etc/crontabs +R:root +a:0:0:600 +Z:Q1vfk1apUWI4yLJGhhNRd0kJixfvY= +F:etc/init.d +F:etc/modprobe.d +R:aliases.conf +Z:Q1WUbh6TBYNVK7e4Y+uUvLs/7viqk= +R:blacklist.conf +Z:Q1xxYGU6S6TLQvb7ervPrWWwAWqMg= +R:i386.conf +Z:Q1pnay/njn6ol9cCssL7KiZZ8etlc= +R:kms.conf +Z:Q1ynbLn3GYDpvajba/ldp1niayeog= +F:etc/modules-load.d +F:etc/network +F:etc/network/if-down.d +F:etc/network/if-post-down.d +F:etc/network/if-pre-up.d +F:etc/network/if-up.d +F:etc/opt +F:etc/periodic +F:etc/periodic/15min +F:etc/periodic/daily +F:etc/periodic/hourly +F:etc/periodic/monthly +F:etc/periodic/weekly +F:etc/profile.d +R:color_prompt +Z:Q10wL23GuSCVfumMRgakabUI6EsSk= +R:locale +Z:Q1R4bIEpnKxxOSrlnZy9AoawqZ5DU= +F:etc/sysctl.d +F:home +F:lib +F:lib/firmware +F:lib/mdev +F:lib/modules-load.d +F:lib/sysctl.d +R:00-alpine.conf +Z:Q1HpElzW1xEgmKfERtTy7oommnq6c= +F:media +F:media/cdrom +F:media/floppy +F:media/usb +F:mnt +F:opt +F:proc +F:root +M:0:0:700 +F:run +F:sbin +R:mkmntdirs +a:0:0:755 +Z:Q1YeuSmC7iDbEWrusPzA/zUQF6YSg= +F:srv +F:sys +F:tmp +M:0:0:1777 +F:usr +F:usr/lib +F:usr/lib/modules-load.d +F:usr/local +F:usr/local/bin +F:usr/local/lib +F:usr/local/share +F:usr/sbin +F:usr/share +F:usr/share/man +F:usr/share/misc +F:var +R:run +a:0:0:777 +Z:Q11/SNZz/8cK2dSKK+cJpVrZIuF4Q= +F:var/cache +F:var/cache/misc +F:var/empty +M:0:0:555 +F:var/lib +F:var/lib/misc +F:var/local +F:var/lock +F:var/lock/subsys +F:var/log +F:var/mail +F:var/opt +F:var/spool +R:mail +a:0:0:777 +Z:Q1dzbdazYZA2nTzSIG3YyNw7d4Juc= +F:var/spool/cron +R:crontabs +a:0:0:777 +Z:Q1OFZt+ZMp7j0Gny0rqSKuWJyqYmA= +F:var/tmp +M:0:0:1777 \ No newline at end of file diff --git a/syft/pkg/apk_metadata.go b/syft/pkg/apk_metadata.go index a77f2f764..ef036509a 100644 --- a/syft/pkg/apk_metadata.go +++ b/syft/pkg/apk_metadata.go @@ -29,10 +29,10 @@ type ApkMetadata struct { // ApkFileRecord represents a single file listing and metadata from a APK DB entry (which may have many of these file records). type ApkFileRecord struct { Path string `json:"path"` - OwnerUID string `json:"ownerUid"` - OwnerGUI string `json:"ownerGid"` - Permissions string `json:"permissions"` - Checksum string `json:"checksum"` + OwnerUID string `json:"ownerUid,omitempty"` + OwnerGID string `json:"ownerGid,omitempty"` + Permissions string `json:"permissions,omitempty"` + Checksum string `json:"checksum,omitempty"` } func (m ApkMetadata) PackageURL() string {