diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp index f85a46f6c2..ef5c760cfc 100644 --- a/tools/compliance/Android.bp +++ b/tools/compliance/Android.bp @@ -142,6 +142,7 @@ blueprint_go_binary { "spdx-tools-builder2v2", "spdx-tools-spdxcommon", "spdx-tools-spdx-json", + "spdx-tools-spdxlib", ], testSrcs: ["cmd/sbom/sbom_test.go"], } diff --git a/tools/compliance/cmd/sbom/sbom.go b/tools/compliance/cmd/sbom/sbom.go index 3cdfa0a889..c378e39efd 100644 --- a/tools/compliance/cmd/sbom/sbom.go +++ b/tools/compliance/cmd/sbom/sbom.go @@ -38,6 +38,7 @@ import ( "github.com/spdx/tools-golang/json" "github.com/spdx/tools-golang/spdx/common" spdx "github.com/spdx/tools-golang/spdx/v2_2" + "github.com/spdx/tools-golang/spdxlib" ) var ( @@ -173,6 +174,7 @@ Options: os.Exit(1) } + // writing the spdx Doc created if err := spdx_json.Save2_2(spdxDoc, ofile); err != nil { fmt.Fprintf(os.Stderr, "failed to write document to %v: %v", *outputFile, err) os.Exit(1) @@ -516,7 +518,7 @@ func sbomGenerator(ctx *context, files ...string) (*spdx.Document, []string, err ci.Created = ctx.creationTime() - return &spdx.Document{ + doc := &spdx.Document{ SPDXVersion: "SPDX-2.2", DataLicense: "CC0-1.0", SPDXIdentifier: "DOCUMENT", @@ -526,5 +528,11 @@ func sbomGenerator(ctx *context, files ...string) (*spdx.Document, []string, err Packages: pkgs, Relationships: relationships, OtherLicenses: otherLicenses, - }, deps, nil + } + + if err := spdxlib.ValidateDocument2_2(doc); err != nil { + return nil, nil, fmt.Errorf("Unable to validate the SPDX doc: %v\n", err) + } + + return doc, deps, nil } diff --git a/tools/compliance/cmd/sbom/sbom_test.go b/tools/compliance/cmd/sbom/sbom_test.go index 65a2df148f..6472f517cb 100644 --- a/tools/compliance/cmd/sbom/sbom_test.go +++ b/tools/compliance/cmd/sbom/sbom_test.go @@ -2226,6 +2226,10 @@ func Test(t *testing.T) { t.Errorf("sbom: gotStderr = %v, want none", stderr) } + if err := validate(spdxDoc); err != nil { + t.Fatalf("sbom: document fails to validate: %v", err) + } + gotData, err := json.Marshal(spdxDoc) if err != nil { t.Fatalf("sbom: failed to marshal spdx doc: %v", err) @@ -2267,6 +2271,36 @@ func getCreationInfo(t *testing.T) *spdx.CreationInfo { return ci } +// validate returns an error if the Document is found to be invalid +func validate(doc *spdx.Document) error { + if doc.SPDXVersion == "" { + return fmt.Errorf("SPDXVersion: got nothing, want spdx version") + } + if doc.DataLicense == "" { + return fmt.Errorf("DataLicense: got nothing, want Data License") + } + if doc.SPDXIdentifier == "" { + return fmt.Errorf("SPDXIdentifier: got nothing, want SPDX Identifier") + } + if doc.DocumentName == "" { + return fmt.Errorf("DocumentName: got nothing, want Document Name") + } + if fmt.Sprintf("%v", doc.CreationInfo.Creators[1].Creator) != "Google LLC" { + return fmt.Errorf("Creator: got %v, want 'Google LLC'") + } + _, err := time.Parse(time.RFC3339, doc.CreationInfo.Created) + if err != nil { + return fmt.Errorf("Invalid time spec: %q: got error %q, want no error", doc.CreationInfo.Created, err) + } + + for _, license := range doc.OtherLicenses { + if license.ExtractedText == "" { + return fmt.Errorf("License file: %q: got nothing, want license text", license.LicenseName) + } + } + return nil +} + // compareSpdxDocs deep-compares two spdx docs by going through the info section, packages, relationships and licenses func compareSpdxDocs(t *testing.T, actual, expected *spdx.Document) {