Skip to content

Commit

Permalink
🐛 Do not stop sbom generation on the first encountered unmarshal erro…
Browse files Browse the repository at this point in the history
…r. (#5204)

* 🐛 Do not stop sbom generation on the first encountered unmarshal error.

Signed-off-by: Vasil Sirakov <[email protected]>

* Reuse existing implementation for retrieving sorted map keys.

Signed-off-by: Vasil Sirakov <[email protected]>

---------

Signed-off-by: Vasil Sirakov <[email protected]>
  • Loading branch information
VasilSirakov authored Feb 11, 2025
1 parent e3c2a46 commit b685f44
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 6 deletions.
10 changes: 7 additions & 3 deletions sbom/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"go.mondoo.com/cnquery/v11/cli/reporter"
"go.mondoo.com/cnquery/v11/mrn"
"go.mondoo.com/cnquery/v11/sbom"
"go.mondoo.com/cnquery/v11/utils/sortx"
)

var LABEL_KERNEL_RUNNING = "mondoo.com/os/kernel-running"
Expand Down Expand Up @@ -60,19 +61,22 @@ func GenerateBom(r *reporter.Report) []*sbom.Sbom {
boms = append(boms, bom)
continue
}
for _, dataValue := range dataPoints.Values {
// ensure deterministic order of enumeration
keys := sortx.Keys(dataPoints.Values)
for _, k := range keys {
dataValue := dataPoints.Values[k]
jsondata, err := reporter.JsonValue(dataValue.Content)
if err != nil {
bom.Status = sbom.Status_STATUS_FAILED
bom.ErrorMessage = errors.Wrap(err, "failed to parse json data").Error()
break
continue
}
rb := BomFields{}
err = json.Unmarshal(jsondata, &rb)
if err != nil {
bom.Status = sbom.Status_STATUS_FAILED
bom.ErrorMessage = errors.Wrap(err, "failed to parse bom fields json data").Error()
break
continue
}
if rb.Asset != nil {
bom.Asset.Name = rb.Asset.Name
Expand Down
141 changes: 138 additions & 3 deletions sbom/generator/sbom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,151 @@ func TestSbomGeneration(t *testing.T) {
Value: "/opt/lib/node_modules/npm/package.json",
})
})
t.Run("generate sbom from a report with a package error", func(t *testing.T) {
report, err := LoadReport("testdata/alpine-failed-package.json")

t.Run("generate sbom from a report with a sbom package error", func(t *testing.T) {
report, err := LoadReport("testdata/alpine-failed-sbom-package.json")
require.NoError(t, err)

sboms := GenerateBom(report)

// store bom in different formats
selectedBom := sboms[0]
assert.Equal(t, sbom.Status_STATUS_FAILED, selectedBom.Status)
assert.Contains(t, selectedBom.ErrorMessage, "failed to parse bom fields json data")
assert.Len(t, selectedBom.Packages, 2)

pkg := findProtoPkg(selectedBom.Packages, "npm")
require.Equal(t, &sbom.Package{
Name: "npm",
Type: "npm",
Cpes: []string{
"cpe:2.3:a:npm:npm:10.2.4:*:*:*:*:*:*:*",
},
EvidenceList: []*sbom.Evidence{
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "/opt/lib/node_modules/npm/package.json",
},
},
Purl: "pkg:npm/[email protected]",
Version: "10.2.4",
}, pkg)

pkg = findProtoPkg(selectedBom.Packages, "pip")
require.Equal(t, &sbom.Package{
Name: "pip",
Type: "pypi",
Cpes: []string{
"cpe:2.3:a:pip_project:pip:21.2.4:*:*:*:*:*:*:*",
},
EvidenceList: []*sbom.Evidence{
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "/opt/lib/python3.9/site-packages/pip-21.2.4.dist-info/METADATA",
},
},
Purl: "pkg:pypi/[email protected]",
Version: "21.2.4",
}, pkg)
})

