featurefmt: Extract source packages and binary packages

The featurefmt now extracts both binary packages and source packages
from the package manager infos.
This commit is contained in:
Sida Chen 2019-02-19 16:38:07 -05:00
parent 7dd989c0f2
commit 0e0d8b38bb
6 changed files with 610 additions and 382 deletions

View File

@ -55,6 +55,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
line := scanner.Text() line := scanner.Text()
if len(line) < 2 { if len(line) < 2 {
if valid(&pkg) { if valid(&pkg) {
pkg.Type = database.BinaryPackage
packages.Add(pkg) packages.Add(pkg)
pkg = database.Feature{VersionFormat: dpkg.ParserName} pkg = database.Feature{VersionFormat: dpkg.ParserName}
} }
@ -81,6 +82,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// in case of no terminal line // in case of no terminal line
if valid(&pkg) { if valid(&pkg) {
pkg.Type = database.BinaryPackage
packages.Add(pkg) packages.Add(pkg)
} }

View File

@ -28,17 +28,17 @@ func TestAPKFeatureDetection(t *testing.T) {
"valid case", "valid case",
map[string]string{"lib/apk/db/installed": "apk/testdata/valid"}, map[string]string{"lib/apk/db/installed": "apk/testdata/valid"},
[]database.Feature{ []database.Feature{
{"musl", "1.1.14-r10", "", "", dpkg.ParserName}, {"apk-tools", "2.6.7-r0", "dpkg", "binary"},
{"busybox", "1.24.2-r9", "", "", dpkg.ParserName}, {"musl", "1.1.14-r10", "dpkg", "binary"},
{"alpine-baselayout", "3.0.3-r0", "", "", dpkg.ParserName}, {"libssl1.0", "1.0.2h-r1", "dpkg", "binary"},
{"alpine-keys", "1.1-r0", "", "", dpkg.ParserName}, {"libc-utils", "0.7-r0", "dpkg", "binary"},
{"zlib", "1.2.8-r2", "", "", dpkg.ParserName}, {"busybox", "1.24.2-r9", "dpkg", "binary"},
{"libcrypto1.0", "1.0.2h-r1", "", "", dpkg.ParserName}, {"scanelf", "1.1.6-r0", "dpkg", "binary"},
{"libssl1.0", "1.0.2h-r1", "", "", dpkg.ParserName}, {"alpine-keys", "1.1-r0", "dpkg", "binary"},
{"apk-tools", "2.6.7-r0", "", "", dpkg.ParserName}, {"libcrypto1.0", "1.0.2h-r1", "dpkg", "binary"},
{"scanelf", "1.1.6-r0", "", "", dpkg.ParserName}, {"zlib", "1.2.8-r2", "dpkg", "binary"},
{"musl-utils", "1.1.14-r10", "", "", dpkg.ParserName}, {"musl-utils", "1.1.14-r10", "dpkg", "binary"},
{"libc-utils", "0.7-r0", "", "", dpkg.ParserName}, {"alpine-baselayout", "3.0.3-r0", "dpkg", "binary"},
}, },
}, },
} { } {

View File

@ -37,45 +37,59 @@ var (
type lister struct{} type lister struct{}
func (l lister) RequiredFilenames() []string {
return []string{"var/lib/dpkg/status"}
}
func init() { func init() {
featurefmt.RegisterLister("dpkg", "1.0", &lister{}) featurefmt.RegisterLister("dpkg", "1.0", &lister{})
} }
func valid(pkg *database.Feature) bool {
return pkg.Name != "" && pkg.Version != ""
}
func addSourcePackage(pkg *database.Feature) {
if pkg.SourceName == "" {
pkg.SourceName = pkg.Name
}
if pkg.SourceVersion == "" {
pkg.SourceVersion = pkg.Version
}
}
func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) { func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
f, hasFile := files["var/lib/dpkg/status"] f, hasFile := files["var/lib/dpkg/status"]
if !hasFile { if !hasFile {
return []database.Feature{}, nil return []database.Feature{}, nil
} }
var ( packages := mapset.NewSet()
pkg = database.Feature{VersionFormat: dpkg.ParserName}
pkgs = mapset.NewSet()
err error
)
scanner := bufio.NewScanner(strings.NewReader(string(f))) scanner := bufio.NewScanner(strings.NewReader(string(f)))
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "Package: ") { if line == "" {
// Package line continue
// Defines the name of the package }
pkg.Name = strings.TrimSpace(strings.TrimPrefix(line, "Package: ")) binary, source := parseDpkgDB(scanner)
pkg.Version = "" if binary != nil {
packages.Add(*binary)
}
if source != nil {
packages.Add(*source)
}
}
return database.ConvertFeatureSetToFeatures(packages), nil
}
// parseDpkgDB consumes the status file scanner exactly one package info, until
// EOF or empty space, and generate the parsed packages from it.
func parseDpkgDB(scanner *bufio.Scanner) (binaryPackage *database.Feature, sourcePackage *database.Feature) {
var (
name string
version string
sourceName string
sourceVersion string
)
for {
line := strings.TrimSpace(scanner.Text())
if line == "" {
break
}
if strings.HasPrefix(line, "Package: ") {
name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
} else if strings.HasPrefix(line, "Source: ") { } else if strings.HasPrefix(line, "Source: ") {
// Source line (Optional) // Source line (Optional)
// Gives the name of the source package // Gives the name of the source package
@ -87,14 +101,9 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n) md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n)
} }
pkg.SourceName = md["name"] sourceName = md["name"]
if md["version"] != "" { if md["version"] != "" {
version := md["version"] sourceVersion = md["version"]
if err = versionfmt.Valid(dpkg.ParserName, version); err != nil {
log.WithError(err).WithField("version", string(line[1])).Warning("could not parse package version. skipping")
} else {
pkg.SourceVersion = version
}
} }
} else if strings.HasPrefix(line, "Version: ") { } else if strings.HasPrefix(line, "Version: ") {
// Version line // Version line
@ -102,25 +111,43 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// This version is less important than a version retrieved from a Source line // This version is less important than a version retrieved from a Source line
// because the Debian vulnerabilities often skips the epoch from the Version field // because the Debian vulnerabilities often skips the epoch from the Version field
// which is not present in the Source version, and because +bX revisions don't matter // which is not present in the Source version, and because +bX revisions don't matter
version := strings.TrimPrefix(line, "Version: ") version = strings.TrimPrefix(line, "Version: ")
if err = versionfmt.Valid(dpkg.ParserName, version); err != nil { }
log.WithError(err).WithField("version", string(line[1])).Warning("could not parse package version. skipping")
if !scanner.Scan() {
break
}
}
if name != "" && version != "" {
if err := versionfmt.Valid(dpkg.ParserName, version); err != nil {
log.WithError(err).WithFields(log.Fields{"name": name, "version": version}).Warning("skipped unparseable package")
} else { } else {
pkg.Version = version binaryPackage = &database.Feature{name, version, dpkg.ParserName, database.BinaryPackage}
}
} else if line == "" {
pkg = database.Feature{VersionFormat: dpkg.ParserName}
}
if valid(&pkg) {
addSourcePackage(&pkg)
pkgs.Add(pkg)
} }
} }
return database.ConvertFeatureSetToFeatures(pkgs), nil // Source version and names are computed from binary package names and versions
} // in dpkg.
// Source package name:
func (l lister) RequiredFilenames() []string { // https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n338
return []string{"var/lib/dpkg/status"} // Source package version:
// https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/pkg-format.c#n355
if sourceName == "" {
sourceName = name
}
if sourceVersion == "" {
sourceVersion = version
}
if sourceName != "" && sourceVersion != "" {
if err := versionfmt.Valid(dpkg.ParserName, version); err != nil {
log.WithError(err).WithFields(log.Fields{"name": name, "version": version}).Warning("skipped unparseable package")
} else {
sourcePackage = &database.Feature{sourceName, sourceVersion, dpkg.ParserName, database.SourcePackage}
}
}
return
} }

View File

