Skip to content

Commit

Permalink
fix(sbom): use Annotation instead of AttributionTexts for SPDX
Browse files Browse the repository at this point in the history
…formats (#7811)
  • Loading branch information
DmitriyLewen authored Oct 30, 2024
1 parent b661d68 commit f2bb9c6
Show file tree
Hide file tree
Showing 6 changed files with 316 additions and 158 deletions.
39 changes: 27 additions & 12 deletions integration/testdata/conda-spdx.json.golden
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@
"referenceLocator": "pkg:conda/openssl@1.1.1q"
}
],
"attributionTexts": [
"PkgType: conda-pkg"
],
"primaryPackagePurpose": "LIBRARY"
"primaryPackagePurpose": "LIBRARY",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgType: conda-pkg"
}
]
},
{
"name": "pip",
Expand All @@ -55,20 +60,30 @@
"referenceLocator": "pkg:conda/pip@22.2.2"
}
],
"attributionTexts": [
"PkgType: conda-pkg"
],
"primaryPackagePurpose": "LIBRARY"
"primaryPackagePurpose": "LIBRARY",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgType: conda-pkg"
}
]
},
{
"name": "testdata/fixtures/repo/conda",
"SPDXID": "SPDXRef-Filesystem-2e2426fd0f2580ef",
"downloadLocation": "NONE",
"filesAnalyzed": false,
"attributionTexts": [
"SchemaVersion: 2"
],
"primaryPackagePurpose": "SOURCE"
"primaryPackagePurpose": "SOURCE",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "SchemaVersion: 2"
}
]
}
],
"files": [
Expand Down
93 changes: 69 additions & 24 deletions integration/testdata/julia-spdx.json.golden
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@
"SPDXID": "SPDXRef-Application-18fc3597717a3e56",
"downloadLocation": "NONE",
"filesAnalyzed": false,
"attributionTexts": [
"Class: lang-pkgs",
"Type: julia"
],
"primaryPackagePurpose": "APPLICATION"
"primaryPackagePurpose": "APPLICATION",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "Class: lang-pkgs"
},
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "Type: julia"
}
]
},
{
"name": "A",
Expand All @@ -40,11 +50,21 @@
"referenceLocator": "pkg:julia/A@1.9.0?uuid=ead4f63c-334e-11e9-00e6-e7f0a5f21b60"
}
],
"attributionTexts": [
"PkgID: ead4f63c-334e-11e9-00e6-e7f0a5f21b60",
"PkgType: julia"
],
"primaryPackagePurpose": "LIBRARY"
"primaryPackagePurpose": "LIBRARY",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgID: ead4f63c-334e-11e9-00e6-e7f0a5f21b60"
},
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgType: julia"
}
]
},
{
"name": "B",
Expand All @@ -63,11 +83,21 @@
"referenceLocator": "pkg:julia/B@1.9.0?uuid=f41f7b98-334e-11e9-1257-49272045fb24"
}
],
"attributionTexts": [
"PkgID: f41f7b98-334e-11e9-1257-49272045fb24",
"PkgType: julia"
],
"primaryPackagePurpose": "LIBRARY"
"primaryPackagePurpose": "LIBRARY",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgID: f41f7b98-334e-11e9-1257-49272045fb24"
},
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgType: julia"
}
]
},
{
"name": "B",
Expand All @@ -86,21 +116,36 @@
"referenceLocator": "pkg:julia/B@1.9.0?uuid=edca9bc6-334e-11e9-3554-9595dbb4349c"
}
],
"attributionTexts": [
"PkgID: edca9bc6-334e-11e9-3554-9595dbb4349c",
"PkgType: julia"
],
"primaryPackagePurpose": "LIBRARY"
"primaryPackagePurpose": "LIBRARY",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgID: edca9bc6-334e-11e9-3554-9595dbb4349c"
},
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "PkgType: julia"
}
]
},
{
"name": "testdata/fixtures/repo/julia",
"SPDXID": "SPDXRef-Filesystem-1be792dd0077c431",
"downloadLocation": "NONE",
"filesAnalyzed": false,
"attributionTexts": [
"SchemaVersion: 2"
],
"primaryPackagePurpose": "SOURCE"
"primaryPackagePurpose": "SOURCE",
"annotations": [
{
"annotator": "Tool: trivy-dev",
"annotationDate": "2021-08-25T12:20:30Z",
"annotationType": "OTHER",
"comment": "SchemaVersion: 2"
}
]
}
],
"relationships": [
Expand Down
42 changes: 27 additions & 15 deletions pkg/sbom/spdx/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const (
PackageSupplierNoAssertion = "NOASSERTION"
PackageSupplierOrganization = "Organization"

PackageAnnotatorToolField = "Tool"

RelationShipContains = common.TypeRelationshipContains
RelationShipDescribe = common.TypeRelationshipDescribe
RelationShipDependsOn = common.TypeRelationshipDependsOn
Expand Down Expand Up @@ -122,14 +124,17 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
packages []*spdx.Package
)

// Lock time to use same time for all spdx fields
timeNow := clock.Now(ctx).UTC().Format(time.RFC3339)

root := bom.Root()
pkgDownloadLocation := m.packageDownloadLocation(root)

// Component ID => SPDX ID
packageIDs := make(map[uuid.UUID]spdx.ElementID)

// Root package contains OS, OS packages, language-specific packages and so on.
rootPkg, err := m.rootSPDXPackage(root, pkgDownloadLocation)
rootPkg, err := m.rootSPDXPackage(root, timeNow, pkgDownloadLocation)
if err != nil {
return nil, xerrors.Errorf("failed to generate a root package: %w", err)
}
Expand All @@ -144,7 +149,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
if c.Root {
continue
}
spdxPackage, err := m.spdxPackage(c, pkgDownloadLocation)
spdxPackage, err := m.spdxPackage(c, timeNow, pkgDownloadLocation)
if err != nil {
return nil, xerrors.Errorf("spdx package error: %w", err)
}
Expand Down Expand Up @@ -216,7 +221,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document,
CreatorType: "Tool",
},
},
Created: clock.Now(ctx).UTC().Format(time.RFC3339),
Created: timeNow,
},
Packages: packages,
Relationships: relationShips,
Expand All @@ -237,7 +242,7 @@ func (m *Marshaler) packageDownloadLocation(root *core.Component) string {
return location
}

