mirror of
https://github.com/anchore/syft.git
synced 2026-11-04 08:26:38 +01:00
Add abstraction for adding relationships from package cataloger results (#2853)
* add internal dependency resolver Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * refactor dependency relationship resolution to common object Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * replace cataloger decorator with generic processor Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * refactor resolver to be a single function Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * use common dependency specifier for debian Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * use common dependency specifier for arch Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * use common dependency specifier for alpine Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * allow for generic pkg and rel assertions in testpkg helper Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * do not allow for empty results Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * move stable deduplicate comment Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * remove relationship resolver type Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -3,9 +3,239 @@ package alpine
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
)
|
||||
|
||||
func TestApkDBCataloger(t *testing.T) {
|
||||
dbLocation := file.NewLocation("lib/apk/db/installed")
|
||||
|
||||
bashPkg := pkg.Package{
|
||||
Name: "bash",
|
||||
Version: "5.2.21-r0",
|
||||
Type: pkg.ApkPkg,
|
||||
FoundBy: "apk-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("GPL-3.0-or-later", dbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(dbLocation),
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "bash",
|
||||
OriginPackage: "bash",
|
||||
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
|
||||
Version: "5.2.21-r0",
|
||||
Architecture: "x86_64",
|
||||
URL: "https://www.gnu.org/software/bash/bash.html",
|
||||
Description: "The GNU Bourne Again shell",
|
||||
Size: 448728,
|
||||
InstalledSize: 1396736,
|
||||
Dependencies: []string{
|
||||
"/bin/sh", "so:libc.musl-x86_64.so.1", "so:libreadline.so.8",
|
||||
},
|
||||
Provides: []string{
|
||||
"cmd:bash=5.2.21-r0",
|
||||
},
|
||||
// note: files not provided and not under test
|
||||
},
|
||||
}
|
||||
|
||||
busyboxBinshPkg := pkg.Package{
|
||||
Name: "busybox-binsh",
|
||||
Version: "1.36.1-r15",
|
||||
Type: pkg.ApkPkg,
|
||||
FoundBy: "apk-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("GPL-2.0-only", dbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(dbLocation),
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "busybox-binsh",
|
||||
OriginPackage: "busybox",
|
||||
Maintainer: "Sören Tempel <soeren+alpine@soeren-tempel.net>",
|
||||
Version: "1.36.1-r15",
|
||||
Architecture: "x86_64",
|
||||
URL: "https://busybox.net/",
|
||||
Description: "busybox ash /bin/sh",
|
||||
Size: 1543,
|
||||
InstalledSize: 8192,
|
||||
Dependencies: []string{
|
||||
"busybox=1.36.1-r15",
|
||||
},
|
||||
Provides: []string{
|
||||
"/bin/sh", "cmd:sh=1.36.1-r15",
|
||||
},
|
||||
// note: files not provided and not under test
|
||||
},
|
||||
}
|
||||
|
||||
muslPkg := pkg.Package{
|
||||
Name: "musl",
|
||||
Version: "1.2.4_git20230717-r4",
|
||||
Type: pkg.ApkPkg,
|
||||
FoundBy: "apk-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("MIT", dbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(dbLocation),
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "musl",
|
||||
OriginPackage: "musl",
|
||||
Maintainer: "Timo Teräs <timo.teras@iki.fi>",
|
||||
Version: "1.2.4_git20230717-r4",
|
||||
Architecture: "x86_64",
|
||||
URL: "https://musl.libc.org/",
|
||||
Description: "the musl c library (libc) implementation",
|
||||
Size: 407278,
|
||||
InstalledSize: 667648,
|
||||
Dependencies: []string{},
|
||||
Provides: []string{
|
||||
"so:libc.musl-x86_64.so.1=1",
|
||||
},
|
||||
// note: files not provided and not under test
|
||||
},
|
||||
}
|
||||
|
||||
readlinePkg := pkg.Package{
|
||||
Name: "readline",
|
||||
Version: "8.2.1-r2",
|
||||
Type: pkg.ApkPkg,
|
||||
FoundBy: "apk-db-cataloger",
|
||||
Licenses: pkg.NewLicenseSet(
|
||||
pkg.NewLicenseFromLocations("GPL-2.0-or-later", dbLocation),
|
||||
),
|
||||
Locations: file.NewLocationSet(dbLocation),
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "readline",
|
||||
OriginPackage: "readline",
|
||||
Maintainer: "Natanael Copa <ncopa@alpinelinux.org>",
|
||||
Version: "8.2.1-r2",
|
||||
Architecture: "x86_64",
|
||||
URL: "https://tiswww.cwru.edu/php/chet/readline/rltop.html",
|
||||
Description: "GNU readline library",
|
||||
Size: 119878,
|
||||
InstalledSize: 303104,
|
||||
Dependencies: []string{
|
||||
"so:libc.musl-x86_64.so.1", "so:libncursesw.so.6",
|
||||
},
|
||||
Provides: []string{
|
||||
"so:libreadline.so.8=8.2",
|
||||
},
|
||||
// note: files not provided and not under test
|
||||
},
|
||||
}
|
||||
|
||||
expectedPkgs := []pkg.Package{
|
||||
bashPkg,
|
||||
busyboxBinshPkg,
|
||||
muslPkg,
|
||||
readlinePkg,
|
||||
}
|
||||
|
||||
// # apk info --depends bash
|
||||
// bash-5.2.21-r0 depends on:
|
||||
// /bin/sh
|
||||
// so:libc.musl-x86_64.so.1
|
||||
// so:libreadline.so.8
|
||||
//
|
||||
// # apk info --who-owns /bin/sh
|
||||
// /bin/sh is owned by busybox-binsh-1.36.1-r15
|
||||
//
|
||||
// # find / | grep musl
|
||||
// /lib/ld-musl-x86_64.so.1
|
||||
// /lib/libc.musl-x86_64.so.1
|
||||
//
|
||||
// # apk info --who-owns '/lib/libc.musl-x86_64.so.1'
|
||||
// /lib/libc.musl-x86_64.so.1 is owned by musl-1.2.4_git20230717-r4
|
||||
//
|
||||
// # find / | grep libreadline
|
||||
// /usr/lib/libreadline.so.8.2
|
||||
// /usr/lib/libreadline.so.8
|
||||
//
|
||||
// # apk info --who-owns '/usr/lib/libreadline.so.8'
|
||||
// /usr/lib/libreadline.so.8 is owned by readline-8.2.1-r2
|
||||
|
||||
expectedRelationships := []artifact.Relationship{
|
||||
{
|
||||
From: busyboxBinshPkg,
|
||||
To: bashPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
{
|
||||
From: readlinePkg,
|
||||
To: bashPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
{
|
||||
From: muslPkg,
|
||||
To: readlinePkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
{
|
||||
From: muslPkg,
|
||||
To: bashPkg,
|
||||
Type: artifact.DependencyOfRelationship,
|
||||
},
|
||||
}
|
||||
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, "test-fixtures/multiple-1").
|
||||
WithCompareOptions(cmpopts.IgnoreFields(pkg.ApkDBEntry{}, "Files", "GitCommit", "Checksum")).
|
||||
Expects(expectedPkgs, expectedRelationships).
|
||||
TestCataloger(t, NewDBCataloger())
|
||||
|
||||
}
|
||||
|
||||
func TestCatalogerDependencyTree(t *testing.T) {
|
||||
assertion := func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
expected := map[string][]string{
|
||||
"alpine-baselayout": {"busybox", "alpine-baselayout-data", "musl"},
|
||||
"apk-tools": {"ca-certificates-bundle", "musl", "libcrypto1.1", "libssl1.1", "zlib"},
|
||||
"busybox": {"musl"},
|
||||
"libc-utils": {"musl-utils"},
|
||||
"libcrypto1.1": {"musl"},
|
||||
"libssl1.1": {"musl", "libcrypto1.1"},
|
||||
"musl-utils": {"scanelf", "musl"},
|
||||
"scanelf": {"musl"},
|
||||
"ssl_client": {"musl", "libcrypto1.1", "libssl1.1"},
|
||||
"zlib": {"musl"},
|
||||
}
|
||||
pkgsByID := make(map[artifact.ID]pkg.Package)
|
||||
for _, p := range pkgs {
|
||||
p.SetID()
|
||||
pkgsByID[p.ID()] = p
|
||||
}
|
||||
|
||||
actualDependencies := make(map[string][]string)
|
||||
|
||||
for _, r := range relationships {
|
||||
switch r.Type {
|
||||
case artifact.DependencyOfRelationship:
|
||||
to := pkgsByID[r.To.ID()]
|
||||
from := pkgsByID[r.From.ID()]
|
||||
actualDependencies[to.Name] = append(actualDependencies[to.Name], from.Name)
|
||||
default:
|
||||
t.Fatalf("unexpected relationship type: %+v", r.Type)
|
||||
}
|
||||
}
|
||||
|
||||
if d := cmp.Diff(expected, actualDependencies); d != "" {
|
||||
t.Fail()
|
||||
t.Log(d)
|
||||
}
|
||||
}
|
||||
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, "test-fixtures/multiple-2").
|
||||
ExpectsAssertion(assertion).
|
||||
TestCataloger(t, NewDBCataloger())
|
||||
|
||||
}
|
||||
|
||||
func TestCataloger_Globs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user