@ -28,105 +28,168 @@ func TestListFeatures(t *testing.T) {
"valid status file", "valid status file",
map[string]string{"var/lib/dpkg/status": "dpkg/testdata/valid"}, map[string]string{"var/lib/dpkg/status": "dpkg/testdata/valid"},
[]database.Feature{ []database.Feature{
{"adduser", "3.116ubuntu1", "adduser", "3.116ubuntu1", dpkg.ParserName}, {"libapt-pkg5.0", "1.6.3ubuntu0.1", "dpkg", "binary"},
{"apt", "1.6.3ubuntu0.1", "apt", "1.6.3ubuntu0.1", dpkg.ParserName}, {"perl-base", "5.26.1-6ubuntu0.2", "dpkg", "binary"},
{"base-files", "10.1ubuntu2.2", "base-files", "10.1ubuntu2.2", dpkg.ParserName}, {"libmount1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"base-passwd", "3.5.44", "base-passwd", "3.5.44", dpkg.ParserName}, {"perl", "5.26.1-6ubuntu0.2", "dpkg", "source"},
{"bash", "4.4.18-2ubuntu1", "bash", "4.4.18-2ubuntu1", dpkg.ParserName}, {"libgnutls30", "3.5.18-1ubuntu1", "dpkg", "binary"},
{"bsdutils", "1:2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"liblzma5", "5.2.2-1.3", "dpkg", "binary"},
{"bzip2", "1.0.6-8.1", "bzip2", "1.0.6-8.1", dpkg.ParserName}, {"ncurses-bin", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
{"coreutils", "8.28-1ubuntu1", "coreutils", "8.28-1ubuntu1", dpkg.ParserName}, {"lsb", "9.20170808ubuntu1", "dpkg", "source"},
{"dash", "0.5.8-2.10", "dash", "0.5.8-2.10", dpkg.ParserName}, {"sed", "4.4-2", "dpkg", "source"},
{"debconf", "1.5.66", "debconf", "1.5.66", dpkg.ParserName}, {"libsystemd0", "237-3ubuntu10.3", "dpkg", "binary"},
{"debianutils", "4.8.4", "debianutils", "4.8.4", dpkg.ParserName}, {"procps", "2:3.3.12-3ubuntu1.1", "dpkg", "source"},
{"diffutils", "1:3.6-1", "diffutils", "1:3.6-1", dpkg.ParserName}, {"login", "1:4.5-1ubuntu1", "dpkg", "binary"},
{"dpkg", "1.19.0.5ubuntu2", "dpkg", "1.19.0.5ubuntu2", dpkg.ParserName}, {"libunistring2", "0.9.9-0ubuntu1", "dpkg", "binary"},
{"e2fsprogs", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName}, {"sed", "4.4-2", "dpkg", "binary"},
{"fdisk", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"libselinux", "2.7-2build2", "dpkg", "source"},
{"findutils", "4.6.0+git+20170828-2", "findutils", "4.6.0+git+20170828-2", dpkg.ParserName}, {"libseccomp", "2.3.1-2.1ubuntu4", "dpkg", "source"},
{"gcc-8-base", "8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2", dpkg.ParserName}, {"libss2", "1.44.1-1", "dpkg", "binary"},
{"gpgv", "2.2.4-1ubuntu1.1", "gnupg2", "2.2.4-1ubuntu1.1", dpkg.ParserName}, {"liblz4-1", "0.0~r131-2ubuntu3", "dpkg", "binary"},
{"grep", "3.1-2", "grep", "3.1-2", dpkg.ParserName}, {"libsemanage1", "2.7-2build2", "dpkg", "binary"},
{"gzip", "1.6-5ubuntu1", "gzip", "1.6-5ubuntu1", dpkg.ParserName}, {"libtasn1-6", "4.13-2", "dpkg", "source"},
{"hostname", "3.20", "hostname", "3.20", dpkg.ParserName}, {"libzstd1", "1.3.3+dfsg-2ubuntu1", "dpkg", "binary"},
{"init-system-helpers", "1.51", "init-system-helpers", "1.51", dpkg.ParserName}, {"fdisk", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"libacl1", "2.2.52-3build1", "acl", "2.2.52-3build1", dpkg.ParserName}, {"xz-utils", "5.2.2-1.3", "dpkg", "source"},
{"libapt-pkg5.0", "1.6.3ubuntu0.1", "apt", "1.6.3ubuntu0.1", dpkg.ParserName}, {"lsb-base", "9.20170808ubuntu1", "dpkg", "binary"},
{"libattr1", "1:2.4.47-2build1", "attr", "1:2.4.47-2build1", dpkg.ParserName}, {"libpam-modules-bin", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
{"libaudit-common", "1:2.8.2-1ubuntu1", "audit", "1:2.8.2-1ubuntu1", dpkg.ParserName}, {"dash", "0.5.8-2.10", "dpkg", "binary"},
{"libaudit1", "1:2.8.2-1ubuntu1", "audit", "1:2.8.2-1ubuntu1", dpkg.ParserName}, {"gnupg2", "2.2.4-1ubuntu1.1", "dpkg", "source"},
{"libblkid1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"libfdisk1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"libbz2-1.0", "1.0.6-8.1", "bzip2", "1.0.6-8.1", dpkg.ParserName}, {"lz4", "0.0~r131-2ubuntu3", "dpkg", "source"},
{"libc-bin", "2.27-3ubuntu1", "glibc", "2.27-3ubuntu1", dpkg.ParserName}, {"libpam0g", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
{"libc6", "2.27-3ubuntu1", "glibc", "2.27-3ubuntu1", dpkg.ParserName}, {"libc-bin", "2.27-3ubuntu1", "dpkg", "binary"},
{"libcap-ng0", "0.7.7-3.1", "libcap-ng", "0.7.7-3.1", dpkg.ParserName}, {"libcap-ng", "0.7.7-3.1", "dpkg", "source"},
{"libcom-err2", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName}, {"libcom-err2", "1.44.1-1", "dpkg", "binary"},
{"libdb5.3", "5.3.28-13.1ubuntu1", "db5.3", "5.3.28-13.1ubuntu1", dpkg.ParserName}, {"libudev1", "237-3ubuntu10.3", "dpkg", "binary"},
{"libdebconfclient0", "0.213ubuntu1", "cdebconf", "0.213ubuntu1", dpkg.ParserName}, {"debconf", "1.5.66", "dpkg", "binary"},
{"libext2fs2", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName}, {"tar", "1.29b-2", "dpkg", "binary"},
{"libfdisk1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"diffutils", "1:3.6-1", "dpkg", "source"},
{"libffi6", "3.2.1-8", "libffi", "3.2.1-8", dpkg.ParserName}, {"gcc-8", "8-20180414-1ubuntu2", "dpkg", "source"},
{"libgcc1", "1:8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2", dpkg.ParserName}, {"e2fsprogs", "1.44.1-1", "dpkg", "source"},
{"libgcrypt20", "1.8.1-4ubuntu1.1", "libgcrypt20", "1.8.1-4ubuntu1.1", dpkg.ParserName}, {"bzip2", "1.0.6-8.1", "dpkg", "source"},
{"libgmp10", "2:6.1.2+dfsg-2", "gmp", "2:6.1.2+dfsg-2", dpkg.ParserName}, {"diffutils", "1:3.6-1", "dpkg", "binary"},
{"libgnutls30", "3.5.18-1ubuntu1", "gnutls28", "3.5.18-1ubuntu1", dpkg.ParserName}, {"grep", "3.1-2", "dpkg", "binary"},
{"libgpg-error0", "1.27-6", "libgpg-error", "1.27-6", dpkg.ParserName}, {"libgcc1", "1:8-20180414-1ubuntu2", "dpkg", "binary"},
{"libhogweed4", "3.4-1", "nettle", "3.4-1", dpkg.ParserName}, {"bash", "4.4.18-2ubuntu1", "dpkg", "source"},
{"libidn2-0", "2.0.4-1.1build2", "libidn2", "2.0.4-1.1build2", dpkg.ParserName}, {"libtinfo5", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
{"liblz4-1", "0.0~r131-2ubuntu3", "lz4", "0.0~r131-2ubuntu3", dpkg.ParserName}, {"procps", "2:3.3.12-3ubuntu1.1", "dpkg", "binary"},
{"liblzma5", "5.2.2-1.3", "xz-utils", "5.2.2-1.3", dpkg.ParserName}, {"bzip2", "1.0.6-8.1", "dpkg", "binary"},
{"libmount1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"init-system-helpers", "1.51", "dpkg", "binary"},
{"libncurses5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName}, {"libncursesw5", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
{"libncursesw5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName}, {"init-system-helpers", "1.51", "dpkg", "source"},
{"libnettle6", "3.4-1", "nettle", "3.4-1", dpkg.ParserName}, {"libpam-modules", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
{"libp11-kit0", "0.23.9-2", "p11-kit", "0.23.9-2", dpkg.ParserName}, {"libext2fs2", "1.44.1-1", "dpkg", "binary"},
{"libpam-modules", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName}, {"libacl1", "2.2.52-3build1", "dpkg", "binary"},
{"libpam-modules-bin", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName}, {"hostname", "3.20", "dpkg", "binary"},
{"libpam-runtime", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName}, {"libgpg-error", "1.27-6", "dpkg", "source"},
{"libpam0g", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2", dpkg.ParserName}, {"acl", "2.2.52-3build1", "dpkg", "source"},
{"libpcre3", "2:8.39-9", "pcre3", "2:8.39-9", dpkg.ParserName}, {"apt", "1.6.3ubuntu0.1", "dpkg", "binary"},
{"libprocps6", "2:3.3.12-3ubuntu1.1", "procps", "2:3.3.12-3ubuntu1.1", dpkg.ParserName}, {"base-files", "10.1ubuntu2.2", "dpkg", "source"},
{"libseccomp2", "2.3.1-2.1ubuntu4", "libseccomp", "2.3.1-2.1ubuntu4", dpkg.ParserName}, {"libgpg-error0", "1.27-6", "dpkg", "binary"},
{"libselinux1", "2.7-2build2", "libselinux", "2.7-2build2", dpkg.ParserName}, {"audit", "1:2.8.2-1ubuntu1", "dpkg", "source"},
{"libsemanage-common", "2.7-2build2", "libsemanage", "2.7-2build2", dpkg.ParserName}, {"hostname", "3.20", "dpkg", "source"},
{"libsemanage1", "2.7-2build2", "libsemanage", "2.7-2build2", dpkg.ParserName}, {"gzip", "1.6-5ubuntu1", "dpkg", "binary"},
{"libsepol1", "2.7-1", "libsepol", "2.7-1", dpkg.ParserName}, {"libc6", "2.27-3ubuntu1", "dpkg", "binary"},
{"libsmartcols1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"libnettle6", "3.4-1", "dpkg", "binary"},
{"libss2", "1.44.1-1", "e2fsprogs", "1.44.1-1", dpkg.ParserName}, {"sysvinit-utils", "2.88dsf-59.10ubuntu1", "dpkg", "binary"},
{"libstdc++6", "8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2", dpkg.ParserName}, {"debianutils", "4.8.4", "dpkg", "source"},
{"libsystemd0", "237-3ubuntu10.3", "systemd", "237-3ubuntu10.3", dpkg.ParserName}, {"libstdc++6", "8-20180414-1ubuntu2", "dpkg", "binary"},
{"libtasn1-6", "4.13-2", "libtasn1-6", "4.13-2", dpkg.ParserName}, {"libsepol", "2.7-1", "dpkg", "source"},
{"libtinfo5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName}, {"libpcre3", "2:8.39-9", "dpkg", "binary"},
{"libudev1", "237-3ubuntu10.3", "systemd", "237-3ubuntu10.3", dpkg.ParserName}, {"libuuid1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"libunistring2", "0.9.9-0ubuntu1", "libunistring", "0.9.9-0ubuntu1", dpkg.ParserName}, {"systemd", "237-3ubuntu10.3", "dpkg", "source"},
{"libuuid1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"tar", "1.29b-2", "dpkg", "source"},
{"libzstd1", "1.3.3+dfsg-2ubuntu1", "libzstd", "1.3.3+dfsg-2ubuntu1", dpkg.ParserName}, {"ubuntu-keyring", "2018.02.28", "dpkg", "source"},
{"login", "1:4.5-1ubuntu1", "shadow", "1:4.5-1ubuntu1", dpkg.ParserName}, {"passwd", "1:4.5-1ubuntu1", "dpkg", "binary"},
{"lsb-base", "9.20170808ubuntu1", "lsb", "9.20170808ubuntu1", dpkg.ParserName}, {"sysvinit", "2.88dsf-59.10ubuntu1", "dpkg", "source"},
{"mawk", "1.3.3-17ubuntu3", "mawk", "1.3.3-17ubuntu3", dpkg.ParserName}, {"libidn2-0", "2.0.4-1.1build2", "dpkg", "binary"},
{"mount", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"libhogweed4", "3.4-1", "dpkg", "binary"},
{"ncurses-base", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName}, {"db5.3", "5.3.28-13.1ubuntu1", "dpkg", "source"},
{"ncurses-bin", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04", dpkg.ParserName}, {"sensible-utils", "0.0.12", "dpkg", "source"},
{"passwd", "1:4.5-1ubuntu1", "shadow", "1:4.5-1ubuntu1", dpkg.ParserName}, {"dpkg", "1.19.0.5ubuntu2", "dpkg", "source"},
{"perl-base", "5.26.1-6ubuntu0.2", "perl", "5.26.1-6ubuntu0.2", dpkg.ParserName}, {"libp11-kit0", "0.23.9-2", "dpkg", "binary"},
{"procps", "2:3.3.12-3ubuntu1.1", "procps", "2:3.3.12-3ubuntu1.1", dpkg.ParserName}, {"glibc", "2.27-3ubuntu1", "dpkg", "source"},
{"sed", "4.4-2", "sed", "4.4-2", dpkg.ParserName}, {"mount", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"sensible-utils", "0.0.12", "sensible-utils", "0.0.12", dpkg.ParserName}, {"libsemanage-common", "2.7-2build2", "dpkg", "binary"},
{"sysvinit-utils", "2.88dsf-59.10ubuntu1", "sysvinit", "2.88dsf-59.10ubuntu1", dpkg.ParserName}, {"libblkid1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"tar", "1.29b-2", "tar", "1.29b-2", dpkg.ParserName}, {"libdebconfclient0", "0.213ubuntu1", "dpkg", "binary"},
{"ubuntu-keyring", "2018.02.28", "ubuntu-keyring", "2018.02.28", dpkg.ParserName}, {"libffi", "3.2.1-8", "dpkg", "source"},
{"util-linux", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1", dpkg.ParserName}, {"pam", "1.1.8-3.6ubuntu2", "dpkg", "source"},
{"zlib1g", "1:1.2.11.dfsg-0ubuntu2", "zlib", "1:1.2.11.dfsg-0ubuntu2", dpkg.ParserName}, {"bsdutils", "1:2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"libtasn1-6", "4.13-2", "dpkg", "binary"},
{"libaudit-common", "1:2.8.2-1ubuntu1", "dpkg", "binary"},
{"gpgv", "2.2.4-1ubuntu1.1", "dpkg", "binary"},
{"libzstd", "1.3.3+dfsg-2ubuntu1", "dpkg", "source"},
{"base-passwd", "3.5.44", "dpkg", "source"},
{"adduser", "3.116ubuntu1", "dpkg", "binary"},
{"libattr1", "1:2.4.47-2build1", "dpkg", "binary"},
{"libncurses5", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
{"coreutils", "8.28-1ubuntu1", "dpkg", "binary"},
{"base-passwd", "3.5.44", "dpkg", "binary"},
{"ubuntu-keyring", "2018.02.28", "dpkg", "binary"},
{"adduser", "3.116ubuntu1", "dpkg", "source"},
{"libsmartcols1", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"libunistring", "0.9.9-0ubuntu1", "dpkg", "source"},
{"mawk", "1.3.3-17ubuntu3", "dpkg", "source"},
{"coreutils", "8.28-1ubuntu1", "dpkg", "source"},
{"attr", "1:2.4.47-2build1", "dpkg", "source"},
{"gmp", "2:6.1.2+dfsg-2", "dpkg", "source"},
{"libsemanage", "2.7-2build2", "dpkg", "source"},
{"libselinux1", "2.7-2build2", "dpkg", "binary"},
{"libseccomp2", "2.3.1-2.1ubuntu4", "dpkg", "binary"},
{"zlib1g", "1:1.2.11.dfsg-0ubuntu2", "dpkg", "binary"},
{"dash", "0.5.8-2.10", "dpkg", "source"},
{"gnutls28", "3.5.18-1ubuntu1", "dpkg", "source"},
{"libpam-runtime", "1.1.8-3.6ubuntu2", "dpkg", "binary"},
{"libgcrypt20", "1.8.1-4ubuntu1.1", "dpkg", "source"},
{"sensible-utils", "0.0.12", "dpkg", "binary"},
{"p11-kit", "0.23.9-2", "dpkg", "source"},
{"ncurses-base", "6.1-1ubuntu1.18.04", "dpkg", "binary"},
{"e2fsprogs", "1.44.1-1", "dpkg", "binary"},
{"libgcrypt20", "1.8.1-4ubuntu1.1", "dpkg", "binary"},
{"libprocps6", "2:3.3.12-3ubuntu1.1", "dpkg", "binary"},
{"debconf", "1.5.66", "dpkg", "source"},
{"gcc-8-base", "8-20180414-1ubuntu2", "dpkg", "binary"},
{"base-files", "10.1ubuntu2.2", "dpkg", "binary"},
{"libbz2-1.0", "1.0.6-8.1", "dpkg", "binary"},
{"grep", "3.1-2", "dpkg", "source"},
{"bash", "4.4.18-2ubuntu1", "dpkg", "binary"},
{"libgmp10", "2:6.1.2+dfsg-2", "dpkg", "binary"},
{"shadow", "1:4.5-1ubuntu1", "dpkg", "source"},
{"libidn2", "2.0.4-1.1build2", "dpkg", "source"},
{"gzip", "1.6-5ubuntu1", "dpkg", "source"},
{"util-linux", "2.31.1-0.4ubuntu3.1", "dpkg", "binary"},
{"libaudit1", "1:2.8.2-1ubuntu1", "dpkg", "binary"},
{"libsepol1", "2.7-1", "dpkg", "binary"},
{"pcre3", "2:8.39-9", "dpkg", "source"},
{"apt", "1.6.3ubuntu0.1", "dpkg", "source"},
{"nettle", "3.4-1", "dpkg", "source"},
{"util-linux", "2.31.1-0.4ubuntu3.1", "dpkg", "source"},
{"libcap-ng0", "0.7.7-3.1", "dpkg", "binary"},
{"debianutils", "4.8.4", "dpkg", "binary"},
{"ncurses", "6.1-1ubuntu1.18.04", "dpkg", "source"},
{"libffi6", "3.2.1-8", "dpkg", "binary"},
{"cdebconf", "0.213ubuntu1", "dpkg", "source"},
{"findutils", "4.6.0+git+20170828-2", "dpkg", "source"},
{"libdb5.3", "5.3.28-13.1ubuntu1", "dpkg", "binary"},
{"zlib", "1:1.2.11.dfsg-0ubuntu2", "dpkg", "source"},
{"findutils", "4.6.0+git+20170828-2", "dpkg", "binary"},
{"dpkg", "1.19.0.5ubuntu2", "dpkg", "binary"},
{"mawk", "1.3.3-17ubuntu3", "dpkg", "binary"},
}, },
}, },
{ {
"corrupted status file", "corrupted status file",
map[string]string{"var/lib/dpkg/status": "dpkg/testdata/corrupted"}, map[string]string{"var/lib/dpkg/status": "dpkg/testdata/corrupted"},
[]database.Feature{ []database.Feature{
{"libpam-runtime", "1.1.8-3.1ubuntu3", "pam", "1.1.8-3.1ubuntu3", dpkg.ParserName}, {"libpam-modules-bin", "1.1.8-3.1ubuntu3", "dpkg", "binary"},
{"libpam-modules-bin", "1.1.8-3.1ubuntu3", "pam", "1.1.8-3.1ubuntu3", dpkg.ParserName}, {"gcc-5", "5.1.1-12ubuntu1", "dpkg", "source"},
{"makedev", "2.3.1-93ubuntu1", "makedev", "2.3.1-93ubuntu1", dpkg.ParserName}, {"makedev", "2.3.1-93ubuntu1", "dpkg", "binary"},
{"libgcc1", "1:5.1.1-12ubuntu1", "gcc-5", "5.1.1-12ubuntu1", dpkg.ParserName}, {"libgcc1", "1:5.1.1-12ubuntu1", "dpkg", "binary"},
{"pam", "1.1.8-3.1ubuntu3", "dpkg", "source"},
{"makedev", "2.3.1-93ubuntu1", "dpkg", "source"},
{"libpam-runtime", "1.1.8-3.1ubuntu3", "dpkg", "binary"},
}, },
}, },
} { } {

View File

@ -45,6 +45,10 @@ func init() {
featurefmt.RegisterLister("rpm", "1.0", &lister{}) featurefmt.RegisterLister("rpm", "1.0", &lister{})
} }
func (l lister) RequiredFilenames() []string {
return []string{"var/lib/rpm/Packages"}
}
func isIgnored(packageName string) bool { func isIgnored(packageName string) bool {
for _, pkg := range ignoredPackages { for _, pkg := range ignoredPackages {
if pkg == packageName { if pkg == packageName {
@ -55,12 +59,6 @@ func isIgnored(packageName string) bool {
return false return false
} }
func valid(pkg *database.Feature) bool {
return pkg.Name != "" && pkg.Version != "" &&
((pkg.SourceName == "" && pkg.SourceVersion != "") ||
(pkg.SourceName != "" && pkg.SourceVersion != ""))
}
func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) { func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
f, hasFile := files["var/lib/rpm/Packages"] f, hasFile := files["var/lib/rpm/Packages"]
if !hasFile { if !hasFile {
@ -84,7 +82,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// Extract binary package names because RHSA refers to binary package names. // Extract binary package names because RHSA refers to binary package names.
out, err := exec.Command("rpm", "--dbpath", tmpDir, "-qa", "--qf", "%{NAME} %{EPOCH}:%{VERSION}-%{RELEASE} %{SOURCERPM}\n").CombinedOutput() out, err := exec.Command("rpm", "--dbpath", tmpDir, "-qa", "--qf", "%{NAME} %{EPOCH}:%{VERSION}-%{RELEASE} %{SOURCERPM}\n").CombinedOutput()
if err != nil { if err != nil {
log.WithError(err).WithField("output", string(out)).Error("could not query RPM") log.WithError(err).WithField("output", string(out)).Error("failed to query RPM")
// Do not bubble up because we probably won't be able to fix it, // Do not bubble up because we probably won't be able to fix it,
// the database must be corrupted // the database must be corrupted
return []database.Feature{}, nil return []database.Feature{}, nil
@ -93,39 +91,51 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
packages := mapset.NewSet() packages := mapset.NewSet()
scanner := bufio.NewScanner(strings.NewReader(string(out))) scanner := bufio.NewScanner(strings.NewReader(string(out)))
for scanner.Scan() { for scanner.Scan() {
line := strings.Split(scanner.Text(), " ") rpmPackage, srpmPackage := parseRPMOutput(scanner.Text())
if len(line) != 3 { if rpmPackage != nil {
// We may see warnings on some RPM versions: packages.Add(*rpmPackage)
// "warning: Generating 12 missing index(es), please wait..."
continue
} }
if isIgnored(line[0]) { if srpmPackage != nil {
continue packages.Add(*srpmPackage)
}
pkg := database.Feature{Name: line[0], VersionFormat: rpm.ParserName}
pkg.Version = strings.Replace(line[1], "(none):", "", -1)
if err := versionfmt.Valid(rpm.ParserName, pkg.Version); err != nil {
log.WithError(err).WithField("version", line[1]).Warning("skipped unparseable package")
continue
}
if err := parseSourceRPM(line[2], &pkg); err != nil {
log.WithError(err).WithField("sourcerpm", line[2]).Warning("skipped unparseable package")
continue
}
if valid(&pkg) {
packages.Add(pkg)
} }
} }
return database.ConvertFeatureSetToFeatures(packages), nil return database.ConvertFeatureSetToFeatures(packages), nil
} }
func (l lister) RequiredFilenames() []string { func parseRPMOutput(raw string) (rpmPackage *database.Feature, srpmPackage *database.Feature) {
return []string{"var/lib/rpm/Packages"} line := strings.Split(raw, " ")
if len(line) != 3 {
// We may see warnings on some RPM versions:
// "warning: Generating 12 missing index(es), please wait..."
return
}
if isIgnored(line[0]) {
return
}
name, version, srpm := line[0], strings.Replace(line[1], "(none):", "", -1), line[2]
if err := versionfmt.Valid(rpm.ParserName, version); err != nil {
log.WithError(err).WithFields(log.Fields{"name": name, "version": version}).Warning("skipped unparseable package")
return
}
rpmPackage = &database.Feature{name, version, rpm.ParserName, database.BinaryPackage}
srpmName, srpmVersion, srpmRelease, _, err := parseSourceRPM(srpm)
if err != nil {
log.WithError(err).WithFields(log.Fields{"name": name, "sourcerpm": srpm}).Warning("skipped unparseable package")
return
}
srpmVersion = srpmVersion + "-" + srpmRelease
if err = versionfmt.Valid(rpm.ParserName, srpmVersion); err != nil {
return
}
srpmPackage = &database.Feature{srpmName, srpmVersion, rpm.ParserName, database.SourcePackage}
return
} }
type rpmParserState string type rpmParserState string
@ -140,11 +150,9 @@ const (
// parseSourceRPM parses the source rpm package representation string // parseSourceRPM parses the source rpm package representation string
// http://ftp.rpm.org/max-rpm/ch-rpm-file-format.html // http://ftp.rpm.org/max-rpm/ch-rpm-file-format.html
func parseSourceRPM(sourceRPM string, pkg *database.Feature) error { func parseSourceRPM(sourceRPM string) (name string, version string, release string, architecture string, err error) {
state := parseRPM state := parseRPM
previousCheckPoint := len(sourceRPM) previousCheckPoint := len(sourceRPM)
release := ""
version := ""
for i := len(sourceRPM) - 1; i >= 0; i-- { for i := len(sourceRPM) - 1; i >= 0; i-- {
switch state { switch state {
case parseRPM: case parseRPM:
@ -153,16 +161,18 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
packageType := strutil.Substring(sourceRPM, i+1, len(sourceRPM)) packageType := strutil.Substring(sourceRPM, i+1, len(sourceRPM))
previousCheckPoint = i previousCheckPoint = i
if packageType != "rpm" { if packageType != "rpm" {
return fmt.Errorf("unexpected package type, expect: 'rpm', got: '%s'", packageType) err = fmt.Errorf("unexpected package type, expect: 'rpm', got: '%s'", packageType)
return
} }
} }
case parseArchitecture: case parseArchitecture:
if string(sourceRPM[i]) == "." { if string(sourceRPM[i]) == "." {
state = parseRelease state = parseRelease
architecture := strutil.Substring(sourceRPM, i+1, previousCheckPoint) architecture = strutil.Substring(sourceRPM, i+1, previousCheckPoint)
previousCheckPoint = i previousCheckPoint = i
if architecture != "src" && architecture != "nosrc" { if architecture != "src" && architecture != "nosrc" {
return fmt.Errorf("unexpected package architecture, expect: 'src' or 'nosrc', got: '%s'", architecture) err = fmt.Errorf("unexpected package architecture, expect: 'src' or 'nosrc', got: '%s'", architecture)
return
} }
} }
case parseRelease: case parseRelease:
@ -171,7 +181,8 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
release = strutil.Substring(sourceRPM, i+1, previousCheckPoint) release = strutil.Substring(sourceRPM, i+1, previousCheckPoint)
previousCheckPoint = i previousCheckPoint = i
if release == "" { if release == "" {
return fmt.Errorf("unexpected package release, expect: not empty") err = fmt.Errorf("unexpected package release, expect: not empty")
return
} }
} }
case parseVersion: case parseVersion:
@ -181,7 +192,8 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
version = strutil.Substring(sourceRPM, i+1, previousCheckPoint) version = strutil.Substring(sourceRPM, i+1, previousCheckPoint)
previousCheckPoint = i previousCheckPoint = i
if version == "" { if version == "" {
return fmt.Errorf("unexpected package version, expect: not empty") err = fmt.Errorf("unexpected package version, expect: not empty")
return
} }
break break
} }
@ -189,20 +201,15 @@ func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
} }
if state != terminate { if state != terminate {
return fmt.Errorf("unexpected termination while parsing '%s'", state) err = fmt.Errorf("unexpected termination while parsing '%s'", state)
return
} }
concatVersion := version + "-" + release name = strutil.Substring(sourceRPM, 0, previousCheckPoint)
if err := versionfmt.Valid(rpm.ParserName, concatVersion); err != nil {
return err
}
name := strutil.Substring(sourceRPM, 0, previousCheckPoint)
if name == "" { if name == "" {
return fmt.Errorf("unexpected package name, expect: not empty") err = fmt.Errorf("unexpected package name, expect: not empty")
return
} }
pkg.SourceName = name return
pkg.SourceVersion = concatVersion
return nil
} }

View File

@ -25,179 +25,307 @@ import (
) )
var expectedBigCaseInfo = []database.Feature{ var expectedBigCaseInfo = []database.Feature{
{"publicsuffix-list-dafsa", "20180514-1.fc28", "publicsuffix-list", "20180514-1.fc28", rpm.ParserName}, {"libmount", "2.32.1-1.fc28", "rpm", "binary"},
{"libreport-filesystem", "2.9.5-1.fc28", "libreport", "2.9.5-1.fc28", rpm.ParserName}, {"libffi", "3.1-16.fc28", "rpm", "binary"},
{"fedora-gpg-keys", "28-5", "fedora-repos", "28-5", rpm.ParserName}, {"libunistring", "0.9.10-1.fc28", "rpm", "binary"},
{"fedora-release", "28-2", "fedora-release", "28-2", rpm.ParserName}, {"fedora-repos", "28-5", "rpm", "binary"},
{"filesystem", "3.8-2.fc28", "filesystem", "3.8-2.fc28", rpm.ParserName}, {"libarchive", "3.3.1-4.fc28", "rpm", "source"},
{"tzdata", "2018e-1.fc28", "tzdata", "2018e-1.fc28", rpm.ParserName}, {"langpacks", "1.0-12.fc28", "rpm", "source"},
{"pcre2", "10.31-10.fc28", "pcre2", "10.31-10.fc28", rpm.ParserName}, {"readline", "7.0-11.fc28", "rpm", "source"},
{"glibc-minimal-langpack", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName}, {"gzip", "1.9-3.fc28", "rpm", "source"},
{"glibc-common", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName}, {"libverto", "0.3.0-5.fc28", "rpm", "source"},
{"bash", "4.4.23-1.fc28", "bash", "4.4.23-1.fc28", rpm.ParserName}, {"ncurses-base", "6.1-5.20180224.fc28", "rpm", "binary"},
{"zlib", "1.2.11-8.fc28", "zlib", "1.2.11-8.fc28", rpm.ParserName}, {"libfdisk", "2.32.1-1.fc28", "rpm", "binary"},
{"bzip2-libs", "1.0.6-26.fc28", "bzip2", "1.0.6-26.fc28", rpm.ParserName}, {"libselinux", "2.8-1.fc28", "rpm", "source"},
{"libcap", "2.25-9.fc28", "libcap", "2.25-9.fc28", rpm.ParserName}, {"nss-util", "3.38.0-1.0.fc28", "rpm", "source"},
{"libgpg-error", "1.31-1.fc28", "libgpg-error", "1.31-1.fc28", rpm.ParserName}, {"mpfr", "3.1.6-1.fc28", "rpm", "source"},
{"libzstd", "1.3.5-1.fc28", "zstd", "1.3.5-1.fc28", rpm.ParserName}, {"libunistring", "0.9.10-1.fc28", "rpm", "source"},
{"expat", "2.2.5-3.fc28", "expat", "2.2.5-3.fc28", rpm.ParserName}, {"libpcap", "14:1.9.0-1.fc28", "rpm", "binary"},
{"nss-util", "3.38.0-1.0.fc28", "nss-util", "3.38.0-1.0.fc28", rpm.ParserName}, {"libarchive", "3.3.1-4.fc28", "rpm", "binary"},
{"libcom_err", "1.44.2-0.fc28", "e2fsprogs", "1.44.2-0.fc28", rpm.ParserName}, {"gmp", "1:6.1.2-7.fc28", "rpm", "binary"},
{"libffi", "3.1-16.fc28", "libffi", "3.1-16.fc28", rpm.ParserName}, {"crypto-policies", "20180425-5.git6ad4018.fc28", "rpm", "source"},
{"libgcrypt", "1.8.3-1.fc28", "libgcrypt", "1.8.3-1.fc28", rpm.ParserName}, {"gzip", "1.9-3.fc28", "rpm", "binary"},
{"libxml2", "2.9.8-4.fc28", "libxml2", "2.9.8-4.fc28", rpm.ParserName}, {"fedora-release", "28-2", "rpm", "source"},
{"libacl", "2.2.53-1.fc28", "acl", "2.2.53-1.fc28", rpm.ParserName}, {"zlib", "1.2.11-8.fc28", "rpm", "binary"},
{"sed", "4.5-1.fc28", "sed", "4.5-1.fc28", rpm.ParserName}, {"crypto-policies", "20180425-5.git6ad4018.fc28", "rpm", "binary"},
{"libmount", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName}, {"lz4", "1.8.1.2-4.fc28", "rpm", "source"},
{"p11-kit", "0.23.12-1.fc28", "p11-kit", "0.23.12-1.fc28", rpm.ParserName}, {"keyutils", "1.5.10-6.fc28", "rpm", "source"},
{"libidn2", "2.0.5-1.fc28", "libidn2", "2.0.5-1.fc28", rpm.ParserName}, {"gpgme", "1.10.0-4.fc28", "rpm", "binary"},
{"libcap-ng", "0.7.9-4.fc28", "libcap-ng", "0.7.9-4.fc28", rpm.ParserName}, {"libgpg-error", "1.31-1.fc28", "rpm", "binary"},
{"lz4-libs", "1.8.1.2-4.fc28", "lz4", "1.8.1.2-4.fc28", rpm.ParserName}, {"gnutls", "3.6.3-4.fc28", "rpm", "source"},
{"libassuan", "2.5.1-3.fc28", "libassuan", "2.5.1-3.fc28", rpm.ParserName}, {"coreutils", "8.29-7.fc28", "rpm", "source"},
{"keyutils-libs", "1.5.10-6.fc28", "keyutils", "1.5.10-6.fc28", rpm.ParserName}, {"libsepol", "2.8-1.fc28", "rpm", "source"},
{"glib2", "2.56.1-4.fc28", "glib2", "2.56.1-4.fc28", rpm.ParserName}, {"libssh", "0.8.2-1.fc28", "rpm", "binary"},
{"systemd-libs", "238-9.git0e0aa59.fc28", "systemd", "238-9.git0e0aa59.fc28", rpm.ParserName}, {"libpwquality", "1.4.0-7.fc28", "rpm", "binary"},
{"dbus-libs", "1:1.12.10-1.fc28", "dbus", "1.12.10-1.fc28", rpm.ParserName}, {"dnf-conf", "2.7.5-12.fc28", "rpm", "binary"},
{"libtasn1", "4.13-2.fc28", "libtasn1", "4.13-2.fc28", rpm.ParserName}, {"basesystem", "11-5.fc28", "rpm", "source"},
{"ca-certificates", "2018.2.24-1.0.fc28", "ca-certificates", "2018.2.24-1.0.fc28", rpm.ParserName}, {"setup", "2.11.4-1.fc28", "rpm", "binary"},
{"libarchive", "3.3.1-4.fc28", "libarchive", "3.3.1-4.fc28", rpm.ParserName}, {"libmetalink", "0.1.3-6.fc28", "rpm", "source"},
{"openssl", "1:1.1.0h-3.fc28", "openssl", "1.1.0h-3.fc28", rpm.ParserName}, {"texinfo", "6.5-4.fc28", "rpm", "source"},
{"libusbx", "1.0.22-1.fc28", "libusbx", "1.0.22-1.fc28", rpm.ParserName}, {"expat", "2.2.5-3.fc28", "rpm", "source"},
{"libsemanage", "2.8-2.fc28", "libsemanage", "2.8-2.fc28", rpm.ParserName}, {"ncurses", "6.1-5.20180224.fc28", "rpm", "source"},
{"libutempter", "1.1.6-14.fc28", "libutempter", "1.1.6-14.fc28", rpm.ParserName}, {"libpwquality", "1.4.0-7.fc28", "rpm", "source"},
{"mpfr", "3.1.6-1.fc28", "mpfr", "3.1.6-1.fc28", rpm.ParserName}, {"pcre", "8.42-3.fc28", "rpm", "binary"},
{"gnutls", "3.6.3-4.fc28", "gnutls", "3.6.3-4.fc28", rpm.ParserName}, {"sssd", "1.16.3-2.fc28", "rpm", "source"},
{"gzip", "1.9-3.fc28", "gzip", "1.9-3.fc28", rpm.ParserName}, {"basesystem", "11-5.fc28", "rpm", "binary"},
{"acl", "2.2.53-1.fc28", "acl", "2.2.53-1.fc28", rpm.ParserName}, {"systemd-pam", "238-9.git0e0aa59.fc28", "rpm", "binary"},
{"nss-softokn-freebl", "3.38.0-1.0.fc28", "nss-softokn", "3.38.0-1.0.fc28", rpm.ParserName}, {"python3-six", "1.11.0-3.fc28", "rpm", "binary"},
{"nss", "3.38.0-1.0.fc28", "nss", "3.38.0-1.0.fc28", rpm.ParserName}, {"libcurl", "7.59.0-6.fc28", "rpm", "binary"},
{"libmetalink", "0.1.3-6.fc28", "libmetalink", "0.1.3-6.fc28", rpm.ParserName}, {"qrencode", "3.4.4-5.fc28", "rpm", "source"},
{"libdb-utils", "5.3.28-30.fc28", "libdb", "5.3.28-30.fc28", rpm.ParserName}, {"xz", "5.2.4-2.fc28", "rpm", "source"},
{"file-libs", "5.33-7.fc28", "file", "5.33-7.fc28", rpm.ParserName}, {"libpkgconf", "1.4.2-1.fc28", "rpm", "binary"},
{"libsss_idmap", "1.16.3-2.fc28", "sssd", "1.16.3-2.fc28", rpm.ParserName}, {"libzstd", "1.3.5-1.fc28", "rpm", "binary"},
{"libsigsegv", "2.11-5.fc28", "libsigsegv", "2.11-5.fc28", rpm.ParserName}, {"bash", "4.4.23-1.fc28", "rpm", "binary"},
{"krb5-libs", "1.16.1-13.fc28", "krb5", "1.16.1-13.fc28", rpm.ParserName}, {"cyrus-sasl", "2.1.27-0.2rc7.fc28", "rpm", "source"},
{"libnsl2", "1.2.0-2.20180605git4a062cf.fc28", "libnsl2", "1.2.0-2.20180605git4a062cf.fc28", rpm.ParserName}, {"ncurses-libs", "6.1-5.20180224.fc28", "rpm", "binary"},
{"python3-pip", "9.0.3-2.fc28", "python-pip", "9.0.3-2.fc28", rpm.ParserName}, {"xz-libs", "5.2.4-2.fc28", "rpm", "binary"},
{"python3", "3.6.6-1.fc28", "python3", "3.6.6-1.fc28", rpm.ParserName}, {"dbus", "1.12.10-1.fc28", "rpm", "source"},
{"pam", "1.3.1-1.fc28", "pam", "1.3.1-1.fc28", rpm.ParserName}, {"grep", "3.1-5.fc28", "rpm", "binary"},
{"python3-gobject-base", "3.28.3-1.fc28", "pygobject3", "3.28.3-1.fc28", rpm.ParserName}, {"libusbx", "1.0.22-1.fc28", "rpm", "binary"},
{"python3-smartcols", "0.3.0-2.fc28", "python-smartcols", "0.3.0-2.fc28", rpm.ParserName}, {"audit", "2.8.4-2.fc28", "rpm", "source"},
{"python3-iniparse", "0.4-30.fc28", "python-iniparse", "0.4-30.fc28", rpm.ParserName}, {"sed", "4.5-1.fc28", "rpm", "binary"},
{"openldap", "2.4.46-3.fc28", "openldap", "2.4.46-3.fc28", rpm.ParserName}, {"sqlite", "3.22.0-4.fc28", "rpm", "source"},
{"libseccomp", "2.3.3-2.fc28", "libseccomp", "2.3.3-2.fc28", rpm.ParserName}, {"openldap", "2.4.46-3.fc28", "rpm", "binary"},
{"npth", "1.5-4.fc28", "npth", "1.5-4.fc28", rpm.ParserName}, {"gawk", "4.2.1-1.fc28", "rpm", "binary"},
{"gpgme", "1.10.0-4.fc28", "gpgme", "1.10.0-4.fc28", rpm.ParserName}, {"gpgme", "1.10.0-4.fc28", "rpm", "source"},
{"json-c", "0.13.1-2.fc28", "json-c", "0.13.1-2.fc28", rpm.ParserName}, {"lvm2", "2.02.177-5.fc28", "rpm", "source"},
{"libyaml", "0.1.7-5.fc28", "libyaml", "0.1.7-5.fc28", rpm.ParserName}, {"nspr", "4.19.0-1.fc28", "rpm", "source"},
{"libpkgconf", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName}, {"libsolv", "0.6.35-1.fc28", "rpm", "source"},
{"pkgconf-pkg-config", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName}, {"info", "6.5-4.fc28", "rpm", "binary"},
{"iptables-libs", "1.6.2-3.fc28", "iptables", "1.6.2-3.fc28", rpm.ParserName}, {"openssl-libs", "1:1.1.0h-3.fc28", "rpm", "binary"},
{"device-mapper-libs", "1.02.146-5.fc28", "lvm2", "2.02.177-5.fc28", rpm.ParserName}, {"libxcrypt", "4.1.2-1.fc28", "rpm", "binary"},
{"systemd-pam", "238-9.git0e0aa59.fc28", "systemd", "238-9.git0e0aa59.fc28", rpm.ParserName}, {"libselinux", "2.8-1.fc28", "rpm", "binary"},
{"systemd", "238-9.git0e0aa59.fc28", "systemd", "238-9.git0e0aa59.fc28", rpm.ParserName}, {"libgcc", "8.1.1-5.fc28", "rpm", "binary"},
{"elfutils-default-yama-scope", "0.173-1.fc28", "elfutils", "0.173-1.fc28", rpm.ParserName}, {"cracklib", "2.9.6-13.fc28", "rpm", "binary"},
{"libcurl", "7.59.0-6.fc28", "curl", "7.59.0-6.fc28", rpm.ParserName}, {"python3-libs", "3.6.6-1.fc28", "rpm", "binary"},
{"python3-librepo", "1.8.1-7.fc28", "librepo", "1.8.1-7.fc28", rpm.ParserName}, {"glibc-langpack-en", "2.27-32.fc28", "rpm", "binary"},
{"rpm-plugin-selinux", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"json-c", "0.13.1-2.fc28", "rpm", "binary"},
{"rpm", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"gnupg2", "2.2.8-1.fc28", "rpm", "source"},
{"libdnf", "0.11.1-3.fc28", "libdnf", "0.11.1-3.fc28", rpm.ParserName}, {"openssl", "1:1.1.0h-3.fc28", "rpm", "binary"},
{"rpm-build-libs", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"glibc-common", "2.27-32.fc28", "rpm", "binary"},
{"python3-rpm", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"p11-kit-trust", "0.23.12-1.fc28", "rpm", "binary"},
{"dnf", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName}, {"zstd", "1.3.5-1.fc28", "rpm", "source"},
{"deltarpm", "3.6-25.fc28", "deltarpm", "3.6-25.fc28", rpm.ParserName}, {"libxml2", "2.9.8-4.fc28", "rpm", "source"},
{"sssd-client", "1.16.3-2.fc28", "sssd", "1.16.3-2.fc28", rpm.ParserName}, {"dbus", "1:1.12.10-1.fc28", "rpm", "binary"},
{"cracklib-dicts", "2.9.6-13.fc28", "cracklib", "2.9.6-13.fc28", rpm.ParserName}, {"ca-certificates", "2018.2.24-1.0.fc28", "rpm", "binary"},
{"tar", "2:1.30-3.fc28", "tar", "1.30-3.fc28", rpm.ParserName}, {"libcomps", "0.1.8-11.fc28", "rpm", "binary"},
{"diffutils", "3.6-4.fc28", "diffutils", "3.6-4.fc28", rpm.ParserName}, {"nss", "3.38.0-1.0.fc28", "rpm", "binary"},
{"langpacks-en", "1.0-12.fc28", "langpacks", "1.0-12.fc28", rpm.ParserName}, {"libcom_err", "1.44.2-0.fc28", "rpm", "binary"},
{"libgcc", "8.1.1-5.fc28", "gcc", "8.1.1-5.fc28", rpm.ParserName}, {"keyutils-libs", "1.5.10-6.fc28", "rpm", "binary"},
{"pkgconf-m4", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName}, {"libseccomp", "2.3.3-2.fc28", "rpm", "binary"},
{"dnf-conf", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName}, {"elfutils-libs", "0.173-1.fc28", "rpm", "binary"},
{"fedora-repos", "28-5", "fedora-repos", "28-5", rpm.ParserName}, {"libuuid", "2.32.1-1.fc28", "rpm", "binary"},
{"setup", "2.11.4-1.fc28", "setup", "2.11.4-1.fc28", rpm.ParserName}, {"pkgconf", "1.4.2-1.fc28", "rpm", "source"},
{"basesystem", "11-5.fc28", "basesystem", "11-5.fc28", rpm.ParserName}, {"grep", "3.1-5.fc28", "rpm", "source"},
{"ncurses-base", "6.1-5.20180224.fc28", "ncurses", "6.1-5.20180224.fc28", rpm.ParserName}, {"libpcap", "1.9.0-1.fc28", "rpm", "source"},
{"libselinux", "2.8-1.fc28", "libselinux", "2.8-1.fc28", rpm.ParserName}, {"deltarpm", "3.6-25.fc28", "rpm", "binary"},
{"ncurses-libs", "6.1-5.20180224.fc28", "ncurses", "6.1-5.20180224.fc28", rpm.ParserName}, {"krb5-libs", "1.16.1-13.fc28", "rpm", "binary"},
{"glibc", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName}, {"glibc", "2.27-32.fc28", "rpm", "binary"},
{"libsepol", "2.8-1.fc28", "libsepol", "2.8-1.fc28", rpm.ParserName}, {"libseccomp", "2.3.3-2.fc28", "rpm", "source"},
{"xz-libs", "5.2.4-2.fc28", "xz", "5.2.4-2.fc28", rpm.ParserName}, {"libsemanage", "2.8-2.fc28", "rpm", "binary"},
{"info", "6.5-4.fc28", "texinfo", "6.5-4.fc28", rpm.ParserName}, {"openssl-pkcs11", "0.4.8-1.fc28", "rpm", "binary"},
{"libdb", "5.3.28-30.fc28", "libdb", "5.3.28-30.fc28", rpm.ParserName}, {"libxml2", "2.9.8-4.fc28", "rpm", "binary"},
{"elfutils-libelf", "0.173-1.fc28", "elfutils", "0.173-1.fc28", rpm.ParserName}, {"e2fsprogs", "1.44.2-0.fc28", "rpm", "source"},
{"popt", "1.16-14.fc28", "popt", "1.16-14.fc28", rpm.ParserName}, {"file-libs", "5.33-7.fc28", "rpm", "binary"},
{"nspr", "4.19.0-1.fc28", "nspr", "4.19.0-1.fc28", rpm.ParserName}, {"elfutils-default-yama-scope", "0.173-1.fc28", "rpm", "binary"},
{"libxcrypt", "4.1.2-1.fc28", "libxcrypt", "4.1.2-1.fc28", rpm.ParserName}, {"glibc", "2.27-32.fc28", "rpm", "source"},
{"lua-libs", "5.3.4-10.fc28", "lua", "5.3.4-10.fc28", rpm.ParserName}, {"publicsuffix-list-dafsa", "20180514-1.fc28", "rpm", "binary"},
{"libuuid", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName}, {"popt", "1.16-14.fc28", "rpm", "binary"},
{"readline", "7.0-11.fc28", "readline", "7.0-11.fc28", rpm.ParserName}, {"libnsl2", "1.2.0-2.20180605git4a062cf.fc28", "rpm", "binary"},
{"libattr", "2.4.48-3.fc28", "attr", "2.4.48-3.fc28", rpm.ParserName}, {"lua-libs", "5.3.4-10.fc28", "rpm", "binary"},
{"coreutils-single", "8.29-7.fc28", "coreutils", "8.29-7.fc28", rpm.ParserName}, {"libsemanage", "2.8-2.fc28", "rpm", "source"},
{"libblkid", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName}, {"glibc-minimal-langpack", "2.27-32.fc28", "rpm", "binary"},
{"gmp", "1:6.1.2-7.fc28", "gmp", "6.1.2-7.fc28", rpm.ParserName}, {"attr", "2.4.48-3.fc28", "rpm", "source"},
{"libunistring", "0.9.10-1.fc28", "libunistring", "0.9.10-1.fc28", rpm.ParserName}, {"gdbm", "1.14.1-4.fc28", "rpm", "source"},
{"sqlite-libs", "3.22.0-4.fc28", "sqlite", "3.22.0-4.fc28", rpm.ParserName}, {"pkgconf", "1.4.2-1.fc28", "rpm", "binary"},
{"audit-libs", "2.8.4-2.fc28", "audit", "2.8.4-2.fc28", rpm.ParserName}, {"acl", "2.2.53-1.fc28", "rpm", "source"},
{"chkconfig", "1.10-4.fc28", "chkconfig", "1.10-4.fc28", rpm.ParserName}, {"gnutls", "3.6.3-4.fc28", "rpm", "binary"},
{"libsmartcols", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName}, {"fedora-repos", "28-5", "rpm", "source"},
{"pcre", "8.42-3.fc28", "pcre", "8.42-3.fc28", rpm.ParserName}, {"python3-pip", "9.0.3-2.fc28", "rpm", "binary"},
{"grep", "3.1-5.fc28", "grep", "3.1-5.fc28", rpm.ParserName}, {"libnsl2", "1.2.0-2.20180605git4a062cf.fc28", "rpm", "source"},
{"crypto-policies", "20180425-5.git6ad4018.fc28", "crypto-policies", "20180425-5.git6ad4018.fc28", rpm.ParserName}, {"rpm", "4.14.1-9.fc28", "rpm", "binary"},
{"gdbm-libs", "1:1.14.1-4.fc28", "gdbm", "1.14.1-4.fc28", rpm.ParserName}, {"libutempter", "1.1.6-14.fc28", "rpm", "source"},
{"p11-kit-trust", "0.23.12-1.fc28", "p11-kit", "0.23.12-1.fc28", rpm.ParserName}, {"libdnf", "0.11.1-3.fc28", "rpm", "source"},
{"openssl-libs", "1:1.1.0h-3.fc28", "openssl", "1.1.0h-3.fc28", rpm.ParserName}, {"vim-minimal", "2:8.1.328-1.fc28", "rpm", "binary"},
{"ima-evm-utils", "1.1-2.fc28", "ima-evm-utils", "1.1-2.fc28", rpm.ParserName}, {"tzdata", "2018e-1.fc28", "rpm", "binary"},
{"gdbm", "1:1.14.1-4.fc28", "gdbm", "1.14.1-4.fc28", rpm.ParserName}, {"nettle", "3.4-2.fc28", "rpm", "binary"},
{"gobject-introspection", "1.56.1-1.fc28", "gobject-introspection", "1.56.1-1.fc28", rpm.ParserName}, {"python-pip", "9.0.3-2.fc28", "rpm", "source"},
{"shadow-utils", "2:4.6-1.fc28", "shadow-utils", "4.6-1.fc28", rpm.ParserName}, {"python-six", "1.11.0-3.fc28", "rpm", "source"},
{"libpsl", "0.20.2-2.fc28", "libpsl", "0.20.2-2.fc28", rpm.ParserName}, {"diffutils", "3.6-4.fc28", "rpm", "binary"},
{"nettle", "3.4-2.fc28", "nettle", "3.4-2.fc28", rpm.ParserName}, {"rpm-plugin-selinux", "4.14.1-9.fc28", "rpm", "binary"},
{"libfdisk", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName}, {"shadow-utils", "2:4.6-1.fc28", "rpm", "binary"},
{"cracklib", "2.9.6-13.fc28", "cracklib", "2.9.6-13.fc28", rpm.ParserName}, {"pkgconf-pkg-config", "1.4.2-1.fc28", "rpm", "binary"},
{"libcomps", "0.1.8-11.fc28", "libcomps", "0.1.8-11.fc28", rpm.ParserName}, {"cracklib-dicts", "2.9.6-13.fc28", "rpm", "binary"},
{"nss-softokn", "3.38.0-1.0.fc28", "nss-softokn", "3.38.0-1.0.fc28", rpm.ParserName}, {"libblkid", "2.32.1-1.fc28", "rpm", "binary"},
{"nss-sysinit", "3.38.0-1.0.fc28", "nss", "3.38.0-1.0.fc28", rpm.ParserName}, {"python-setuptools", "39.2.0-6.fc28", "rpm", "source"},
{"libksba", "1.3.5-7.fc28", "libksba", "1.3.5-7.fc28", rpm.ParserName}, {"libsss_idmap", "1.16.3-2.fc28", "rpm", "binary"},
{"kmod-libs", "25-2.fc28", "kmod", "25-2.fc28", rpm.ParserName}, {"libksba", "1.3.5-7.fc28", "rpm", "source"},
{"libsss_nss_idmap", "1.16.3-2.fc28", "sssd", "1.16.3-2.fc28", rpm.ParserName}, {"sssd-client", "1.16.3-2.fc28", "rpm", "binary"},
{"libverto", "0.3.0-5.fc28", "libverto", "0.3.0-5.fc28", rpm.ParserName}, {"curl", "7.59.0-6.fc28", "rpm", "binary"},
{"gawk", "4.2.1-1.fc28", "gawk", "4.2.1-1.fc28", rpm.ParserName}, {"pam", "1.3.1-1.fc28", "rpm", "binary"},
{"libtirpc", "1.0.3-3.rc2.fc28", "libtirpc", "1.0.3-3.rc2.fc28", rpm.ParserName}, {"libsigsegv", "2.11-5.fc28", "rpm", "binary"},
{"python3-libs", "3.6.6-1.fc28", "python3", "3.6.6-1.fc28", rpm.ParserName}, {"langpacks-en", "1.0-12.fc28", "rpm", "binary"},
{"python3-setuptools", "39.2.0-6.fc28", "python-setuptools", "39.2.0-6.fc28", rpm.ParserName}, {"nss-softokn-freebl", "3.38.0-1.0.fc28", "rpm", "binary"},
{"libpwquality", "1.4.0-7.fc28", "libpwquality", "1.4.0-7.fc28", rpm.ParserName}, {"glib2", "2.56.1-4.fc28", "rpm", "binary"},
{"util-linux", "2.32.1-1.fc28", "util-linux", "2.32.1-1.fc28", rpm.ParserName}, {"python3-gobject-base", "3.28.3-1.fc28", "rpm", "binary"},
{"python3-libcomps", "0.1.8-11.fc28", "libcomps", "0.1.8-11.fc28", rpm.ParserName}, {"libffi", "3.1-16.fc28", "rpm", "source"},
{"python3-six", "1.11.0-3.fc28", "python-six", "1.11.0-3.fc28", rpm.ParserName}, {"libmodulemd", "1.6.2-2.fc28", "rpm", "source"},
{"cyrus-sasl-lib", "2.1.27-0.2rc7.fc28", "cyrus-sasl", "2.1.27-0.2rc7.fc28", rpm.ParserName}, {"openssl", "1.1.0h-3.fc28", "rpm", "source"},
{"libssh", "0.8.2-1.fc28", "libssh", "0.8.2-1.fc28", rpm.ParserName}, {"libyaml", "0.1.7-5.fc28", "rpm", "source"},
{"qrencode-libs", "3.4.4-5.fc28", "qrencode", "3.4.4-5.fc28", rpm.ParserName}, {"pam", "1.3.1-1.fc28", "rpm", "source"},
{"gnupg2", "2.2.8-1.fc28", "gnupg2", "2.2.8-1.fc28", rpm.ParserName}, {"iptables", "1.6.2-3.fc28", "rpm", "source"},
{"python3-gpg", "1.10.0-4.fc28", "gpgme", "1.10.0-4.fc28", rpm.ParserName}, {"util-linux", "2.32.1-1.fc28", "rpm", "source"},
{"libargon2", "20161029-5.fc28", "argon2", "20161029-5.fc28", rpm.ParserName}, {"libsmartcols", "2.32.1-1.fc28", "rpm", "binary"},
{"libmodulemd", "1.6.2-2.fc28", "libmodulemd", "1.6.2-2.fc28", rpm.ParserName}, {"dnf", "2.7.5-12.fc28", "rpm", "binary"},
{"pkgconf", "1.4.2-1.fc28", "pkgconf", "1.4.2-1.fc28", rpm.ParserName}, {"glib2", "2.56.1-4.fc28", "rpm", "source"},
{"libpcap", "14:1.9.0-1.fc28", "libpcap", "1.9.0-1.fc28", rpm.ParserName}, {"lua", "5.3.4-10.fc28", "rpm", "source"},
{"device-mapper", "1.02.146-5.fc28", "lvm2", "2.02.177-5.fc28", rpm.ParserName}, {"nss-softokn", "3.38.0-1.0.fc28", "rpm", "source"},
{"cryptsetup-libs", "2.0.4-1.fc28", "cryptsetup", "2.0.4-1.fc28", rpm.ParserName}, {"python3-dnf", "2.7.5-12.fc28", "rpm", "binary"},
{"elfutils-libs", "0.173-1.fc28", "elfutils", "0.173-1.fc28", rpm.ParserName}, {"filesystem", "3.8-2.fc28", "rpm", "binary"},
{"dbus", "1:1.12.10-1.fc28", "dbus", "1.12.10-1.fc28", rpm.ParserName}, {"libsss_nss_idmap", "1.16.3-2.fc28", "rpm", "binary"},
{"libnghttp2", "1.32.1-1.fc28", "nghttp2", "1.32.1-1.fc28", rpm.ParserName}, {"pcre2", "10.31-10.fc28", "rpm", "source"},
{"librepo", "1.8.1-7.fc28", "librepo", "1.8.1-7.fc28", rpm.ParserName}, {"libyaml", "0.1.7-5.fc28", "rpm", "binary"},
{"curl", "7.59.0-6.fc28", "curl", "7.59.0-6.fc28", rpm.ParserName}, {"python3-rpm", "4.14.1-9.fc28", "rpm", "binary"},
{"rpm-libs", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"zlib", "1.2.11-8.fc28", "rpm", "source"},
{"libsolv", "0.6.35-1.fc28", "libsolv", "0.6.35-1.fc28", rpm.ParserName}, {"libutempter", "1.1.6-14.fc28", "rpm", "binary"},
{"python3-hawkey", "0.11.1-3.fc28", "libdnf", "0.11.1-3.fc28", rpm.ParserName}, {"pcre2", "10.31-10.fc28", "rpm", "binary"},
{"rpm-sign-libs", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"libtirpc", "1.0.3-3.rc2.fc28", "rpm", "source"},
{"python3-dnf", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName}, {"pkgconf-m4", "1.4.2-1.fc28", "rpm", "binary"},
{"dnf-yum", "2.7.5-12.fc28", "dnf", "2.7.5-12.fc28", rpm.ParserName}, {"libreport", "2.9.5-1.fc28", "rpm", "source"},
{"rpm-plugin-systemd-inhibit", "4.14.1-9.fc28", "rpm", "4.14.1-9.fc28", rpm.ParserName}, {"vim", "8.1.328-1.fc28", "rpm", "source"},
{"nss-tools", "3.38.0-1.0.fc28", "nss", "3.38.0-1.0.fc28", rpm.ParserName}, {"file", "5.33-7.fc28", "rpm", "source"},
{"openssl-pkcs11", "0.4.8-1.fc28", "openssl-pkcs11", "0.4.8-1.fc28", rpm.ParserName}, {"shadow-utils", "4.6-1.fc28", "rpm", "source"},
{"vim-minimal", "2:8.1.328-1.fc28", "vim", "8.1.328-1.fc28", rpm.ParserName}, {"sqlite-libs", "3.22.0-4.fc28", "rpm", "binary"},
{"glibc-langpack-en", "2.27-32.fc28", "glibc", "2.27-32.fc28", rpm.ParserName}, {"setup", "2.11.4-1.fc28", "rpm", "source"},
{"rootfiles", "8.1-22.fc28", "rootfiles", "8.1-22.fc28", rpm.ParserName}, {"gcc", "8.1.1-5.fc28", "rpm", "source"},
{"mpfr", "3.1.6-1.fc28", "rpm", "binary"},
{"device-mapper", "1.02.146-5.fc28", "rpm", "binary"},
{"p11-kit", "0.23.12-1.fc28", "rpm", "source"},
{"fedora-release", "28-2", "rpm", "binary"},
{"libnghttp2", "1.32.1-1.fc28", "rpm", "binary"},
{"libcap-ng", "0.7.9-4.fc28", "rpm", "source"},
{"iptables-libs", "1.6.2-3.fc28", "rpm", "binary"},
{"audit-libs", "2.8.4-2.fc28", "rpm", "binary"},
{"libsigsegv", "2.11-5.fc28", "rpm", "source"},
{"rootfiles", "8.1-22.fc28", "rpm", "source"},
{"kmod-libs", "25-2.fc28", "rpm", "binary"},
{"lz4-libs", "1.8.1.2-4.fc28", "rpm", "binary"},
{"libassuan", "2.5.1-3.fc28", "rpm", "source"},
{"p11-kit", "0.23.12-1.fc28", "rpm", "binary"},
{"nss-sysinit", "3.38.0-1.0.fc28", "rpm", "binary"},
{"libcap-ng", "0.7.9-4.fc28", "rpm", "binary"},
{"bash", "4.4.23-1.fc28", "rpm", "source"},
{"pygobject3", "3.28.3-1.fc28", "rpm", "source"},
{"dnf-yum", "2.7.5-12.fc28", "rpm", "binary"},
{"nss-softokn", "3.38.0-1.0.fc28", "rpm", "binary"},
{"expat", "2.2.5-3.fc28", "rpm", "binary"},
{"libassuan", "2.5.1-3.fc28", "rpm", "binary"},
{"libdb", "5.3.28-30.fc28", "rpm", "binary"},
{"tar", "2:1.30-3.fc28", "rpm", "binary"},
{"sed", "4.5-1.fc28", "rpm", "source"},
{"libmetalink", "0.1.3-6.fc28", "rpm", "binary"},
{"python-smartcols", "0.3.0-2.fc28", "rpm", "source"},
{"systemd", "238-9.git0e0aa59.fc28", "rpm", "source"},
{"python-iniparse", "0.4-30.fc28", "rpm", "source"},
{"libsepol", "2.8-1.fc28", "rpm", "binary"},
{"libattr", "2.4.48-3.fc28", "rpm", "binary"},
{"python3-smartcols", "0.3.0-2.fc28", "rpm", "binary"},
{"libdb", "5.3.28-30.fc28", "rpm", "source"},
{"libmodulemd", "1.6.2-2.fc28", "rpm", "binary"},
{"python3-hawkey", "0.11.1-3.fc28", "rpm", "binary"},
{"dbus-libs", "1:1.12.10-1.fc28", "rpm", "binary"},
{"chkconfig", "1.10-4.fc28", "rpm", "source"},
{"libargon2", "20161029-5.fc28", "rpm", "binary"},
{"openssl-pkcs11", "0.4.8-1.fc28", "rpm", "source"},
{"libusbx", "1.0.22-1.fc28", "rpm", "source"},
{"python3-setuptools", "39.2.0-6.fc28", "rpm", "binary"},
{"chkconfig", "1.10-4.fc28", "rpm", "binary"},
{"openldap", "2.4.46-3.fc28", "rpm", "source"},
{"bzip2", "1.0.6-26.fc28", "rpm", "source"},
{"npth", "1.5-4.fc28", "rpm", "source"},
{"libtirpc", "1.0.3-3.rc2.fc28", "rpm", "binary"},
{"util-linux", "2.32.1-1.fc28", "rpm", "binary"},
{"nss", "3.38.0-1.0.fc28", "rpm", "source"},
{"elfutils", "0.173-1.fc28", "rpm", "source"},
{"libcomps", "0.1.8-11.fc28", "rpm", "source"},
{"libxcrypt", "4.1.2-1.fc28", "rpm", "source"},
{"gnupg2", "2.2.8-1.fc28", "rpm", "binary"},
{"libdnf", "0.11.1-3.fc28", "rpm", "binary"},
{"cracklib", "2.9.6-13.fc28", "rpm", "source"},
{"libidn2", "2.0.5-1.fc28", "rpm", "source"},
{"bzip2-libs", "1.0.6-26.fc28", "rpm", "binary"},
{"json-c", "0.13.1-2.fc28", "rpm", "source"},
{"gdbm", "1:1.14.1-4.fc28", "rpm", "binary"},
{"pcre", "8.42-3.fc28", "rpm", "source"},
{"systemd", "238-9.git0e0aa59.fc28", "rpm", "binary"},
{"cryptsetup-libs", "2.0.4-1.fc28", "rpm", "binary"},
{"dnf", "2.7.5-12.fc28", "rpm", "source"},
{"ca-certificates", "2018.2.24-1.0.fc28", "rpm", "source"},
{"libidn2", "2.0.5-1.fc28", "rpm", "binary"},
{"libpsl", "0.20.2-2.fc28", "rpm", "binary"},
{"gdbm-libs", "1:1.14.1-4.fc28", "rpm", "binary"},
{"kmod", "25-2.fc28", "rpm", "source"},
{"libreport-filesystem", "2.9.5-1.fc28", "rpm", "binary"},
{"ima-evm-utils", "1.1-2.fc28", "rpm", "source"},
{"nghttp2", "1.32.1-1.fc28", "rpm", "source"},
{"cyrus-sasl-lib", "2.1.27-0.2rc7.fc28", "rpm", "binary"},
{"libsolv", "0.6.35-1.fc28", "rpm", "binary"},
{"cryptsetup", "2.0.4-1.fc28", "rpm", "source"},
{"filesystem", "3.8-2.fc28", "rpm", "source"},
{"libcap", "2.25-9.fc28", "rpm", "source"},
{"libpsl", "0.20.2-2.fc28", "rpm", "source"},
{"deltarpm", "3.6-25.fc28", "rpm", "source"},
{"fedora-gpg-keys", "28-5", "rpm", "binary"},
{"ima-evm-utils", "1.1-2.fc28", "rpm", "binary"},
{"nss-tools", "3.38.0-1.0.fc28", "rpm", "binary"},
{"libtasn1", "4.13-2.fc28", "rpm", "source"},
{"elfutils-libelf", "0.173-1.fc28", "rpm", "binary"},
{"device-mapper-libs", "1.02.146-5.fc28", "rpm", "binary"},
{"gobject-introspection", "1.56.1-1.fc28", "rpm", "source"},
{"publicsuffix-list", "20180514-1.fc28", "rpm", "source"},
{"libcap", "2.25-9.fc28", "rpm", "binary"},
{"librepo", "1.8.1-7.fc28", "rpm", "binary"},
{"rpm-sign-libs", "4.14.1-9.fc28", "rpm", "binary"},
{"coreutils-single", "8.29-7.fc28", "rpm", "binary"},
{"libacl", "2.2.53-1.fc28", "rpm", "binary"},
{"popt", "1.16-14.fc28", "rpm", "source"},
{"libtasn1", "4.13-2.fc28", "rpm", "binary"},
{"gawk", "4.2.1-1.fc28", "rpm", "source"},
{"diffutils", "3.6-4.fc28", "rpm", "source"},
{"libgpg-error", "1.31-1.fc28", "rpm", "source"},
{"libdb-utils", "5.3.28-30.fc28", "rpm", "binary"},
{"python3-iniparse", "0.4-30.fc28", "rpm", "binary"},
{"acl", "2.2.53-1.fc28", "rpm", "binary"},
{"libssh", "0.8.2-1.fc28", "rpm", "source"},
{"python3-librepo", "1.8.1-7.fc28", "rpm", "binary"},
{"gobject-introspection", "1.56.1-1.fc28", "rpm", "binary"},
{"rpm", "4.14.1-9.fc28", "rpm", "source"},
{"libgcrypt", "1.8.3-1.fc28", "rpm", "source"},
{"curl", "7.59.0-6.fc28", "rpm", "source"},
{"tzdata", "2018e-1.fc28", "rpm", "source"},
{"krb5", "1.16.1-13.fc28", "rpm", "source"},
{"librepo", "1.8.1-7.fc28", "rpm", "source"},
{"python3-gpg", "1.10.0-4.fc28", "rpm", "binary"},
{"nettle", "3.4-2.fc28", "rpm", "source"},
{"libgcrypt", "1.8.3-1.fc28", "rpm", "binary"},
{"python3", "3.6.6-1.fc28", "rpm", "binary"},
{"python3-libcomps", "0.1.8-11.fc28", "rpm", "binary"},
{"rpm-libs", "4.14.1-9.fc28", "rpm", "binary"},
{"nspr", "4.19.0-1.fc28", "rpm", "binary"},
{"argon2", "20161029-5.fc28", "rpm", "source"},
{"tar", "1.30-3.fc28", "rpm", "source"},
{"qrencode-libs", "3.4.4-5.fc28", "rpm", "binary"},
{"gmp", "6.1.2-7.fc28", "rpm", "source"},
{"libverto", "0.3.0-5.fc28", "rpm", "binary"},
{"python3", "3.6.6-1.fc28", "rpm", "source"},
{"libksba", "1.3.5-7.fc28", "rpm", "binary"},
{"readline", "7.0-11.fc28", "rpm", "binary"},
{"rpm-build-libs", "4.14.1-9.fc28", "rpm", "binary"},
{"npth", "1.5-4.fc28", "rpm", "binary"},
{"rootfiles", "8.1-22.fc28", "rpm", "binary"},
{"rpm-plugin-systemd-inhibit", "4.14.1-9.fc28", "rpm", "binary"},
{"systemd-libs", "238-9.git0e0aa59.fc28", "rpm", "binary"},
{"nss-util", "3.38.0-1.0.fc28", "rpm", "binary"},
} }
func TestRpmFeatureDetection(t *testing.T) { func TestRpmFeatureDetection(t *testing.T) {
@ -206,8 +334,10 @@ func TestRpmFeatureDetection(t *testing.T) {
"valid small case", "valid small case",
map[string]string{"var/lib/rpm/Packages": "rpm/testdata/valid"}, map[string]string{"var/lib/rpm/Packages": "rpm/testdata/valid"},
[]database.Feature{ []database.Feature{
{"centos-release", "7-1.1503.el7.centos.2.8", "centos-release", "7-1.1503.el7.centos.2.8", rpm.ParserName}, {"centos-release", "7-1.1503.el7.centos.2.8", "rpm", "binary"},
{"filesystem", "3.2-18.el7", "filesystem", "3.2-18.el7", rpm.ParserName}, {"filesystem", "3.2-18.el7", "rpm", "binary"},
{"centos-release", "7-1.1503.el7.centos.2.8", "rpm", "source"},
{"filesystem", "3.2-18.el7", "rpm", "source"},
}, },
}, },
{ {
@ -248,15 +378,14 @@ func TestParseSourceRPM(t *testing.T) {
// actual expected: name="lua", version="5.3.4", release="10.fc-28" // actual expected: name="lua", version="5.3.4", release="10.fc-28"
{"lua-5.3.4-10.fc-28.src.rpm", "lua-5.3.4", "10.fc-28", ""}, {"lua-5.3.4-10.fc-28.src.rpm", "lua-5.3.4", "10.fc-28", ""},
} { } {
pkg := database.Feature{} name, version, release, _, err := parseSourceRPM(test.sourceRPM)
err := parseSourceRPM(test.sourceRPM, &pkg)
if test.expectedErr != "" { if test.expectedErr != "" {
require.EqualError(t, err, test.expectedErr) require.EqualError(t, err, test.expectedErr)
continue continue
} }
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, test.expectedName, pkg.SourceName) require.Equal(t, test.expectedName, name)
require.Equal(t, test.expectedVersion, pkg.SourceVersion) require.Equal(t, test.expectedVersion, version+"-"+release)
} }
} }