mirror of
https://github.com/anchore/syft.git
synced 2026-07-04 18:18:26 +02:00
fix(purl-backfill): respect arch qualifier (#4987)
* fix(purl-backfill): respect arch qualifier Previously, when constructing rpm, alpm, and apk metadata struct from a PURL, Syft would ignore the arch qualifier. Start respecting that qualifier. Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com> * chore: fix static analysis Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com> * Clean up control flow in PURL backfill code Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com> --------- Signed-off-by: Will Murphy <willmurphyscode@users.noreply.github.com>
This commit is contained in:
parent
fea4a50124
commit
fe42bcec38
@ -48,6 +48,7 @@ func backfillFromPurl(p *pkg.Package) {
|
||||
var cpes []cpe.CPE
|
||||
epoch := ""
|
||||
rpmmod := ""
|
||||
arch := ""
|
||||
|
||||
for _, qualifier := range purl.Qualifiers {
|
||||
switch qualifier.Key {
|
||||
@ -65,6 +66,8 @@ func backfillFromPurl(p *pkg.Package) {
|
||||
epoch = qualifier.Value
|
||||
case pkg.PURLQualifierRpmModularity:
|
||||
rpmmod = qualifier.Value
|
||||
case pkg.PURLQualifierArch:
|
||||
arch = qualifier.Value
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,9 +87,7 @@ func backfillFromPurl(p *pkg.Package) {
|
||||
setJavaMetadataFromPurl(p, purl)
|
||||
}
|
||||
|
||||
if p.Type == pkg.RpmPkg {
|
||||
setRpmMetadataFromPurl(p, rpmmod)
|
||||
}
|
||||
setDistroMetadata(p, rpmmod, arch)
|
||||
|
||||
for _, c := range cpes {
|
||||
if slices.Contains(p.CPEs, c) {
|
||||
@ -96,6 +97,19 @@ func backfillFromPurl(p *pkg.Package) {
|
||||
}
|
||||
}
|
||||
|
||||
func setDistroMetadata(p *pkg.Package, rpmmod, arch string) {
|
||||
switch p.Type {
|
||||
case pkg.RpmPkg:
|
||||
setRpmMetadataFromPurl(p, rpmmod, arch)
|
||||
case pkg.DebPkg:
|
||||
setDpkgMetadataFromPurl(p, arch)
|
||||
case pkg.AlpmPkg:
|
||||
setAlpmMetadataFromPurl(p, arch)
|
||||
case pkg.ApkPkg:
|
||||
setApkMetadataFromPurl(p, arch)
|
||||
}
|
||||
}
|
||||
|
||||
func setJavaMetadataFromPurl(p *pkg.Package, _ packageurl.PackageURL) {
|
||||
if p.Type != pkg.JavaPkg {
|
||||
return
|
||||
@ -107,32 +121,103 @@ func setJavaMetadataFromPurl(p *pkg.Package, _ packageurl.PackageURL) {
|
||||
}
|
||||
}
|
||||
|
||||
func setRpmMetadataFromPurl(p *pkg.Package, rpmmod string) {
|
||||
func setRpmMetadataFromPurl(p *pkg.Package, rpmmod, arch string) {
|
||||
if p.Type != pkg.RpmPkg {
|
||||
return
|
||||
}
|
||||
if rpmmod == "" {
|
||||
if rpmmod == "" && arch == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if p.Metadata == nil {
|
||||
p.Metadata = pkg.RpmDBEntry{
|
||||
ModularityLabel: &rpmmod,
|
||||
}
|
||||
return
|
||||
p.Metadata = pkg.RpmDBEntry{}
|
||||
}
|
||||
|
||||
switch m := p.Metadata.(type) {
|
||||
case pkg.RpmDBEntry:
|
||||
if m.ModularityLabel == nil {
|
||||
if m.ModularityLabel == nil && rpmmod != "" {
|
||||
m.ModularityLabel = &rpmmod
|
||||
p.Metadata = m
|
||||
}
|
||||
if m.Arch == "" {
|
||||
m.Arch = arch
|
||||
}
|
||||
p.Metadata = m
|
||||
case pkg.RpmArchive:
|
||||
if m.ModularityLabel == nil {
|
||||
if m.ModularityLabel == nil && rpmmod != "" {
|
||||
m.ModularityLabel = &rpmmod
|
||||
p.Metadata = m
|
||||
}
|
||||
if m.Arch == "" {
|
||||
m.Arch = arch
|
||||
}
|
||||
p.Metadata = m
|
||||
}
|
||||
}
|
||||
|
||||
func setDpkgMetadataFromPurl(p *pkg.Package, arch string) {
|
||||
if p.Type != pkg.DebPkg {
|
||||
return
|
||||
}
|
||||
if arch == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if p.Metadata == nil {
|
||||
p.Metadata = pkg.DpkgDBEntry{}
|
||||
}
|
||||
|
||||
switch m := p.Metadata.(type) {
|
||||
case pkg.DpkgDBEntry:
|
||||
if m.Architecture == "" {
|
||||
m.Architecture = arch
|
||||
}
|
||||
p.Metadata = m
|
||||
case pkg.DpkgArchiveEntry:
|
||||
if m.Architecture == "" {
|
||||
m.Architecture = arch
|
||||
}
|
||||
p.Metadata = m
|
||||
}
|
||||
}
|
||||
|
||||
func setAlpmMetadataFromPurl(p *pkg.Package, arch string) {
|
||||
if p.Type != pkg.AlpmPkg {
|
||||
return
|
||||
}
|
||||
if arch == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if p.Metadata == nil {
|
||||
p.Metadata = pkg.AlpmDBEntry{Architecture: arch}
|
||||
return
|
||||
}
|
||||
|
||||
if m, ok := p.Metadata.(pkg.AlpmDBEntry); ok {
|
||||
if m.Architecture == "" {
|
||||
m.Architecture = arch
|
||||
}
|
||||
p.Metadata = m
|
||||
}
|
||||
}
|
||||
|
||||
func setApkMetadataFromPurl(p *pkg.Package, arch string) {
|
||||
if p.Type != pkg.ApkPkg {
|
||||
return
|
||||
}
|
||||
if arch == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if p.Metadata == nil {
|
||||
p.Metadata = pkg.ApkDBEntry{Architecture: arch}
|
||||
return
|
||||
}
|
||||
|
||||
if m, ok := p.Metadata.(pkg.ApkDBEntry); ok {
|
||||
if m.Architecture == "" {
|
||||
m.Architecture = arch
|
||||
}
|
||||
p.Metadata = m
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,9 @@ func Test_Backfill(t *testing.T) {
|
||||
Type: pkg.RpmPkg,
|
||||
Name: "dbus-common",
|
||||
Version: "1.12.8-26.el8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Arch: "noarch",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -51,6 +54,9 @@ func Test_Backfill(t *testing.T) {
|
||||
Type: pkg.RpmPkg,
|
||||
Name: "dbus-common",
|
||||
Version: "1:1.12.8-26.el8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Arch: "noarch",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -65,6 +71,22 @@ func Test_Backfill(t *testing.T) {
|
||||
Version: "2.4.37-51",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
ModularityLabel: strRef("httpd:2.4"),
|
||||
Arch: "x86_64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "rpm with arch and no rpmmod",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:rpm/redhat/httpd@2.4.37-51?arch=x86_64&distro=rhel-8.7",
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:rpm/redhat/httpd@2.4.37-51?arch=x86_64&distro=rhel-8.7",
|
||||
Type: pkg.RpmPkg,
|
||||
Name: "httpd",
|
||||
Version: "2.4.37-51",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Arch: "x86_64",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -121,6 +143,225 @@ func Test_Backfill(t *testing.T) {
|
||||
Metadata: pkg.JavaArchive{},
|
||||
},
|
||||
},
|
||||
// deb cases
|
||||
{
|
||||
name: "deb nil metadata gets arch set",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Type: pkg.DebPkg,
|
||||
Name: "curl",
|
||||
Version: "7.74.0-1.3+deb11u7",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deb arch:all preserved (nil metadata)",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:deb/debian/tzdata@2021a-1+deb11u10?arch=all&distro=debian-11",
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:deb/debian/tzdata@2021a-1+deb11u10?arch=all&distro=debian-11",
|
||||
Type: pkg.DebPkg,
|
||||
Name: "tzdata",
|
||||
Version: "2021a-1+deb11u10",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Architecture: "all",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deb populated metadata empty arch gets filled",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "curl",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Type: pkg.DebPkg,
|
||||
Name: "curl",
|
||||
Version: "7.74.0-1.3+deb11u7",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deb populated metadata with arch preserved",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "arm64",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Type: pkg.DebPkg,
|
||||
Name: "curl",
|
||||
Version: "7.74.0-1.3+deb11u7",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deb archive entry empty arch gets filled",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Metadata: pkg.DpkgArchiveEntry{
|
||||
Package: "curl",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Type: pkg.DebPkg,
|
||||
Name: "curl",
|
||||
Version: "7.74.0-1.3+deb11u7",
|
||||
Metadata: pkg.DpkgArchiveEntry{
|
||||
Package: "curl",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "deb archive entry with arch preserved",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Metadata: pkg.DpkgArchiveEntry{
|
||||
Package: "curl",
|
||||
Architecture: "arm64",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:deb/debian/curl@7.74.0-1.3+deb11u7?arch=amd64&distro=debian-11",
|
||||
Type: pkg.DebPkg,
|
||||
Name: "curl",
|
||||
Version: "7.74.0-1.3+deb11u7",
|
||||
Metadata: pkg.DpkgArchiveEntry{
|
||||
Package: "curl",
|
||||
Architecture: "arm64",
|
||||
},
|
||||
},
|
||||
},
|
||||
// alpm cases
|
||||
{
|
||||
name: "alpm nil metadata gets arch set",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:alpm/arch/curl@7.88.1-1?arch=x86_64&distro=arch-rolling",
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:alpm/arch/curl@7.88.1-1?arch=x86_64&distro=arch-rolling",
|
||||
Type: pkg.AlpmPkg,
|
||||
Name: "curl",
|
||||
Version: "7.88.1-1",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "alpm populated metadata empty arch gets filled",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:alpm/arch/curl@7.88.1-1?arch=x86_64&distro=arch-rolling",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "curl",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:alpm/arch/curl@7.88.1-1?arch=x86_64&distro=arch-rolling",
|
||||
Type: pkg.AlpmPkg,
|
||||
Name: "curl",
|
||||
Version: "7.88.1-1",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "alpm populated metadata with arch preserved",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:alpm/arch/curl@7.88.1-1?arch=x86_64&distro=arch-rolling",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "aarch64",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:alpm/arch/curl@7.88.1-1?arch=x86_64&distro=arch-rolling",
|
||||
Type: pkg.AlpmPkg,
|
||||
Name: "curl",
|
||||
Version: "7.88.1-1",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "aarch64",
|
||||
},
|
||||
},
|
||||
},
|
||||
// apk cases
|
||||
{
|
||||
name: "apk nil metadata gets arch set",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:apk/alpine/curl@7.83.1-r2?arch=aarch64&distro=alpine-3.16.2",
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:apk/alpine/curl@7.83.1-r2?arch=aarch64&distro=alpine-3.16.2",
|
||||
Type: pkg.ApkPkg,
|
||||
Name: "curl",
|
||||
Version: "7.83.1-r2",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Architecture: "aarch64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apk populated metadata empty arch gets filled",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:apk/alpine/curl@7.83.1-r2?arch=aarch64&distro=alpine-3.16.2",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "curl",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:apk/alpine/curl@7.83.1-r2?arch=aarch64&distro=alpine-3.16.2",
|
||||
Type: pkg.ApkPkg,
|
||||
Name: "curl",
|
||||
Version: "7.83.1-r2",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "aarch64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apk populated metadata with arch preserved",
|
||||
in: pkg.Package{
|
||||
PURL: "pkg:apk/alpine/curl@7.83.1-r2?arch=aarch64&distro=alpine-3.16.2",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
},
|
||||
expected: pkg.Package{
|
||||
PURL: "pkg:apk/alpine/curl@7.83.1-r2?arch=aarch64&distro=alpine-3.16.2",
|
||||
Type: pkg.ApkPkg,
|
||||
Name: "curl",
|
||||
Version: "7.83.1-r2",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "curl",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "target-sw from CPE",
|
||||
in: pkg.Package{
|
||||
|
||||
@ -317,7 +317,7 @@ func Test_decodeComponent(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantMetadata: pkg.RpmDBEntry{},
|
||||
wantMetadata: pkg.RpmDBEntry{Arch: "x86_64"},
|
||||
wantPURL: "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8",
|
||||
},
|
||||
{
|
||||
@ -341,6 +341,7 @@ func Test_decodeComponent(t *testing.T) {
|
||||
},
|
||||
wantMetadata: pkg.RpmDBEntry{
|
||||
Release: "some-release",
|
||||
Arch: "x86_64",
|
||||
},
|
||||
wantPURL: "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8",
|
||||
},
|
||||
|
||||
@ -58,10 +58,11 @@ func TestDecoder_Decode(t *testing.T) {
|
||||
purl: "pkg:deb/debian/sysv-rc@2.88dsf-59?arch=all&distro=debian-jessie&upstream=sysvinit",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "sysv-rc",
|
||||
Version: "2.88dsf-59",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/debian/sysv-rc@2.88dsf-59?arch=all&distro=debian-jessie&upstream=sysvinit",
|
||||
Name: "sysv-rc",
|
||||
Version: "2.88dsf-59",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/debian/sysv-rc@2.88dsf-59?arch=all&distro=debian-jessie&upstream=sysvinit",
|
||||
Metadata: pkg.DpkgDBEntry{Architecture: "all"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -91,10 +92,11 @@ func TestDecoder_Decode(t *testing.T) {
|
||||
purl: "pkg:rpm/redhat/systemd-x@239-82.el8_10.2?arch=aarch64&distro=rhel-8.10&upstream=systemd-239-82.el8_10.2.src.rpm",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "systemd-x",
|
||||
Version: "239-82.el8_10.2",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/systemd-x@239-82.el8_10.2?arch=aarch64&distro=rhel-8.10&upstream=systemd-239-82.el8_10.2.src.rpm",
|
||||
Name: "systemd-x",
|
||||
Version: "239-82.el8_10.2",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/systemd-x@239-82.el8_10.2?arch=aarch64&distro=rhel-8.10&upstream=systemd-239-82.el8_10.2.src.rpm",
|
||||
Metadata: pkg.RpmDBEntry{Arch: "aarch64"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -102,10 +104,11 @@ func TestDecoder_Decode(t *testing.T) {
|
||||
purl: "pkg:rpm/redhat/dbus-common@1.12.8-26.el8?arch=noarch&distro=rhel-8.10&epoch=1&upstream=dbus-1.12.8-26.el8.src.rpm",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "dbus-common",
|
||||
Version: "1:1.12.8-26.el8",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/dbus-common@1.12.8-26.el8?arch=noarch&distro=rhel-8.10&epoch=1&upstream=dbus-1.12.8-26.el8.src.rpm",
|
||||
Name: "dbus-common",
|
||||
Version: "1:1.12.8-26.el8",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/dbus-common@1.12.8-26.el8?arch=noarch&distro=rhel-8.10&epoch=1&upstream=dbus-1.12.8-26.el8.src.rpm",
|
||||
Metadata: pkg.RpmDBEntry{Arch: "noarch"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -113,10 +116,11 @@ func TestDecoder_Decode(t *testing.T) {
|
||||
purl: "pkg:apk/curl@7.61.1?arch=aarch64&distro=alpine-3.20.3",
|
||||
expected: []pkg.Package{
|
||||
{
|
||||
Name: "curl",
|
||||
Version: "7.61.1",
|
||||
Type: pkg.ApkPkg,
|
||||
PURL: "pkg:apk/curl@7.61.1?arch=aarch64&distro=alpine-3.20.3",
|
||||
Name: "curl",
|
||||
Version: "7.61.1",
|
||||
Type: pkg.ApkPkg,
|
||||
PURL: "pkg:apk/curl@7.61.1?arch=aarch64&distro=alpine-3.20.3",
|
||||
Metadata: pkg.ApkDBEntry{Architecture: "aarch64"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user