Thanks to visit codestin.com
Credit goes to github.com

Skip to content
35 changes: 31 additions & 4 deletions internal/presenter/packages/spdx_json_presenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/json"
"fmt"
"io"
"path"
"strings"
"time"

"github.com/anchore/syft/internal"
Expand All @@ -12,8 +14,11 @@ import (
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
"github.com/google/uuid"
)

const anchoreNamespace = "https://anchore.com/syft"

// SPDXJsonPresenter is a SPDX presentation object for the syft results (see https://github.com/spdx/spdx-spec)
type SPDXJsonPresenter struct {
catalog *pkg.Catalog
Expand Down Expand Up @@ -41,14 +46,25 @@ func (pres *SPDXJsonPresenter) Present(output io.Writer) error {

// newSPDXJsonDocument creates and populates a new JSON document struct that follows the SPDX 2.2 spec from the given cataloging results.
func newSPDXJsonDocument(catalog *pkg.Catalog, srcMetadata source.Metadata) spdx22.Document {
var name string
uniqueID := uuid.Must(uuid.NewRandom())

var name, input, identifier string
switch srcMetadata.Scheme {
case source.ImageScheme:
name = srcMetadata.ImageMetadata.UserInput
name = cleanSPDXName(srcMetadata.ImageMetadata.UserInput)
input = "image"
case source.DirectoryScheme:
name = srcMetadata.Path
name = cleanSPDXName(srcMetadata.Path)
input = "dir"
}

if name != "." {
identifier = path.Join(input, fmt.Sprintf("%s-%s", name, uniqueID.String()))
} else {
identifier = path.Join(input, uniqueID.String())
}

namespace := path.Join(anchoreNamespace, identifier)
packages, files, relationships := newSPDXJsonElements(catalog)

return spdx22.Document{
Expand All @@ -67,7 +83,7 @@ func newSPDXJsonDocument(catalog *pkg.Catalog, srcMetadata source.Metadata) spdx
LicenseListVersion: spdxlicense.Version,
},
DataLicense: "CC0-1.0",
DocumentNamespace: fmt.Sprintf("https://anchore.com/syft/image/%s", srcMetadata.ImageMetadata.UserInput),
DocumentNamespace: namespace,
Packages: packages,
Files: files,
Relationships: relationships,
Expand Down Expand Up @@ -113,3 +129,14 @@ func newSPDXJsonElements(catalog *pkg.Catalog) ([]spdx22.Package, []spdx22.File,

return packages, files, relationships
}

func cleanSPDXName(name string) string {
// remove # according to specification
name = strings.Replace(name, "#", "-", -1)

// remove : for url construction
name = strings.Replace(name, ":", "-", -1)

// clean relative pathing
return path.Clean(name)
}
4 changes: 4 additions & 0 deletions internal/presenter/packages/spdx_json_presenter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func TestSPDXJSONImagePresenter(t *testing.T) {
func spdxJsonRedactor(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"))

// each SBOM reports a unique documentNamespace when generated, this is not useful for snapshot testing
s = regexp.MustCompile(`"documentNamespace": .*`).ReplaceAll(s, []byte("redacted"))

// the license list will be updated periodically, the value here should not be directly tested in snapshot tests
return regexp.MustCompile(`"licenseListVersion": .*`).ReplaceAll(s, []byte("redacted"))
}