Merge "Added Document Fields to SBOM generator" am: aeeea61aa0

Original change: https://android-review.googlesource.com/c/platform/build/+/2521055

Change-Id: Id8010c266ac0d7f915b093276e40b9f4c828d92d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Ibrahim Kanouche 2023-04-05 20:50:59 +00:00 committed by Automerger Merge Worker
commit ac35dfa24a
2 changed files with 217 additions and 61 deletions

View file

@ -16,6 +16,8 @@ package main
import (
"bytes"
"crypto/sha1"
"encoding/hex"
"flag"
"fmt"
"io"
@ -194,11 +196,12 @@ Options:
os.Exit(0)
}
type creationTimeGetter func() time.Time
type creationTimeGetter func() string
// actualTime returns current time in UTC
func actualTime() time.Time {
return time.Now().UTC()
func actualTime() string {
t := time.Now().UTC()
return t.UTC().Format("2006-01-02T15:04:05Z")
}
// replaceSlashes replaces "/" by "-" for the library path to be used for packages & files SPDXID
@ -206,6 +209,23 @@ func replaceSlashes(x string) string {
return strings.ReplaceAll(x, "/", "-")
}
// stripDocName removes the outdir prefix and meta_lic suffix from a target Name
func stripDocName(name string) string {
// remove outdir prefix
if strings.HasPrefix(name, "out/") {
name = name[4:]
}
// remove suffix
if strings.HasSuffix(name, ".meta_lic") {
name = name[:len(name)-9]
} else if strings.HasSuffix(name, "/meta_lic") {
name = name[:len(name)-9] + "/"
}
return name
}
// getPackageName returns a package name of a target Node
func getPackageName(_ *context, tn *compliance.TargetNode) string {
return replaceSlashes(tn.Name())
@ -223,8 +243,7 @@ func getDocumentName(ctx *context, tn *compliance.TargetNode, pm *projectmetadat
return replaceSlashes(tn.ModuleName())
}
// TO DO: Replace tn.Name() with pm.Name() + parts of the target name
return replaceSlashes(tn.Name())
return stripDocName(replaceSlashes(tn.Name()))
}
// getDownloadUrl returns the download URL if available (GIT, SVN, etc..),
@ -295,6 +314,19 @@ func inputFiles(lg *compliance.LicenseGraph, pmix *projectmetadata.Index, licens
return files
}
// generateSPDXNamespace generates a unique SPDX Document Namespace using a SHA1 checksum
// and the CreationInfo.Created field as the date.
func generateSPDXNamespace(created string) string {
// Compute a SHA1 checksum of the CreationInfo.Created field.
hash := sha1.Sum([]byte(created))
checksum := hex.EncodeToString(hash[:])
// Combine the checksum and timestamp to generate the SPDX Namespace.
namespace := fmt.Sprintf("SPDXRef-DOCUMENT-%s-%s", created, checksum)
return namespace
}
// sbomGenerator implements the spdx bom utility
// SBOM is part of the new government regulation issued to improve national cyber security
@ -325,8 +357,11 @@ func sbomGenerator(ctx *context, files ...string) (*spdx.Document, []string, err
// creating the license section
otherLicenses := []*spdx.OtherLicense{}
// main package name
var mainPkgName string
// spdx document name
var docName string
// main package name
var mainPkgName string
// implementing the licenses references for the packages
licenses := make(map[string]string)
@ -365,6 +400,7 @@ func sbomGenerator(ctx *context, files ...string) (*spdx.Document, []string, err
}
if isMainPackage {
docName = getDocumentName(ctx, tn, pm)
mainPkgName = replaceSlashes(getPackageName(ctx, tn))
isMainPackage = false
}
@ -478,11 +514,17 @@ func sbomGenerator(ctx *context, files ...string) (*spdx.Document, []string, err
return nil, nil, fmt.Errorf("Unable to build creation info section for SPDX doc: %v\n", err)
}
ci.Created = ctx.creationTime()
return &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: ci,
Packages: pkgs,
Relationships: relationships,
OtherLicenses: otherLicenses,
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: docName,
DocumentNamespace: generateSPDXNamespace(ci.Created),
CreationInfo: ci,
Packages: pkgs,
Relationships: relationships,
OtherLicenses: otherLicenses,
}, deps, nil
}

View file

