diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp index 2527df727b..8e13f2f661 100644 --- a/tools/compliance/Android.bp +++ b/tools/compliance/Android.bp @@ -131,6 +131,17 @@ blueprint_go_binary { testSrcs: ["cmd/xmlnotice/xmlnotice_test.go"], } +blueprint_go_binary { + name: "compliance_sbom", + srcs: ["cmd/sbom/sbom.go"], + deps: [ + "compliance-module", + "blueprint-deptools", + "soong-response", + ], + testSrcs: ["cmd/sbom/sbom_test.go"], +} + bootstrap_go_package { name: "compliance-module", srcs: [ diff --git a/tools/compliance/cmd/sbom/sbom.go b/tools/compliance/cmd/sbom/sbom.go new file mode 100644 index 0000000000..afb377efb7 --- /dev/null +++ b/tools/compliance/cmd/sbom/sbom.go @@ -0,0 +1,399 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bytes" + "flag" + "fmt" + "io" + "io/fs" + "os" + "path/filepath" + "sort" + "strings" + "time" + + "android/soong/response" + "android/soong/tools/compliance" + "android/soong/tools/compliance/projectmetadata" + + "github.com/google/blueprint/deptools" +) + +var ( + failNoneRequested = fmt.Errorf("\nNo license metadata files requested") + failNoLicenses = fmt.Errorf("No licenses found") +) + +type context struct { + stdout io.Writer + stderr io.Writer + rootFS fs.FS + product string + stripPrefix []string + creationTime creationTimeGetter +} + +func (ctx context) strip(installPath string) string { + for _, prefix := range ctx.stripPrefix { + if strings.HasPrefix(installPath, prefix) { + p := strings.TrimPrefix(installPath, prefix) + if 0 == len(p) { + p = ctx.product + } + if 0 == len(p) { + continue + } + return p + } + } + return installPath +} + +// newMultiString creates a flag that allows multiple values in an array. +func newMultiString(flags *flag.FlagSet, name, usage string) *multiString { + var f multiString + flags.Var(&f, name, usage) + return &f +} + +// multiString implements the flag `Value` interface for multiple strings. +type multiString []string + +func (ms *multiString) String() string { return strings.Join(*ms, ", ") } +func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil } + +func main() { + var expandedArgs []string + for _, arg := range os.Args[1:] { + if strings.HasPrefix(arg, "@") { + f, err := os.Open(strings.TrimPrefix(arg, "@")) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + + respArgs, err := response.ReadRspFile(f) + f.Close() + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + expandedArgs = append(expandedArgs, respArgs...) + } else { + expandedArgs = append(expandedArgs, arg) + } + } + + flags := flag.NewFlagSet("flags", flag.ExitOnError) + + flags.Usage = func() { + fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...} + +Outputs an SBOM.spdx. + +Options: +`, filepath.Base(os.Args[0])) + flags.PrintDefaults() + } + + outputFile := flags.String("o", "-", "Where to write the SBOM spdx file. (default stdout)") + depsFile := flags.String("d", "", "Where to write the deps file") + product := flags.String("product", "", "The name of the product for which the notice is generated.") + stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)") + + flags.Parse(expandedArgs) + + // Must specify at least one root target. + if flags.NArg() == 0 { + flags.Usage() + os.Exit(2) + } + + if len(*outputFile) == 0 { + flags.Usage() + fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n") + os.Exit(2) + } else { + dir, err := filepath.Abs(filepath.Dir(*outputFile)) + if err != nil { + fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err) + os.Exit(1) + } + fi, err := os.Stat(dir) + if err != nil { + fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err) + os.Exit(1) + } + if !fi.IsDir() { + fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile) + os.Exit(1) + } + } + + var ofile io.Writer + ofile = os.Stdout + var obuf *bytes.Buffer + if *outputFile != "-" { + obuf = &bytes.Buffer{} + ofile = obuf + } + + ctx := &context{ofile, os.Stderr, compliance.FS, *product, *stripPrefix, actualTime} + + deps, err := sbomGenerator(ctx, flags.Args()...) + if err != nil { + if err == failNoneRequested { + flags.Usage() + } + fmt.Fprintf(os.Stderr, "%s\n", err.Error()) + os.Exit(1) + } + + if *outputFile != "-" { + err := os.WriteFile(*outputFile, obuf.Bytes(), 0666) + if err != nil { + fmt.Fprintf(os.Stderr, "could not write output to %q: %s\n", *outputFile, err) + os.Exit(1) + } + } + + if *depsFile != "" { + err := deptools.WriteDepFile(*depsFile, *outputFile, deps) + if err != nil { + fmt.Fprintf(os.Stderr, "could not write deps to %q: %s\n", *depsFile, err) + os.Exit(1) + } + } + os.Exit(0) +} + +type creationTimeGetter func() time.Time + +// actualTime returns current time in UTC +func actualTime() time.Time { + return time.Now().UTC() +} + +// replaceSlashes replaces "/" by "-" for the library path to be used for packages & files SPDXID +func replaceSlashes(x string) string { + return strings.ReplaceAll(x, "/", "-") +} + +// getPackageName returns a package name of a target Node +func getPackageName(_ *context, tn *compliance.TargetNode) string { + return replaceSlashes(tn.Name()) +} + +// getDocumentName returns a package name of a target Node +func getDocumentName(ctx *context, tn *compliance.TargetNode, pm *projectmetadata.ProjectMetadata) string { + if len(ctx.product) > 0 { + return replaceSlashes(ctx.product) + } + if len(tn.ModuleName()) > 0 { + if pm != nil { + return replaceSlashes(pm.Name() + ":" + tn.ModuleName()) + } + return replaceSlashes(tn.ModuleName()) + } + + // TO DO: Replace tn.Name() with pm.Name() + parts of the target name + return replaceSlashes(tn.Name()) +} + +// getDownloadUrl returns the download URL if available (GIT, SVN, etc..), +// or NOASSERTION if not available, none determined or ambiguous +func getDownloadUrl(_ *context, pm *projectmetadata.ProjectMetadata) string { + if pm == nil { + return "NOASSERTION" + } + + urlsByTypeName := pm.UrlsByTypeName() + if urlsByTypeName == nil { + return "NOASSERTION" + } + + url := urlsByTypeName.DownloadUrl() + if url == "" { + return "NOASSERTION" + } + return url +} + +// getProjectMetadata returns the project metadata for the target node +func getProjectMetadata(_ *context, pmix *projectmetadata.Index, + tn *compliance.TargetNode) (*projectmetadata.ProjectMetadata, error) { + pms, err := pmix.MetadataForProjects(tn.Projects()...) + if err != nil { + return nil, fmt.Errorf("Unable to read projects for %q: %w\n", tn, err) + } + if len(pms) == 0 { + return nil, nil + } + + // TO DO: skip first element if it doesn't have one of the three info needed + return pms[0], nil +} + +// sbomGenerator implements the spdx bom utility + +// SBOM is part of the new government regulation issued to improve national cyber security +// and enhance software supply chain and transparency, see https://www.cisa.gov/sbom + +// sbomGenerator uses the SPDX standard, see the SPDX specification (https://spdx.github.io/spdx-spec/) +// sbomGenerator is also following the internal google SBOM styleguide (http://goto.google.com/spdx-style-guide) +func sbomGenerator(ctx *context, files ...string) ([]string, error) { + // Must be at least one root file. + if len(files) < 1 { + return nil, failNoneRequested + } + + pmix := projectmetadata.NewIndex(ctx.rootFS) + + lg, err := compliance.ReadLicenseGraph(ctx.rootFS, ctx.stderr, files) + + if err != nil { + return nil, fmt.Errorf("Unable to read license text file(s) for %q: %v\n", files, err) + } + + // implementing the licenses references for the packages + licenses := make(map[string]string) + concludedLicenses := func(licenseTexts []string) string { + licenseRefs := make([]string, 0, len(licenseTexts)) + for _, licenseText := range licenseTexts { + license := strings.SplitN(licenseText, ":", 2)[0] + if _, ok := licenses[license]; !ok { + licenseRef := "LicenseRef-" + replaceSlashes(license) + licenses[license] = licenseRef + } + + licenseRefs = append(licenseRefs, licenses[license]) + } + if len(licenseRefs) > 1 { + return "(" + strings.Join(licenseRefs, " AND ") + ")" + } else if len(licenseRefs) == 1 { + return licenseRefs[0] + } + return "NONE" + } + + isMainPackage := true + var mainPackage string + visitedNodes := make(map[*compliance.TargetNode]struct{}) + + // performing a Breadth-first top down walk of licensegraph and building package information + compliance.WalkTopDownBreadthFirst(nil, lg, + func(lg *compliance.LicenseGraph, tn *compliance.TargetNode, path compliance.TargetEdgePath) bool { + if err != nil { + return false + } + var pm *projectmetadata.ProjectMetadata + pm, err = getProjectMetadata(ctx, pmix, tn) + if err != nil { + return false + } + + if isMainPackage { + mainPackage = getDocumentName(ctx, tn, pm) + fmt.Fprintf(ctx.stdout, "SPDXVersion: SPDX-2.2\n") + fmt.Fprintf(ctx.stdout, "DataLicense: CC-1.0\n") + fmt.Fprintf(ctx.stdout, "DocumentName: %s\n", mainPackage) + fmt.Fprintf(ctx.stdout, "SPDXID: SPDXRef-DOCUMENT-%s\n", mainPackage) + fmt.Fprintf(ctx.stdout, "DocumentNamespace: Android\n") + fmt.Fprintf(ctx.stdout, "Creator: Organization: Google LLC\n") + fmt.Fprintf(ctx.stdout, "Created: %s\n", ctx.creationTime().Format("2006-01-02T15:04:05Z")) + isMainPackage = false + } + + relationships := make([]string, 0, 1) + defer func() { + if r := recover(); r != nil { + panic(r) + } + for _, relationship := range relationships { + fmt.Fprintln(ctx.stdout, relationship) + } + }() + if len(path) == 0 { + relationships = append(relationships, + fmt.Sprintf("Relationship: SPDXRef-DOCUMENT-%s DESCRIBES SPDXRef-Package-%s", + mainPackage, getPackageName(ctx, tn))) + } else { + // Check parent and identify annotation + parent := path[len(path)-1] + targetEdge := parent.Edge() + if targetEdge.IsRuntimeDependency() { + // Adding the dynamic link annotation RUNTIME_DEPENDENCY_OF relationship + relationships = append(relationships, fmt.Sprintf("Relationship: SPDXRef-Package-%s RUNTIME_DEPENDENCY_OF SPDXRef-Package-%s", getPackageName(ctx, tn), getPackageName(ctx, targetEdge.Target()))) + + } else if targetEdge.IsDerivation() { + // Adding the derivation annotation as a CONTAINS relationship + relationships = append(relationships, fmt.Sprintf("Relationship: SPDXRef-Package-%s CONTAINS SPDXRef-Package-%s", getPackageName(ctx, targetEdge.Target()), getPackageName(ctx, tn))) + + } else if targetEdge.IsBuildTool() { + // Adding the toolchain annotation as a BUILD_TOOL_OF relationship + relationships = append(relationships, fmt.Sprintf("Relationship: SPDXRef-Package-%s BUILD_TOOL_OF SPDXRef-Package-%s", getPackageName(ctx, tn), getPackageName(ctx, targetEdge.Target()))) + } else { + panic(fmt.Errorf("Unknown dependency type: %v", targetEdge.Annotations())) + } + } + + if _, alreadyVisited := visitedNodes[tn]; alreadyVisited { + return false + } + visitedNodes[tn] = struct{}{} + pkgName := getPackageName(ctx, tn) + fmt.Fprintf(ctx.stdout, "##### Package: %s\n", strings.Replace(pkgName, "-", "/", -2)) + fmt.Fprintf(ctx.stdout, "PackageName: %s\n", pkgName) + if pm != nil && pm.Version() != "" { + fmt.Fprintf(ctx.stdout, "PackageVersion: %s\n", pm.Version()) + } + fmt.Fprintf(ctx.stdout, "SPDXID: SPDXRef-Package-%s\n", pkgName) + fmt.Fprintf(ctx.stdout, "PackageDownloadLocation: %s\n", getDownloadUrl(ctx, pm)) + fmt.Fprintf(ctx.stdout, "PackageLicenseConcluded: %s\n", concludedLicenses(tn.LicenseTexts())) + return true + }) + + fmt.Fprintf(ctx.stdout, "##### Non-standard license:\n") + + licenseTexts := make([]string, 0, len(licenses)) + + for licenseText := range licenses { + licenseTexts = append(licenseTexts, licenseText) + } + + sort.Strings(licenseTexts) + + for _, licenseText := range licenseTexts { + fmt.Fprintf(ctx.stdout, "LicenseID: %s\n", licenses[licenseText]) + // open the file + f, err := ctx.rootFS.Open(filepath.Clean(licenseText)) + if err != nil { + return nil, fmt.Errorf("error opening license text file %q: %w", licenseText, err) + } + + // read the file + text, err := io.ReadAll(f) + if err != nil { + return nil, fmt.Errorf("error reading license text file %q: %w", licenseText, err) + } + // adding the extracted license text + fmt.Fprintf(ctx.stdout, "ExtractedText: %v\n", string(text)) + } + + deps := licenseTexts + return deps, nil +} diff --git a/tools/compliance/cmd/sbom/sbom_test.go b/tools/compliance/cmd/sbom/sbom_test.go new file mode 100644 index 0000000000..5e70580137 --- /dev/null +++ b/tools/compliance/cmd/sbom/sbom_test.go @@ -0,0 +1,1629 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "bufio" + "bytes" + "fmt" + "os" + "reflect" + "regexp" + "strings" + "testing" + "time" + + "android/soong/tools/compliance" +) + +var ( + spdxVersionTag = regexp.MustCompile(`^\s*SPDXVersion: SPDX-2.2\s*$`) + spdxDataLicenseTag = regexp.MustCompile(`^\s*DataLicense: CC-1.0\s*$`) + spdxDocumentNameTag = regexp.MustCompile(`^\s*DocumentName:\s*Android*\s*$`) + spdxIDTag = regexp.MustCompile(`^\s*SPDXID:\s*SPDXRef-DOCUMENT-(.*)\s*$`) + spdxDocumentNameSpaceTag = regexp.MustCompile(`^\s*DocumentNamespace:\s*Android\s*$`) + spdxCreatorOrganizationTag = regexp.MustCompile(`^\s*Creator:\s*Organization:\s*Google LLC\s*$`) + spdxCreatedTimeTag = regexp.MustCompile(`^\s*Created: 1970-01-01T00:00:00Z\s*$`) + spdxPackageTag = regexp.MustCompile(`^\s*#####\s*Package:\s*(.*)\s*$`) + spdxPackageNameTag = regexp.MustCompile(`^\s*PackageName:\s*(.*)\s*$`) + spdxPkgIDTag = regexp.MustCompile(`^\s*SPDXID:\s*SPDXRef-Package-(.*)\s*$`) + spdxPkgDownloadLocationTag = regexp.MustCompile(`^\s*PackageDownloadLocation:\s*NOASSERTION\s*$`) + spdxPkgLicenseDeclaredTag = regexp.MustCompile(`^\s*PackageLicenseConcluded:\s*LicenseRef-(.*)\s*$`) + spdxRelationshipTag = regexp.MustCompile(`^\s*Relationship:\s*SPDXRef-(.*)\s*(DESCRIBES|CONTAINS|BUILD_TOOL_OF|RUNTIME_DEPENDENCY_OF)\s*SPDXRef-Package-(.*)\s*$`) + spdxLicenseTag = regexp.MustCompile(`^\s*##### Non-standard license:\s*$`) + spdxLicenseIDTag = regexp.MustCompile(`^\s*LicenseID: LicenseRef-(.*)\s*$`) + spdxExtractedTextTag = regexp.MustCompile(`^\s*ExtractedText:\s*(.*)\s*$`) + spdxExtractedClosingTextTag = regexp.MustCompile(`^\s*\s*$`) +) + +func TestMain(m *testing.M) { + // Change into the parent directory before running the tests + // so they can find the testdata directory. + if err := os.Chdir(".."); err != nil { + fmt.Printf("failed to change to testdata directory: %s\n", err) + os.Exit(1) + } + os.Exit(m.Run()) +} + +func Test(t *testing.T) { + tests := []struct { + condition string + name string + outDir string + roots []string + stripPrefix string + expectedOut []matcher + expectedDeps []string + }{ + { + condition: "firstparty", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/firstparty/highest.apex.meta_lic"}, + packageName{"testdata/firstparty/highest.apex.meta_lic"}, + spdxPkgID{"testdata/firstparty/highest.apex.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata-firstparty-highest.apex.meta_lic", "DESCRIBES"}, + packageTag{"testdata/firstparty/bin/bin1.meta_lic"}, + packageName{"testdata/firstparty/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/firstparty/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/highest.apex.meta_lic ", "testdata/firstparty/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/bin/bin2.meta_lic"}, + packageName{"testdata/firstparty/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/firstparty/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/highest.apex.meta_lic ", "testdata-firstparty-bin-bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/liba.so.meta_lic"}, + packageName{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/highest.apex.meta_lic ", "testdata/firstparty/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/libb.so.meta_lic"}, + packageName{"testdata/firstparty/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/highest.apex.meta_lic ", "testdata/firstparty/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/firstparty/bin/bin1.meta_lic ", "testdata/firstparty/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/libc.a.meta_lic"}, + packageName{"testdata/firstparty/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata-firstparty-bin-bin1.meta_lic ", "testdata/firstparty/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/firstparty/lib/libb.so.meta_lic ", "testdata/firstparty/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/firstparty/lib/libd.so.meta_lic"}, + packageName{"testdata/firstparty/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/lib/libd.so.meta_lic ", "testdata/firstparty/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"}, + }, + { + condition: "firstparty", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/firstparty/application.meta_lic"}, + packageName{"testdata/firstparty/application.meta_lic"}, + spdxPkgID{"testdata/firstparty/application.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/firstparty/application.meta_lic", "DESCRIBES"}, + packageTag{"testdata/firstparty/bin/bin3.meta_lic"}, + packageName{"testdata/firstparty/bin/bin3.meta_lic"}, + spdxPkgID{"testdata/firstparty/bin/bin3.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/bin/bin3.meta_lic ", "testdata-firstparty-application.meta_lic", "BUILD_TOOL_OF"}, + packageTag{"testdata/firstparty/lib/liba.so.meta_lic"}, + packageName{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/application.meta_lic ", "testdata/firstparty/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/libb.so.meta_lic"}, + packageName{"testdata/firstparty/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/lib/libb.so.meta_lic ", "testdata-firstparty-application.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"}, + }, + { + condition: "firstparty", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/firstparty/container.zip.meta_lic"}, + packageName{"testdata/firstparty/container.zip.meta_lic"}, + spdxPkgID{"testdata/firstparty/container.zip.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/firstparty/container.zip.meta_lic", "DESCRIBES"}, + packageTag{"testdata/firstparty/bin/bin1.meta_lic"}, + packageName{"testdata/firstparty/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/firstparty/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/container.zip.meta_lic ", "testdata/firstparty/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/bin/bin2.meta_lic"}, + packageName{"testdata/firstparty/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/firstparty/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/container.zip.meta_lic ", "testdata/firstparty/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/liba.so.meta_lic"}, + packageName{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/container.zip.meta_lic ", "testdata/firstparty/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/libb.so.meta_lic"}, + packageName{"testdata/firstparty/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/container.zip.meta_lic ", "testdata/firstparty/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/firstparty/bin/bin1.meta_lic ", "testdata/firstparty/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/libc.a.meta_lic"}, + packageName{"testdata/firstparty/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/bin/bin1.meta_lic ", "testdata/firstparty/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/firstparty/lib/libb.so.meta_lic ", "testdata/firstparty/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/firstparty/lib/libd.so.meta_lic"}, + packageName{"testdata/firstparty/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/lib/libd.so.meta_lic ", "testdata/firstparty/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"}, + }, + { + condition: "firstparty", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/firstparty/bin/bin1.meta_lic"}, + packageName{"testdata/firstparty/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/firstparty/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/firstparty/bin/bin1.meta_lic", "DESCRIBES"}, + packageTag{"testdata/firstparty/lib/liba.so.meta_lic"}, + packageName{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/bin/bin1.meta_lic ", "testdata/firstparty/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/firstparty/lib/libc.a.meta_lic"}, + packageName{"testdata/firstparty/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/firstparty/bin/bin1.meta_lic ", "testdata/firstparty/lib/libc.a.meta_lic", "CONTAINS"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"}, + }, + { + condition: "firstparty", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/firstparty/lib/libd.so.meta_lic"}, + packageName{"testdata/firstparty/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/firstparty/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/firstparty/lib/libd.so.meta_lic", "DESCRIBES"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"}, + }, + { + condition: "notice", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/notice/highest.apex.meta_lic"}, + packageName{"testdata/notice/highest.apex.meta_lic"}, + spdxPkgID{"testdata/notice/highest.apex.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/notice/highest.apex.meta_lic", "DESCRIBES"}, + packageTag{"testdata/notice/bin/bin1.meta_lic"}, + packageName{"testdata/notice/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/notice/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/notice/highest.apex.meta_lic ", "testdata/notice/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/bin/bin2.meta_lic"}, + packageName{"testdata/notice/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/notice/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/notice/highest.apex.meta_lic ", "testdata/notice/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/liba.so.meta_lic"}, + packageName{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/highest.apex.meta_lic ", "testdata/notice/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/libb.so.meta_lic"}, + packageName{"testdata/notice/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/notice/highest.apex.meta_lic ", "testdata/notice/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/notice/bin/bin1.meta_lic ", "testdata/notice/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/libc.a.meta_lic"}, + packageName{"testdata/notice/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/bin/bin1.meta_lic ", "testdata/notice/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/notice/lib/libb.so.meta_lic ", "testdata/notice/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/notice/lib/libd.so.meta_lic"}, + packageName{"testdata/notice/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/lib/libd.so.meta_lic ", "testdata/notice/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + }, + }, + { + condition: "notice", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/notice/container.zip.meta_lic"}, + packageName{"testdata/notice/container.zip.meta_lic"}, + spdxPkgID{"testdata/notice/container.zip.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/notice/container.zip.meta_lic", "DESCRIBES"}, + packageTag{"testdata/notice/bin/bin1.meta_lic"}, + packageName{"testdata/notice/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/notice/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/notice/container.zip.meta_lic ", "testdata/notice/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/bin/bin2.meta_lic"}, + packageName{"testdata/notice/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/notice/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/notice/container.zip.meta_lic ", "testdata/notice/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/liba.so.meta_lic"}, + packageName{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/container.zip.meta_lic ", "testdata/notice/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/libb.so.meta_lic"}, + packageName{"testdata/notice/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/notice/container.zip.meta_lic ", "testdata/notice/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/notice/bin/bin1.meta_lic ", "testdata/notice/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/libc.a.meta_lic"}, + packageName{"testdata/notice/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/bin/bin1.meta_lic ", "testdata/notice/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/notice/lib/libb.so.meta_lic ", "testdata/notice/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/notice/lib/libd.so.meta_lic"}, + packageName{"testdata/notice/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/lib/libd.so.meta_lic ", "testdata/notice/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + }, + }, + { + condition: "notice", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/notice/application.meta_lic"}, + packageName{"testdata/notice/application.meta_lic"}, + spdxPkgID{"testdata/notice/application.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata-notice-application.meta_lic", "DESCRIBES"}, + packageTag{"testdata/notice/bin/bin3.meta_lic"}, + packageName{"testdata/notice/bin/bin3.meta_lic"}, + spdxPkgID{"testdata/notice/bin/bin3.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata-notice-bin-bin3.meta_lic ", "testdata/notice/application.meta_lic", "BUILD_TOOL_OF"}, + packageTag{"testdata/notice/lib/liba.so.meta_lic"}, + packageName{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/application.meta_lic ", "testdata-notice-lib-liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/libb.so.meta_lic"}, + packageName{"testdata/notice/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata-notice-lib-libb.so.meta_lic ", "testdata/notice/application.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + }, + }, + { + condition: "notice", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/notice/bin/bin1.meta_lic"}, + packageName{"testdata/notice/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/notice/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/notice/bin/bin1.meta_lic", "DESCRIBES"}, + packageTag{"testdata/notice/lib/liba.so.meta_lic"}, + packageName{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/bin/bin1.meta_lic ", "testdata/notice/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/notice/lib/libc.a.meta_lic"}, + packageName{"testdata/notice/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/notice/bin/bin1.meta_lic ", "testdata/notice/lib/libc.a.meta_lic", "CONTAINS"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + }, + }, + { + condition: "notice", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/notice/lib/libd.so.meta_lic"}, + packageName{"testdata/notice/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/notice/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/notice/lib/libd.so.meta_lic", "DESCRIBES"}, + spdxLicense{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"}, + }, + { + condition: "reciprocal", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/reciprocal/highest.apex.meta_lic"}, + packageName{"testdata/reciprocal/highest.apex.meta_lic"}, + spdxPkgID{"testdata/reciprocal/highest.apex.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/reciprocal/highest.apex.meta_lic", "DESCRIBES"}, + packageTag{"testdata/reciprocal/bin/bin1.meta_lic"}, + packageName{"testdata/reciprocal/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/reciprocal/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/highest.apex.meta_lic ", "testdata-reciprocal-bin-bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/bin/bin2.meta_lic"}, + packageName{"testdata/reciprocal/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/reciprocal/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/highest.apex.meta_lic ", "testdata-reciprocal-bin-bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/liba.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/highest.apex.meta_lic ", "testdata/reciprocal/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/libb.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/highest.apex.meta_lic ", "testdata/reciprocal/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/reciprocal/bin/bin1.meta_lic ", "testdata/reciprocal/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/libc.a.meta_lic"}, + packageName{"testdata/reciprocal/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/bin/bin1.meta_lic ", "testdata/reciprocal/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/reciprocal/lib/libb.so.meta_lic ", "testdata/reciprocal/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/reciprocal/lib/libd.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/lib/libd.so.meta_lic ", "testdata/reciprocal/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + }, + }, + { + condition: "reciprocal", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/reciprocal/container.zip.meta_lic"}, + packageName{"testdata/reciprocal/container.zip.meta_lic"}, + spdxPkgID{"testdata/reciprocal/container.zip.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/reciprocal/container.zip.meta_lic", "DESCRIBES"}, + packageTag{"testdata/reciprocal/bin/bin1.meta_lic"}, + packageName{"testdata/reciprocal/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/reciprocal/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/container.zip.meta_lic ", "testdata-reciprocal-bin-bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/bin/bin2.meta_lic"}, + packageName{"testdata/reciprocal/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/reciprocal/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/container.zip.meta_lic ", "testdata-reciprocal-bin-bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/liba.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/container.zip.meta_lic ", "testdata/reciprocal/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/libb.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/container.zip.meta_lic ", "testdata/reciprocal/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/reciprocal/bin/bin1.meta_lic ", "testdata/reciprocal/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/libc.a.meta_lic"}, + packageName{"testdata/reciprocal/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/bin/bin1.meta_lic ", "testdata/reciprocal/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/reciprocal/lib/libb.so.meta_lic ", "testdata/reciprocal/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/reciprocal/lib/libd.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/lib/libd.so.meta_lic ", "testdata/reciprocal/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + }, + }, + { + condition: "reciprocal", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/reciprocal/application.meta_lic"}, + packageName{"testdata/reciprocal/application.meta_lic"}, + spdxPkgID{"testdata/reciprocal/application.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/reciprocal/application.meta_lic", "DESCRIBES"}, + packageTag{"testdata/reciprocal/bin/bin3.meta_lic"}, + packageName{"testdata/reciprocal/bin/bin3.meta_lic"}, + spdxPkgID{"testdata/reciprocal/bin/bin3.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata-reciprocal-bin-bin3.meta_lic ", "testdata/reciprocal/application.meta_lic", "BUILD_TOOL_OF"}, + packageTag{"testdata/reciprocal/lib/liba.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/application.meta_lic ", "testdata/reciprocal/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/libb.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/lib/libb.so.meta_lic ", "testdata/reciprocal/application.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + }, + }, + { + condition: "reciprocal", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/reciprocal/bin/bin1.meta_lic"}, + packageName{"testdata/reciprocal/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/reciprocal/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/reciprocal/bin/bin1.meta_lic", "DESCRIBES"}, + packageTag{"testdata/reciprocal/lib/liba.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/bin/bin1.meta_lic ", "testdata/reciprocal/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/reciprocal/lib/libc.a.meta_lic"}, + packageName{"testdata/reciprocal/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/reciprocal/bin/bin1.meta_lic ", "testdata/reciprocal/lib/libc.a.meta_lic", "CONTAINS"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + }, + }, + { + condition: "reciprocal", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/reciprocal/lib/libd.so.meta_lic"}, + packageName{"testdata/reciprocal/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/reciprocal/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/reciprocal/lib/libd.so.meta_lic", "DESCRIBES"}, + spdxLicense{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/notice/NOTICE_LICENSE", + }, + }, + { + condition: "restricted", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + stripPrefix: "out/target/product/fictional/system/apex/", + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/restricted/highest.apex.meta_lic"}, + packageName{"testdata/restricted/highest.apex.meta_lic"}, + spdxPkgID{"testdata/restricted/highest.apex.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/restricted/highest.apex.meta_lic", "DESCRIBES"}, + packageTag{"testdata/restricted/bin/bin1.meta_lic"}, + packageName{"testdata/restricted/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/restricted/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/highest.apex.meta_lic ", "testdata/restricted/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/bin/bin2.meta_lic"}, + packageName{"testdata/restricted/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/restricted/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/highest.apex.meta_lic ", "testdata/restricted/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/liba.so.meta_lic"}, + packageName{"testdata/restricted/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/highest.apex.meta_lic ", "testdata/restricted/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/libb.so.meta_lic"}, + packageName{"testdata/restricted/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/highest.apex.meta_lic ", "testdata/restricted/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/restricted/bin/bin1.meta_lic ", "testdata/restricted/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/libc.a.meta_lic"}, + packageName{"testdata/restricted/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/bin/bin1.meta_lic ", "testdata/restricted/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/restricted/lib/libb.so.meta_lic ", "testdata/restricted/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/restricted/lib/libd.so.meta_lic"}, + packageName{"testdata/restricted/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/lib/libd.so.meta_lic ", "testdata/restricted/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxExtractedText{"###Restricted License###"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + "testdata/restricted/RESTRICTED_LICENSE", + }, + }, + { + condition: "restricted", + name: "container", + roots: []string{"container.zip.meta_lic"}, + stripPrefix: "out/target/product/fictional/system/apex/", + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/restricted/container.zip.meta_lic"}, + packageName{"testdata/restricted/container.zip.meta_lic"}, + spdxPkgID{"testdata/restricted/container.zip.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/restricted/container.zip.meta_lic", "DESCRIBES"}, + packageTag{"testdata/restricted/bin/bin1.meta_lic"}, + packageName{"testdata/restricted/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/restricted/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/container.zip.meta_lic ", "testdata/restricted/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/bin/bin2.meta_lic"}, + packageName{"testdata/restricted/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/restricted/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/container.zip.meta_lic ", "testdata/restricted/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/liba.so.meta_lic"}, + packageName{"testdata/restricted/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/container.zip.meta_lic ", "testdata/restricted/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/libb.so.meta_lic"}, + packageName{"testdata/restricted/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/container.zip.meta_lic ", "testdata/restricted/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/restricted/bin/bin1.meta_lic ", "testdata/restricted/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/libc.a.meta_lic"}, + packageName{"testdata/restricted/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/bin/bin1.meta_lic ", "testdata/restricted/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/restricted/lib/libb.so.meta_lic ", "testdata/restricted/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/restricted/lib/libd.so.meta_lic"}, + packageName{"testdata/restricted/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/lib/libd.so.meta_lic ", "testdata/restricted/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxExtractedText{"###Restricted License###"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + "testdata/restricted/RESTRICTED_LICENSE", + }, + }, + { + condition: "restricted", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/restricted/bin/bin1.meta_lic"}, + packageName{"testdata/restricted/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/restricted/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/restricted/bin/bin1.meta_lic", "DESCRIBES"}, + packageTag{"testdata/restricted/lib/liba.so.meta_lic"}, + packageName{"testdata/restricted/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/bin/bin1.meta_lic ", "testdata/restricted/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/restricted/lib/libc.a.meta_lic"}, + packageName{"testdata/restricted/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxRelationship{"Package-testdata/restricted/bin/bin1.meta_lic ", "testdata/restricted/lib/libc.a.meta_lic", "CONTAINS"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-reciprocal-RECIPROCAL_LICENSE"}, + spdxExtractedText{"$$$Reciprocal License$$$"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxExtractedText{"###Restricted License###"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/reciprocal/RECIPROCAL_LICENSE", + "testdata/restricted/RESTRICTED_LICENSE", + }, + }, + { + condition: "restricted", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/restricted/lib/libd.so.meta_lic"}, + packageName{"testdata/restricted/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/restricted/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/restricted/lib/libd.so.meta_lic", "DESCRIBES"}, + spdxLicense{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"}, + }, + { + condition: "proprietary", + name: "apex", + roots: []string{"highest.apex.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/proprietary/highest.apex.meta_lic"}, + packageName{"testdata/proprietary/highest.apex.meta_lic"}, + spdxPkgID{"testdata/proprietary/highest.apex.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/proprietary/highest.apex.meta_lic", "DESCRIBES"}, + packageTag{"testdata/proprietary/bin/bin1.meta_lic"}, + packageName{"testdata/proprietary/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/proprietary/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/highest.apex.meta_lic ", "testdata/proprietary/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/bin/bin2.meta_lic"}, + packageName{"testdata/proprietary/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/proprietary/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/highest.apex.meta_lic ", "testdata/proprietary/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/liba.so.meta_lic"}, + packageName{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/highest.apex.meta_lic ", "testdata/proprietary/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/libb.so.meta_lic"}, + packageName{"testdata/proprietary/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/highest.apex.meta_lic ", "testdata/proprietary/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin1.meta_lic ", "testdata/proprietary/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/libc.a.meta_lic"}, + packageName{"testdata/proprietary/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin1.meta_lic ", "testdata/proprietary/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata-proprietary-lib-libb.so.meta_lic ", "testdata/proprietary/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/proprietary/lib/libd.so.meta_lic"}, + packageName{"testdata/proprietary/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata-proprietary-lib-libd.so.meta_lic ", "testdata/proprietary/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxExtractedText{"@@@Proprietary License@@@"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxExtractedText{"###Restricted License###"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/proprietary/PROPRIETARY_LICENSE", + "testdata/restricted/RESTRICTED_LICENSE", + }, + }, + { + condition: "proprietary", + name: "container", + roots: []string{"container.zip.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/proprietary/container.zip.meta_lic"}, + packageName{"testdata/proprietary/container.zip.meta_lic"}, + spdxPkgID{"testdata/proprietary/container.zip.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/proprietary/container.zip.meta_lic", "DESCRIBES"}, + packageTag{"testdata/proprietary/bin/bin1.meta_lic"}, + packageName{"testdata/proprietary/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/proprietary/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/container.zip.meta_lic ", "testdata/proprietary/bin/bin1.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/bin/bin2.meta_lic"}, + packageName{"testdata/proprietary/bin/bin2.meta_lic"}, + spdxPkgID{"testdata/proprietary/bin/bin2.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/container.zip.meta_lic ", "testdata/proprietary/bin/bin2.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/liba.so.meta_lic"}, + packageName{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/container.zip.meta_lic ", "testdata/proprietary/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/libb.so.meta_lic"}, + packageName{"testdata/proprietary/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/container.zip.meta_lic ", "testdata/proprietary/lib/libb.so.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin1.meta_lic ", "testdata/proprietary/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/libc.a.meta_lic"}, + packageName{"testdata/proprietary/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin1.meta_lic ", "testdata/proprietary/lib/libc.a.meta_lic", "CONTAINS"}, + spdxRelationship{"Package-testdata-proprietary-lib-libb.so.meta_lic ", "testdata/proprietary/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + packageTag{"testdata/proprietary/lib/libd.so.meta_lic"}, + packageName{"testdata/proprietary/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"Package-testdata-proprietary-lib-libd.so.meta_lic ", "testdata/proprietary/bin/bin2.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxExtractedText{"@@@Proprietary License@@@"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxExtractedText{"###Restricted License###"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/notice/NOTICE_LICENSE", + "testdata/proprietary/PROPRIETARY_LICENSE", + "testdata/restricted/RESTRICTED_LICENSE", + }, + }, + { + condition: "proprietary", + name: "application", + roots: []string{"application.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/proprietary/application.meta_lic"}, + packageName{"testdata/proprietary/application.meta_lic"}, + spdxPkgID{"testdata/proprietary/application.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/proprietary/application.meta_lic", "DESCRIBES"}, + packageTag{"testdata/proprietary/bin/bin3.meta_lic"}, + packageName{"testdata/proprietary/bin/bin3.meta_lic"}, + spdxPkgID{"testdata/proprietary/bin/bin3.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin3.meta_lic ", "testdata/proprietary/application.meta_lic", "BUILD_TOOL_OF"}, + packageTag{"testdata/proprietary/lib/liba.so.meta_lic"}, + packageName{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/application.meta_lic ", "testdata/proprietary/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/libb.so.meta_lic"}, + packageName{"testdata/proprietary/lib/libb.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libb.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/lib/libb.so.meta_lic ", "testdata/proprietary/application.meta_lic", "RUNTIME_DEPENDENCY_OF"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxExtractedText{"@@@Proprietary License@@@"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-restricted-RESTRICTED_LICENSE"}, + spdxExtractedText{"###Restricted License###"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/proprietary/PROPRIETARY_LICENSE", + "testdata/restricted/RESTRICTED_LICENSE", + }, + }, + { + condition: "proprietary", + name: "binary", + roots: []string{"bin/bin1.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/proprietary/bin/bin1.meta_lic"}, + packageName{"testdata/proprietary/bin/bin1.meta_lic"}, + spdxPkgID{"testdata/proprietary/bin/bin1.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/proprietary/bin/bin1.meta_lic", "DESCRIBES"}, + packageTag{"testdata/proprietary/lib/liba.so.meta_lic"}, + packageName{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/liba.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin1.meta_lic ", "testdata/proprietary/lib/liba.so.meta_lic", "CONTAINS"}, + packageTag{"testdata/proprietary/lib/libc.a.meta_lic"}, + packageName{"testdata/proprietary/lib/libc.a.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libc.a.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxRelationship{"Package-testdata/proprietary/bin/bin1.meta_lic ", "testdata/proprietary/lib/libc.a.meta_lic", "CONTAINS"}, + spdxLicense{}, + spdxLicenseID{"testdata-firstparty-FIRST_PARTY_LICENSE"}, + spdxExtractedText{"&&&First Party License&&&"}, + spdxExtractedClosingText{}, + spdxLicenseID{"testdata-proprietary-PROPRIETARY_LICENSE"}, + spdxExtractedText{"@@@Proprietary License@@@"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{ + "testdata/firstparty/FIRST_PARTY_LICENSE", + "testdata/proprietary/PROPRIETARY_LICENSE", + }, + }, + { + condition: "proprietary", + name: "library", + roots: []string{"lib/libd.so.meta_lic"}, + expectedOut: []matcher{ + spdxVersion{}, + spdxDataLicense{}, + spdxDocumentName{"Android"}, + spdxID{"Android"}, + spdxDocumentNameSpace{}, + spdxCreatorOrganization{}, + spdxCreatedTime{}, + packageTag{"testdata/proprietary/lib/libd.so.meta_lic"}, + packageName{"testdata/proprietary/lib/libd.so.meta_lic"}, + spdxPkgID{"testdata/proprietary/lib/libd.so.meta_lic"}, + spdxPkgDownloadLocation{"NOASSERTION"}, + spdxPkgLicenseDeclared{"testdata-notice-NOTICE_LICENSE"}, + spdxRelationship{"DOCUMENT-Android ", "testdata/proprietary/lib/libd.so.meta_lic", "DESCRIBES"}, + spdxLicense{}, + spdxLicenseID{"testdata-notice-NOTICE_LICENSE"}, + spdxExtractedText{"%%%Notice License%%%"}, + spdxExtractedClosingText{}, + }, + expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"}, + }, + } + for _, tt := range tests { + t.Run(tt.condition+" "+tt.name, func(t *testing.T) { + stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + + rootFiles := make([]string, 0, len(tt.roots)) + for _, r := range tt.roots { + rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r) + } + + ctx := context{stdout, stderr, compliance.GetFS(tt.outDir), "Android", []string{tt.stripPrefix}, fakeTime} + + deps, err := sbomGenerator(&ctx, rootFiles...) + if err != nil { + t.Fatalf("sbom: error = %v, stderr = %v", err, stderr) + return + } + if stderr.Len() > 0 { + t.Errorf("sbom: gotStderr = %v, want none", stderr) + } + + t.Logf("got stdout: %s", stdout.String()) + + t.Logf("want stdout: %s", matcherList(tt.expectedOut).String()) + + out := bufio.NewScanner(stdout) + lineno := 0 + for out.Scan() { + line := out.Text() + if strings.TrimLeft(line, " ") == "" { + continue + } + if len(tt.expectedOut) <= lineno { + t.Errorf("sbom: unexpected output at line %d: got %q, want nothing (wanted %d lines)", lineno+1, line, len(tt.expectedOut)) + } else if !tt.expectedOut[lineno].isMatch(line) { + t.Errorf("sbom: unexpected output at line %d: got %q, want %q", lineno+1, line, tt.expectedOut[lineno]) + } + lineno++ + } + for ; lineno < len(tt.expectedOut); lineno++ { + t.Errorf("bom: missing output line %d: ended early, want %q", lineno+1, tt.expectedOut[lineno]) + } + + t.Logf("got deps: %q", deps) + + t.Logf("want deps: %q", tt.expectedDeps) + + if g, w := deps, tt.expectedDeps; !reflect.DeepEqual(g, w) { + t.Errorf("unexpected deps, wanted:\n%s\ngot:\n%s\n", + strings.Join(w, "\n"), strings.Join(g, "\n")) + } + }) + } +} + +type matcher interface { + isMatch(line string) bool + String() string +} + +type packageTag struct { + name string +} + +func (m packageTag) isMatch(line string) bool { + groups := spdxPackageTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == m.name +} + +func (m packageTag) String() string { + return "##### Package: " + m.name +} + +type packageName struct { + name string +} + +func (m packageName) isMatch(line string) bool { + groups := spdxPackageNameTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == replaceSlashes(m.name) +} + +func (m packageName) String() string { + return "PackageName: " + replaceSlashes(m.name) +} + +type spdxID struct { + name string +} + +func (m spdxID) isMatch(line string) bool { + groups := spdxIDTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == replaceSlashes(m.name) +} + +func (m spdxID) String() string { + return "SPDXID: SPDXRef-DOCUMENT-" + replaceSlashes(m.name) +} + +type spdxPkgID struct { + name string +} + +func (m spdxPkgID) isMatch(line string) bool { + groups := spdxPkgIDTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == replaceSlashes(m.name) +} + +func (m spdxPkgID) String() string { + return "SPDXID: SPDXRef-Package-" + replaceSlashes(m.name) +} + +type spdxVersion struct{} + +func (m spdxVersion) isMatch(line string) bool { + return spdxVersionTag.MatchString(line) +} + +func (m spdxVersion) String() string { + return "SPDXVersion: SPDX-2.2" +} + +type spdxDataLicense struct{} + +func (m spdxDataLicense) isMatch(line string) bool { + return spdxDataLicenseTag.MatchString(line) +} + +func (m spdxDataLicense) String() string { + return "DataLicense: CC-1.0" +} + +type spdxDocumentName struct { + name string +} + +func (m spdxDocumentName) isMatch(line string) bool { + return spdxDocumentNameTag.MatchString(line) +} + +func (m spdxDocumentName) String() string { + return "DocumentName: " + m.name +} + +type spdxDocumentNameSpace struct { + name string +} + +func (m spdxDocumentNameSpace) isMatch(line string) bool { + return spdxDocumentNameSpaceTag.MatchString(line) +} + +func (m spdxDocumentNameSpace) String() string { + return "DocumentNameSpace: Android" +} + +type spdxCreatorOrganization struct{} + +func (m spdxCreatorOrganization) isMatch(line string) bool { + return spdxCreatorOrganizationTag.MatchString(line) +} + +func (m spdxCreatorOrganization) String() string { + return "Creator: Organization: Google LLC" +} + +func fakeTime() time.Time { + return time.UnixMicro(0) +} + +type spdxCreatedTime struct{} + +func (m spdxCreatedTime) isMatch(line string) bool { + return spdxCreatedTimeTag.MatchString(line) +} + +func (m spdxCreatedTime) String() string { + return "Created: 1970-01-01T00:00:00Z" +} + +type spdxPkgDownloadLocation struct { + name string +} + +func (m spdxPkgDownloadLocation) isMatch(line string) bool { + return spdxPkgDownloadLocationTag.MatchString(line) +} + +func (m spdxPkgDownloadLocation) String() string { + return "PackageDownloadLocation: " + m.name +} + +type spdxPkgLicenseDeclared struct { + name string +} + +func (m spdxPkgLicenseDeclared) isMatch(line string) bool { + groups := spdxPkgLicenseDeclaredTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == replaceSlashes(m.name) +} + +func (m spdxPkgLicenseDeclared) String() string { + return "PackageLicenseConcluded: LicenseRef-" + m.name +} + +type spdxRelationship struct { + pkg1 string + pkg2 string + relation string +} + +func (m spdxRelationship) isMatch(line string) bool { + groups := spdxRelationshipTag.FindStringSubmatch(line) + if len(groups) != 4 { + return false + } + return groups[1] == replaceSlashes(m.pkg1) && groups[2] == m.relation && groups[3] == replaceSlashes(m.pkg2) +} + +func (m spdxRelationship) String() string { + return "Relationship: SPDXRef-" + replaceSlashes(m.pkg1) + " " + m.relation + " SPDXRef-Package-" + replaceSlashes(m.pkg2) +} + +type spdxLicense struct{} + +func (m spdxLicense) isMatch(line string) bool { + return spdxLicenseTag.MatchString(line) +} + +func (m spdxLicense) String() string { + return "##### Non-standard license:" +} + +type spdxLicenseID struct { + name string +} + +func (m spdxLicenseID) isMatch(line string) bool { + groups := spdxLicenseIDTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == replaceSlashes(m.name) +} + +func (m spdxLicenseID) String() string { + return "LicenseID: LicenseRef-" + m.name +} + +type spdxExtractedText struct { + name string +} + +func (m spdxExtractedText) isMatch(line string) bool { + groups := spdxExtractedTextTag.FindStringSubmatch(line) + if len(groups) != 2 { + return false + } + return groups[1] == replaceSlashes(m.name) +} + +func (m spdxExtractedText) String() string { + return "ExtractedText: " + m.name +} + +type spdxExtractedClosingText struct{} + +func (m spdxExtractedClosingText) isMatch(line string) bool { + return spdxExtractedClosingTextTag.MatchString(line) +} + +func (m spdxExtractedClosingText) String() string { + return "" +} + +type matcherList []matcher + +func (l matcherList) String() string { + var sb strings.Builder + for _, m := range l { + s := m.String() + fmt.Fprintf(&sb, "%s\n", s) + } + return sb.String() +} diff --git a/tools/compliance/graph.go b/tools/compliance/graph.go index cd5fd5908b..80a2f47e58 100644 --- a/tools/compliance/graph.go +++ b/tools/compliance/graph.go @@ -137,6 +137,24 @@ func (e *TargetEdge) Annotations() TargetEdgeAnnotations { return e.annotations } +// IsRuntimeDependency returns true for edges representing shared libraries +// linked dynamically at runtime. +func (e *TargetEdge) IsRuntimeDependency() bool { + return edgeIsDynamicLink(e) +} + +// IsDerivation returns true for edges where the target is a derivative +// work of dependency. +func (e *TargetEdge) IsDerivation() bool { + return edgeIsDerivation(e) +} + +// IsBuildTool returns true for edges where the target is built +// by dependency. +func (e *TargetEdge) IsBuildTool() bool { + return !edgeIsDerivation(e) && !edgeIsDynamicLink(e) +} + // String returns a human-readable string representation of the edge. func (e *TargetEdge) String() string { return fmt.Sprintf("%s -[%s]> %s", e.target.name, strings.Join(e.annotations.AsList(), ", "), e.dependency.name) @@ -186,6 +204,11 @@ func (s TargetEdgePathSegment) Dependency() *TargetNode { return s.edge.dependency } +// Edge describes the target edge. +func (s TargetEdgePathSegment) Edge() *TargetEdge { + return s.edge +} + // Annotations describes the type of edge by the set of annotations attached to // it. // @@ -298,6 +321,11 @@ func (tn *TargetNode) PackageName() string { return tn.proto.GetPackageName() } +// ModuleName returns the module name of the target. +func (tn *TargetNode) ModuleName() string { + return tn.proto.GetModuleName() +} + // Projects returns the projects defining the target node. (unordered) // // In an ideal world, only 1 project defines a target, but the interaction