Skip to content

Commit ea3e8df

Browse files
committed
fix(validate_sbom): do not require a CPE on nested wolfcrypt
Matching rides on the wolfssl CPE. wolfcrypt stays a provenance component and must still carry a version and a PURL.
1 parent af1ed32 commit ea3e8df

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

share/validate_sbom.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
* at least one component or component property recorded
1414
* optional --min-properties N on metadata.component.properties
1515
* optional --require-dep-version NAME: a components[] entry with that
16-
name must exist and carry a non-empty version and CPE. Nested
17-
sub-components count, since wolfcrypt ships inside wolfssl.
16+
name must exist and carry a non-empty version. Nested sub-components
17+
count, since wolfcrypt ships inside wolfssl. wolfcrypt is provenance
18+
only (PURL, no CPE); matching rides on the parent wolfssl CPE. Every
19+
other required dep must also carry a CPE.
1820
1921
SPDX (*.spdx.json):
2022
* spdxVersion starts with "SPDX-2"
@@ -34,6 +36,12 @@
3436
import sys
3537

3638

39+
# Nested wolfcrypt is a provenance component. NVD files crypto CVEs against
40+
# wolfssl, not wolfcrypt; requiring a wolfcrypt CPE would fail a correct
41+
# SBOM and would later double-match. The unique id is the PURL.
42+
_CPE_OPTIONAL_DEPS = frozenset({"wolfcrypt"})
43+
44+
3745
def fail(path, msg):
3846
print(f"FAIL [{path}]: {msg}", file=sys.stderr)
3947
sys.exit(1)
@@ -81,6 +89,11 @@ def validate_cyclonedx(path, d, name_prefix, min_properties, require_deps):
8189
if not matches[0].get("version"):
8290
fail(path, f"dependency component {dep_name!r} has no version "
8391
f"(pass --dep-version or set WOLFSSL_DIR)")
92+
if dep_name in _CPE_OPTIONAL_DEPS:
93+
if not matches[0].get("purl"):
94+
fail(path, f"dependency component {dep_name!r} has no purl "
95+
f"(provenance id; matching uses the wolfssl CPE)")
96+
continue
8497
if not matches[0].get("cpe"):
8598
fail(path, f"dependency component {dep_name!r} has no cpe "
8699
f"(CPE-driven scanners cannot match it)")

tests/test_sbom.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ def unit_tests():
176176
"cpe": "cpe:2.3:a:wolfssl:wolfssl:5.9.1:*:*:*:*:*:*:*",
177177
"components": [{
178178
"name": "wolfcrypt", "version": "5.9.1",
179+
"purl": "pkg:github/wolfssl/wolfssl@v5.9.1-stable#wolfcrypt",
179180
}],
180181
}],
181182
}, f)
@@ -185,6 +186,44 @@ def unit_tests():
185186
stdout=subprocess.DEVNULL)
186187
check(rc == 0, "validator finds a nested dependency component")
187188

189+
no_purl = os.path.join(d, "no-purl.cdx.json")
190+
with open(no_purl, "w") as f:
191+
json.dump({
192+
"bomFormat": "CycloneDX", "specVersion": "1.6",
193+
"metadata": {"component": {"name": "wolfboot",
194+
"version": "2.9.0",
195+
"properties": [{"a": "b"}]}},
196+
"components": [{
197+
"name": "wolfssl", "version": "5.9.1",
198+
"cpe": "cpe:2.3:a:wolfssl:wolfssl:5.9.1:*:*:*:*:*:*:*",
199+
"components": [{
200+
"name": "wolfcrypt", "version": "5.9.1",
201+
}],
202+
}],
203+
}, f)
204+
rc = subprocess.call([sys.executable, VALIDATE,
205+
"--require-dep-version", "wolfcrypt", no_purl],
206+
stdout=subprocess.DEVNULL,
207+
stderr=subprocess.DEVNULL)
208+
check(rc != 0, "validator rejects nested wolfcrypt without a PURL")
209+
210+
no_cpe = os.path.join(d, "no-cpe.cdx.json")
211+
with open(no_cpe, "w") as f:
212+
json.dump({
213+
"bomFormat": "CycloneDX", "specVersion": "1.6",
214+
"metadata": {"component": {"name": "wolfboot",
215+
"version": "2.9.0",
216+
"properties": [{"a": "b"}]}},
217+
"components": [{
218+
"name": "wolfssl", "version": "5.9.1",
219+
}],
220+
}, f)
221+
rc = subprocess.call([sys.executable, VALIDATE,
222+
"--require-dep-version", "wolfssl", no_cpe],
223+
stdout=subprocess.DEVNULL,
224+
stderr=subprocess.DEVNULL)
225+
check(rc != 0, "validator still requires a CPE on wolfssl")
226+
188227

189228
def find_gen_sbom(explicit):
190229
if explicit and os.path.isfile(explicit):

0 commit comments

Comments
 (0)