@ -55,8 +55,12 @@ func Test(t *testing.T) {
name: "apex",
roots: []string{"highest.apex.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-firstparty-highest.apex",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-firstparty-highest.apex.meta_lic",
@ -179,8 +183,12 @@ func Test(t *testing.T) {
name: "application",
roots: []string{"application.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-firstparty-application",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-firstparty-application.meta_lic",
@ -254,8 +262,12 @@ func Test(t *testing.T) {
name: "container",
roots: []string{"container.zip.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-firstparty-container.zip",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-firstparty-container.zip.meta_lic",
@ -378,8 +390,12 @@ func Test(t *testing.T) {
name: "binary",
roots: []string{"bin/bin1.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-firstparty-bin-bin1",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-firstparty-bin-bin1.meta_lic",
@ -440,8 +456,12 @@ func Test(t *testing.T) {
name: "library",
roots: []string{"lib/libd.so.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-firstparty-lib-libd.so",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-firstparty-lib-libd.so.meta_lic",
@ -476,8 +496,12 @@ func Test(t *testing.T) {
name: "apex",
roots: []string{"highest.apex.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-notice-highest.apex",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-notice-highest.apex.meta_lic",
@ -606,8 +630,12 @@ func Test(t *testing.T) {
name: "container",
roots: []string{"container.zip.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-notice-container.zip",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-notice-container.zip.meta_lic",
@ -736,8 +764,12 @@ func Test(t *testing.T) {
name: "application",
roots: []string{"application.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-notice-application",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-notice-application.meta_lic",
@ -817,8 +849,12 @@ func Test(t *testing.T) {
name: "binary",
roots: []string{"bin/bin1.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-notice-bin-bin1",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-notice-bin-bin1.meta_lic",
@ -885,8 +921,12 @@ func Test(t *testing.T) {
name: "library",
roots: []string{"lib/libd.so.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-notice-lib-libd.so",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-notice-lib-libd.so.meta_lic",
@ -921,8 +961,12 @@ func Test(t *testing.T) {
name: "apex",
roots: []string{"highest.apex.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-reciprocal-highest.apex",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-reciprocal-highest.apex.meta_lic",
@ -1057,8 +1101,12 @@ func Test(t *testing.T) {
name: "application",
roots: []string{"application.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-reciprocal-application",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-reciprocal-application.meta_lic",
@ -1144,8 +1192,12 @@ func Test(t *testing.T) {
name: "binary",
roots: []string{"bin/bin1.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-reciprocal-bin-bin1",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-reciprocal-bin-bin1.meta_lic",
@ -1212,8 +1264,12 @@ func Test(t *testing.T) {
name: "library",
roots: []string{"lib/libd.so.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-reciprocal-lib-libd.so",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-reciprocal-lib-libd.so.meta_lic",
@ -1248,8 +1304,12 @@ func Test(t *testing.T) {
name: "apex",
roots: []string{"highest.apex.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-restricted-highest.apex",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-restricted-highest.apex.meta_lic",
@ -1390,8 +1450,12 @@ func Test(t *testing.T) {
name: "container",
roots: []string{"container.zip.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-restricted-container.zip",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-restricted-container.zip.meta_lic",
@ -1532,8 +1596,12 @@ func Test(t *testing.T) {
name: "binary",
roots: []string{"bin/bin1.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-restricted-bin-bin1",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-restricted-bin-bin1.meta_lic",
@ -1606,8 +1674,12 @@ func Test(t *testing.T) {
name: "library",
roots: []string{"lib/libd.so.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-restricted-lib-libd.so",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-restricted-lib-libd.so.meta_lic",
@ -1642,8 +1714,12 @@ func Test(t *testing.T) {
name: "apex",
roots: []string{"highest.apex.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-proprietary-highest.apex",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-proprietary-highest.apex.meta_lic",
@ -1784,8 +1860,12 @@ func Test(t *testing.T) {
name: "container",
roots: []string{"container.zip.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-proprietary-container.zip",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-proprietary-container.zip.meta_lic",
@ -1926,8 +2006,12 @@ func Test(t *testing.T) {
name: "application",
roots: []string{"application.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-proprietary-application",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-proprietary-application.meta_lic",
@ -2013,8 +2097,12 @@ func Test(t *testing.T) {
name: "binary",
roots: []string{"bin/bin1.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-proprietary-bin-bin1",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-proprietary-bin-bin1.meta_lic",
@ -2081,8 +2169,12 @@ func Test(t *testing.T) {
name: "library",
roots: []string{"lib/libd.so.meta_lic"},
expectedOut: &spdx.Document{
SPDXIdentifier: "DOCUMENT",
CreationInfo: getCreationInfo(t),
SPDXVersion: "SPDX-2.2",
DataLicense: "CC0-1.0",
SPDXIdentifier: "DOCUMENT",
DocumentName: "testdata-proprietary-lib-libd.so",
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
CreationInfo: getCreationInfo(t),
Packages: []*spdx.Package{
{
PackageName: "testdata-proprietary-lib-libd.so.meta_lic",
@ -2123,7 +2215,7 @@ func Test(t *testing.T) {
rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
}
ctx := context{stdout, stderr, compliance.GetFS(tt.outDir), "Android", []string{tt.stripPrefix}, fakeTime}
ctx := context{stdout, stderr, compliance.GetFS(tt.outDir), "", []string{tt.stripPrefix}, fakeTime}
spdxDoc, deps, err := sbomGenerator(&ctx, rootFiles...)
if err != nil {
@ -2181,6 +2273,27 @@ func compareSpdxDocs(t *testing.T, actual, expected *spdx.Document) {
if actual == nil || expected == nil {
t.Errorf("SBOM: SPDX Doc is nil! Got %v: Expected %v", actual, expected)
}
if actual.DocumentName != expected.DocumentName {
t.Errorf("sbom: unexpected SPDX Document Name got %q, want %q", actual.DocumentName, expected.DocumentName)
}
if actual.SPDXVersion != expected.SPDXVersion {
t.Errorf("sbom: unexpected SPDX Version got %s, want %s", actual.SPDXVersion, expected.SPDXVersion)
}
if actual.DataLicense != expected.DataLicense {
t.Errorf("sbom: unexpected SPDX DataLicense got %s, want %s", actual.DataLicense, expected.DataLicense)
}
if actual.SPDXIdentifier != expected.SPDXIdentifier {
t.Errorf("sbom: unexpected SPDX Identified got %s, want %s", actual.SPDXIdentifier, expected.SPDXIdentifier)
}
if actual.DocumentNamespace != expected.DocumentNamespace {
t.Errorf("sbom: unexpected SPDX Document Namespace got %s, want %s", actual.DocumentNamespace, expected.DocumentNamespace)
}
// compare creation info
compareSpdxCreationInfo(t, actual.CreationInfo, expected.CreationInfo)
@ -2314,6 +2427,7 @@ func compareLicenses(t *testing.T, i int, actual, expected *spdx.OtherLicense) b
return true
}
func fakeTime() time.Time {
return time.UnixMicro(0).UTC()
func fakeTime() string {
t := time.UnixMicro(0)
return t.UTC().Format("2006-01-02T15:04:05Z")
}