mirror of
https://github.com/anchore/syft.git
synced 2026-11-02 07:26:34 +01:00
--------- Signed-off-by: Sueun Cho <sueun.dev@gmail.com> Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com> Co-authored-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
125 lines
3.8 KiB
Go
125 lines
3.8 KiB
Go
package redhat
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/anchore/packageurl-go"
|
|
"github.com/anchore/syft/syft/file"
|
|
"github.com/anchore/syft/syft/linux"
|
|
"github.com/anchore/syft/syft/pkg"
|
|
)
|
|
|
|
func newDBPackage(ctx context.Context, dbOrRpmLocation file.Location, m pkg.RpmDBEntry, distro *linux.Release, licenses []string) pkg.Package {
|
|
p := pkg.Package{
|
|
Name: m.Name,
|
|
Version: toELVersion(m.Epoch, m.Version, m.Release),
|
|
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocationWithContext(ctx, dbOrRpmLocation, licenses...)...),
|
|
PURL: packageURL(m.Name, m.Arch, m.Epoch, m.SourceRpm, m.Version, m.Release, distro),
|
|
Locations: file.NewLocationSet(dbOrRpmLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
|
Type: pkg.RpmPkg,
|
|
Metadata: m,
|
|
}
|
|
|
|
p.SetID()
|
|
return p
|
|
}
|
|
|
|
func newArchivePackage(ctx context.Context, archiveLocation file.Location, m pkg.RpmArchive, licenses []string) pkg.Package {
|
|
p := pkg.Package{
|
|
Name: m.Name,
|
|
Version: toELVersion(m.Epoch, m.Version, m.Release),
|
|
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocationWithContext(ctx, archiveLocation, licenses...)...),
|
|
PURL: packageURL(m.Name, m.Arch, m.Epoch, m.SourceRpm, m.Version, m.Release, nil),
|
|
Locations: file.NewLocationSet(archiveLocation.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
|
Type: pkg.RpmPkg,
|
|
Metadata: m,
|
|
}
|
|
|
|
p.SetID()
|
|
return p
|
|
}
|
|
|
|
// newMetadataFromManifestLine parses an entry in an RPM manifest file as used in Mariner distroless containers.
|
|
// Each line is the output from:
|
|
// - rpm --query --all --query-format "%{NAME}\t%{VERSION}-%{RELEASE}\t%{INSTALLTIME}\t%{BUILDTIME}\t%{VENDOR}\t%{EPOCH}\t%{SIZE}\t%{ARCH}\t%{EPOCHNUM}\t%{SOURCERPM}\n"
|
|
// - https://github.com/microsoft/CBL-Mariner/blob/3df18fac373aba13a54bd02466e64969574f13af/toolkit/docs/how_it_works/5_misc.md?plain=1#L150
|
|
func newMetadataFromManifestLine(entry string) (*pkg.RpmDBEntry, error) {
|
|
parts := strings.Split(entry, "\t")
|
|
if len(parts) < 10 {
|
|
return nil, fmt.Errorf("unexpected number of fields in line: %s", entry)
|
|
}
|
|
|
|
versionParts := strings.Split(parts[1], "-")
|
|
if len(versionParts) != 2 {
|
|
return nil, fmt.Errorf("unexpected version field: %s", parts[1])
|
|
}
|
|
version := versionParts[0]
|
|
release := versionParts[1]
|
|
|
|
// EPOCH is "(none)" when the package has no epoch; EPOCHNUM is the numeric form ("0" in that case)
|
|
var epoch *int
|
|
if parts[5] != "(none)" {
|
|
epoch = parseEpoch(parts[8])
|
|
}
|
|
|
|
var size int
|
|
if converted, err := strconv.Atoi(parts[6]); err == nil {
|
|
size = converted
|
|
}
|
|
return &pkg.RpmDBEntry{
|
|
Name: parts[0],
|
|
Version: version,
|
|
Epoch: epoch,
|
|
Arch: parts[7],
|
|
Release: release,
|
|
SourceRpm: parts[9],
|
|
Vendor: parts[4],
|
|
Size: size,
|
|
}, nil
|
|
}
|
|
|
|
// packageURL returns the PURL for the specific RHEL or Hummingbird package (see https://github.com/package-url/purl-spec)
|
|
func packageURL(name, arch string, epoch *int, srpm string, version, release string, distro *linux.Release) string {
|
|
var namespace string
|
|
if distro != nil {
|
|
namespace = distro.ID
|
|
}
|
|
if namespace == "rhel" || namespace == "hummingbird" {
|
|
namespace = "redhat"
|
|
}
|
|
if strings.HasPrefix(namespace, "opensuse") {
|
|
namespace = "opensuse"
|
|
}
|
|
|
|
qualifiers := map[string]string{}
|
|
|
|
if arch != "" {
|
|
qualifiers[pkg.PURLQualifierArch] = arch
|
|
}
|
|
|
|
if epoch != nil {
|
|
qualifiers[pkg.PURLQualifierEpoch] = strconv.Itoa(*epoch)
|
|
}
|
|
|
|
if srpm != "" {
|
|
qualifiers[pkg.PURLQualifierUpstream] = srpm
|
|
}
|
|
|
|
return packageurl.NewPackageURL(
|
|
packageurl.TypeRPM,
|
|
namespace,
|
|
name,
|
|
// for purl the epoch is a qualifier, not part of the version
|
|
// see https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst under the RPM section
|
|
fmt.Sprintf("%s-%s", version, release),
|
|
pkg.PURLQualifiers(
|
|
qualifiers,
|
|
distro,
|
|
),
|
|
"",
|
|
).ToString()
|
|
}
|