feat: update spdx format model to produce valid spdx json documents (#1418)

This commit is contained in:
Christopher Angelo Phillips 2022-12-21 15:56:03 -05:00 committed by GitHub
parent 5dd726fc86
commit 3690f979b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 159 additions and 28 deletions

View File

@ -8,6 +8,11 @@ const (
// Example: The package 'WildFly' is described by SPDX document WildFly.spdx.
DescribedByRelationship RelationshipType = "DESCRIBED_BY"
// Describes is to be used when SPDXRef-DOCUMENT describes SPDXRef-A.
// Example: An SPDX document WildFly.spdx describes package WildFly.
// Note this is a logical relationship to help organize related items within an SPDX document that is mandatory if more than one package or set of files (not in a package) is present.
DescribesRelationship RelationshipType = "DESCRIBES"
// ContainsRelationship is to be used when SPDXRef-A contains SPDXRef-B.
// Example: An ARCHIVE file bar.tgz contains a SOURCE file foo.c.
ContainsRelationship RelationshipType = "CONTAINS"

View File

@ -33,6 +33,24 @@ const (
//nolint:funlen
func ToFormatModel(s sbom.SBOM) *spdx.Document {
name, namespace := DocumentNameAndNamespace(s.Source)
relationships := toRelationships(s.RelationshipsSorted())
// for valid SPDX we need a document describes relationship
// TODO: remove this placeholder after deciding on correct behavior
// for the primary package purpose field:
// https://spdx.github.io/spdx-spec/v2.3/package-information/#724-primary-package-purpose-field
documentDescribesRelationship := &spdx.Relationship{
RefA: common.DocElementID{
ElementRefID: "DOCUMENT",
},
Relationship: string(DescribesRelationship),
RefB: common.DocElementID{
ElementRefID: "DOCUMENT",
},
RelationshipComment: "",
}
relationships = append(relationships, documentDescribesRelationship)
return &spdx.Document{
// 6.1: SPDX Version; should be in the format "SPDX-x.x"
@ -107,7 +125,7 @@ func ToFormatModel(s sbom.SBOM) *spdx.Document {
},
Packages: toPackages(s.Artifacts.PackageCatalog, s),
Files: toFiles(s),
Relationships: toRelationships(s.RelationshipsSorted()),
Relationships: relationships,
}
}
@ -407,6 +425,15 @@ func toFiles(s sbom.SBOM) (results []*spdx.File) {
digests = digestsForLocation
}
// if we don't have any metadata or digests for this location
// then the file is most likely a symlink or non-regular file
// for now we include a 0 sha1 digest as requested by the spdx spec
// TODO: update location code in core SBOM so that we can map complex links
// back to their real file digest location.
if len(digests) == 0 {
digests = append(digests, file.Digest{Algorithm: "sha1", Value: "0000000000000000000000000000000000000000"})
}
// TODO: add file classifications (?) and content as a snippet
var comment string

View File

@ -3,14 +3,14 @@
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "/some/path",
"documentNamespace": "https://anchore.com/syft/dir/some/path-4bf54cdd-0a0f-4560-bf4f-39cac2ef7a5b",
"documentNamespace": "https://anchore.com/syft/dir/some/path-116e86ba-a976-48ed-909d-9278807ee7fe",
"creationInfo": {
"licenseListVersion": "3.18",
"licenseListVersion": "3.19",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"created": "2022-11-19T13:46:57Z",
"created": "2022-12-21T03:39:05Z",
"comment": ""
},
"packages": [
@ -62,5 +62,12 @@
}
]
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES"
}
]
}

View File

@ -3,14 +3,14 @@
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "user-image-input",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-102ca7dc-3d1e-46d2-b130-28968831ebcc",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-006b9b96-66f1-4de3-897f-6583b4358c87",
"creationInfo": {
"licenseListVersion": "3.18",
"licenseListVersion": "3.19",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"created": "2022-11-19T13:46:57Z",
"created": "2022-12-21T03:39:05Z",
"comment": ""
},
"packages": [
@ -62,5 +62,12 @@
}
]
}
],
"relationships": [
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES"
}
]
}

View File

