diff --git a/lib/enrich.go b/lib/enrich.go index e4f1173..ecc5aad 100644 --- a/lib/enrich.go +++ b/lib/enrich.go @@ -26,15 +26,41 @@ func enrichLicense(component cdx.Component, packageData *packages.Package) cdx.C return component } -func EnrichSBOM(bom *cdx.BOM) *cdx.BOM { - wg := sizedwaitgroup.New(20) - - if bom.Components == nil { - return bom +func enrichExternalReference(component cdx.Component, packageData *packages.Package, url *string, refType cdx.ExternalReferenceType) cdx.Component { + if url == nil { + return component + } + ext := cdx.ExternalReference{ + URL: *url, + Type: refType, } + if component.ExternalReferences == nil { + component.ExternalReferences = &[]cdx.ExternalReference{ext} + } else { + *component.ExternalReferences = append(*component.ExternalReferences, ext) + } + return component +} - newComponents := make([]cdx.Component, len(*bom.Components)) +func enrichHomepage(component cdx.Component, packageData *packages.Package) cdx.Component { + return enrichExternalReference(component, packageData, packageData.Homepage, cdx.ERTypeWebsite) +} + +func enrichRegistryURL(component cdx.Component, packageData *packages.Package) cdx.Component { + return enrichExternalReference(component, packageData, packageData.RegistryUrl, cdx.ERTypeDistribution) +} + +func enrichRepositoryURL(component cdx.Component, packageData *packages.Package) cdx.Component { + return enrichExternalReference(component, packageData, packageData.RepositoryUrl, cdx.ERTypeVCS) +} +func enrichDocumentationURL(component cdx.Component, packageData *packages.Package) cdx.Component { + return enrichExternalReference(component, packageData, packageData.DocumentationUrl, cdx.ERTypeDocumentation) +} + +func enrichComponents(bom *cdx.BOM, enrichFuncs []func(cdx.Component, *packages.Package) cdx.Component) { + wg := sizedwaitgroup.New(20) + newComponents := make([]cdx.Component, len(*bom.Components)) for i, component := range *bom.Components { wg.Add() go func(component cdx.Component, i int) { @@ -43,17 +69,33 @@ func EnrichSBOM(bom *cdx.BOM) *cdx.BOM { if err == nil { packageData := resp.JSON200 if packageData != nil { - component = enrichDescription(component, packageData) - component = enrichLicense(component, packageData) + for _, enrichFunc := range enrichFuncs { + component = enrichFunc(component, packageData) + } } } newComponents[i] = component wg.Done() }(component, i) } - wg.Wait() - bom.Components = &newComponents +} + +func EnrichSBOM(bom *cdx.BOM) *cdx.BOM { + if bom.Components == nil { + return bom + } + + enrichFuncs := []func(cdx.Component, *packages.Package) cdx.Component{ + enrichDescription, + enrichLicense, + enrichHomepage, + enrichRegistryURL, + enrichRepositoryURL, + enrichDocumentationURL, + } + + enrichComponents(bom, enrichFuncs) return bom } diff --git a/lib/enrich_test.go b/lib/enrich_test.go index 0f1df9c..9ba3a92 100644 --- a/lib/enrich_test.go +++ b/lib/enrich_test.go @@ -127,3 +127,76 @@ func TestEnrichBlankSBOM(t *testing.T) { bom = EnrichSBOM(bom) assert.Nil(t, bom.Components) } + +func TestEnrichExternalReferenceWithNilURL(t *testing.T) { + component := cdx.Component{} + packageData := &packages.Package{Homepage: nil} + + result := enrichExternalReference(component, packageData, packageData.Homepage, cdx.ERTypeWebsite) + + assert.Equal(t, component, result) +} + +func TestEnrichExternalReferenceWithNonNullURL(t *testing.T) { + component := cdx.Component{} + packageData := &packages.Package{Homepage: pointerToString("https://example.com")} + + result := enrichExternalReference(component, packageData, packageData.Homepage, cdx.ERTypeWebsite) + + expected := cdx.Component{ + ExternalReferences: &[]cdx.ExternalReference{ + {URL: "https://example.com", Type: cdx.ERTypeWebsite}, + }, + } + assert.Equal(t, expected, result) +} + +func TestEnrichHomepageWithNilHomepage(t *testing.T) { + component := cdx.Component{} + packageData := &packages.Package{Homepage: nil} + + result := enrichHomepage(component, packageData) + + assert.Equal(t, component, result) +} + +func TestEnrichHomepageWithNonNullHomepage(t *testing.T) { + component := cdx.Component{} + packageData := &packages.Package{Homepage: pointerToString("https://example.com")} + + result := enrichHomepage(component, packageData) + + expected := cdx.Component{ + ExternalReferences: &[]cdx.ExternalReference{ + {URL: "https://example.com", Type: cdx.ERTypeWebsite}, + }, + } + assert.Equal(t, expected, result) +} + +func TestEnrichRegistryURLWithNilRegistryURL(t *testing.T) { + component := cdx.Component{} + packageData := &packages.Package{RegistryUrl: nil} + + result := enrichRegistryURL(component, packageData) + + assert.Equal(t, component, result) +} + +func TestEnrichRegistryURLWithNonNullRegistryURL(t *testing.T) { + component := cdx.Component{} + packageData := &packages.Package{RegistryUrl: pointerToString("https://example.com")} + + result := enrichRegistryURL(component, packageData) + + expected := cdx.Component{ + ExternalReferences: &[]cdx.ExternalReference{ + {URL: "https://example.com", Type: cdx.ERTypeDistribution}, + }, + } + assert.Equal(t, expected, result) +} + +func pointerToString(s string) *string { + return &s +}