func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation string) (*spdx.Package, error) {
func (m *Marshaler) rootSPDXPackage(root *core.Component, timeNow, pkgDownloadLocation string) (*spdx.Package, error) {
var externalReferences []*spdx.PackageExternalReference
// When the target is a container image, add PURL to the external references of the root package.
if root.PkgIdentifier.PURL != nil {
Expand All @@ -258,17 +263,25 @@ func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation st
PackageName: root.Name,
PackageSPDXIdentifier: elementID(camelCase(string(root.Type)), pkgID),
PackageDownloadLocation: pkgDownloadLocation,
PackageAttributionTexts: m.spdxAttributionTexts(root),
Annotations: m.spdxAnnotations(root, timeNow),
PackageExternalReferences: externalReferences,
PrimaryPackagePurpose: pkgPurpose,
}, nil
}

func (m *Marshaler) appendAttributionText(attributionTexts []string, key, value string) []string {
func (m *Marshaler) appendAnnotation(annotations []spdx.Annotation, timeNow, key, value string) []spdx.Annotation {
if value == "" {
return attributionTexts
return annotations
}
return append(attributionTexts, fmt.Sprintf("%s: %s", key, value))
return append(annotations, spdx.Annotation{
AnnotationDate: timeNow,
AnnotationType: spdx.CategoryOther,
Annotator: spdx.Annotator{
Annotator: fmt.Sprintf("%s-%s", CreatorTool, m.appVersion),
AnnotatorType: PackageAnnotatorToolField,
},
AnnotationComment: fmt.Sprintf("%s: %s", key, value),
})
}

func (m *Marshaler) purlExternalReference(packageURL string) *spdx.PackageExternalReference {
Expand All @@ -287,7 +300,7 @@ func (m *Marshaler) advisoryExternalReference(primaryURL string) *spdx.PackageEx
}
}

func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (spdx.Package, error) {
func (m *Marshaler) spdxPackage(c *core.Component, timeNow, pkgDownloadLocation string) (spdx.Package, error) {
pkgID, err := calcPkgID(m.hasher, c)
if err != nil {
return spdx.Package{}, xerrors.Errorf("failed to get os metadata package ID: %w", err)
Expand Down Expand Up @@ -343,7 +356,7 @@ func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (
PrimaryPackagePurpose: purpose,
PackageDownloadLocation: pkgDownloadLocation,
PackageExternalReferences: pkgExtRefs,
PackageAttributionTexts: m.spdxAttributionTexts(c),
Annotations: m.spdxAnnotations(c, timeNow),
PackageSourceInfo: sourceInfo,
PackageSupplier: supplier,
PackageChecksums: m.spdxChecksums(digests),
Expand All @@ -365,16 +378,15 @@ func spdxPkgName(component *core.Component) string {
}
return component.Name
}

func (m *Marshaler) spdxAttributionTexts(c *core.Component) []string {
var texts []string
func (m *Marshaler) spdxAnnotations(c *core.Component, timeNow string) []spdx.Annotation {
var annotations []spdx.Annotation
for _, p := range c.Properties {
// Add properties that are not in other fields.
if !slices.Contains(duplicateProperties, p.Name) {
texts = m.appendAttributionText(texts, p.Name, p.Value)
annotations = m.appendAnnotation(annotations, timeNow, p.Name, p.Value)
}
}
return texts
return annotations
}

func (m *Marshaler) spdxLicense(c *core.Component) string {
Expand Down
Loading

0 comments on commit f2bb9c6

Please sign in to comment.