@ -3,14 +3,14 @@
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "user-image-input",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-ace88a38-4633-4bff-8fa3-8ae929dab37d",
"documentNamespace": "https://anchore.com/syft/image/user-image-input-552a9cfc-49ee-4706-81cb-723fd7146b4f",
"creationInfo": {
"licenseListVersion": "3.19",
"creators": [
"Organization: Anchore, Inc",
"Tool: syft-v0.42.0-bogus"
],
"created": "2022-12-14T18:21:40Z",
"created": "2022-12-21T03:39:05Z",
"comment": ""
},
"packages": [
@ -70,7 +70,12 @@
"fileTypes": [
"OTHER"
],
"checksums": [],
"checksums": [
{
"algorithm": "SHA1",
"checksumValue": "0000000000000000000000000000000000000000"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": ""
},
@ -80,7 +85,12 @@
"fileTypes": [
"OTHER"
],
"checksums": [],
"checksums": [
{
"algorithm": "SHA1",
"checksumValue": "0000000000000000000000000000000000000000"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": ""
},
@ -90,7 +100,12 @@
"fileTypes": [
"OTHER"
],
"checksums": [],
"checksums": [
{
"algorithm": "SHA1",
"checksumValue": "0000000000000000000000000000000000000000"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": ""
},
@ -100,7 +115,12 @@
"fileTypes": [
"OTHER"
],
"checksums": [],
"checksums": [
{
"algorithm": "SHA1",
"checksumValue": "0000000000000000000000000000000000000000"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": ""
},
@ -110,7 +130,12 @@
"fileTypes": [
"OTHER"
],
"checksums": [],
"checksums": [
{
"algorithm": "SHA1",
"checksumValue": "0000000000000000000000000000000000000000"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": ""
},
@ -120,7 +145,12 @@
"fileTypes": [
"OTHER"
],
"checksums": [],
"checksums": [
{
"algorithm": "SHA1",
"checksumValue": "0000000000000000000000000000000000000000"
}
],
"licenseConcluded": "NOASSERTION",
"copyrightText": ""
}
@ -155,6 +185,11 @@
"spdxElementId": "SPDXRef-Package-python-package-1-66ba429119b8bec6",
"relatedSpdxElement": "SPDXRef-f9e49132a4b96ccd",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-DOCUMENT",
"relatedSpdxElement": "SPDXRef-DOCUMENT",
"relationshipType": "DESCRIBES"
}
]
}

View File

@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: foobar/baz
DocumentNamespace: https://anchore.com/syft/dir/foobar/baz-62bc0aae-2b37-4c86-ab79-63c6fc4198ed
LicenseListVersion: 3.18
DocumentNamespace: https://anchore.com/syft/dir/foobar/baz-478e410d-7fad-472c-b4e9-a4068ef28160
LicenseListVersion: 3.19
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-19T13:48:30Z
Created: 2022-12-21T03:39:05Z
##### Package: @at-sign
@ -41,3 +41,7 @@ PackageLicenseConcluded: NONE
PackageLicenseDeclared: NONE
PackageCopyrightText: NOASSERTION
##### Relationships
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DOCUMENT

View File

@ -2,42 +2,48 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: user-image-input
DocumentNamespace: https://anchore.com/syft/image/user-image-input-cc20e416-9c74-401c-b4aa-245556bada5e
LicenseListVersion: 3.18
DocumentNamespace: https://anchore.com/syft/image/user-image-input-73433e8c-364f-42b6-b5b7-9a4da8799868
LicenseListVersion: 3.19
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-19T13:48:30Z
Created: 2022-12-21T03:39:05Z
##### Unpackaged files
FileName: /f1
SPDXID: SPDXRef-5265a4dde3edbf7c
FileType: OTHER
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
FileName: /z1/f5
SPDXID: SPDXRef-839d99ee67d9d174
FileType: OTHER
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
FileName: /a1/f6
SPDXID: SPDXRef-9c2f7510199b17f6
FileType: OTHER
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
FileName: /d2/f4
SPDXID: SPDXRef-c641caa71518099f
FileType: OTHER
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
FileName: /d1/f3
SPDXID: SPDXRef-c6f5b29dca12661f
FileType: OTHER
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
FileName: /f2
SPDXID: SPDXRef-f9e49132a4b96ccd
FileType: OTHER
FileChecksum: SHA1: 0000000000000000000000000000000000000000
LicenseConcluded: NOASSERTION
##### Package: package-2
@ -76,4 +82,5 @@ Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-c641caa71518099f
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-c6f5b29dca12661f
Relationship: SPDXRef-Package-python-package-1-66ba429119b8bec6 CONTAINS SPDXRef-f9e49132a4b96ccd
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DOCUMENT

View File

@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: /some/path
DocumentNamespace: https://anchore.com/syft/dir/some/path-7a4b2140-6669-4a28-80dd-5c8e795c5da0
LicenseListVersion: 3.18
DocumentNamespace: https://anchore.com/syft/dir/some/path-1d303762-46d2-47b5-9c81-defa91387275
LicenseListVersion: 3.19
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-19T13:48:30Z
Created: 2022-12-21T03:39:05Z
##### Package: package-2
@ -36,3 +36,7 @@ PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:*:some:package:2:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl a-purl-2
##### Relationships
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DOCUMENT

View File

@ -2,11 +2,11 @@ SPDXVersion: SPDX-2.3
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: user-image-input
DocumentNamespace: https://anchore.com/syft/image/user-image-input-baff7ada-85cb-403e-90d7-05b0c6d79490
LicenseListVersion: 3.18
DocumentNamespace: https://anchore.com/syft/image/user-image-input-559af225-63af-4bc0-94fb-bce94913bcfa
LicenseListVersion: 3.19
Creator: Organization: Anchore, Inc
Creator: Tool: syft-v0.42.0-bogus
Created: 2022-11-19T13:48:30Z
Created: 2022-12-21T03:39:05Z
##### Package: package-2
@ -36,3 +36,7 @@ PackageCopyrightText: NOASSERTION
ExternalRef: SECURITY cpe23Type cpe:2.3:*:some:package:1:*:*:*:*:*:*:*
ExternalRef: PACKAGE-MANAGER purl a-purl-1
##### Relationships
Relationship: SPDXRef-DOCUMENT DESCRIBES SPDXRef-DOCUMENT

View File

@ -6,6 +6,7 @@ import (
"os/exec"
"path"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
@ -26,6 +27,29 @@ func TestSpdxValidationTooling(t *testing.T) {
images: []string{"alpine:latest", "photon:3.0", "debian:latest"},
env: map[string]string{
"SYFT_FILE_METADATA_CATALOGER_ENABLED": "true",
"SYFT_FILE_CONTENTS_CATALOGER_ENABLED": "true",
"SYFT_FILE_METADATA_DIGESTS": "sha1",
},
setup: func(t *testing.T) {
cwd, err := os.Getwd()
require.NoError(t, err)
fixturesPath := filepath.Join(cwd, "test-fixtures", "image-java-spdx-tools")
buildCmd := exec.Command("make", "build")
buildCmd.Dir = fixturesPath
err = buildCmd.Run()
require.NoError(t, err)
},
assertions: []traitAssertion{
assertSuccessfulReturnCode,
},
},
{
name: "spdx validation tooling json",
syftArgs: []string{"packages", "-o", "spdx-json"},
images: []string{"alpine:latest", "photon:3.0", "debian:latest"},
env: map[string]string{
"SYFT_FILE_METADATA_CATALOGER_ENABLED": "true",
"SYFT_FILE_CONTENTS_CATALOGER_ENABLED": "true",
"SYFT_FILE_METADATA_DIGESTS": "sha1",
},
setup: func(t *testing.T) {
@ -61,8 +85,15 @@ func TestSpdxValidationTooling(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "temp")
require.NoError(t, err)
var suffix string
if strings.Contains(test.name, "json") {
suffix = ".json"
} else {
suffix = ".spdx"
}
// spdx tooling only takes a file with suffix spdx
rename := path.Join(path.Dir(f.Name()), fmt.Sprintf("%s.spdx", path.Base(f.Name())))
rename := path.Join(path.Dir(f.Name()), fmt.Sprintf("%s.%s", path.Base(f.Name()), suffix))
err = os.Rename(f.Name(), rename)
require.NoError(t, err)