ext/featurefmt/dpkg: Extract source package metadata

The source package metadata is extracted from the source line instead
of forcing the binary package to have source package information.
master
Sida Chen 6 years ago
parent 1c40e7d016
commit 4ac046642f

@ -20,6 +20,7 @@ import (
"regexp"
"strings"
"github.com/deckarep/golang-set"
log "github.com/sirupsen/logrus"
"github.com/coreos/clair/database"
@ -40,29 +41,39 @@ func init() {
featurefmt.RegisterLister("dpkg", "1.0", &lister{})
}
func valid(pkg *featurefmt.PackageInfo) bool {
return pkg.PackageName != "" && pkg.PackageVersion != ""
}
func addSourceVersion(pkg *featurefmt.PackageInfo) {
if pkg.SourceName != "" && pkg.SourceVersion == "" {
pkg.SourceVersion = pkg.PackageVersion
}
}
func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
f, hasFile := files["var/lib/dpkg/status"]
if !hasFile {
return []database.Feature{}, nil
}
// Create a map to store packages and ensure their uniqueness
packagesMap := make(map[string]database.Feature)
var (
pkg featurefmt.PackageInfo
pkgs = mapset.NewSet()
err error
)
var pkg database.Feature
var err error
scanner := bufio.NewScanner(strings.NewReader(string(f)))
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "Package: ") {
// Package line
// Defines the name of the package
pkg.Name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
pkg.Version = ""
pkg.PackageName = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
pkg.PackageVersion = ""
} else if strings.HasPrefix(line, "Source: ") {
// Source line (Optionnal)
// Source line (Optional)
// Gives the name of the source package
// May also specifies a version
@ -72,50 +83,38 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
md[dpkgSrcCaptureRegexpNames[i]] = strings.TrimSpace(n)
}
pkg.Name = md["name"]
pkg.SourceName = md["name"]
if md["version"] != "" {
version := md["version"]
err = versionfmt.Valid(dpkg.ParserName, version)
if 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")
} else {
pkg.Version = version
pkg.SourceVersion = version
}
}
} else if strings.HasPrefix(line, "Version: ") && pkg.Version == "" {
} else if strings.HasPrefix(line, "Version: ") {
// Version line
// Defines the version of the package
// 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
// which is not present in the Source version, and because +bX revisions don't matter
version := strings.TrimPrefix(line, "Version: ")
err = versionfmt.Valid(dpkg.ParserName, version)
if 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")
} else {
pkg.Version = version
pkg.PackageVersion = version
}
} else if line == "" {
pkg.Name = ""
pkg.Version = ""
pkg.Reset()
}
// Add the package to the result array if we have all the informations
if pkg.Name != "" && pkg.Version != "" {
packagesMap[pkg.Name+"#"+pkg.Version] = pkg
pkg.Name = ""
pkg.Version = ""
if valid(&pkg) {
addSourceVersion(&pkg)
pkgs.Add(pkg)
}
}
// Convert the map to a slice and add version format.
packages := make([]database.Feature, 0, len(packagesMap))
for _, pkg := range packagesMap {
pkg.VersionFormat = dpkg.ParserName
packages = append(packages, pkg)
}
return packages, nil
return featurefmt.PackageSetToFeatures(dpkg.ParserName, pkgs), nil
}
func (l lister) RequiredFilenames() []string {

@ -17,42 +17,118 @@ package dpkg
import (
"testing"
"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/featurefmt"
"github.com/coreos/clair/ext/versionfmt/dpkg"
"github.com/coreos/clair/pkg/tarutil"
)
func TestDpkgFeatureDetection(t *testing.T) {
testFeatures := []database.Feature{
// Two packages from this source are installed, it should only appear one time
func TestListFeatures(t *testing.T) {
for _, test := range []featurefmt.TestCase{
{
Name: "pam",
Version: "1.1.8-3.1ubuntu3",
},
{
Name: "makedev", // The source name and the package name are equals
Version: "2.3.1-93ubuntu1", // The version comes from the "Version:" line
},
{
Name: "gcc-5",
Version: "5.1.1-12ubuntu1", // The version comes from the "Source:" line
"valid status file",
map[string]string{"var/lib/dpkg/status": "dpkg/testdata/valid"},
[]featurefmt.PackageInfo{
{"adduser", "3.116ubuntu1", "", ""},
{"apt", "1.6.3ubuntu0.1", "", ""},
{"base-files", "10.1ubuntu2.2", "", ""},
{"base-passwd", "3.5.44", "", ""},
{"bash", "4.4.18-2ubuntu1", "", ""},
{"bsdutils", "1:2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"bzip2", "1.0.6-8.1", "", ""},
{"coreutils", "8.28-1ubuntu1", "", ""},
{"dash", "0.5.8-2.10", "", ""},
{"debconf", "1.5.66", "", ""},
{"debianutils", "4.8.4", "", ""},
{"diffutils", "1:3.6-1", "", ""},
{"dpkg", "1.19.0.5ubuntu2", "", ""},
{"e2fsprogs", "1.44.1-1", "", ""},
{"fdisk", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"findutils", "4.6.0+git+20170828-2", "", ""},
{"gcc-8-base", "8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2"},
{"gpgv", "2.2.4-1ubuntu1.1", "gnupg2", "2.2.4-1ubuntu1.1"},
{"grep", "3.1-2", "", ""},
{"gzip", "1.6-5ubuntu1", "", ""},
{"hostname", "3.20", "", ""},
{"init-system-helpers", "1.51", "", ""},
{"libacl1", "2.2.52-3build1", "acl", "2.2.52-3build1"},
{"libapt-pkg5.0", "1.6.3ubuntu0.1", "apt", "1.6.3ubuntu0.1"},
{"libattr1", "1:2.4.47-2build1", "attr", "1:2.4.47-2build1"},
{"libaudit-common", "1:2.8.2-1ubuntu1", "audit", "1:2.8.2-1ubuntu1"},
{"libaudit1", "1:2.8.2-1ubuntu1", "audit", "1:2.8.2-1ubuntu1"},
{"libblkid1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"libbz2-1.0", "1.0.6-8.1", "bzip2", "1.0.6-8.1"},
{"libc-bin", "2.27-3ubuntu1", "glibc", "2.27-3ubuntu1"},
{"libc6", "2.27-3ubuntu1", "glibc", "2.27-3ubuntu1"},
{"libcap-ng0", "0.7.7-3.1", "libcap-ng", "0.7.7-3.1"},
{"libcom-err2", "1.44.1-1", "e2fsprogs", "1.44.1-1"},
{"libdb5.3", "5.3.28-13.1ubuntu1", "db5.3", "5.3.28-13.1ubuntu1"},
{"libdebconfclient0", "0.213ubuntu1", "cdebconf", "0.213ubuntu1"},
{"libext2fs2", "1.44.1-1", "e2fsprogs", "1.44.1-1"},
{"libfdisk1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"libffi6", "3.2.1-8", "libffi", "3.2.1-8"},
{"libgcc1", "1:8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2"},
{"libgcrypt20", "1.8.1-4ubuntu1.1", "", ""},
{"libgmp10", "2:6.1.2+dfsg-2", "gmp", "2:6.1.2+dfsg-2"},
{"libgnutls30", "3.5.18-1ubuntu1", "gnutls28", "3.5.18-1ubuntu1"},
{"libgpg-error0", "1.27-6", "libgpg-error", "1.27-6"},
{"libhogweed4", "3.4-1", "nettle", "3.4-1"},
{"libidn2-0", "2.0.4-1.1build2", "libidn2", "2.0.4-1.1build2"},
{"liblz4-1", "0.0~r131-2ubuntu3", "lz4", "0.0~r131-2ubuntu3"},
{"liblzma5", "5.2.2-1.3", "xz-utils", "5.2.2-1.3"},
{"libmount1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"libncurses5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04"},
{"libncursesw5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04"},
{"libnettle6", "3.4-1", "nettle", "3.4-1"},
{"libp11-kit0", "0.23.9-2", "p11-kit", "0.23.9-2"},
{"libpam-modules", "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"},
{"libpam-runtime", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2"},
{"libpam0g", "1.1.8-3.6ubuntu2", "pam", "1.1.8-3.6ubuntu2"},
{"libpcre3", "2:8.39-9", "pcre3", "2:8.39-9"},
{"libprocps6", "2:3.3.12-3ubuntu1.1", "procps", "2:3.3.12-3ubuntu1.1"},
{"libseccomp2", "2.3.1-2.1ubuntu4", "libseccomp", "2.3.1-2.1ubuntu4"},
{"libselinux1", "2.7-2build2", "libselinux", "2.7-2build2"},
{"libsemanage-common", "2.7-2build2", "libsemanage", "2.7-2build2"},
{"libsemanage1", "2.7-2build2", "libsemanage", "2.7-2build2"},
{"libsepol1", "2.7-1", "libsepol", "2.7-1"},
{"libsmartcols1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"libss2", "1.44.1-1", "e2fsprogs", "1.44.1-1"},
{"libstdc++6", "8-20180414-1ubuntu2", "gcc-8", "8-20180414-1ubuntu2"},
{"libsystemd0", "237-3ubuntu10.3", "systemd", "237-3ubuntu10.3"},
{"libtasn1-6", "4.13-2", "", ""},
{"libtinfo5", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04"},
{"libudev1", "237-3ubuntu10.3", "systemd", "237-3ubuntu10.3"},
{"libunistring2", "0.9.9-0ubuntu1", "libunistring", "0.9.9-0ubuntu1"},
{"libuuid1", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"libzstd1", "1.3.3+dfsg-2ubuntu1", "libzstd", "1.3.3+dfsg-2ubuntu1"},
{"login", "1:4.5-1ubuntu1", "shadow", "1:4.5-1ubuntu1"},
{"lsb-base", "9.20170808ubuntu1", "lsb", "9.20170808ubuntu1"},
{"mawk", "1.3.3-17ubuntu3", "", ""},
{"mount", "2.31.1-0.4ubuntu3.1", "util-linux", "2.31.1-0.4ubuntu3.1"},
{"ncurses-base", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04"},
{"ncurses-bin", "6.1-1ubuntu1.18.04", "ncurses", "6.1-1ubuntu1.18.04"},
{"passwd", "1:4.5-1ubuntu1", "shadow", "1:4.5-1ubuntu1"},
{"perl-base", "5.26.1-6ubuntu0.2", "perl", "5.26.1-6ubuntu0.2"},
{"procps", "2:3.3.12-3ubuntu1.1", "", ""},
{"sed", "4.4-2", "", ""},
{"sensible-utils", "0.0.12", "", ""},
{"sysvinit-utils", "2.88dsf-59.10ubuntu1", "sysvinit", "2.88dsf-59.10ubuntu1"},
{"tar", "1.29b-2", "", ""},
{"ubuntu-keyring", "2018.02.28", "", ""},
{"util-linux", "2.31.1-0.4ubuntu3.1", "", ""},
{"zlib1g", "1:1.2.11.dfsg-0ubuntu2", "zlib", "1:1.2.11.dfsg-0ubuntu2"},
},
},
}
for i := range testFeatures {
testFeatures[i].VersionFormat = dpkg.ParserName
}
testData := []featurefmt.TestData{
// Test an Ubuntu dpkg status file
{
Features: testFeatures,
Files: tarutil.FilesMap{
"var/lib/dpkg/status": featurefmt.LoadFileForTest("dpkg/testdata/status"),
"corrupted status file",
map[string]string{"var/lib/dpkg/status": "dpkg/testdata/corrupted"},
[]featurefmt.PackageInfo{
{"libpam-runtime", "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"},
{"makedev", "2.3.1-93ubuntu1", "", ""},
{"libgcc1", "1:5.1.1-12ubuntu1", "gcc-5", "5.1.1-12ubuntu1"},
},
},
} {
featurefmt.RunTest(t, test, &lister{}, dpkg.ParserName)
}
featurefmt.TestLister(t, &lister{}, testData)
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save