t.Run("generate sbom from a report with a npm package error", func(t *testing.T) {
report, err := LoadReport("testdata/alpine-failed-npm-package.json")
require.NoError(t, err)

sboms := GenerateBom(report)

selectedBom := sboms[0]
assert.Equal(t, sbom.Status_STATUS_FAILED, selectedBom.Status)
assert.Contains(t, selectedBom.ErrorMessage, "failed to parse bom fields json data")
assert.Len(t, selectedBom.Packages, 2)

pkg := findProtoPkg(selectedBom.Packages, "apk-tools")
require.Equal(t, &sbom.Package{
Name: "apk-tools",
Type: "apk",
Cpes: []string{
"cpe:2.3:a:apk-tools:apk-tools:1684120357:aarch64:*:*:*:*:*:*",
},
EvidenceList: []*sbom.Evidence{
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "lib/libapk.so.2.14.0",
},
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "sbin/apk",
},
},
Purl: "pkg:apk/alpine/apk-tools@1684120357%3A2.14.0-r5?arch=aarch64\u0026distro=alpine-3.19.0\u0026epoch=1684120357",
Version: "1684120357:2.14.0-r5",
}, pkg)

pkg = findProtoPkg(selectedBom.Packages, "pip")
require.Equal(t, &sbom.Package{
Name: "pip",
Type: "pypi",
Cpes: []string{
"cpe:2.3:a:pip_project:pip:21.2.4:*:*:*:*:*:*:*",
},
EvidenceList: []*sbom.Evidence{
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "/opt/lib/python3.9/site-packages/pip-21.2.4.dist-info/METADATA",
},
},
Purl: "pkg:pypi/[email protected]",
Version: "21.2.4",
}, pkg)
})

t.Run("generate sbom from a report with a python package error", func(t *testing.T) {
report, err := LoadReport("testdata/alpine-failed-python-package.json")
require.NoError(t, err)

sboms := GenerateBom(report)

selectedBom := sboms[0]
assert.Equal(t, sbom.Status_STATUS_FAILED, selectedBom.Status)
assert.Contains(t, selectedBom.ErrorMessage, "failed to parse bom fields json data")
assert.Len(t, selectedBom.Packages, 2)

pkg := findProtoPkg(selectedBom.Packages, "apk-tools")
require.Equal(t, &sbom.Package{
Name: "apk-tools",
Type: "apk",
Cpes: []string{
"cpe:2.3:a:apk-tools:apk-tools:1684120357:aarch64:*:*:*:*:*:*",
},
EvidenceList: []*sbom.Evidence{
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "lib/libapk.so.2.14.0",
},
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "sbin/apk",
},
},
Purl: "pkg:apk/alpine/apk-tools@1684120357%3A2.14.0-r5?arch=aarch64\u0026distro=alpine-3.19.0\u0026epoch=1684120357",
Version: "1684120357:2.14.0-r5",
}, pkg)

pkg = findProtoPkg(selectedBom.Packages, "npm")
require.Equal(t, &sbom.Package{
Name: "npm",
Type: "npm",
Cpes: []string{
"cpe:2.3:a:npm:npm:10.2.4:*:*:*:*:*:*:*",
},
EvidenceList: []*sbom.Evidence{
{
Type: sbom.EvidenceType_EVIDENCE_TYPE_FILE,
Value: "/opt/lib/node_modules/npm/package.json",
},
},
Purl: "pkg:npm/[email protected]",
Version: "10.2.4",
}, pkg)
})
}

