feat: add support for user to flag root package supplier and package supplier inheritance
Description
This PR adds a new flag to syft called --source-supplier. This flag allows syft users to associate an optional supplier to the root component of the final document. It makes no determination about other packages cataloged by syft.
Formats updated
- [x]
syft-json - [x]
spdx-json - [x]
cyclonedx-json - [x]
spdx - [x]
cyclonedx
The --source-supplier will be used to determine the supplier of the root component of the SBOM
This allows organizations generating SBOMs who want to produce NTIA compliant documents to assume the supplier field for software/containers they are producing.
Adds supplier to the following outputs:
spdx
go run cmd/syft/main.go -o spdx alpine:latest --source-supplier optional-supplier > test.json
##### Package: alpine
PackageName: alpine
SPDXID: SPDXRef-DocumentRoot-Image-alpine
PackageVersion: sha256:47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337
PackageSupplier: optional-supplier <-----------
PackageDownloadLocation: NOASSERTION
PrimaryPackagePurpose: CONTAINER
FilesAnalyzed: false
PackageChecksum: SHA256: 47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
ExternalRef: PACKAGE-MANAGER purl pkg:oci/alpine@sha256%3A47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337?arch=arm64&tag=latest
spdx-json
go run cmd/syft/main.go -o spdx-json alpine:latest --supplier optional-supplier > test.json
{
"name": "alpine",
"SPDXID": "SPDXRef-DocumentRoot-Image-alpine",
"versionInfo": "sha256:47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337",
"supplier": "Organization: optional-supplier", <-----------
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
"checksums": [
{
"algorithm": "SHA256",
"checksumValue": "47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337"
}
],
"licenseConcluded": "NOASSERTION",
"licenseDeclared": "NOASSERTION",
"copyrightText": "NOASSERTION",
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:oci/alpine@sha256%3A47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337?arch=arm64&tag=latest"
}
],
"primaryPackagePurpose": "CONTAINER"
}
syft-json
go run cmd/syft/main.go -o json alpine:latest --supplier optional-supplier > test.json
"source": {
"id": "47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337",
"name": "alpine",
"version": "sha256:47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337",
"supplier": "optional-supplier", <-----------
"type": "image",
"metadata": {
"userInput": "alpine:latest",
"imageID": "sha256:7ad00e65ee25911881c06b97a3e562675d255e1265ba4abadd3e906d266c1dcc",
"manifestDigest": "sha256:47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"tags": [
"alpine:latest"
],
"imageSize": 8169605,
cyclonedx-json
Note: for cyclonedx-json we're putting supplier in two spots that the format supports. One is the top level BOM description. The other is for the root component identified in the bom
- `metadata.supplier`
The organization that supplied the component that the BOM describes.
The supplier may often be the manufacturer, but may also be a distributor or repackager.
- `metadata.component.supplier`
The organization that supplied the component.
The supplier may often be the manufacturer, but may also be a distributor or repackager.
go run cmd/syft/main.go -o cyclonedx-json alpine:latest --supplier optional-supplier > test.json
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:f6d124b0-c4ba-48dc-96a4-6b0e12d8eefe",
"version": 1,
"metadata": {
"timestamp": "2025-02-07T12:54:04-05:00",
"tools": {
"components": [
{
"type": "application",
"author": "anchore",
"name": "syft",
"version": "[not provided]"
}
]
},
"component": {
"bom-ref": "327aecd176f7b31f",
"type": "container",
"supplier": {
"name": "optional-supplier" <------
},
"name": "alpine",
"version": "sha256:47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337"
},
"supplier": {
"name": "optional-supplier" <-------
}
},
cyclonedx
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:64f0a96d-319a-4faa-a13c-5deb1f46f8c9" version="1">
<metadata>
<timestamp>2025-02-07T12:59:47-05:00</timestamp>
<tools>
<components>
<component type="application">
<author>anchore</author>
<name>syft</name>
<version>[not provided]</version>
</component>
</components>
</tools>
<component bom-ref="327aecd176f7b31f" type="container">
<supplier>
<name>optional-supplier</name> <------
</supplier>
<name>alpine</name>
<version>sha256:47badde288cf303fe43766ba3c0be01df313b84ad91480c1f21b7e907a7f2337</version>
</component>
<supplier>
<name>optional-supplier</name> <-----
</supplier>
</metadata>
<components>
Fixes
- #3098
Type of change
- [x] New feature (non-breaking change which adds functionality)
- [x] Documentation (updates the documentation)
Checklist:
- [x] I have added unit tests that cover changed behavior
- [x] I have tested my code in common scenarios and confirmed there are no regressions
- [x] I have added comments to my code, particularly in hard-to-understand sections