Skip to content

Commit 772d1d0

Browse files
authored
fix(sbom): Use UUID as BomRef for packages with empty purl (#5448)
1 parent df47073 commit 772d1d0

File tree

7 files changed

+78
-51
lines changed

7 files changed

+78
-51
lines changed

pkg/k8s/scanner/scanner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Comp
383383
return nil, xerrors.Errorf("failed to create PURL: %w", err)
384384
}
385385
imageComponents = append(imageComponents, &core.Component{
386-
PackageURL: &imagePURL,
386+
PackageURL: imagePURL,
387387
Type: cdx.ComponentTypeContainer,
388388
Name: name,
389389
Version: cDigest,

pkg/purl/purl.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ func (p *PackageURL) BOMRef() string {
199199
}
200200

201201
// nolint: gocyclo
202-
func NewPackageURL(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (PackageURL, error) {
202+
func NewPackageURL(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (*PackageURL, error) {
203203
var qualifiers packageurl.Qualifiers
204204
if metadata.OS != nil {
205205
qualifiers = parseQualifier(pkg)
@@ -235,7 +235,7 @@ func NewPackageURL(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Pack
235235
case packageurl.TypeGolang:
236236
namespace, name = parseGolang(name)
237237
if name == "" {
238-
return PackageURL{PackageURL: *packageurl.NewPackageURL("", "", "", "", nil, "")}, nil
238+
return nil, nil
239239
}
240240
case packageurl.TypeNPM:
241241
namespace, name = parseNpm(name)
@@ -246,12 +246,15 @@ func NewPackageURL(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Pack
246246
case packageurl.TypeOCI:
247247
purl, err := parseOCI(metadata)
248248
if err != nil {
249-
return PackageURL{}, err
249+
return nil, err
250250
}
251-
return PackageURL{PackageURL: purl}, nil
251+
if purl.Type == "" {
252+
return nil, nil
253+
}
254+
return &PackageURL{PackageURL: purl}, nil
252255
}
253256

254-
return PackageURL{
257+
return &PackageURL{
255258
PackageURL: *packageurl.NewPackageURL(ptype, namespace, name, ver, qualifiers, subpath),
256259
FilePath: pkg.FilePath,
257260
}, nil

pkg/purl/purl_test.go

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestNewPackageURL(t *testing.T) {
2020
typ ftypes.TargetType
2121
pkg ftypes.Package
2222
metadata types.Metadata
23-
want purl.PackageURL
23+
want *purl.PackageURL
2424
wantErr string
2525
}{
2626
{
@@ -30,7 +30,7 @@ func TestNewPackageURL(t *testing.T) {
3030
Name: "org.springframework:spring-core",
3131
Version: "5.3.14",
3232
},
33-
want: purl.PackageURL{
33+
want: &purl.PackageURL{
3434
PackageURL: packageurl.PackageURL{
3535
Type: packageurl.TypeMaven,
3636
Namespace: "org.springframework",
@@ -46,7 +46,7 @@ func TestNewPackageURL(t *testing.T) {
4646
Name: "org.springframework:spring-core",
4747
Version: "5.3.14",
4848
},
49-
want: purl.PackageURL{
49+
want: &purl.PackageURL{
5050
PackageURL: packageurl.PackageURL{
5151
Type: packageurl.TypeMaven,
5252
Namespace: "org.springframework",
@@ -62,7 +62,7 @@ func TestNewPackageURL(t *testing.T) {
6262
Name: "@xtuc/ieee754",
6363
Version: "1.2.0",
6464
},
65-
want: purl.PackageURL{
65+
want: &purl.PackageURL{
6666
PackageURL: packageurl.PackageURL{
6767
Type: packageurl.TypeNPM,
6868
Namespace: "@xtuc",
@@ -78,7 +78,7 @@ func TestNewPackageURL(t *testing.T) {
7878
Name: "lodash",
7979
Version: "4.17.21",
8080
},
81-
want: purl.PackageURL{
81+
want: &purl.PackageURL{
8282
PackageURL: packageurl.PackageURL{
8383
Type: packageurl.TypeNPM,
8484
Name: "lodash",
@@ -93,7 +93,7 @@ func TestNewPackageURL(t *testing.T) {
9393
Name: "@xtuc/ieee754",
9494
Version: "1.2.0",
9595
},
96-
want: purl.PackageURL{
96+
want: &purl.PackageURL{
9797
PackageURL: packageurl.PackageURL{
9898
Type: packageurl.TypeNPM,
9999
Namespace: "@xtuc",
@@ -109,7 +109,7 @@ func TestNewPackageURL(t *testing.T) {
109109
Name: "lodash",
110110
Version: "4.17.21",
111111
},
112-
want: purl.PackageURL{
112+
want: &purl.PackageURL{
113113
PackageURL: packageurl.PackageURL{
114114
Type: packageurl.TypeNPM,
115115
Name: "lodash",
@@ -124,7 +124,7 @@ func TestNewPackageURL(t *testing.T) {
124124
Name: "Django_test",
125125
Version: "1.2.0",
126126
},
127-
want: purl.PackageURL{
127+
want: &purl.PackageURL{
128128
PackageURL: packageurl.PackageURL{
129129
Type: packageurl.TypePyPi,
130130
Name: "django-test",
@@ -139,7 +139,7 @@ func TestNewPackageURL(t *testing.T) {
139139
Name: "absl-py",
140140
Version: "0.4.1",
141141
},
142-
want: purl.PackageURL{
142+
want: &purl.PackageURL{
143143
PackageURL: packageurl.PackageURL{
144144
Type: packageurl.TypeConda,
145145
Name: "absl-py",
@@ -154,7 +154,7 @@ func TestNewPackageURL(t *testing.T) {
154154
Name: "symfony/contracts",
155155
Version: "v1.0.2",
156156
},
157-
want: purl.PackageURL{
157+
want: &purl.PackageURL{
158158
PackageURL: packageurl.PackageURL{
159159
Type: packageurl.TypeComposer,
160160
Namespace: "symfony",
@@ -170,7 +170,7 @@ func TestNewPackageURL(t *testing.T) {
170170
Name: "github.com/go-sql-driver/Mysql",
171171
Version: "v1.5.0",
172172
},
173-
want: purl.PackageURL{
173+
want: &purl.PackageURL{
174174
PackageURL: packageurl.PackageURL{
175175
Type: packageurl.TypeGolang,
176176
Namespace: "github.com/go-sql-driver",
@@ -186,14 +186,7 @@ func TestNewPackageURL(t *testing.T) {
186186
Name: "./private_repos/cnrm.googlesource.com/cnrm/",
187187
Version: "(devel)",
188188
},
189-
want: purl.PackageURL{
190-
PackageURL: packageurl.PackageURL{
191-
Type: "",
192-
Namespace: "",
193-
Name: "",
194-
Version: "",
195-
},
196-
},
189+
want: nil,
197190
},
198191
{
199192
name: "hex package",
@@ -209,7 +202,7 @@ func TestNewPackageURL(t *testing.T) {
209202
},
210203
},
211204
},
212-
want: purl.PackageURL{
205+
want: &purl.PackageURL{
213206
PackageURL: packageurl.PackageURL{
214207
Type: packageurl.TypeHex,
215208
Name: "bunt",
@@ -224,7 +217,7 @@ func TestNewPackageURL(t *testing.T) {
224217
Name: "http",
225218
Version: "0.13.2",
226219
},
227-
want: purl.PackageURL{
220+
want: &purl.PackageURL{
228221
PackageURL: packageurl.PackageURL{
229222
Type: purl.TypeDart,
230223
Name: "http",
@@ -240,7 +233,7 @@ func TestNewPackageURL(t *testing.T) {
240233
Name: "github.com/apple/swift-atomics",
241234
Version: "1.1.0",
242235
},
243-
want: purl.PackageURL{
236+
want: &purl.PackageURL{
244237
PackageURL: packageurl.PackageURL{
245238
Type: packageurl.TypeSwift,
246239
Namespace: "github.com/apple",
@@ -257,7 +250,7 @@ func TestNewPackageURL(t *testing.T) {
257250
Name: "GoogleUtilities/NSData+zlib",
258251
Version: "7.5.2",
259252
},
260-
want: purl.PackageURL{
253+
want: &purl.PackageURL{
261254
PackageURL: packageurl.PackageURL{
262255
Type: packageurl.TypeCocoapods,
263256
Name: "GoogleUtilities",
@@ -274,7 +267,7 @@ func TestNewPackageURL(t *testing.T) {
274267
Name: "abomination",
275268
Version: "0.7.3",
276269
},
277-
want: purl.PackageURL{
270+
want: &purl.PackageURL{
278271
PackageURL: packageurl.PackageURL{
279272
Type: packageurl.TypeCargo,
280273
Name: "abomination",
@@ -304,7 +297,7 @@ func TestNewPackageURL(t *testing.T) {
304297
Name: "8",
305298
},
306299
},
307-
want: purl.PackageURL{
300+
want: &purl.PackageURL{
308301
PackageURL: packageurl.PackageURL{
309302
Type: packageurl.TypeRPM,
310303
Namespace: "redhat",
@@ -342,7 +335,7 @@ func TestNewPackageURL(t *testing.T) {
342335
Architecture: "amd64",
343336
},
344337
},
345-
want: purl.PackageURL{
338+
want: &purl.PackageURL{
346339
PackageURL: packageurl.PackageURL{
347340
Type: packageurl.TypeOCI,
348341
Namespace: "",
@@ -372,14 +365,7 @@ func TestNewPackageURL(t *testing.T) {
372365
},
373366
ImageID: "sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260",
374367
},
375-
want: purl.PackageURL{
376-
PackageURL: packageurl.PackageURL{
377-
Type: "",
378-
Namespace: "",
379-
Name: "",
380-
Version: "",
381-
},
382-
},
368+
want: nil,
383369
},
384370
{
385371
name: "container with implicit registry",
@@ -397,7 +383,7 @@ func TestNewPackageURL(t *testing.T) {
397383
Architecture: "amd64",
398384
},
399385
},
400-
want: purl.PackageURL{
386+
want: &purl.PackageURL{
401387
PackageURL: packageurl.PackageURL{
402388
Type: packageurl.TypeOCI,
403389
Namespace: "",

pkg/report/github/github.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,8 @@ func buildPurl(t ftypes.TargetType, pkg ftypes.Package) (string, error) {
165165
if err != nil {
166166
return "", xerrors.Errorf("purl error: %w", err)
167167
}
168+
if packageUrl == nil {
169+
return "", nil
170+
}
168171
return packageUrl.ToString(), nil
169172
}

pkg/sbom/cyclonedx/marshal.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ func (e *Marshaler) marshalPackage(pkg Package, pkgs map[string]Package, compone
193193
if err != nil {
194194
return nil, xerrors.Errorf("failed to parse pkg: %w", err)
195195
}
196+
197+
// Skip component that can't be converted from `Package`
198+
if component == nil {
199+
return nil, nil
200+
}
196201
components[pkg.ID] = component
197202

198203
// Iterate dependencies
@@ -234,8 +239,9 @@ func (e *Marshaler) rootComponent(r types.Report) (*core.Component, error) {
234239
p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{})
235240
if err != nil {
236241
return nil, xerrors.Errorf("failed to new package url for oci: %w", err)
237-
} else if p.Type != "" {
238-
root.PackageURL = &p
242+
}
243+
if p != nil {
244+
root.PackageURL = p
239245
}
240246

241247
case ftypes.ArtifactVM:
@@ -315,11 +321,17 @@ func pkgComponent(pkg Package) (*core.Component, error) {
315321
}
316322

317323
name := pkg.Name
324+
version := pkg.Version
318325
var group string
319-
// use `group` field for GroupID and `name` for ArtifactID for jar files
320-
if pkg.Type == ftypes.Jar {
321-
name = pu.Name
322-
group = pu.Namespace
326+
// there are cases when we can't build purl
327+
// e.g. local Go packages
328+
if pu != nil {
329+
version = pu.Version
330+
// use `group` field for GroupID and `name` for ArtifactID for jar files
331+
if pkg.Type == ftypes.Jar {
332+
name = pu.Name
333+
group = pu.Namespace
334+
}
323335
}
324336

325337
properties := []core.Property{
@@ -369,8 +381,8 @@ func pkgComponent(pkg Package) (*core.Component, error) {
369381
Type: cdx.ComponentTypeLibrary,
370382
Name: name,
371383
Group: group,
372-
Version: pu.Version,
373-
PackageURL: &pu,
384+
Version: version,
385+
PackageURL: pu,
374386
Supplier: pkg.Maintainer,
375387
Licenses: pkg.Licenses,
376388
Hashes: lo.Ternary(pkg.Digest == "", nil, []digest.Digest{pkg.Digest}),

pkg/sbom/cyclonedx/marshal_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ func TestMarshaler_Marshal(t *testing.T) {
168168
Name: "golang.org/x/crypto",
169169
Version: "v0.0.0-20210421170649-83a5a9bb288b",
170170
},
171+
// dependency has been replaced with local directory
172+
{
173+
Name: "./api",
174+
Version: "(devel)",
175+
},
171176
},
172177
},
173178
},
@@ -302,6 +307,19 @@ func TestMarshaler_Marshal(t *testing.T) {
302307
},
303308
},
304309
},
310+
{
311+
// Use UUID for local Go packages
312+
BOMRef: "3ff14136-e09f-4df9-80ea-000000000007",
313+
Type: cdx.ComponentTypeLibrary,
314+
Name: "./api",
315+
Version: "(devel)",
316+
Properties: &[]cdx.Property{
317+
{
318+
Name: "aquasecurity:trivy:PkgType",
319+
Value: "gobinary",
320+
},
321+
},
322+
},
305323
{
306324
BOMRef: "pkg:gem/[email protected]",
307325
Type: cdx.ComponentTypeLibrary,
@@ -441,9 +459,14 @@ func TestMarshaler_Marshal(t *testing.T) {
441459
{
442460
Ref: "3ff14136-e09f-4df9-80ea-000000000006",
443461
Dependencies: &[]string{
462+
"3ff14136-e09f-4df9-80ea-000000000007",
444463
"pkg:golang/golang.org/x/[email protected]",
445464
},
446465
},
466+
{
467+
Ref: "3ff14136-e09f-4df9-80ea-000000000007",
468+
Dependencies: lo.ToPtr([]string{}),
469+
},
447470
{
448471
Ref: "pkg:gem/[email protected]",
449472
Dependencies: &[]string{

pkg/sbom/spdx/marshal.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ func (m *Marshaler) rootPackage(r types.Report, pkgDownloadLocation string) (*sp
233233
// When the target is a container image, add PURL to the external references of the root package.
234234
if p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{}); err != nil {
235235
return nil, xerrors.Errorf("failed to new package url for oci: %w", err)
236-
} else if p.Type != "" {
236+
} else if p != nil {
237237
externalReferences = append(externalReferences, purlExternalReference(p.ToString()))
238238
}
239239

@@ -327,7 +327,7 @@ func (m *Marshaler) pkgToSpdxPackage(t ftypes.TargetType, pkgDownloadLocation st
327327
}
328328

329329
var pkgExtRefs []*spdx.PackageExternalReference
330-
if packageURL.Type != "" {
330+
if packageURL != nil {
331331
pkgExtRefs = []*spdx.PackageExternalReference{purlExternalReference(packageURL.String())}
332332
}
333333

0 commit comments

Comments
 (0)