mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 02:26:42 +01:00
Track supporting DPKG evidence (#3228)
* add dpkg evidence support Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * use path over filepath 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:
parent
770fdc53ea
commit
13c6876906
@ -9,15 +9,18 @@ func EvidentBy(catalog *pkg.Collection) []artifact.Relationship {
|
|||||||
var edges []artifact.Relationship
|
var edges []artifact.Relationship
|
||||||
for _, p := range catalog.Sorted() {
|
for _, p := range catalog.Sorted() {
|
||||||
for _, l := range p.Locations.ToSlice() {
|
for _, l := range p.Locations.ToSlice() {
|
||||||
if v, exists := l.Annotations[pkg.EvidenceAnnotationKey]; !exists || v != pkg.PrimaryEvidenceAnnotation {
|
kind := pkg.SupportingEvidenceAnnotation
|
||||||
// skip non-primary evidence from being expressed as a relationship.
|
if v, exists := l.Annotations[pkg.EvidenceAnnotationKey]; exists {
|
||||||
// note: this may be configurable in the future.
|
kind = v
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
edges = append(edges, artifact.Relationship{
|
edges = append(edges, artifact.Relationship{
|
||||||
From: p,
|
From: p,
|
||||||
To: l.Coordinates,
|
To: l.Coordinates,
|
||||||
Type: artifact.EvidentByRelationship,
|
Type: artifact.EvidentByRelationship,
|
||||||
|
Data: map[string]string{
|
||||||
|
"kind": kind,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,9 +134,10 @@ func coordinatesForSelection(selection file.Selection, accessor sbomsync.Accesso
|
|||||||
}
|
}
|
||||||
|
|
||||||
if selection == file.FilesOwnedByPackageSelection {
|
if selection == file.FilesOwnedByPackageSelection {
|
||||||
var coordinates []file.Coordinates
|
var coordinates file.CoordinateSet
|
||||||
|
|
||||||
accessor.ReadFromSBOM(func(sbom *sbom.SBOM) {
|
accessor.ReadFromSBOM(func(sbom *sbom.SBOM) {
|
||||||
|
// get any file coordinates that are owned by a package
|
||||||
for _, r := range sbom.Relationships {
|
for _, r := range sbom.Relationships {
|
||||||
if r.Type != artifact.ContainsRelationship {
|
if r.Type != artifact.ContainsRelationship {
|
||||||
continue
|
continue
|
||||||
@ -145,16 +146,23 @@ func coordinatesForSelection(selection file.Selection, accessor sbomsync.Accesso
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c, ok := r.To.(file.Coordinates); ok {
|
if c, ok := r.To.(file.Coordinates); ok {
|
||||||
coordinates = append(coordinates, c)
|
coordinates.Add(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get any file coordinates referenced by a package directly
|
||||||
|
for p := range sbom.Artifacts.Packages.Enumerate() {
|
||||||
|
coordinates.Add(p.Locations.CoordinateSet().ToSlice()...)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if len(coordinates) == 0 {
|
coords := coordinates.ToSlice()
|
||||||
|
|
||||||
|
if len(coords) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return coordinates, true
|
return coords, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, false
|
return nil, false
|
||||||
|
|||||||
@ -25,15 +25,16 @@ func TestDpkgCataloger(t *testing.T) {
|
|||||||
Version: "1.1.8-3.6",
|
Version: "1.1.8-3.6",
|
||||||
FoundBy: "dpkg-db-cataloger",
|
FoundBy: "dpkg-db-cataloger",
|
||||||
Licenses: pkg.NewLicenseSet(
|
Licenses: pkg.NewLicenseSet(
|
||||||
pkg.NewLicenseFromLocations("GPL-1", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")),
|
pkg.NewLicenseFromLocations("GPL-1", file.NewLocation("/usr/share/doc/libpam-runtime/copyright")),
|
||||||
pkg.NewLicenseFromLocations("GPL-2", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")),
|
pkg.NewLicenseFromLocations("GPL-2", file.NewLocation("/usr/share/doc/libpam-runtime/copyright")),
|
||||||
pkg.NewLicenseFromLocations("LGPL-2.1", file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright")),
|
pkg.NewLicenseFromLocations("LGPL-2.1", file.NewLocation("/usr/share/doc/libpam-runtime/copyright")),
|
||||||
),
|
),
|
||||||
Locations: file.NewLocationSet(
|
Locations: file.NewLocationSet(
|
||||||
file.NewVirtualLocation("/var/lib/dpkg/status", "/var/lib/dpkg/status"),
|
file.NewLocation("/var/lib/dpkg/status"),
|
||||||
file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.md5sums", "/var/lib/dpkg/info/libpam-runtime.md5sums"),
|
file.NewLocation("/var/lib/dpkg/info/libpam-runtime.preinst"),
|
||||||
file.NewVirtualLocation("/var/lib/dpkg/info/libpam-runtime.conffiles", "/var/lib/dpkg/info/libpam-runtime.conffiles"),
|
file.NewLocation("/var/lib/dpkg/info/libpam-runtime.md5sums"),
|
||||||
file.NewVirtualLocation("/usr/share/doc/libpam-runtime/copyright", "/usr/share/doc/libpam-runtime/copyright"),
|
file.NewLocation("/var/lib/dpkg/info/libpam-runtime.conffiles"),
|
||||||
|
file.NewLocation("/usr/share/doc/libpam-runtime/copyright"),
|
||||||
),
|
),
|
||||||
Type: pkg.DebPkg,
|
Type: pkg.DebPkg,
|
||||||
Metadata: pkg.DpkgDBEntry{
|
Metadata: pkg.DpkgDBEntry{
|
||||||
@ -98,14 +99,15 @@ func TestDpkgCataloger(t *testing.T) {
|
|||||||
Version: "3.34.1-3",
|
Version: "3.34.1-3",
|
||||||
FoundBy: "dpkg-db-cataloger",
|
FoundBy: "dpkg-db-cataloger",
|
||||||
Licenses: pkg.NewLicenseSet(
|
Licenses: pkg.NewLicenseSet(
|
||||||
pkg.NewLicenseFromLocations("public-domain", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")),
|
pkg.NewLicenseFromLocations("public-domain", file.NewLocation("/usr/share/doc/libsqlite3-0/copyright")),
|
||||||
pkg.NewLicenseFromLocations("GPL-2+", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")),
|
pkg.NewLicenseFromLocations("GPL-2+", file.NewLocation("/usr/share/doc/libsqlite3-0/copyright")),
|
||||||
pkg.NewLicenseFromLocations("GPL-2", file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright")),
|
pkg.NewLicenseFromLocations("GPL-2", file.NewLocation("/usr/share/doc/libsqlite3-0/copyright")),
|
||||||
),
|
),
|
||||||
Locations: file.NewLocationSet(
|
Locations: file.NewLocationSet(
|
||||||
file.NewVirtualLocation("/var/lib/dpkg/status.d/libsqlite3-0", "/var/lib/dpkg/status.d/libsqlite3-0"),
|
file.NewLocation("/var/lib/dpkg/status.d/libsqlite3-0"),
|
||||||
file.NewVirtualLocation("/var/lib/dpkg/status.d/libsqlite3-0.md5sums", "/var/lib/dpkg/status.d/libsqlite3-0.md5sums"),
|
file.NewLocation("/var/lib/dpkg/status.d/libsqlite3-0.md5sums"),
|
||||||
file.NewVirtualLocation("/usr/share/doc/libsqlite3-0/copyright", "/usr/share/doc/libsqlite3-0/copyright"),
|
file.NewLocation("/var/lib/dpkg/status.d/libsqlite3-0.preinst"),
|
||||||
|
file.NewLocation("/usr/share/doc/libsqlite3-0/copyright"),
|
||||||
),
|
),
|
||||||
Type: pkg.DebPkg,
|
Type: pkg.DebPkg,
|
||||||
Metadata: pkg.DpkgDBEntry{
|
Metadata: pkg.DpkgDBEntry{
|
||||||
|
|||||||
@ -22,14 +22,18 @@ const (
|
|||||||
docsPath = "/usr/share/doc"
|
docsPath = "/usr/share/doc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newDpkgPackage(d pkg.DpkgDBEntry, dbLocation file.Location, resolver file.Resolver, release *linux.Release) pkg.Package {
|
func newDpkgPackage(d pkg.DpkgDBEntry, dbLocation file.Location, resolver file.Resolver, release *linux.Release, evidence ...file.Location) pkg.Package {
|
||||||
// TODO: separate pr to license refactor, but explore extracting dpkg-specific license parsing into a separate function
|
// TODO: separate pr to license refactor, but explore extracting dpkg-specific license parsing into a separate function
|
||||||
licenses := make([]pkg.License, 0)
|
licenses := make([]pkg.License, 0)
|
||||||
|
|
||||||
|
locations := file.NewLocationSet(dbLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||||
|
locations.Add(evidence...)
|
||||||
|
|
||||||
p := pkg.Package{
|
p := pkg.Package{
|
||||||
Name: d.Package,
|
Name: d.Package,
|
||||||
Version: d.Version,
|
Version: d.Version,
|
||||||
Licenses: pkg.NewLicenseSet(licenses...),
|
Licenses: pkg.NewLicenseSet(licenses...),
|
||||||
Locations: file.NewLocationSet(dbLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
Locations: locations,
|
||||||
PURL: packageURL(d, release),
|
PURL: packageURL(d, release),
|
||||||
Type: pkg.DebPkg,
|
Type: pkg.DebPkg,
|
||||||
Metadata: d,
|
Metadata: d,
|
||||||
@ -88,7 +92,7 @@ func packageURL(m pkg.DpkgDBEntry, distro *linux.Release) string {
|
|||||||
func addLicenses(resolver file.Resolver, dbLocation file.Location, p *pkg.Package) {
|
func addLicenses(resolver file.Resolver, dbLocation file.Location, p *pkg.Package) {
|
||||||
metadata, ok := p.Metadata.(pkg.DpkgDBEntry)
|
metadata, ok := p.Metadata.(pkg.DpkgDBEntry)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.WithFields("package", p).Warn("unable to extract DPKG metadata to add licenses")
|
log.WithFields("package", p).Trace("unable to extract DPKG metadata to add licenses")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +114,7 @@ func addLicenses(resolver file.Resolver, dbLocation file.Location, p *pkg.Packag
|
|||||||
func mergeFileListing(resolver file.Resolver, dbLocation file.Location, p *pkg.Package) {
|
func mergeFileListing(resolver file.Resolver, dbLocation file.Location, p *pkg.Package) {
|
||||||
metadata, ok := p.Metadata.(pkg.DpkgDBEntry)
|
metadata, ok := p.Metadata.(pkg.DpkgDBEntry)
|
||||||
if !ok {
|
if !ok {
|
||||||
log.WithFields("package", p).Warn("unable to extract DPKG metadata to file listing")
|
log.WithFields("package", p).Trace("unable to extract DPKG metadata to file listing")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +208,7 @@ func fetchMd5Contents(resolver file.Resolver, dbLocation file.Location, m pkg.Dp
|
|||||||
// this is unexpected, but not a show-stopper
|
// this is unexpected, but not a show-stopper
|
||||||
md5Reader, err = resolver.FileContentsByLocation(*location)
|
md5Reader, err = resolver.FileContentsByLocation(*location)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to fetch deb md5 contents (package=%s): %+v", m.Package, err)
|
log.Tracef("failed to fetch deb md5 contents (package=%s): %+v", m.Package, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
||||||
@ -239,7 +243,7 @@ func fetchConffileContents(resolver file.Resolver, dbLocation file.Location, m p
|
|||||||
// this is unexpected, but not a show-stopper
|
// this is unexpected, but not a show-stopper
|
||||||
reader, err = resolver.FileContentsByLocation(*location)
|
reader, err = resolver.FileContentsByLocation(*location)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to fetch deb conffiles contents (package=%s): %+v", m.Package, err)
|
log.Tracef("failed to fetch deb conffiles contents (package=%s): %+v", m.Package, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
l := location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.SupportingEvidenceAnnotation)
|
||||||
@ -263,7 +267,7 @@ func fetchCopyrightContents(resolver file.Resolver, dbLocation file.Location, m
|
|||||||
|
|
||||||
reader, err := resolver.FileContentsByLocation(*location)
|
reader, err := resolver.FileContentsByLocation(*location)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to fetch deb copyright contents (package=%s): %s", m.Package, err)
|
log.Tracef("failed to fetch deb copyright contents (package=%s): %s", m.Package, err)
|
||||||
}
|
}
|
||||||
defer internal.CloseAndLogError(reader, location.RealPath)
|
defer internal.CloseAndLogError(reader, location.RealPath)
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -34,12 +35,41 @@ func parseDpkgDB(_ context.Context, resolver file.Resolver, env *generic.Environ
|
|||||||
|
|
||||||
var pkgs []pkg.Package
|
var pkgs []pkg.Package
|
||||||
for _, m := range metadata {
|
for _, m := range metadata {
|
||||||
pkgs = append(pkgs, newDpkgPackage(m, reader.Location, resolver, env.LinuxRelease))
|
p := newDpkgPackage(m, reader.Location, resolver, env.LinuxRelease, findDpkgInfoFiles(m.Package, resolver, reader.Location)...)
|
||||||
|
pkgs = append(pkgs, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pkgs, nil, nil
|
return pkgs, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findDpkgInfoFiles(name string, resolver file.Resolver, dbLocation file.Location) []file.Location {
|
||||||
|
if resolver == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(name) == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// for typical debian-base distributions, the installed package info is at /var/lib/dpkg/status
|
||||||
|
// and the md5sum information is under /var/lib/dpkg/info/; however, for distroless the installed
|
||||||
|
// package info is across multiple files under /var/lib/dpkg/status.d/ and the md5sums are contained in
|
||||||
|
// the same directory
|
||||||
|
searchPath := path.Dir(dbLocation.RealPath)
|
||||||
|
|
||||||
|
if !strings.HasSuffix(searchPath, "status.d") {
|
||||||
|
searchPath = path.Join(searchPath, "info")
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for /var/lib/dpkg/info/NAME.*
|
||||||
|
locations, err := resolver.FilesByGlob(path.Join(searchPath, name+".*"))
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields("error", err, "pkg", name).Trace("failed to fetch related dpkg info files")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return locations
|
||||||
|
}
|
||||||
|
|
||||||
// parseDpkgStatus is a parser function for Debian DB status contents, returning all Debian packages listed.
|
// parseDpkgStatus is a parser function for Debian DB status contents, returning all Debian packages listed.
|
||||||
func parseDpkgStatus(reader io.Reader) ([]pkg.DpkgDBEntry, error) {
|
func parseDpkgStatus(reader io.Reader) ([]pkg.DpkgDBEntry, error) {
|
||||||
buffedReader := bufio.NewReader(reader)
|
buffedReader := bufio.NewReader(reader)
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
# some shell script...
|
||||||
@ -0,0 +1 @@
|
|||||||
|
# some shell script...
|
||||||
Loading…
x
Reference in New Issue
Block a user