Skip to content

Commit

Permalink
feat(sbom): Add unmarshal for spdx (#2868)
Browse files Browse the repository at this point in the history
Signed-off-by: knqyf263 <knqyf263@gmail.com>
Co-authored-by: knqyf263 <knqyf263@gmail.com>
  • Loading branch information
masahiro331 and knqyf263 committed Sep 15, 2022
1 parent db0aaf1 commit 9f6680a
Show file tree
Hide file tree
Showing 15 changed files with 1,159 additions and 24 deletions.
3 changes: 1 addition & 2 deletions integration/client_server_test.go
Expand Up @@ -12,10 +12,9 @@ import (
"testing"
"time"

"github.com/samber/lo"

cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/docker/go-connections/nat"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
testcontainers "github.com/testcontainers/testcontainers-go"
Expand Down
8 changes: 4 additions & 4 deletions integration/docker_engine_test.go
Expand Up @@ -11,7 +11,7 @@ import (
"strings"
"testing"

"github.com/docker/docker/api/types"
api "github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -213,7 +213,7 @@ func TestDockerEngine(t *testing.T) {
require.NoError(t, err, tt.name)

// ensure image doesnt already exists
_, _ = cli.ImageRemove(ctx, tt.input, types.ImageRemoveOptions{
_, _ = cli.ImageRemove(ctx, tt.input, api.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
Expand Down Expand Up @@ -264,11 +264,11 @@ func TestDockerEngine(t *testing.T) {
compareReports(t, tt.golden, output)

// cleanup
_, err = cli.ImageRemove(ctx, tt.input, types.ImageRemoveOptions{
_, err = cli.ImageRemove(ctx, tt.input, api.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
_, err = cli.ImageRemove(ctx, tt.imageTag, types.ImageRemoveOptions{
_, err = cli.ImageRemove(ctx, tt.imageTag, api.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
Expand Down
106 changes: 95 additions & 11 deletions integration/sbom_test.go
Expand Up @@ -8,23 +8,28 @@ import (
"testing"

cdx "github.com/CycloneDX/cyclonedx-go"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
)

func TestCycloneDX(t *testing.T) {
func TestSBOM(t *testing.T) {
type args struct {
input string
format string
artifactType string
}
tests := []struct {
name string
args args
golden string
name string
args args
golden string
override types.Report
}{
{
name: "centos7-bom by trivy",
name: "centos7 cyclonedx",
args: args{
input: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
format: "cyclonedx",
Expand All @@ -33,7 +38,7 @@ func TestCycloneDX(t *testing.T) {
golden: "testdata/centos-7-cyclonedx.json.golden",
},
{
name: "fluentd-multiple-lockfiles-bom by trivy",
name: "fluentd-multiple-lockfiles cyclonedx",
args: args{
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
format: "cyclonedx",
Expand All @@ -42,14 +47,60 @@ func TestCycloneDX(t *testing.T) {
golden: "testdata/fluentd-multiple-lockfiles-cyclonedx.json.golden",
},
{
name: "centos7-bom in in-toto attestation",
name: "centos7 in in-toto attestation",
args: args{
input: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
format: "cyclonedx",
artifactType: "cyclonedx",
},
golden: "testdata/centos-7-cyclonedx.json.golden",
},
{
name: "centos7 spdx tag-value",
args: args{
input: "testdata/fixtures/sbom/centos-7-spdx.txt",
format: "json",
artifactType: "spdx",
},
golden: "testdata/centos-7.json.golden",
override: types.Report{
ArtifactName: "testdata/fixtures/sbom/centos-7-spdx.txt",
ArtifactType: ftypes.ArtifactType("spdx"),
Results: types.Results{
{
Target: "testdata/fixtures/sbom/centos-7-spdx.txt (centos 7.6.1810)",
Vulnerabilities: []types.DetectedVulnerability{
{Ref: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"},
{Ref: "pkg:rpm/centos/openssl-libs@1:1.0.2k-16.el7?arch=x86_64&distro=centos-7.6.1810"},
{Ref: "pkg:rpm/centos/openssl-libs@1:1.0.2k-16.el7?arch=x86_64&distro=centos-7.6.1810"},
},
},
},
},
},
{
name: "centos7 spdx json",
args: args{
input: "testdata/fixtures/sbom/centos-7-spdx.json",
format: "json",
artifactType: "spdx",
},
golden: "testdata/centos-7.json.golden",
override: types.Report{
ArtifactName: "testdata/fixtures/sbom/centos-7-spdx.json",
ArtifactType: ftypes.ArtifactType("spdx"),
Results: types.Results{
{
Target: "testdata/fixtures/sbom/centos-7-spdx.json (centos 7.6.1810)",
Vulnerabilities: []types.DetectedVulnerability{
{Ref: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"},
{Ref: "pkg:rpm/centos/openssl-libs@1:1.0.2k-16.el7?arch=x86_64&distro=centos-7.6.1810"},
{Ref: "pkg:rpm/centos/openssl-libs@1:1.0.2k-16.el7?arch=x86_64&distro=centos-7.6.1810"},
},
},
},
},
},
}

// Set up testing DB
Expand All @@ -61,7 +112,7 @@ func TestCycloneDX(t *testing.T) {
"--cache-dir", cacheDir, "sbom", "-q", "--skip-db-update", "--format", tt.args.format,
}

// Setup the output file
// Set up the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
if *update {
outputFile = tt.golden
Expand All @@ -75,13 +126,46 @@ func TestCycloneDX(t *testing.T) {
assert.NoError(t, err)

// Compare want and got
want := decodeCycloneDX(t, tt.golden)
got := decodeCycloneDX(t, outputFile)
assert.Equal(t, want, got)
switch tt.args.format {
case "cyclonedx":
want := decodeCycloneDX(t, tt.golden)
got := decodeCycloneDX(t, outputFile)
assert.Equal(t, want, got)
case "json":
compareSBOMReports(t, tt.golden, outputFile, tt.override)
default:
require.Fail(t, "invalid format", "format: %s", tt.args.format)
}
})
}
}

// TODO(teppei): merge into compareReports
func compareSBOMReports(t *testing.T, wantFile, gotFile string, overrideWant types.Report) {
want := readReport(t, wantFile)

want.ArtifactName = overrideWant.ArtifactName
want.ArtifactType = overrideWant.ArtifactType
want.Metadata.ImageID = ""
want.Metadata.ImageConfig = v1.ConfigFile{}
want.Metadata.DiffIDs = nil
for i, result := range want.Results {
for j := range result.Vulnerabilities {
want.Results[i].Vulnerabilities[j].Layer.DiffID = ""
}
}

for i, result := range overrideWant.Results {
want.Results[i].Target = result.Target
for j, vuln := range result.Vulnerabilities {
want.Results[i].Vulnerabilities[j].Ref = vuln.Ref
}
}

got := readReport(t, gotFile)
assert.Equal(t, want, got)
}

func decodeCycloneDX(t *testing.T, filePath string) *cdx.BOM {
f, err := os.Open(filePath)
require.NoError(t, err)
Expand Down
94 changes: 94 additions & 0 deletions integration/testdata/fixtures/sbom/centos-7-spdx.json
@@ -0,0 +1,94 @@
{
"SPDXID": "SPDXRef-DOCUMENT",
"creationInfo": {
"created": "2022-09-13T13:27:55.874784Z",
"creators": [
"Tool: trivy",
"Organization: aquasecurity"
]
},
"dataLicense": "CC0-1.0",
"documentNamespace": "http://aquasecurity.github.io/trivy/container_image/integration/testdata/fixtures/images/centos-7.tar.gz-2906855d-5098-4a22-9a72-4f7099ea3d66",
"name": "integration/testdata/fixtures/images/centos-7.tar.gz",
"packages": [
{
"SPDXID": "SPDXRef-ContainerImage-dd5cad897c6263",
"attributionTexts": [
"SchemaVersion: 2",
"ImageID: sha256:f1cb7c7d58b73eac859c395882eec49d50651244e342cd6c68a5c7809785f427",
"DiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a"
],
"filesAnalyzed": false,
"name": "integration/testdata/fixtures/images/centos-7.tar.gz"
},
{
"SPDXID": "SPDXRef-OperatingSystem-2e91c856c499a371",
"filesAnalyzed": false,
"name": "centos",
"versionInfo": "7.6.1810"
},
{
"SPDXID": "SPDXRef-Package-5a18334f22149877",
"attributionTexts": [
"LayerDigest: sha256:ac9208207adaac3a48e54a4dc6b49c69e78c3072d2b3add7efdabf814db2133b",
"LayerDiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a"
],
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64\u0026distro=centos-7.6.1810",
"referenceType": "purl"
}
],
"filesAnalyzed": false,
"licenseConcluded": "GPLv3+",
"licenseDeclared": "GPLv3+",
"name": "bash",
"sourceInfo": "built package from: bash 4.2.46-31.el7",
"versionInfo": "4.2.46"
},
{
"SPDXID": "SPDXRef-Package-e16b1cbaa5186199",
"attributionTexts": [
"LayerDigest: sha256:ac9208207adaac3a48e54a4dc6b49c69e78c3072d2b3add7efdabf814db2133b",
"LayerDiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a"
],
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceLocator": "pkg:rpm/centos/openssl-libs@1:1.0.2k-16.el7?arch=x86_64\u0026distro=centos-7.6.1810",
"referenceType": "purl"
}
],
"filesAnalyzed": false,
"licenseConcluded": "OpenSSL",
"licenseDeclared": "OpenSSL",
"name": "openssl-libs",
"sourceInfo": "built package from: openssl-libs 1:1.0.2k-16.el7",
"versionInfo": "1.0.2k"
}
],
"relationships": [
{
"relatedSpdxElement": "SPDXRef-ContainerImage-dd5cad897c6263",
"relationshipType": "DESCRIBE",
"spdxElementId": "SPDXRef-DOCUMENT"
},
{
"relatedSpdxElement": "SPDXRef-OperatingSystem-2e91c856c499a371",
"relationshipType": "CONTAINS",
"spdxElementId": "SPDXRef-ContainerImage-dd5cad897c6263"
},
{
"relatedSpdxElement": "SPDXRef-Package-5a18334f22149877",
"relationshipType": "CONTAINS",
"spdxElementId": "SPDXRef-OperatingSystem-2e91c856c499a371"
},
{
"relatedSpdxElement": "SPDXRef-Package-e16b1cbaa5186199",
"relationshipType": "CONTAINS",
"spdxElementId": "SPDXRef-OperatingSystem-2e91c856c499a371"
}
],
"spdxVersion": "SPDX-2.2"
}
57 changes: 57 additions & 0 deletions integration/testdata/fixtures/sbom/centos-7-spdx.txt
@@ -0,0 +1,57 @@
SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: integration/testdata/fixtures/images/centos-7.tar.gz
DocumentNamespace: http://aquasecurity.github.io/trivy/container_image/integration/testdata/fixtures/images/centos-7.tar.gz-6a2c050f-bc12-46dc-b2df-1f4e3e0b5e1d
Creator: Organization: aquasecurity
Creator: Tool: trivy
Created: 2022-09-13T13:24:58.796907Z

##### Package: integration/testdata/fixtures/images/centos-7.tar.gz

PackageName: integration/testdata/fixtures/images/centos-7.tar.gz
SPDXID: SPDXRef-ContainerImage-dd5cad897c6263
FilesAnalyzed: false
PackageAttributionText: SchemaVersion: 2
PackageAttributionText: ImageID: sha256:f1cb7c7d58b73eac859c395882eec49d50651244e342cd6c68a5c7809785f427
PackageAttributionText: DiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a

##### Package: centos

PackageName: centos
SPDXID: SPDXRef-OperatingSystem-2e91c856c499a371
PackageVersion: 7.6.1810
FilesAnalyzed: false

##### Package: bash

PackageName: bash
SPDXID: SPDXRef-Package-5a18334f22149877
PackageVersion: 4.2.46
FilesAnalyzed: false
PackageSourceInfo: built package from: bash 4.2.46-31.el7
PackageLicenseConcluded: GPLv3+
PackageLicenseDeclared: GPLv3+
ExternalRef: PACKAGE-MANAGER purl pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810
PackageAttributionText: LayerDigest: sha256:ac9208207adaac3a48e54a4dc6b49c69e78c3072d2b3add7efdabf814db2133b
PackageAttributionText: LayerDiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a

##### Package: openssl-libs

PackageName: openssl-libs
SPDXID: SPDXRef-Package-e16b1cbaa5186199
PackageVersion: 1.0.2k
FilesAnalyzed: false
PackageSourceInfo: built package from: openssl-libs 1:1.0.2k-16.el7
PackageLicenseConcluded: OpenSSL
PackageLicenseDeclared: OpenSSL
ExternalRef: PACKAGE-MANAGER purl pkg:rpm/centos/openssl-libs@1:1.0.2k-16.el7?arch=x86_64&distro=centos-7.6.1810
PackageAttributionText: LayerDigest: sha256:ac9208207adaac3a48e54a4dc6b49c69e78c3072d2b3add7efdabf814db2133b
PackageAttributionText: LayerDiffID: sha256:89169d87dbe2b72ba42bfbb3579c957322baca28e03a1e558076542a1c1b2b4a

##### Relationships

Relationship: SPDXRef-DOCUMENT DESCRIBE SPDXRef-ContainerImage-dd5cad897c6263
Relationship: SPDXRef-ContainerImage-dd5cad897c6263 CONTAINS SPDXRef-OperatingSystem-2e91c856c499a371
Relationship: SPDXRef-OperatingSystem-2e91c856c499a371 DEPENDS_ON SPDXRef-Package-5a18334f22149877
Relationship: SPDXRef-OperatingSystem-2e91c856c499a371 DEPENDS_ON SPDXRef-Package-e16b1cbaa5186199
11 changes: 11 additions & 0 deletions pkg/fanal/artifact/sbom/sbom.go
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/sbom"
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
"github.com/aquasecurity/trivy/pkg/sbom/spdx"
)

type Artifact struct {
Expand Down Expand Up @@ -83,6 +84,9 @@ func (a Artifact) Inspect(_ context.Context) (types.ArtifactReference, error) {
switch format {
case sbom.FormatCycloneDXJSON, sbom.FormatCycloneDXXML, sbom.FormatAttestCycloneDXJSON:
artifactType = types.ArtifactCycloneDX
case sbom.FormatSPDXTV, sbom.FormatSPDXJSON:
artifactType = types.ArtifactSPDX

}

return types.ArtifactReference{
Expand Down Expand Up @@ -117,6 +121,13 @@ func (a Artifact) Decode(f io.Reader, format sbom.Format) (sbom.SBOM, error) {
},
}
decoder = json.NewDecoder(f)
case sbom.FormatSPDXJSON:
v = &spdx.SPDX{SBOM: &bom}
decoder = json.NewDecoder(f)
case sbom.FormatSPDXTV:
v = &spdx.SPDX{SBOM: &bom}
decoder = spdx.NewTVDecoder(f)

default:
return sbom.SBOM{}, xerrors.Errorf("%s scanning is not yet supported", format)

Expand Down

0 comments on commit 9f6680a

Please sign in to comment.