build source PURL from metadata and gate it to CycloneDX 1.6+

- the source PURL is built from package metadata instead of editing the binary PURL: only `distro` (plus `epoch` and `rpmmod` for rpm) is carried over, subpath is dropped, and the ref is skipped when the PURL type does not match the metadata ecosystem
- one emission rule for all ecosystems: only when the source name or version differs from the binary, so self-sourced rpm and alpm packages no longer get a redundant ref
- source RPM names must end in `.src.rpm` or `.nosrc.rpm`, and `nosrc` maps to `arch=nosrc`
- `source-distribution` refs are dropped when encoding below spec 1.6, since cyclonedx-go does not downgrade them (CycloneDX/cyclonedx-go#291)

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2026-09-30 12:56:05 -04:00
parent d53a8d283f
commit bf8ded3cf8
5 changed files with 291 additions and 65 deletions
@@ -47,14 +47,6 @@ func EncodeComponent(p pkg.Package, supplier string, locationSorter func(a, b fi
componentType = cyclonedx.ComponentTypeMachineLearningModel
}
externalRefs := encodeExternalReferences(p)
if srcRef := encodeSourcePackageExternalReference(p); srcRef != nil {
if externalRefs == nil {
externalRefs = &[]cyclonedx.ExternalReference{}
}
*externalRefs = append(*externalRefs, *srcRef)
}
return cyclonedx.Component{
Type: componentType,
Name: p.Name,
@@ -67,7 +59,7 @@ func EncodeComponent(p pkg.Package, supplier string, locationSorter func(a, b fi
Author: encodeAuthor(p),
Publisher: encodePublisher(p),
Description: encodeDescription(p),
ExternalReferences: externalRefs,
ExternalReferences: encodeExternalReferences(p),
Properties: properties,
BOMRef: DeriveBomRef(p),
}