Expand Down
76 changes: 76 additions & 0 deletions sbom/generator/testdata/alpine-failed-npm-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"assets": {
"//explorer.api.mondoo.com/assets/2cNOBxIv7117UjcqsDBvKUgwkKw": {
"mrn": "//explorer.api.mondoo.com/assets/2cNOBxIv7117UjcqsDBvKUgwkKw",
"name": "alpine:latest",
"trace_id": "trace-alpine"
}
},
"data": {
"//explorer.api.mondoo.com/assets/2cNOBxIv7117UjcqsDBvKUgwkKw": {
"values": {
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-asset": {
"content": {
"asset": {
"version": "3.19.0",
"arch": "aarch64",
"labels": {
"distro-id": "alpine"
},
"platform": "alpine",
"ids": [
"//platformid.api.mondoo.app/runtime/docker/images/1dc785547989b0db1c3cd9949c57574393e69bea98bfe044b0588e24721aa402"
],
"name": "alpine:latest",
"cpes.map": [
"cpe:2.3:o:alpinelinux:alpine_linux:3.19.0:*:*:*:*:*:*:*"
]
}
}
},
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-packages": {
"content": {
"packages.list": [
{
"purl": "pkg:apk/alpine/apk-tools@1684120357%3A2.14.0-r5?arch=aarch64\u0026distro=alpine-3.19.0\u0026epoch=1684120357",
"version": "1684120357:2.14.0-r5",
"name": "apk-tools",
"format": "apk",
"cpes.map": [
"cpe:2.3:a:apk-tools:apk-tools:1684120357:aarch64:*:*:*:*:*:*"
],
"files.map": [
"lib/libapk.so.2.14.0",
"sbin/apk"
]
}
]
}
},
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-python-packages": {
"content": {
"python.packages": [
{
"name": "pip",
"version": "21.2.4",
"cpes.map": [
"cpe:2.3:a:pip_project:pip:21.2.4:*:*:*:*:*:*:*"
],
"purl": "pkg:pypi/[email protected]",
"file.path": "/opt/lib/python3.9/site-packages/pip-21.2.4.dist-info/METADATA"
}
]
}
},
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-npm-packages": {
"content": {
"npm.packages.list": {
"error": "error fetching python packages"
}
}
}
}
}
},
"errors": {}
}
78 changes: 78 additions & 0 deletions sbom/generator/testdata/alpine-failed-python-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{
"assets": {
"//explorer.api.mondoo.com/assets/2cNOBxIv7117UjcqsDBvKUgwkKw": {
"mrn": "//explorer.api.mondoo.com/assets/2cNOBxIv7117UjcqsDBvKUgwkKw",
"name": "alpine:latest",
"trace_id": "trace-alpine"
}
},
"data": {
"//explorer.api.mondoo.com/assets/2cNOBxIv7117UjcqsDBvKUgwkKw": {
"values": {
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-asset": {
"content": {
"asset": {
"version": "3.19.0",
"arch": "aarch64",
"labels": {
"distro-id": "alpine"
},
"platform": "alpine",
"ids": [
"//platformid.api.mondoo.app/runtime/docker/images/1dc785547989b0db1c3cd9949c57574393e69bea98bfe044b0588e24721aa402"
],
"name": "alpine:latest",
"cpes.map": [
"cpe:2.3:o:alpinelinux:alpine_linux:3.19.0:*:*:*:*:*:*:*"
]
}
}
},
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-packages": {
"content": {
"packages.list": [
{
"purl": "pkg:apk/alpine/apk-tools@1684120357%3A2.14.0-r5?arch=aarch64\u0026distro=alpine-3.19.0\u0026epoch=1684120357",
"version": "1684120357:2.14.0-r5",
"name": "apk-tools",
"format": "apk",
"cpes.map": [
"cpe:2.3:a:apk-tools:apk-tools:1684120357:aarch64:*:*:*:*:*:*"
],
"files.map": [
"lib/libapk.so.2.14.0",
"sbin/apk"
]
}
]
}
},
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-python-packages": {
"content": {
"python.packages": {
"error": "error fetching python packages"
}
}
},
"//local.cnquery.io/run/local-execution/queries/mondoo-sbom-npm-packages": {
"content": {
"npm.packages.list": [
{
"name": "npm",
"files.map": [
"/opt/lib/node_modules/npm/package.json"
],
"cpes.map": [
"cpe:2.3:a:npm:npm:10.2.4:*:*:*:*:*:*:*"
],
"purl": "pkg:npm/[email protected]",
"version": "10.2.4"
}
]
}
}
}
}
},
"errors": {}
}

0 comments on commit b685f44

Please sign in to comment.