database: Replace Parent Feature with source metadata

Feature's source feature string is directly stored in the database
instead of having the parent pointer to simplify the database.
This commit is contained in:
Sida Chen 2018-10-15 16:26:24 -04:00
parent 2ac088dd0f
commit f759dd54c0
11 changed files with 341 additions and 419 deletions

View File

@ -40,8 +40,13 @@ func DeduplicateFeatures(features ...Feature) []Feature {
fSet.Add(f) fSet.Add(f)
} }
uniqueFeatures := make([]Feature, 0, fSet.Cardinality()) return ConvertFeatureSetToFeatures(fSet)
for f := range fSet.Iter() { }
// ConvertFeatureSetToFeatures converts a feature set to an array of features
func ConvertFeatureSetToFeatures(features mapset.Set) []Feature {
uniqueFeatures := make([]Feature, 0, features.Cardinality())
for f := range features.Iter() {
uniqueFeatures = append(uniqueFeatures, f.(Feature)) uniqueFeatures = append(uniqueFeatures, f.(Feature))
} }

View File

@ -158,19 +158,15 @@ type Namespace struct {
// Feature represents a package detected in a layer but the namespace is not // Feature represents a package detected in a layer but the namespace is not
// determined. // determined.
// //
// e.g. Name: OpenSSL, Version: 1.0, VersionFormat: dpkg. // e.g. Name: Libssl1.0, Version: 1.0, Name: Openssl, Version: 1.0, VersionFormat: dpkg.
// dpkg is the version format of the installer package manager, which in this // dpkg is the version format of the installer package manager, which in this
// case could be dpkg or apk. // case could be dpkg or apk.
type Feature struct { type Feature struct {
Name string Name string
Version string Version string
SourceName string
SourceVersion string
VersionFormat string VersionFormat string
// Parent feature indicates that the vulnerability affects parent feature
// will also affect this feature.
//
// e.g. A source package is the parent feature of a binary package.
Parent *Feature
} }
// NamespacedFeature is a feature with determined namespace and can be affected // NamespacedFeature is a feature with determined namespace and can be affected

View File

@ -26,10 +26,10 @@ import (
// int keys must be the consistent with the database ID. // int keys must be the consistent with the database ID.
var ( var (
realFeatures = map[int]database.Feature{ realFeatures = map[int]database.Feature{
1: {"ourchat", "0.5", "dpkg", nil}, 1: {"ourchat", "0.5", "ourchat", "0.5", "dpkg"},
2: {"openssl", "1.0", "dpkg", nil}, 2: {"openssl", "1.0", "openssl", "1.0", "dpkg"},
3: {"openssl", "2.0", "dpkg", nil}, 3: {"openssl", "2.0", "openssl", "2.0", "dpkg"},
4: {"fake", "2.0", "rpm", nil}, 4: {"fake", "2.0", "fake", "2.0", "rpm"},
} }
realNamespaces = map[int]database.Namespace{ realNamespaces = map[int]database.Namespace{

View File

@ -35,14 +35,8 @@ func init() {
type lister struct{} type lister struct{}
func valid(pkg *featurefmt.PackageInfo) bool { func valid(pkg *database.Feature) bool {
return pkg.PackageName != "" && pkg.PackageVersion != "" return pkg.Name != "" && pkg.Version != ""
}
func addSourceVersion(pkg *featurefmt.PackageInfo) {
if pkg.SourceName != "" {
pkg.SourceVersion = pkg.PackageVersion
}
} }
func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) { func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
@ -55,23 +49,24 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// package into a feature that will be stored in a set to guarantee // package into a feature that will be stored in a set to guarantee
// uniqueness. // uniqueness.
packages := mapset.NewSet() packages := mapset.NewSet()
pkg := featurefmt.PackageInfo{} pkg := database.Feature{VersionFormat: dpkg.ParserName}
scanner := bufio.NewScanner(bytes.NewBuffer(file)) scanner := bufio.NewScanner(bytes.NewBuffer(file))
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
if len(line) < 2 { if len(line) < 2 {
if valid(&pkg) { if valid(&pkg) {
addSourceVersion(&pkg)
packages.Add(pkg) packages.Add(pkg)
pkg.Reset() pkg = database.Feature{VersionFormat: dpkg.ParserName}
} }
continue continue
} }
// Parse the package name or version. // Parse the package name or version.
// Alpine package doesn't have specific source package. The "origin"
// package is sub package.
switch line[:2] { switch line[:2] {
case "P:": case "P:":
pkg.PackageName = line[2:] pkg.Name = line[2:]
case "V:": case "V:":
version := string(line[2:]) version := string(line[2:])
err := versionfmt.Valid(dpkg.ParserName, version) err := versionfmt.Valid(dpkg.ParserName, version)
@ -79,20 +74,17 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
log.WithError(err).WithField("version", version).Warning("could not parse package version. skipping") log.WithError(err).WithField("version", version).Warning("could not parse package version. skipping")
continue continue
} else { } else {
pkg.PackageVersion = version pkg.Version = version
} }
case "o:":
pkg.SourceName = line[2:]
} }
} }
// in case of no terminal line // in case of no terminal line
if valid(&pkg) { if valid(&pkg) {
addSourceVersion(&pkg)
packages.Add(pkg) packages.Add(pkg)
} }
return featurefmt.PackageSetToFeatures(dpkg.ParserName, packages), nil return database.ConvertFeatureSetToFeatures(packages), nil
} }
func (l lister) RequiredFilenames() []string { func (l lister) RequiredFilenames() []string {

View File

@ -17,6 +17,7 @@ package apk
import ( import (
"testing" "testing"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/featurefmt" "github.com/coreos/clair/ext/featurefmt"
"github.com/coreos/clair/ext/versionfmt/dpkg" "github.com/coreos/clair/ext/versionfmt/dpkg"
) )
@ -26,18 +27,18 @@ 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"},
[]featurefmt.PackageInfo{ []database.Feature{
{"musl", "1.1.14-r10", "", ""}, {"musl", "1.1.14-r10", "", "", dpkg.ParserName},
{"busybox", "1.24.2-r9", "", ""}, {"busybox", "1.24.2-r9", "", "", dpkg.ParserName},
{"alpine-baselayout", "3.0.3-r0", "", ""}, {"alpine-baselayout", "3.0.3-r0", "", "", dpkg.ParserName},
{"alpine-keys", "1.1-r0", "", ""}, {"alpine-keys", "1.1-r0", "", "", dpkg.ParserName},
{"zlib", "1.2.8-r2", "", ""}, {"zlib", "1.2.8-r2", "", "", dpkg.ParserName},
{"libcrypto1.0", "1.0.2h-r1", "openssl", "1.0.2h-r1"}, {"libcrypto1.0", "1.0.2h-r1", "", "", dpkg.ParserName},
{"libssl1.0", "1.0.2h-r1", "openssl", "1.0.2h-r1"}, {"libssl1.0", "1.0.2h-r1", "", "", dpkg.ParserName},
{"apk-tools", "2.6.7-r0", "", ""}, {"apk-tools", "2.6.7-r0", "", "", dpkg.ParserName},
{"scanelf", "1.1.6-r0", "pax-utils", "1.1.6-r0"}, {"scanelf", "1.1.6-r0", "", "", dpkg.ParserName},
{"musl-utils", "1.1.14-r10", "musl", "1.1.14-r10"}, {"musl-utils", "1.1.14-r10", "", "", dpkg.ParserName},
{"libc-utils", "0.7-r0", "libc-dev", "0.7-r0"}, {"libc-utils", "0.7-r0", "", "", dpkg.ParserName},
}, },
}, },
} { } {

View File

@ -41,13 +41,17 @@ func init() {
featurefmt.RegisterLister("dpkg", "1.0", &lister{}) featurefmt.RegisterLister("dpkg", "1.0", &lister{})
} }
func valid(pkg *featurefmt.PackageInfo) bool { func valid(pkg *database.Feature) bool {
return pkg.PackageName != "" && pkg.PackageVersion != "" return pkg.Name != "" && pkg.Version != ""
} }
func addSourceVersion(pkg *featurefmt.PackageInfo) { func addSourcePackage(pkg *database.Feature) {
if pkg.SourceName != "" && pkg.SourceVersion == "" { if pkg.SourceName == "" {
pkg.SourceVersion = pkg.PackageVersion pkg.SourceName = pkg.Name
}
if pkg.SourceVersion == "" {
pkg.SourceVersion = pkg.Version
} }
} }
@ -58,7 +62,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
} }
var ( var (
pkg featurefmt.PackageInfo pkg = database.Feature{VersionFormat: dpkg.ParserName}
pkgs = mapset.NewSet() pkgs = mapset.NewSet()
err error err error
) )
@ -70,8 +74,8 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// Package line // Package line
// Defines the name of the package // Defines the name of the package
pkg.PackageName = strings.TrimSpace(strings.TrimPrefix(line, "Package: ")) pkg.Name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
pkg.PackageVersion = "" pkg.Version = ""
} 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
@ -102,19 +106,19 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
if err = versionfmt.Valid(dpkg.ParserName, version); err != nil { if err = versionfmt.Valid(dpkg.ParserName, version); err != nil {
log.WithError(err).WithField("version", string(line[1])).Warning("could not parse package version. skipping") log.WithError(err).WithField("version", string(line[1])).Warning("could not parse package version. skipping")
} else { } else {
pkg.PackageVersion = version pkg.Version = version
} }
} else if line == "" { } else if line == "" {
pkg.Reset() pkg = database.Feature{VersionFormat: dpkg.ParserName}
} }
if valid(&pkg) { if valid(&pkg) {
addSourceVersion(&pkg) addSourcePackage(&pkg)
pkgs.Add(pkg) pkgs.Add(pkg)
} }
} }
return featurefmt.PackageSetToFeatures(dpkg.ParserName, pkgs), nil return database.ConvertFeatureSetToFeatures(pkgs), nil
} }
func (l lister) RequiredFilenames() []string { func (l lister) RequiredFilenames() []string {

View File

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

View File

@ -1,56 +0,0 @@
package featurefmt
import (
"github.com/coreos/clair/database"
"github.com/deckarep/golang-set"
)
// PackageInfo is the extracted raw information from the package managers that
// can be converted to a feature.
type PackageInfo struct {
PackageName string
PackageVersion string
SourceName string
SourceVersion string
}
// Reset defaults the internal string fields to empty strings.
func (pkg *PackageInfo) Reset() {
pkg.PackageName = ""
pkg.PackageVersion = ""
pkg.SourceName = ""
pkg.SourceVersion = ""
}
func (pkg *PackageInfo) asFeature(versionFormat string) database.Feature {
feature := database.Feature{
Name: pkg.PackageName,
Version: pkg.PackageVersion,
VersionFormat: versionFormat,
}
if pkg.SourceName != "" {
parent := database.Feature{
Name: pkg.SourceName,
Version: pkg.SourceVersion,
VersionFormat: versionFormat,
}
if parent != feature {
feature.Parent = &parent
}
}
return feature
}
// PackageSetToFeatures converts a package set to feature slice
func PackageSetToFeatures(versionFormat string, pkgs mapset.Set) []database.Feature {
features := make([]database.Feature, 0, pkgs.Cardinality())
for pkg := range pkgs.Iter() {
p := pkg.(PackageInfo)
features = append(features, p.asFeature(versionFormat))
}
return features
}

View File

@ -55,8 +55,8 @@ func isIgnored(packageName string) bool {
return false return false
} }
func valid(pkg *featurefmt.PackageInfo) bool { func valid(pkg *database.Feature) bool {
return pkg.PackageName != "" && pkg.PackageVersion != "" && return pkg.Name != "" && pkg.Version != "" &&
((pkg.SourceName == "" && pkg.SourceVersion != "") || ((pkg.SourceName == "" && pkg.SourceVersion != "") ||
(pkg.SourceName != "" && pkg.SourceVersion != "")) (pkg.SourceName != "" && pkg.SourceVersion != ""))
} }
@ -104,9 +104,9 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
continue continue
} }
pkg := featurefmt.PackageInfo{PackageName: line[0]} pkg := database.Feature{Name: line[0], VersionFormat: rpm.ParserName}
pkg.PackageVersion = strings.Replace(line[1], "(none):", "", -1) pkg.Version = strings.Replace(line[1], "(none):", "", -1)
if err := versionfmt.Valid(rpm.ParserName, pkg.PackageVersion); err != nil { if err := versionfmt.Valid(rpm.ParserName, pkg.Version); err != nil {
log.WithError(err).WithField("version", line[1]).Warning("skipped unparseable package") log.WithError(err).WithField("version", line[1]).Warning("skipped unparseable package")
continue continue
} }
@ -121,7 +121,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
} }
} }
return featurefmt.PackageSetToFeatures(rpm.ParserName, packages), nil return database.ConvertFeatureSetToFeatures(packages), nil
} }
func (l lister) RequiredFilenames() []string { func (l lister) RequiredFilenames() []string {
@ -140,7 +140,7 @@ 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 *featurefmt.PackageInfo) error { func parseSourceRPM(sourceRPM string, pkg *database.Feature) error {
state := parseRPM state := parseRPM
previousCheckPoint := len(sourceRPM) previousCheckPoint := len(sourceRPM)
release := "" release := ""

View File

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

View File

@ -54,7 +54,7 @@ func loadTestFiles(testFilePaths map[string]string) tarutil.FilesMap {
type TestCase struct { type TestCase struct {
Name string Name string
FilePaths map[string]string FilePaths map[string]string
ExpectedResult []PackageInfo ExpectedResult []database.Feature
} }
// RunTest runs a featurefmt test by loading the package info database files and // RunTest runs a featurefmt test by loading the package info database files and
@ -65,7 +65,7 @@ func RunTest(t *testing.T, test TestCase, lister Lister, expectedVersionFormat s
expected := test.ExpectedResult expected := test.ExpectedResult
features, err := lister.ListFeatures(filesMap) features, err := lister.ListFeatures(filesMap)
require.Nil(t, err) require.Nil(t, err)
visited := map[PackageInfo]bool{} visited := map[database.Feature]bool{}
// we only enforce the unique packages to match, the result features // we only enforce the unique packages to match, the result features
// should be always deduplicated. // should be always deduplicated.
for _, pkg := range expected { for _, pkg := range expected {
@ -75,22 +75,16 @@ func RunTest(t *testing.T, test TestCase, lister Lister, expectedVersionFormat s
assert.Len(t, features, len(visited)) assert.Len(t, features, len(visited))
for _, f := range features { for _, f := range features {
assert.Equal(t, expectedVersionFormat, f.VersionFormat) assert.Equal(t, expectedVersionFormat, f.VersionFormat)
if f.Parent != nil { if ok, found := visited[f]; ok {
// currently we don't have more than 2 levels deep features. assert.Fail(t, "duplicated features is not allowed", "feature=%#v", f)
assert.Equal(t, expectedVersionFormat, f.Parent.VersionFormat)
}
pkg := convertToPackageInfo(&f)
if ok, found := visited[pkg]; ok {
assert.Fail(t, "duplicated features is not allowed", "feature=%#v", f, pkg)
} else if !found { } else if !found {
assert.Fail(t, "unexpected feature", "feature = %#v", pkg) assert.Fail(t, "unexpected feature", "feature = %#v", f)
} }
visited[pkg] = true visited[f] = true
} }
missingPackages := []PackageInfo{} missingPackages := []database.Feature{}
for pkg, ok := range visited { for pkg, ok := range visited {
if !ok { if !ok {
missingPackages = append(missingPackages, pkg) missingPackages = append(missingPackages, pkg)
@ -100,19 +94,3 @@ func RunTest(t *testing.T, test TestCase, lister Lister, expectedVersionFormat s
assert.Len(t, missingPackages, 0, "missing packages") assert.Len(t, missingPackages, 0, "missing packages")
}) })
} }
func convertToPackageInfo(feature *database.Feature) PackageInfo {
pkg := PackageInfo{
PackageName: feature.Name,
PackageVersion: feature.Version,
}
// Since in the actual package manager metadata file, there's no explicit
// tree structure, the features are converted to compare the metadata only.
if feature.Parent != nil {
pkg.SourceName = feature.Parent.Name
pkg.SourceVersion = feature.Parent.Version
}
return pkg
}