mirror of
https://github.com/anchore/syft.git
synced 2026-10-12 22:27:22 +02:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab69742d25 | ||
|
|
bf8ded3cf8 | ||
|
|
d53a8d283f | ||
|
|
13c6591cb2 | ||
|
|
4ffde9f891 | ||
|
|
06451adc43 | ||
|
|
ecf6b9eff5 |
@@ -114,6 +114,45 @@ func TestCycloneDxImageEncoder(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestCycloneDxSourcePackageEncoder(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: testutil.SourcePackagesInput(t, dir),
|
||||
Format: getEncoder(t),
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: true,
|
||||
Redactor: redactor(dir),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestCycloneDxSourcePackageEncoder_SpecVersions(t *testing.T) {
|
||||
s := testutil.SourcePackagesInput(t, t.TempDir())
|
||||
tests := []struct {
|
||||
version string
|
||||
want bool
|
||||
}{
|
||||
{version: "1.4", want: false},
|
||||
{version: "1.5", want: false},
|
||||
{version: "1.6", want: true},
|
||||
{version: cyclonedxutil.DefaultVersion, want: true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.version, func(t *testing.T) {
|
||||
enc, err := NewFormatEncoderWithConfig(EncoderConfig{Version: tt.version})
|
||||
require.NoError(t, err)
|
||||
|
||||
var buf bytes.Buffer
|
||||
require.NoError(t, enc.Encode(&buf, s))
|
||||
|
||||
// the source-distribution reference type only exists from spec 1.6
|
||||
assert.Equal(t, tt.want, strings.Contains(buf.String(), `"source-distribution"`))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func redactor(values ...string) testutil.Redactor {
|
||||
return testutil.NewRedactions().
|
||||
WithValuesRedacted(values...).
|
||||
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
{
|
||||
"$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json",
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.7",
|
||||
"serialNumber": "urn:uuid:redacted",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "timestamp:redacted",
|
||||
"tools": {
|
||||
"components": [
|
||||
{
|
||||
"type": "application",
|
||||
"author": "anchore",
|
||||
"name": "syft",
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"component": {
|
||||
"bom-ref": "redacted",
|
||||
"type": "file",
|
||||
"name": "some/path"
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"bom-ref": "pkg:deb/debian/attr@1%3A2.4.47-2%2Bb1?arch=amd64&distro=debian-12&package-id=5cc0e8979d7f5115&upstream=attr%401%3A2.4.47-2",
|
||||
"type": "library",
|
||||
"name": "attr",
|
||||
"version": "1:2.4.47-2+b1",
|
||||
"purl": "pkg:deb/debian/attr@1%3A2.4.47-2%2Bb1?arch=amd64&distro=debian-12&upstream=attr%401%3A2.4.47-2",
|
||||
"externalReferences": [
|
||||
{
|
||||
"url": "pkg:deb/debian/attr@1%3A2.4.47-2?arch=source&distro=debian-12",
|
||||
"type": "source-distribution"
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
{
|
||||
"name": "syft:package:foundBy",
|
||||
"value": "dpkg-db-cataloger"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:type",
|
||||
"value": "deb"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:metadataType",
|
||||
"value": "dpkg-db-entry"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
"value": "/var/lib/dpkg/status"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:installedSize",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:source",
|
||||
"value": "attr"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:sourceVersion",
|
||||
"value": "1:2.4.47-2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:rpm/centos/bind-export-libs@9.11.13-3.el8?arch=x86_64&distro=centos-8&epoch=32&package-id=6008fca05ca7b418&upstream=bind-9.11.13-3.el8.src.rpm",
|
||||
"type": "library",
|
||||
"name": "bind-export-libs",
|
||||
"version": "32:9.11.13-3.el8",
|
||||
"purl": "pkg:rpm/centos/bind-export-libs@9.11.13-3.el8?arch=x86_64&distro=centos-8&epoch=32&upstream=bind-9.11.13-3.el8.src.rpm",
|
||||
"externalReferences": [
|
||||
{
|
||||
"url": "pkg:rpm/centos/bind@9.11.13-3.el8?arch=src&distro=centos-8&epoch=32",
|
||||
"type": "source-distribution"
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
{
|
||||
"name": "syft:package:foundBy",
|
||||
"value": "rpm-db-cataloger"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:type",
|
||||
"value": "rpm"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:metadataType",
|
||||
"value": "rpm-db-entry"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
"value": "/var/lib/rpm/Packages"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:epoch",
|
||||
"value": "32"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:release",
|
||||
"value": "3.el8"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:size",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:sourceRpm",
|
||||
"value": "bind-9.11.13-3.el8.src.rpm"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:apk/alpine/busybox@1.35.0-r17?arch=x86_64&distro=alpine-3.16.3&package-id=aa74af1190de1c40",
|
||||
"type": "library",
|
||||
"name": "busybox",
|
||||
"version": "1.35.0-r17",
|
||||
"purl": "pkg:apk/alpine/busybox@1.35.0-r17?arch=x86_64&distro=alpine-3.16.3",
|
||||
"properties": [
|
||||
{
|
||||
"name": "syft:package:foundBy",
|
||||
"value": "apk-db-cataloger"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:type",
|
||||
"value": "apk"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:metadataType",
|
||||
"value": "apk-db-entry"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
"value": "/lib/apk/db/installed"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:installedSize",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:originPackage",
|
||||
"value": "busybox"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:size",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:alpm/arch/gcc-libs@13.2.1-3?arch=x86_64&distro=arch-rolling&package-id=58a2fcf749a9a3cc&upstream=gcc",
|
||||
"type": "library",
|
||||
"name": "gcc-libs",
|
||||
"version": "13.2.1-3",
|
||||
"purl": "pkg:alpm/arch/gcc-libs@13.2.1-3?arch=x86_64&distro=arch-rolling&upstream=gcc",
|
||||
"properties": [
|
||||
{
|
||||
"name": "syft:package:foundBy",
|
||||
"value": "alpm-db-cataloger"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:type",
|
||||
"value": "alpm"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:metadataType",
|
||||
"value": "alpm-db-entry"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
"value": "/var/lib/pacman/local/gcc-libs-13.2.1-3/desc"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:architecture",
|
||||
"value": "x86_64"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:basepackage",
|
||||
"value": "gcc"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:package",
|
||||
"value": "gcc-libs"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:size",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:version",
|
||||
"value": "13.2.1-3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:apk/alpine/libc-utils@0.7.2-r3?arch=x86_64&distro=alpine-3.16.3&package-id=16a8c7b19fde6f4f&upstream=libc-dev",
|
||||
"type": "library",
|
||||
"name": "libc-utils",
|
||||
"version": "0.7.2-r3",
|
||||
"purl": "pkg:apk/alpine/libc-utils@0.7.2-r3?arch=x86_64&distro=alpine-3.16.3&upstream=libc-dev",
|
||||
"properties": [
|
||||
{
|
||||
"name": "syft:package:foundBy",
|
||||
"value": "apk-db-cataloger"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:type",
|
||||
"value": "apk"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:metadataType",
|
||||
"value": "apk-db-entry"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
"value": "/lib/apk/db/installed"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:installedSize",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:originPackage",
|
||||
"value": "libc-dev"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:size",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"bom-ref": "pkg:deb/debian/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&distro=debian-12&package-id=7b4ddc97df57aec4&upstream=pam",
|
||||
"type": "library",
|
||||
"name": "libpam-runtime",
|
||||
"version": "1.5.2-6+deb12u1",
|
||||
"purl": "pkg:deb/debian/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&distro=debian-12&upstream=pam",
|
||||
"externalReferences": [
|
||||
{
|
||||
"url": "pkg:deb/debian/pam@1.5.2-6%2Bdeb12u1?arch=source&distro=debian-12",
|
||||
"type": "source-distribution"
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
{
|
||||
"name": "syft:package:foundBy",
|
||||
"value": "dpkg-db-cataloger"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:type",
|
||||
"value": "deb"
|
||||
},
|
||||
{
|
||||
"name": "syft:package:metadataType",
|
||||
"value": "dpkg-db-entry"
|
||||
},
|
||||
{
|
||||
"name": "syft:location:0:path",
|
||||
"value": "/var/lib/dpkg/status"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:installedSize",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "syft:metadata:source",
|
||||
"value": "pam"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -87,6 +87,20 @@ func TestCycloneDxImageEncoder(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestCycloneDxSourcePackageEncoder(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: testutil.SourcePackagesInput(t, dir),
|
||||
Format: getEncoder(t),
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: false,
|
||||
Redactor: redactor(dir),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func redactor(values ...string) testutil.Redactor {
|
||||
return testutil.NewRedactions().
|
||||
WithValuesRedacted(values...).
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.7" serialNumber="redacted" version="1">
|
||||
<metadata>
|
||||
<timestamp>redacted</timestamp>
|
||||
<tools>
|
||||
<components>
|
||||
<component type="application">
|
||||
<author>anchore</author>
|
||||
<name>syft</name>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</component>
|
||||
</components>
|
||||
</tools>
|
||||
<component bom-ref="redacted" type="file">
|
||||
<name>some/path</name>
|
||||
</component>
|
||||
</metadata>
|
||||
<components>
|
||||
<component bom-ref="pkg:deb/debian/attr@1%3A2.4.47-2%2Bb1?arch=amd64&distro=debian-12&package-id=5cc0e8979d7f5115&upstream=attr%401%3A2.4.47-2" type="library">
|
||||
<name>attr</name>
|
||||
<version>1:2.4.47-2+b1</version>
|
||||
<purl>pkg:deb/debian/attr@1%3A2.4.47-2%2Bb1?arch=amd64&distro=debian-12&upstream=attr%401%3A2.4.47-2</purl>
|
||||
<externalReferences>
|
||||
<reference type="source-distribution">
|
||||
<url>pkg:deb/debian/attr@1%3A2.4.47-2?arch=source&distro=debian-12</url>
|
||||
</reference>
|
||||
</externalReferences>
|
||||
<properties>
|
||||
<property name="syft:package:foundBy">dpkg-db-cataloger</property>
|
||||
<property name="syft:package:type">deb</property>
|
||||
<property name="syft:package:metadataType">dpkg-db-entry</property>
|
||||
<property name="syft:location:0:path">/var/lib/dpkg/status</property>
|
||||
<property name="syft:metadata:installedSize">0</property>
|
||||
<property name="syft:metadata:source">attr</property>
|
||||
<property name="syft:metadata:sourceVersion">1:2.4.47-2</property>
|
||||
</properties>
|
||||
</component>
|
||||
<component bom-ref="pkg:rpm/centos/bind-export-libs@9.11.13-3.el8?arch=x86_64&distro=centos-8&epoch=32&package-id=6008fca05ca7b418&upstream=bind-9.11.13-3.el8.src.rpm" type="library">
|
||||
<name>bind-export-libs</name>
|
||||
<version>32:9.11.13-3.el8</version>
|
||||
<purl>pkg:rpm/centos/bind-export-libs@9.11.13-3.el8?arch=x86_64&distro=centos-8&epoch=32&upstream=bind-9.11.13-3.el8.src.rpm</purl>
|
||||
<externalReferences>
|
||||
<reference type="source-distribution">
|
||||
<url>pkg:rpm/centos/bind@9.11.13-3.el8?arch=src&distro=centos-8&epoch=32</url>
|
||||
</reference>
|
||||
</externalReferences>
|
||||
<properties>
|
||||
<property name="syft:package:foundBy">rpm-db-cataloger</property>
|
||||
<property name="syft:package:type">rpm</property>
|
||||
<property name="syft:package:metadataType">rpm-db-entry</property>
|
||||
<property name="syft:location:0:path">/var/lib/rpm/Packages</property>
|
||||
<property name="syft:metadata:epoch">32</property>
|
||||
<property name="syft:metadata:release">3.el8</property>
|
||||
<property name="syft:metadata:size">0</property>
|
||||
<property name="syft:metadata:sourceRpm">bind-9.11.13-3.el8.src.rpm</property>
|
||||
</properties>
|
||||
</component>
|
||||
<component bom-ref="pkg:apk/alpine/busybox@1.35.0-r17?arch=x86_64&distro=alpine-3.16.3&package-id=aa74af1190de1c40" type="library">
|
||||
<name>busybox</name>
|
||||
<version>1.35.0-r17</version>
|
||||
<purl>pkg:apk/alpine/busybox@1.35.0-r17?arch=x86_64&distro=alpine-3.16.3</purl>
|
||||
<properties>
|
||||
<property name="syft:package:foundBy">apk-db-cataloger</property>
|
||||
<property name="syft:package:type">apk</property>
|
||||
<property name="syft:package:metadataType">apk-db-entry</property>
|
||||
<property name="syft:location:0:path">/lib/apk/db/installed</property>
|
||||
<property name="syft:metadata:installedSize">0</property>
|
||||
<property name="syft:metadata:originPackage">busybox</property>
|
||||
<property name="syft:metadata:size">0</property>
|
||||
</properties>
|
||||
</component>
|
||||
<component bom-ref="pkg:alpm/arch/gcc-libs@13.2.1-3?arch=x86_64&distro=arch-rolling&package-id=58a2fcf749a9a3cc&upstream=gcc" type="library">
|
||||
<name>gcc-libs</name>
|
||||
<version>13.2.1-3</version>
|
||||
<purl>pkg:alpm/arch/gcc-libs@13.2.1-3?arch=x86_64&distro=arch-rolling&upstream=gcc</purl>
|
||||
<properties>
|
||||
<property name="syft:package:foundBy">alpm-db-cataloger</property>
|
||||
<property name="syft:package:type">alpm</property>
|
||||
<property name="syft:package:metadataType">alpm-db-entry</property>
|
||||
<property name="syft:location:0:path">/var/lib/pacman/local/gcc-libs-13.2.1-3/desc</property>
|
||||
<property name="syft:metadata:architecture">x86_64</property>
|
||||
<property name="syft:metadata:basepackage">gcc</property>
|
||||
<property name="syft:metadata:package">gcc-libs</property>
|
||||
<property name="syft:metadata:size">0</property>
|
||||
<property name="syft:metadata:version">13.2.1-3</property>
|
||||
</properties>
|
||||
</component>
|
||||
<component bom-ref="pkg:apk/alpine/libc-utils@0.7.2-r3?arch=x86_64&distro=alpine-3.16.3&package-id=16a8c7b19fde6f4f&upstream=libc-dev" type="library">
|
||||
<name>libc-utils</name>
|
||||
<version>0.7.2-r3</version>
|
||||
<purl>pkg:apk/alpine/libc-utils@0.7.2-r3?arch=x86_64&distro=alpine-3.16.3&upstream=libc-dev</purl>
|
||||
<properties>
|
||||
<property name="syft:package:foundBy">apk-db-cataloger</property>
|
||||
<property name="syft:package:type">apk</property>
|
||||
<property name="syft:package:metadataType">apk-db-entry</property>
|
||||
<property name="syft:location:0:path">/lib/apk/db/installed</property>
|
||||
<property name="syft:metadata:installedSize">0</property>
|
||||
<property name="syft:metadata:originPackage">libc-dev</property>
|
||||
<property name="syft:metadata:size">0</property>
|
||||
</properties>
|
||||
</component>
|
||||
<component bom-ref="pkg:deb/debian/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&distro=debian-12&package-id=7b4ddc97df57aec4&upstream=pam" type="library">
|
||||
<name>libpam-runtime</name>
|
||||
<version>1.5.2-6+deb12u1</version>
|
||||
<purl>pkg:deb/debian/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&distro=debian-12&upstream=pam</purl>
|
||||
<externalReferences>
|
||||
<reference type="source-distribution">
|
||||
<url>pkg:deb/debian/pam@1.5.2-6%2Bdeb12u1?arch=source&distro=debian-12</url>
|
||||
</reference>
|
||||
</externalReferences>
|
||||
<properties>
|
||||
<property name="syft:package:foundBy">dpkg-db-cataloger</property>
|
||||
<property name="syft:package:type">deb</property>
|
||||
<property name="syft:package:metadataType">dpkg-db-entry</property>
|
||||
<property name="syft:location:0:path">/var/lib/dpkg/status</property>
|
||||
<property name="syft:metadata:installedSize">0</property>
|
||||
<property name="syft:metadata:source">pam</property>
|
||||
</properties>
|
||||
</component>
|
||||
</components>
|
||||
</bom>
|
||||
@@ -2,6 +2,7 @@ package cyclonedxutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
|
||||
@@ -29,9 +30,35 @@ func NewEncoder(version string, format cyclonedx.BOMFileFormat, pretty bool) (En
|
||||
|
||||
func (e Encoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
||||
bom := cyclonedxhelpers.ToFormatModel(s)
|
||||
if e.version < cyclonedx.SpecVersion1_6 {
|
||||
// cyclonedx-go does not downgrade this 1.6+ reference type for older spec versions
|
||||
// (see https://github.com/CycloneDX/cyclonedx-go/issues/291), so drop it rather than emit an invalid document
|
||||
dropExternalReferenceType(bom.Components, cyclonedx.ERTypeSourceDistribution)
|
||||
}
|
||||
enc := cyclonedx.NewBOMEncoder(writer, e.format)
|
||||
enc.SetPretty(e.pretty)
|
||||
enc.SetEscapeHTML(false)
|
||||
|
||||
return enc.EncodeVersion(bom, e.version)
|
||||
}
|
||||
|
||||
func dropExternalReferenceType(components *[]cyclonedx.Component, refType cyclonedx.ExternalReferenceType) {
|
||||
if components == nil {
|
||||
return
|
||||
}
|
||||
for i := range *components {
|
||||
c := &(*components)[i]
|
||||
dropExternalReferenceType(c.Components, refType)
|
||||
if c.ExternalReferences == nil {
|
||||
continue
|
||||
}
|
||||
refs := slices.DeleteFunc(*c.ExternalReferences, func(r cyclonedx.ExternalReference) bool {
|
||||
return r.Type == refType
|
||||
})
|
||||
if len(refs) == 0 {
|
||||
c.ExternalReferences = nil
|
||||
continue
|
||||
}
|
||||
c.ExternalReferences = &refs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal/file"
|
||||
syftFile "github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -79,12 +80,162 @@ func encodeExternalReferences(p pkg.Package) *[]cyclonedx.ExternalReference {
|
||||
}
|
||||
}
|
||||
}
|
||||
if srcRef := encodeSourcePackageExternalReference(p); srcRef != nil {
|
||||
refs = append(refs, *srcRef)
|
||||
}
|
||||
if len(refs) > 0 {
|
||||
return &refs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// encodeSourcePackageExternalReference returns a "source-distribution" reference holding the PURL of the distro
|
||||
// source package that a binary OS package was built from (e.g. libpam-runtime -> pkg:deb/debian/pam@...?arch=source).
|
||||
// It is only emitted when the source differs from the binary package (by name or version) and when the package PURL
|
||||
// is of the type implied by the metadata. The main consumer is vulnerability matching, since distros tend to report
|
||||
// vulnerabilities against the source package rather than each binary package built from it.
|
||||
//
|
||||
// why an external reference and not pedigree: `component.pedigree.ancestors` looks like the obvious spot for "this
|
||||
// binary came from that source", but pedigree describes code lineage (forks, patched variants, and the patches that
|
||||
// separate them). A binary built unmodified from its own distro source package is the same code in a different form,
|
||||
// not a fork, and CycloneDX components are deliberately agnostic to source vs binary form (see the comments from the
|
||||
// CycloneDX maintainers in https://github.com/CycloneDX/specification/issues/612#issuecomment-2958800363). The
|
||||
// ancestor slot is better left for the upstream project a distro patched (e.g. Linux-PAM for Debian's pam), which
|
||||
// syft does not know today.
|
||||
//
|
||||
// why "source-distribution": the spec defines it as "the location where the source code distributable can be
|
||||
// obtained", and a deb/rpm source package is exactly that distributable (a .dsc and tarballs in the Debian source
|
||||
// pool, a .src.rpm in an SRPMS repo). The value is a PURL (an identifier) rather than a download URL, which the
|
||||
// schema allows since external reference URLs are URIs of any scheme, and a CycloneDX maintainer confirmed this exact
|
||||
// shape is valid in https://github.com/CycloneDX/specification/issues/612#issuecomment-5428057874. A first-class
|
||||
// "source" component type was discussed in that issue and deferred to CycloneDX 2.0.
|
||||
func encodeSourcePackageExternalReference(p pkg.Package) *cyclonedx.ExternalReference {
|
||||
if p.PURL == "" {
|
||||
return nil
|
||||
}
|
||||
src := sourcePackageOf(p)
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// the binary PURL is only consulted for the namespace and a small set of qualifiers (e.g. distro), everything
|
||||
// else describes the binary package and must not be restated as a fact about the source package.
|
||||
binPurl, err := packageurl.FromString(p.PURL)
|
||||
if err != nil || binPurl.Type != src.purlType {
|
||||
return nil
|
||||
}
|
||||
|
||||
qualifiers := map[string]string{}
|
||||
for _, q := range binPurl.Qualifiers {
|
||||
if src.keepQualifier(q.Key) {
|
||||
qualifiers[q.Key] = q.Value
|
||||
}
|
||||
}
|
||||
if src.arch != "" {
|
||||
qualifiers[pkg.PURLQualifierArch] = src.arch
|
||||
}
|
||||
|
||||
srcPurl := packageurl.NewPackageURL(
|
||||
src.purlType,
|
||||
binPurl.Namespace,
|
||||
src.name,
|
||||
src.version,
|
||||
packageurl.QualifiersFromMap(qualifiers),
|
||||
"",
|
||||
)
|
||||
|
||||
return &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution,
|
||||
URL: srcPurl.ToString(),
|
||||
}
|
||||
}
|
||||
|
||||
// sourcePackage is the identity of the source package a binary OS package was built from.
|
||||
type sourcePackage struct {
|
||||
purlType string
|
||||
name string
|
||||
version string
|
||||
// arch is the ecosystem's source architecture marker ("source" for deb, "src" or "nosrc" for rpm)
|
||||
arch string
|
||||
}
|
||||
|
||||
func (s sourcePackage) keepQualifier(key string) bool {
|
||||
switch key {
|
||||
case pkg.PURLQualifierDistro:
|
||||
return true
|
||||
case pkg.PURLQualifierEpoch, pkg.PURLQualifierRpmModularity:
|
||||
return s.purlType == pkg.RpmPkg.PackageURLType()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// sourcePackageOf returns the source package for p, or nil when there is none or it is the same as the binary.
|
||||
//
|
||||
// only deb and rpm are supported, since those are the ecosystems that publish real source packages with their own
|
||||
// PURL identity (arch=source / arch=src). apk (origin) and alpm (pkgbase) are intentionally left out: there the
|
||||
// "source" is a build recipe rather than a published source distributable, and its name is usually also the name of
|
||||
// a real binary package (e.g. pkg:apk/alpine/libc-dev@0.7.2-r3 is an installable package, not a source archive), so
|
||||
// a "source-distribution" reference would point at a binary package. Whether those ecosystems have a meaningful
|
||||
// source PURL is still an open question, and until then the `upstream` PURL qualifier continues to carry that info.
|
||||
func sourcePackageOf(p pkg.Package) *sourcePackage {
|
||||
var src sourcePackage
|
||||
var binName, binVersion string
|
||||
switch m := p.Metadata.(type) {
|
||||
case pkg.DpkgDBEntry:
|
||||
src = dpkgSourcePackage(m)
|
||||
binName, binVersion = m.Package, m.Version
|
||||
case pkg.DpkgArchiveEntry:
|
||||
src = dpkgSourcePackage(pkg.DpkgDBEntry(m))
|
||||
binName, binVersion = m.Package, m.Version
|
||||
case pkg.RpmDBEntry:
|
||||
src = rpmSourcePackage(m.SourceRpm)
|
||||
binName, binVersion = m.Name, m.Version+"-"+m.Release
|
||||
case pkg.RpmArchive:
|
||||
src = rpmSourcePackage(m.SourceRpm)
|
||||
binName, binVersion = m.Name, m.Version+"-"+m.Release
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
if src.name == "" || src.version == "" {
|
||||
return nil
|
||||
}
|
||||
if src.name == binName && src.version == binVersion {
|
||||
return nil
|
||||
}
|
||||
return &src
|
||||
}
|
||||
|
||||
func dpkgSourcePackage(entry pkg.DpkgDBEntry) sourcePackage {
|
||||
version := entry.SourceVersion
|
||||
if version == "" {
|
||||
version = entry.Version
|
||||
}
|
||||
return sourcePackage{purlType: pkg.DebPkg.PackageURLType(), name: entry.Source, version: version, arch: "source"}
|
||||
}
|
||||
|
||||
// rpmSourcePackage parses a source RPM filename of the form <name>-<version>-<release>.(no)src.rpm.
|
||||
func rpmSourcePackage(sourceRpm string) sourcePackage {
|
||||
var arch string
|
||||
switch {
|
||||
case strings.HasSuffix(sourceRpm, ".src.rpm"):
|
||||
arch = "src"
|
||||
case strings.HasSuffix(sourceRpm, ".nosrc.rpm"):
|
||||
arch = "nosrc"
|
||||
default:
|
||||
return sourcePackage{}
|
||||
}
|
||||
nvr := strings.TrimSuffix(sourceRpm, "."+arch+".rpm")
|
||||
release := strings.LastIndex(nvr, "-")
|
||||
if release < 0 {
|
||||
return sourcePackage{}
|
||||
}
|
||||
ver := strings.LastIndex(nvr[:release], "-")
|
||||
if ver < 0 {
|
||||
return sourcePackage{}
|
||||
}
|
||||
return sourcePackage{purlType: pkg.RpmPkg.PackageURLType(), name: nvr[:ver], version: nvr[ver+1:], arch: arch}
|
||||
}
|
||||
|
||||
// supported algorithm in cycloneDX as of 1.4
|
||||
// "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512",
|
||||
// "SHA3-256", "SHA3-384", "SHA3-512", "BLAKE2b-256", "BLAKE2b-384", "BLAKE2b-512", "BLAKE3"
|
||||
|
||||
@@ -144,6 +144,342 @@ func Test_encodeExternalReferences(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_encodeSourcePackage(t *testing.T) {
|
||||
rpmEpoch := 32
|
||||
tests := []struct {
|
||||
name string
|
||||
input pkg.Package
|
||||
expected *cyclonedx.ExternalReference
|
||||
}{
|
||||
{
|
||||
name: "no metadata",
|
||||
input: pkg.Package{},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "no PURL",
|
||||
input: pkg.Package{
|
||||
Name: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Type: pkg.DebPkg,
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Source: "pam",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
// apk origins are build recipes, not published source packages, so they are not supported
|
||||
name: "from apk is not supported",
|
||||
input: pkg.Package{
|
||||
Name: "libc-utils",
|
||||
Version: "0.7.2-r3",
|
||||
Type: pkg.ApkPkg,
|
||||
PURL: "pkg:apk/alpine/libc-utils@0.7.2-r3?arch=x86_64&distro=alpine-3.16.3&upstream=libc-dev",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "libc-utils",
|
||||
OriginPackage: "libc-dev",
|
||||
Version: "0.7.2-r3",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "from deb",
|
||||
input: pkg.Package{
|
||||
Name: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/debian/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&distro=debian-12&upstream=pam",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Source: "pam",
|
||||
Architecture: "all",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:deb/debian/pam@1.5.2-6%2Bdeb12u1?arch=source&distro=debian-12",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from deb with source version",
|
||||
input: pkg.Package{
|
||||
Name: "attr",
|
||||
Version: "1:2.4.47-2+b1",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/debian/attr@1%3A2.4.47-2%2Bb1?arch=amd64&distro=debian-12&upstream=attr%401%3A2.4.47-2",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "attr",
|
||||
Version: "1:2.4.47-2+b1",
|
||||
Source: "attr",
|
||||
SourceVersion: "1:2.4.47-2",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:deb/debian/attr@1%3A2.4.47-2?arch=source&distro=debian-12",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from deb with empty source",
|
||||
input: pkg.Package{
|
||||
Name: "some-package",
|
||||
Version: "1.0.0",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/debian/some-package@1.0.0?arch=all&distro=debian-12",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "some-package",
|
||||
Version: "1.0.0",
|
||||
Architecture: "all",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "from deb archive",
|
||||
input: pkg.Package{
|
||||
Name: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&upstream=pam",
|
||||
Metadata: pkg.DpkgArchiveEntry{
|
||||
Package: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Source: "pam",
|
||||
Architecture: "all",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:deb/pam@1.5.2-6%2Bdeb12u1?arch=source",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from rpm",
|
||||
input: pkg.Package{
|
||||
Name: "bind-export-libs",
|
||||
Version: "32:9.11.13-3.el8",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/centos/bind-export-libs@9.11.13-3.el8?arch=x86_64&distro=centos-8&epoch=32&upstream=bind-9.11.13-3.el8.src.rpm",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "bind-export-libs",
|
||||
Version: "9.11.13",
|
||||
Release: "3.el8",
|
||||
Epoch: &rpmEpoch,
|
||||
Arch: "x86_64",
|
||||
SourceRpm: "bind-9.11.13-3.el8.src.rpm",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:rpm/centos/bind@9.11.13-3.el8?arch=src&distro=centos-8&epoch=32",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from rpm with source = bin",
|
||||
input: pkg.Package{
|
||||
Name: "some-package",
|
||||
Version: "32:1.0.0-1.el8",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/centos/some-package@1.0.0-1.el8?arch=x86_64&distro=centos-8&epoch=32&upstream=some-package-1.0.0-1.el8.src.rpm",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "some-package",
|
||||
Version: "1.0.0",
|
||||
Release: "1.el8",
|
||||
Epoch: &rpmEpoch,
|
||||
Arch: "x86_64",
|
||||
SourceRpm: "some-package-1.0.0-1.el8.src.rpm",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "from rpm archive",
|
||||
input: pkg.Package{
|
||||
Name: "bind-export-libs",
|
||||
Version: "32:9.11.13-3.el8",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/bind-export-libs@9.11.13-3.el8?arch=x86_64&epoch=32&upstream=bind-9.11.13-3.el8.src.rpm",
|
||||
Metadata: pkg.RpmArchive{
|
||||
Name: "bind-export-libs",
|
||||
Version: "9.11.13",
|
||||
Release: "3.el8",
|
||||
Epoch: &rpmEpoch,
|
||||
Arch: "x86_64",
|
||||
SourceRpm: "bind-9.11.13-3.el8.src.rpm",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:rpm/bind@9.11.13-3.el8?arch=src&epoch=32",
|
||||
},
|
||||
},
|
||||
{
|
||||
// alpm pkgbases are build recipes, not published source packages, so they are not supported
|
||||
name: "from alpm is not supported",
|
||||
input: pkg.Package{
|
||||
Name: "gcc-libs",
|
||||
Version: "13.2.1-3",
|
||||
Type: pkg.AlpmPkg,
|
||||
PURL: "pkg:alpm/arch/gcc-libs@13.2.1-3?arch=x86_64&distro=arch-rolling&upstream=gcc",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "gcc-libs",
|
||||
Version: "13.2.1-3",
|
||||
BasePackage: "gcc",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "from rpm with dashes in the source name",
|
||||
input: pkg.Package{
|
||||
Name: "perl-Foo-Bar-libs",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/perl-Foo-Bar-libs@1.0-1.el8?arch=x86_64&distro=rhel-8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "perl-Foo-Bar-libs",
|
||||
Version: "1.0",
|
||||
Release: "1.el8",
|
||||
SourceRpm: "perl-Foo-Bar-1.0-1.el8.src.rpm",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:rpm/redhat/perl-Foo-Bar@1.0-1.el8?arch=src&distro=rhel-8",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from rpm nosrc",
|
||||
input: pkg.Package{
|
||||
Name: "some-firmware",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/some-firmware@1.0-1.el8?arch=noarch&distro=rhel-8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "some-firmware",
|
||||
Version: "1.0",
|
||||
Release: "1.el8",
|
||||
SourceRpm: "firmware-1.0-1.el8.nosrc.rpm",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:rpm/redhat/firmware@1.0-1.el8?arch=nosrc&distro=rhel-8",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from rpm keeps rpmmod",
|
||||
input: pkg.Package{
|
||||
Name: "nodejs-libs",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/nodejs-libs@18.0-1.el8?arch=x86_64&distro=rhel-8&rpmmod=nodejs%3A18",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "nodejs-libs",
|
||||
Version: "18.0",
|
||||
Release: "1.el8",
|
||||
SourceRpm: "nodejs-18.0-1.el8.src.rpm",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:rpm/redhat/nodejs@18.0-1.el8?arch=src&distro=rhel-8&rpmmod=nodejs%3A18",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "from rpm with malformed source rpm",
|
||||
input: pkg.Package{
|
||||
Name: "gpg-pubkey",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/gpg-pubkey@1-1?distro=rhel-8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "gpg-pubkey",
|
||||
Version: "1",
|
||||
Release: "1",
|
||||
SourceRpm: "(none)",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "from rpm with non-source rpm filename",
|
||||
input: pkg.Package{
|
||||
Name: "bash",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/bash@5.1-2?arch=x86_64&distro=rhel-8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "bash",
|
||||
Version: "5.1",
|
||||
Release: "2",
|
||||
SourceRpm: "bash-5.1-2.x86_64.rpm",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "from rpm with too few dashes",
|
||||
input: pkg.Package{
|
||||
Name: "bash",
|
||||
Type: pkg.RpmPkg,
|
||||
PURL: "pkg:rpm/redhat/bash@5.1-2?arch=x86_64&distro=rhel-8",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "bash",
|
||||
Version: "5.1",
|
||||
Release: "2",
|
||||
SourceRpm: "bash-5.1.src.rpm",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "binary qualifiers and subpath are not carried over",
|
||||
input: pkg.Package{
|
||||
Name: "libssl3",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:deb/debian/libssl3@3.0.0-1?arch=amd64&distro=debian-12&checksum=sha256:dead&download_url=https://example.com/x.deb&cpes=cpe:2.3:a:x:x:1:*:*:*:*:*:*:*#sub/dir",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "libssl3",
|
||||
Version: "3.0.0-1",
|
||||
Source: "openssl",
|
||||
},
|
||||
},
|
||||
expected: &cyclonedx.ExternalReference{
|
||||
Type: cyclonedx.ERTypeSourceDistribution, URL: "pkg:deb/debian/openssl@3.0.0-1?arch=source&distro=debian-12",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PURL type does not match metadata",
|
||||
input: pkg.Package{
|
||||
Name: "x",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "pkg:npm/x@1",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "x",
|
||||
Version: "1",
|
||||
Source: "lodash",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "invalid PURL",
|
||||
input: pkg.Package{
|
||||
Name: "x",
|
||||
Type: pkg.DebPkg,
|
||||
PURL: "not-a-purl",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "x",
|
||||
Version: "1",
|
||||
Source: "y",
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
assert.Equal(t, test.expected, encodeSourcePackageExternalReference(test.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_isValidExternalRef(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source/directorysource"
|
||||
)
|
||||
|
||||
func SourcePackagesInput(t testing.TB, dir string) sbom.SBOM {
|
||||
path := filepath.Join(dir, "some", "path")
|
||||
require.NoError(t, os.MkdirAll(path, 0755))
|
||||
|
||||
src, err := directorysource.New(
|
||||
directorysource.Config{
|
||||
Path: path,
|
||||
Base: dir,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
return sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
Packages: newSourcePackageCatalog(),
|
||||
},
|
||||
Source: src.Describe(),
|
||||
Descriptor: sbom.Descriptor{
|
||||
Name: "syft",
|
||||
Version: "v0.42.0-bogus",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:funlen
|
||||
func newSourcePackageCatalog() *pkg.Collection {
|
||||
epoch := 32
|
||||
|
||||
catalog := pkg.NewCollection()
|
||||
|
||||
// apk: the origin differs from the package name, but apk is not supported so no source reference is expected
|
||||
catalog.Add(pkg.Package{
|
||||
Name: "libc-utils",
|
||||
Version: "0.7.2-r3",
|
||||
Type: pkg.ApkPkg,
|
||||
FoundBy: "apk-db-cataloger",
|
||||
Locations: file.NewLocationSet(file.NewLocation("/lib/apk/db/installed")),
|
||||
PURL: "pkg:apk/alpine/libc-utils@0.7.2-r3?arch=x86_64&distro=alpine-3.16.3&upstream=libc-dev",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "libc-utils",
|
||||
OriginPackage: "libc-dev",
|
||||
Version: "0.7.2-r3",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
})
|
||||
|
||||
// apk: negative control -- the package is its own origin
|
||||
catalog.Add(pkg.Package{
|
||||
Name: "busybox",
|
||||
Version: "1.35.0-r17",
|
||||
Type: pkg.ApkPkg,
|
||||
FoundBy: "apk-db-cataloger",
|
||||
Locations: file.NewLocationSet(file.NewLocation("/lib/apk/db/installed")),
|
||||
PURL: "pkg:apk/alpine/busybox@1.35.0-r17?arch=x86_64&distro=alpine-3.16.3",
|
||||
Metadata: pkg.ApkDBEntry{
|
||||
Package: "busybox",
|
||||
OriginPackage: "busybox",
|
||||
Version: "1.35.0-r17",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
})
|
||||
|
||||
// deb: source name differs, and the source version is implied by the binary version
|
||||
catalog.Add(pkg.Package{
|
||||
Name: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Type: pkg.DebPkg,
|
||||
FoundBy: "dpkg-db-cataloger",
|
||||
Locations: file.NewLocationSet(file.NewLocation("/var/lib/dpkg/status")),
|
||||
PURL: "pkg:deb/debian/libpam-runtime@1.5.2-6%2Bdeb12u1?arch=all&distro=debian-12&upstream=pam",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "libpam-runtime",
|
||||
Version: "1.5.2-6+deb12u1",
|
||||
Source: "pam",
|
||||
Architecture: "all",
|
||||
},
|
||||
})
|
||||
|
||||
// deb: the source version differs from the binary version
|
||||
catalog.Add(pkg.Package{
|
||||
Name: "attr",
|
||||
Version: "1:2.4.47-2+b1",
|
||||
Type: pkg.DebPkg,
|
||||
FoundBy: "dpkg-db-cataloger",
|
||||
Locations: file.NewLocationSet(file.NewLocation("/var/lib/dpkg/status")),
|
||||
PURL: "pkg:deb/debian/attr@1%3A2.4.47-2%2Bb1?arch=amd64&distro=debian-12&upstream=attr%401%3A2.4.47-2",
|
||||
Metadata: pkg.DpkgDBEntry{
|
||||
Package: "attr",
|
||||
Version: "1:2.4.47-2+b1",
|
||||
Source: "attr",
|
||||
SourceVersion: "1:2.4.47-2",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
})
|
||||
|
||||
// rpm: name and version both come out of the source RPM filename, and the epoch is carried over
|
||||
catalog.Add(pkg.Package{
|
||||
Name: "bind-export-libs",
|
||||
Version: "32:9.11.13-3.el8",
|
||||
Type: pkg.RpmPkg,
|
||||
FoundBy: "rpm-db-cataloger",
|
||||
Locations: file.NewLocationSet(file.NewLocation("/var/lib/rpm/Packages")),
|
||||
PURL: "pkg:rpm/centos/bind-export-libs@9.11.13-3.el8?arch=x86_64&distro=centos-8&epoch=32&upstream=bind-9.11.13-3.el8.src.rpm",
|
||||
Metadata: pkg.RpmDBEntry{
|
||||
Name: "bind-export-libs",
|
||||
Version: "9.11.13",
|
||||
Release: "3.el8",
|
||||
Epoch: &epoch,
|
||||
Arch: "x86_64",
|
||||
SourceRpm: "bind-9.11.13-3.el8.src.rpm",
|
||||
},
|
||||
})
|
||||
|
||||
// alpm: the base package differs from the package name, but alpm is not supported so no source reference is expected
|
||||
catalog.Add(pkg.Package{
|
||||
Name: "gcc-libs",
|
||||
Version: "13.2.1-3",
|
||||
Type: pkg.AlpmPkg,
|
||||
FoundBy: "alpm-db-cataloger",
|
||||
Locations: file.NewLocationSet(file.NewLocation("/var/lib/pacman/local/gcc-libs-13.2.1-3/desc")),
|
||||
PURL: "pkg:alpm/arch/gcc-libs@13.2.1-3?arch=x86_64&distro=arch-rolling&upstream=gcc",
|
||||
Metadata: pkg.AlpmDBEntry{
|
||||
Package: "gcc-libs",
|
||||
Version: "13.2.1-3",
|
||||
BasePackage: "gcc",
|
||||
Architecture: "x86_64",
|
||||
},
|
||||
})
|
||||
|
||||
return catalog
|
||||
}
|
||||
Reference in New Issue
Block a user