mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
Ensure SPDXIDs are valid (#955)
This commit is contained in:
parent
321eddf874
commit
b7295b79de
13
internal/formats/common/spdxhelpers/spdxid.go
Normal file
13
internal/formats/common/spdxhelpers/spdxid.go
Normal file
@ -0,0 +1,13 @@
|
||||
package spdxhelpers
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var expr = regexp.MustCompile("[^a-zA-Z0-9.-]")
|
||||
|
||||
// SPDX spec says SPDXID must be:
|
||||
// "SPDXRef-"[idstring] where [idstring] is a unique string containing letters, numbers, ., and/or -
|
||||
func SanitizeElementID(id string) string {
|
||||
return expr.ReplaceAllString(id, "-")
|
||||
}
|
||||
39
internal/formats/common/spdxhelpers/spdxid_test.go
Normal file
39
internal/formats/common/spdxhelpers/spdxid_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package spdxhelpers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_SanitizeElementID(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "letters",
|
||||
expected: "letters",
|
||||
},
|
||||
{
|
||||
input: "ssl-client",
|
||||
expected: "ssl-client",
|
||||
},
|
||||
{
|
||||
input: "ssl_client",
|
||||
expected: "ssl-client",
|
||||
},
|
||||
{
|
||||
input: "go-module-sigs.k8s.io/structured-merge-diff/v3",
|
||||
expected: "go-module-sigs.k8s.io-structured-merge-diff-v3",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
actual := SanitizeElementID(test.input)
|
||||
|
||||
assert.Equal(t, test.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package model
|
||||
|
||||
import "github.com/anchore/syft/internal/formats/common/spdxhelpers"
|
||||
|
||||
// ElementID represents the identifier string portion of an SPDX element
|
||||
// identifier. DocElementID should be used for any attributes which can
|
||||
// contain identifiers defined in a different SPDX document.
|
||||
@ -7,31 +9,5 @@ package model
|
||||
type ElementID string
|
||||
|
||||
func (e ElementID) String() string {
|
||||
return "SPDXRef-" + string(e)
|
||||
}
|
||||
|
||||
// DocElementID represents an SPDX element identifier that could be defined
|
||||
// in a different SPDX document, and therefore could have a "DocumentRef-"
|
||||
// portion, such as Relationship and Annotations.
|
||||
// ElementID is used for attributes in which a "DocumentRef-" portion cannot
|
||||
// appear, such as a Package or File definition (since it is necessarily
|
||||
// being defined in the present document).
|
||||
// DocumentRefID will be the empty string for elements defined in the
|
||||
// present document.
|
||||
// DocElementIDs should NOT contain the mandatory 'DocumentRef-' or
|
||||
// 'SPDXRef-' portions.
|
||||
type DocElementID struct {
|
||||
DocumentRefID string
|
||||
ElementRefID ElementID
|
||||
}
|
||||
|
||||
// RenderDocElementID takes a DocElementID and returns the string equivalent,
|
||||
// with the SPDXRef- prefix (and, if applicable, the DocumentRef- prefix)
|
||||
// reinserted.
|
||||
func (d DocElementID) String() string {
|
||||
prefix := ""
|
||||
if d.DocumentRefID != "" {
|
||||
prefix = "DocumentRef-" + d.DocumentRefID + ":"
|
||||
}
|
||||
return prefix + d.ElementRefID.String()
|
||||
return "SPDXRef-" + spdxhelpers.SanitizeElementID(string(e))
|
||||
}
|
||||
|
||||
@ -6,6 +6,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/internal/formats/common/testutils"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
var updateSpdxTagValue = flag.Bool("update-spdx-tv", false, "update the *.golden files for spdx-tv encoders")
|
||||
@ -31,6 +34,32 @@ func TestSPDXTagValueImageEncoder(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
func TestSPDXJSONSPDXIDs(t *testing.T) {
|
||||
var pkgs []pkg.Package
|
||||
for _, name := range []string{"some/slashes", "@at-sign", "under_scores"} {
|
||||
p := pkg.Package{
|
||||
Name: name,
|
||||
}
|
||||
p.SetID()
|
||||
pkgs = append(pkgs, p)
|
||||
}
|
||||
testutils.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
Format(),
|
||||
sbom.SBOM{
|
||||
Artifacts: sbom.Artifacts{
|
||||
PackageCatalog: pkg.NewCatalog(pkgs...),
|
||||
},
|
||||
Relationships: nil,
|
||||
Source: source.Metadata{
|
||||
Scheme: source.DirectoryScheme,
|
||||
},
|
||||
Descriptor: sbom.Descriptor{},
|
||||
},
|
||||
true,
|
||||
spdxTagValueRedactor,
|
||||
)
|
||||
}
|
||||
|
||||
func spdxTagValueRedactor(s []byte) []byte {
|
||||
// each SBOM reports the time it was generated, which is not useful during snapshot testing
|
||||
s = regexp.MustCompile(`Created: .*`).ReplaceAll(s, []byte("redacted"))
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
SPDXVersion: SPDX-2.2
|
||||
DataLicense: CC0-1.0
|
||||
SPDXID: SPDXRef-DOCUMENT
|
||||
DocumentName: .
|
||||
DocumentNamespace: https://anchore.com/syft/dir/e69056a9-935e-4f00-b85f-9467f5d99a92
|
||||
LicenseListVersion: 3.16
|
||||
Creator: Organization: Anchore, Inc
|
||||
Creator: Tool: syft-[not provided]
|
||||
Created: 2022-04-13T16:38:03Z
|
||||
|
||||
##### Package: @at-sign
|
||||
|
||||
PackageName: @at-sign
|
||||
SPDXID: SPDXRef-Package---at-sign-739e4f0d93fb8298
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NONE
|
||||
PackageLicenseDeclared: NONE
|
||||
PackageCopyrightText: NOASSERTION
|
||||
|
||||
##### Package: some/slashes
|
||||
|
||||
PackageName: some/slashes
|
||||
SPDXID: SPDXRef-Package--some-slashes-26db06648b24bff9
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NONE
|
||||
PackageLicenseDeclared: NONE
|
||||
PackageCopyrightText: NOASSERTION
|
||||
|
||||
##### Package: under_scores
|
||||
|
||||
PackageName: under_scores
|
||||
SPDXID: SPDXRef-Package--under-scores-250cbfefcdea318b
|
||||
PackageDownloadLocation: NOASSERTION
|
||||
FilesAnalyzed: false
|
||||
PackageLicenseConcluded: NONE
|
||||
PackageLicenseDeclared: NONE
|
||||
PackageCopyrightText: NOASSERTION
|
||||
|
||||
@ -96,7 +96,7 @@ func toFormatPackages(catalog *pkg.Catalog) map[spdx.ElementID]*spdx.Package2_2
|
||||
|
||||
for _, p := range catalog.Sorted() {
|
||||
// name should be guaranteed to be unique, but semantically useful and stable
|
||||
id := fmt.Sprintf("Package-%+v-%s-%s", p.Type, p.Name, p.ID())
|
||||
id := spdxhelpers.SanitizeElementID(fmt.Sprintf("Package-%+v-%s-%s", p.Type, p.Name, p.ID()))
|
||||
|
||||
// If the Concluded License is not the same as the Declared License, a written explanation should be provided
|
||||
// in the Comments on License field (section 3.16). With respect to NOASSERTION, a written explanation in
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user