Skip to content

Commit

Permalink
database: Replace Parent Feature with source metadata
Browse files Browse the repository at this point in the history
Feature's source feature string is directly stored in the database
instead of having the parent pointer to simplify the database.
  • Loading branch information
KeyboardNerd committed Oct 15, 2018
1 parent 2ac088d commit f759dd5
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 419 deletions.
9 changes: 7 additions & 2 deletions database/dbutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,13 @@ func DeduplicateFeatures(features ...Feature) []Feature {
fSet.Add(f)
}

uniqueFeatures := make([]Feature, 0, fSet.Cardinality())
for f := range fSet.Iter() {
return ConvertFeatureSetToFeatures(fSet)
}

// 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))
}

Expand Down
10 changes: 3 additions & 7 deletions database/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,15 @@ type Namespace struct {
// Feature represents a package detected in a layer but the namespace is not
// 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
// case could be dpkg or apk.
type Feature struct {
Name string
Version string
SourceName string
SourceVersion 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
Expand Down
8 changes: 4 additions & 4 deletions database/pgsql/testutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import (
// int keys must be the consistent with the database ID.
var (
realFeatures = map[int]database.Feature{
1: {"ourchat", "0.5", "dpkg", nil},
2: {"openssl", "1.0", "dpkg", nil},
3: {"openssl", "2.0", "dpkg", nil},
4: {"fake", "2.0", "rpm", nil},
1: {"ourchat", "0.5", "ourchat", "0.5", "dpkg"},
2: {"openssl", "1.0", "openssl", "1.0", "dpkg"},
3: {"openssl", "2.0", "openssl", "2.0", "dpkg"},
4: {"fake", "2.0", "fake", "2.0", "rpm"},
}

realNamespaces = map[int]database.Namespace{
Expand Down
26 changes: 9 additions & 17 deletions ext/featurefmt/apk/apk.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,8 @@ func init() {

type lister struct{}

func valid(pkg *featurefmt.PackageInfo) bool {
return pkg.PackageName != "" && pkg.PackageVersion != ""
}

func addSourceVersion(pkg *featurefmt.PackageInfo) {
if pkg.SourceName != "" {
pkg.SourceVersion = pkg.PackageVersion
}
func valid(pkg *database.Feature) bool {
return pkg.Name != "" && pkg.Version != ""
}

func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error) {
Expand All @@ -55,44 +49,42 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// package into a feature that will be stored in a set to guarantee
// uniqueness.
packages := mapset.NewSet()
pkg := featurefmt.PackageInfo{}
pkg := database.Feature{VersionFormat: dpkg.ParserName}
scanner := bufio.NewScanner(bytes.NewBuffer(file))
for scanner.Scan() {
line := scanner.Text()
if len(line) < 2 {
if valid(&pkg) {
addSourceVersion(&pkg)
packages.Add(pkg)
pkg.Reset()
pkg = database.Feature{VersionFormat: dpkg.ParserName}
}
continue
}

// Parse the package name or version.
// Alpine package doesn't have specific source package. The "origin"
// package is sub package.
switch line[:2] {
case "P:":
pkg.PackageName = line[2:]
pkg.Name = line[2:]
case "V:":
version := string(line[2:])
err := versionfmt.Valid(dpkg.ParserName, version)
if err != nil {
log.WithError(err).WithField("version", version).Warning("could not parse package version. skipping")
continue
} else {
pkg.PackageVersion = version
pkg.Version = version
}
case "o:":
pkg.SourceName = line[2:]
}
}

// in case of no terminal line
if valid(&pkg) {
addSourceVersion(&pkg)
packages.Add(pkg)
}

return featurefmt.PackageSetToFeatures(dpkg.ParserName, packages), nil
return database.ConvertFeatureSetToFeatures(packages), nil
}

func (l lister) RequiredFilenames() []string {
Expand Down
25 changes: 13 additions & 12 deletions ext/featurefmt/apk/apk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package apk
import (
"testing"

"github.com/coreos/clair/database"
"github.com/coreos/clair/ext/featurefmt"
"github.com/coreos/clair/ext/versionfmt/dpkg"
)
Expand All @@ -26,18 +27,18 @@ func TestAPKFeatureDetection(t *testing.T) {
{
"valid case",
map[string]string{"lib/apk/db/installed": "apk/testdata/valid"},
[]featurefmt.PackageInfo{
{"musl", "1.1.14-r10", "", ""},
{"busybox", "1.24.2-r9", "", ""},
{"alpine-baselayout", "3.0.3-r0", "", ""},
{"alpine-keys", "1.1-r0", "", ""},
{"zlib", "1.2.8-r2", "", ""},
{"libcrypto1.0", "1.0.2h-r1", "openssl", "1.0.2h-r1"},
{"libssl1.0", "1.0.2h-r1", "openssl", "1.0.2h-r1"},
{"apk-tools", "2.6.7-r0", "", ""},
{"scanelf", "1.1.6-r0", "pax-utils", "1.1.6-r0"},
{"musl-utils", "1.1.14-r10", "musl", "1.1.14-r10"},
{"libc-utils", "0.7-r0", "libc-dev", "0.7-r0"},
[]database.Feature{
{"musl", "1.1.14-r10", "", "", dpkg.ParserName},
{"busybox", "1.24.2-r9", "", "", dpkg.ParserName},
{"alpine-baselayout", "3.0.3-r0", "", "", dpkg.ParserName},
{"alpine-keys", "1.1-r0", "", "", dpkg.ParserName},
{"zlib", "1.2.8-r2", "", "", dpkg.ParserName},
{"libcrypto1.0", "1.0.2h-r1", "", "", dpkg.ParserName},
{"libssl1.0", "1.0.2h-r1", "", "", dpkg.ParserName},
{"apk-tools", "2.6.7-r0", "", "", dpkg.ParserName},
{"scanelf", "1.1.6-r0", "", "", dpkg.ParserName},
{"musl-utils", "1.1.14-r10", "", "", dpkg.ParserName},
{"libc-utils", "0.7-r0", "", "", dpkg.ParserName},
},
},
} {
Expand Down
28 changes: 16 additions & 12 deletions ext/featurefmt/dpkg/dpkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,17 @@ func init() {
featurefmt.RegisterLister("dpkg", "1.0", &lister{})
}

func valid(pkg *featurefmt.PackageInfo) bool {
return pkg.PackageName != "" && pkg.PackageVersion != ""
func valid(pkg *database.Feature) bool {
return pkg.Name != "" && pkg.Version != ""
}

func addSourceVersion(pkg *featurefmt.PackageInfo) {
if pkg.SourceName != "" && pkg.SourceVersion == "" {
pkg.SourceVersion = pkg.PackageVersion
func addSourcePackage(pkg *database.Feature) {
if pkg.SourceName == "" {
pkg.SourceName = pkg.Name
}

if pkg.SourceVersion == "" {
pkg.SourceVersion = pkg.Version
}
}

Expand All @@ -58,7 +62,7 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
}

var (
pkg featurefmt.PackageInfo
pkg = database.Feature{VersionFormat: dpkg.ParserName}
pkgs = mapset.NewSet()
err error
)
Expand All @@ -70,8 +74,8 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
// Package line
// Defines the name of the package

pkg.PackageName = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
pkg.PackageVersion = ""
pkg.Name = strings.TrimSpace(strings.TrimPrefix(line, "Package: "))
pkg.Version = ""
} else if strings.HasPrefix(line, "Source: ") {
// Source line (Optional)
// Gives the name of the source package
Expand Down Expand Up @@ -102,19 +106,19 @@ func (l lister) ListFeatures(files tarutil.FilesMap) ([]database.Feature, error)
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.PackageVersion = version
pkg.Version = version
}
} else if line == "" {
pkg.Reset()
pkg = database.Feature{VersionFormat: dpkg.ParserName}
}

if valid(&pkg) {
addSourceVersion(&pkg)
addSourcePackage(&pkg)
pkgs.Add(pkg)
}
}

return featurefmt.PackageSetToFeatures(dpkg.ParserName, pkgs), nil
return database.ConvertFeatureSetToFeatures(pkgs), nil
}

func (l lister) RequiredFilenames() []string {
Expand Down

0 comments on commit f759dd5

Please sign in to comment.