Skip to content

Commit

Permalink
rpm: implement an RPM Resolver
Browse files Browse the repository at this point in the history
The Resolver compares file paths gleaned from RPM DBs and compares them
to a Package.Filepath to try and determine if a package needs to be
removed from an index report because its RPM counterpart has already
been included.

Signed-off-by: crozzy <[email protected]>
  • Loading branch information
crozzy committed May 22, 2024
1 parent deaae6d commit 74673cc
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 0 deletions.
1 change: 1 addition & 0 deletions libindex/libindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func New(ctx context.Context, opts *Options, cl *http.Client) (*Libindex, error)
opts.Ecosystems = append(opts.Ecosystems, whiteout.NewEcosystem(ctx))
opts.Resolvers = []indexer.Resolver{
&whiteout.Resolver{},
&rhel.Resolver{},
}

if cl == nil {
Expand Down
60 changes: 60 additions & 0 deletions rhel/resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package rhel

import (
"context"

"github.com/quay/zlog"

"github.com/quay/claircore"
"github.com/quay/claircore/indexer"
)

var (
_ indexer.Resolver = (*Resolver)(nil)
)

type Resolver struct{}

// Resolve takes a claircore.IndexReport and uses the rpm Files
// to determine if the package originate from an RPM. If the package
// was deemed to have been installed via RPM it isn't inclided in the
// final report.
func (r *Resolver) Resolve(ctx context.Context, ir *claircore.IndexReport, layers []*claircore.Layer) *claircore.IndexReport {
finalPackages := map[string]*claircore.Package{}
finalEnvironments := map[string][]*claircore.Environment{}
for pkgID, pkg := range ir.Packages {
isRPMPackage := false
for i := 0; i < len(ir.Environments[pkgID]); i++ {
if ir.Environments[pkgID][i].RepositoryIDs != nil {
for _, rID := range ir.Environments[pkgID][i].RepositoryIDs {
r := ir.Repositories[rID]
if r.Key == repositoryKey {
isRPMPackage = true
goto found
}
}
}
}
found:
isRemovable := false
for _, fs := range ir.Files {
for _, f := range fs {
if f.Kind == claircore.FileKindRPM && !isRPMPackage && pkg.Filepath == f.Path {
isRemovable = true
zlog.Debug(ctx).
Str("package name", pkg.Name).
Str("package file", pkg.Filepath).
Str("rpm file", f.Path).
Msg("package determined to have come from RPM, deleting")
}
}
}
if !isRemovable {
finalPackages[pkgID] = pkg
finalEnvironments[pkgID] = ir.Environments[pkgID]
}
}
ir.Packages = finalPackages
ir.Environments = finalEnvironments
return ir
}
179 changes: 179 additions & 0 deletions rhel/resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package rhel

import (
"context"
"strings"
"testing"

"github.com/quay/zlog"

"github.com/quay/claircore"
"github.com/quay/claircore/pkg/cpe"
)

var resolverTestcases = []struct {
name string
expectedPackages int
indexReport *claircore.IndexReport
}{
{
name: "No files",
expectedPackages: 2,
indexReport: &claircore.IndexReport{
Hash: claircore.MustParseDigest(`sha256:` + strings.Repeat(`a`, 64)),
Packages: map[string]*claircore.Package{
"123": {
ID: "123",
Name: "package A",
Version: "v1.0.0",
Source: &claircore.Package{
ID: "122",
Name: "package B source",
Kind: claircore.SOURCE,
Version: "v1.0.0",
},
Kind: claircore.BINARY,
},
"456": {
ID: "456",
Name: "package B",
Version: "v2.0.0",
Kind: claircore.BINARY,
},
},
Environments: map[string][]*claircore.Environment{
"123": {
{
PackageDB: "bdb:var/lib/rpm",
IntroducedIn: claircore.MustParseDigest(`sha256:` + strings.Repeat(`b`, 64)),
RepositoryIDs: []string{"11"},
DistributionID: "13",
},
},
"456": {
{
PackageDB: "maven:opt/couchbase/lib/cbas/repo/eventstream-1.0.1.jar",
IntroducedIn: claircore.MustParseDigest(`sha256:` + strings.Repeat(`c`, 64)),
RepositoryIDs: []string{"12"},
},
},
},
Repositories: map[string]*claircore.Repository{
"11": {
ID: "11",
Name: "cpe:/a:redhat:rhel_eus:8.6::appstream",
Key: repositoryKey,
CPE: cpe.MustUnbind("cpe:2.3:a:redhat:rhel_eus:8.6:*:appstream:*:*:*:*:*"),
},
"12": {
ID: "12",
Name: "maven",
URI: "https://repo1.maven.apache.org/maven2",
},
},
Distributions: map[string]*claircore.Distribution{
"13": {
ID: "13",
DID: "rhel",
Name: "Red Hat Enterprise Linux Server",
Version: "7",
VersionID: "7",
CPE: cpe.MustUnbind("cpe:2.3:o:redhat:enterprise_linux:7:*:*:*:*:*:*:*"),
PrettyName: "Red Hat Enterprise Linux Server 7",
},
},
Success: true,
},
},
{
name: "an RPM and a native JAVA package",
expectedPackages: 1,
indexReport: &claircore.IndexReport{
Hash: claircore.MustParseDigest(`sha256:` + strings.Repeat(`a`, 64)),
Packages: map[string]*claircore.Package{
"123": {
ID: "123",
Name: "rpm java package A",
Version: "v2.0.0-1-1",
Source: &claircore.Package{
ID: "122",
Name: "rpm java package A source",
Kind: claircore.SOURCE,
Version: "v2.0.0-1-1",
},
Kind: claircore.BINARY,
Filepath: "some/rpm/filepath.rpm",
},
"456": {
ID: "456",
Name: "java package A",
Version: "v2.0.0",
Kind: claircore.BINARY,
Filepath: "an/actual/rpm/filepath.java",
},
},
Files: map[string][]claircore.File{
"111": {
{Kind: claircore.FileKindRPM, Path: "some/rpm/filepath/one.java"},
{Kind: claircore.FileKindRPM, Path: "some/rpm/filepath/two.java"},
{Kind: claircore.FileKindRPM, Path: "an/actual/rpm/filepath.java"},
},
},
Environments: map[string][]*claircore.Environment{
"123": {
{
PackageDB: "bdb:var/lib/rpm",
IntroducedIn: claircore.MustParseDigest(`sha256:` + strings.Repeat(`b`, 64)),
RepositoryIDs: []string{"11"},
DistributionID: "13",
},
},
"456": {
{
PackageDB: "maven:opt/couchbase/lib/cbas/repo/eventstream-1.0.1.jar",
IntroducedIn: claircore.MustParseDigest(`sha256:` + strings.Repeat(`c`, 64)),
RepositoryIDs: []string{"12"},
},
},
},
Repositories: map[string]*claircore.Repository{
"11": {
ID: "11",
Name: "cpe:/a:redhat:rhel_eus:8.6::appstream",
Key: repositoryKey,
CPE: cpe.MustUnbind("cpe:2.3:a:redhat:rhel_eus:8.6:*:appstream:*:*:*:*:*"),
},
"12": {
ID: "12",
Name: "maven",
URI: "https://repo1.maven.apache.org/maven2",
},
},
Distributions: map[string]*claircore.Distribution{
"13": {
ID: "13",
DID: "rhel",
Name: "Red Hat Enterprise Linux Server",
Version: "7",
VersionID: "7",
CPE: cpe.MustUnbind("cpe:2.3:o:redhat:enterprise_linux:7:*:*:*:*:*:*:*"),
PrettyName: "Red Hat Enterprise Linux Server 7",
},
},
Success: true,
},
},
}

func TestResolver(t *testing.T) {
ctx := zlog.Test(context.Background(), t)
for _, tt := range resolverTestcases {
t.Run(tt.name, func(t *testing.T) {
r := &Resolver{}
ir := r.Resolve(ctx, tt.indexReport, nil)
if len(ir.Packages) != tt.expectedPackages {
t.Errorf("expected %d packages but got %d", tt.expectedPackages, len(ir.Packages))
}
})
}
}

0 comments on commit 74673cc

Please sign in to comment.