Skip to content

Commit

Permalink
Fix SPDX SBOM ingestion with multiple purls in externalRefs array (gu…
Browse files Browse the repository at this point in the history
…acsec#2101)

Signed-off-by: mrizzi <mrizzi@redhat.com>
  • Loading branch information
mrizzi committed Sep 3, 2024
1 parent a37fef2 commit c9c6acc
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 12 deletions.
26 changes: 14 additions & 12 deletions pkg/ingestor/parser/spdx/parse_spdx.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,27 +143,29 @@ func (s *spdxParser) getTopLevelSPDXIDs() ([]string, error) {
func (s *spdxParser) getPackages(topLevelSPDXIDs []string) error {
for _, pac := range s.spdxDoc.Packages {
// for each package create a package for each of them
purl := ""
purls := make([]string, 0)
for _, ext := range pac.PackageExternalReferences {
if ext.RefType == spdx_common.TypePackageManagerPURL {
purl = ext.Locator
purls = append(purls, ext.Locator)
}
}
if purl == "" {
purl = asmhelpers.GuacPkgPurl(pac.PackageName, &pac.PackageVersion)
if len(purls) == 0 {
purls = append(purls, asmhelpers.GuacPkgPurl(pac.PackageName, &pac.PackageVersion))
}

s.identifierStrings.PurlStrings = append(s.identifierStrings.PurlStrings, purl)
s.identifierStrings.PurlStrings = append(s.identifierStrings.PurlStrings, purls...)

pkg, err := asmhelpers.PurlToPkg(purl)
if err != nil {
return err
}
for _, purl := range purls {
pkg, err := asmhelpers.PurlToPkg(purl)
if err != nil {
return err
}

if slices.Contains(topLevelSPDXIDs, string(pac.PackageSPDXIdentifier)) {
s.topLevelPackages = append(s.topLevelPackages, pkg)
if slices.Contains(topLevelSPDXIDs, string(pac.PackageSPDXIdentifier)) {
s.topLevelPackages = append(s.topLevelPackages, pkg)
}
s.packagePackages[string(pac.PackageSPDXIdentifier)] = append(s.packagePackages[string(pac.PackageSPDXIdentifier)], pkg)
}
s.packagePackages[string(pac.PackageSPDXIdentifier)] = append(s.packagePackages[string(pac.PackageSPDXIdentifier)], pkg)

// if checksums exists create an artifact for each of them
for _, checksum := range pac.PackageChecksums {
Expand Down
119 changes: 119 additions & 0 deletions pkg/ingestor/parser/spdx/parse_spdx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,125 @@ func Test_spdxParser(t *testing.T) {
wantErr: false,
wantWarning: "Top-level unique artifact count (1) and top-level package count (2) are mismatched. SBOM ingestion may not be as expected.",
},
{
name: "SPDX with multiple referenceType=purl for a single package",
additionalOpts: []cmp.Option{
cmpopts.IgnoreFields(assembler.HasSBOMIngest{},
"HasSBOM"),
},
doc: &processor.Document{
Blob: []byte(`
{
"spdxVersion": "SPDX-2.3",
"SPDXID":"SPDXRef-DOCUMENT",
"name":"openssl-3.0.7-18.el9_2",
"creationInfo": { "created": "2023-01-01T01:01:01.00Z" },
"packages":[
{
"SPDXID":"SPDXRef-SRPM",
"name":"openssl",
"versionInfo": "3.0.7-18.el9_2",
"packageFileName": "openssl-3.0.7-18.el9_2.src.rpm",
"externalRefs":[
{
"referenceCategory":"PACKAGE_MANAGER",
"referenceLocator":"pkg:rpm/redhat/openssl@3.0.7-18.el9_2?repository_id=rhel-9-baseos-eus",
"referenceType":"purl"
},
{
"referenceCategory":"PACKAGE_MANAGER",
"referenceLocator":"pkg:rpm/redhat/openssl@3.0.7-18.el9_2?repository_id=rhel-9-baseos-tus",
"referenceType":"purl"
}
]
}
],
"relationships":[
{
"spdxElementId":"SPDXRef-DOCUMENT",
"relationshipType":"PACKAGE_OF",
"relatedSpdxElement":"SPDXRef-SRPM"
}
]
}
`),
Format: processor.FormatJSON,
Type: processor.DocumentSPDX,
SourceInformation: processor.SourceInformation{
Collector: "TestCollector",
Source: "TestSource",
},
},
wantPredicates: &assembler.IngestPredicates{
IsDependency: []assembler.IsDependencyIngest{
{
Pkg: &generated.PkgInputSpec{
Type: "guac",
Namespace: &packageOfns,
Name: "openssl-3.0.7-18.el9_2",
Version: &packageOfEmptyString,
Subpath: &packageOfEmptyString,
},
DepPkg: &generated.PkgInputSpec{
Type: "rpm",
Namespace: ptrfrom.String("redhat"),
Name: "openssl",
Version: ptrfrom.String("3.0.7-18.el9_2"),
Qualifiers: []generated.PackageQualifierInputSpec{
{Key: "repository_id", Value: "rhel-9-baseos-eus"},
},
Subpath: &packageOfEmptyString,
},
IsDependency: &generated.IsDependencyInputSpec{
DependencyType: "UNKNOWN",
Justification: "top-level package GUAC heuristic connecting to each file/package",
},
},
{
Pkg: &generated.PkgInputSpec{
Type: "guac",
Namespace: &packageOfns,
Name: "openssl-3.0.7-18.el9_2",
Version: &packageOfEmptyString,
Subpath: &packageOfEmptyString,
},
DepPkg: &generated.PkgInputSpec{
Type: "rpm",
Namespace: ptrfrom.String("redhat"),
Name: "openssl",
Version: ptrfrom.String("3.0.7-18.el9_2"),
Qualifiers: []generated.PackageQualifierInputSpec{
{Key: "repository_id", Value: "rhel-9-baseos-tus"},
},
Subpath: &packageOfEmptyString,
},
IsDependency: &generated.IsDependencyInputSpec{
DependencyType: "UNKNOWN",
Justification: "top-level package GUAC heuristic connecting to each file/package",
},
},
},

HasSBOM: []assembler.HasSBOMIngest{
{
Pkg: &generated.PkgInputSpec{
Type: "guac",
Namespace: &packageOfns,
Name: "openssl-3.0.7-18.el9_2",
Version: &packageOfEmptyString,
Subpath: &packageOfEmptyString,
},
HasSBOM: &generated.HasSBOMInputSpec{
Uri: "https://anchore.com/syft/image/alpine-latest-e78eca08-d9f4-49c7-97e0-6d4b9bfa99c2",
Algorithm: "sha256",
Digest: "ba096464061993bbbdfc30a26b42cd8beb1bfff301726fe6c58cb45d468c7648",
DownloadLocation: "TestSource",
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down

0 comments on commit c9c6acc

Please sign in to comment.