@@ -854,13 +854,14 @@ def test_wolfssl_dep_entry_describes_the_linked_artefact(self):
854854 wolfssl ['cpe' ]('5.7.4' ),
855855 'cpe:2.3:a:wolfssl:wolfssl:5.7.4:*:*:*:*:*:*:*' )
856856
857- def test_wolfcrypt_dep_entry_carries_registered_nvd_cpe (self ):
857+ def test_wolfcrypt_dep_entry_has_purl_and_no_cpe (self ):
858+ # Provenance only: NVD files crypto CVEs against wolfssl, not
859+ # wolfcrypt. A nested CPE would not match today and would
860+ # double-match later.
858861 wc = gs .DEP_META ['wolfcrypt' ]
859862 self .assertEqual (wc ['name' ], 'wolfcrypt' )
860863 self .assertIsNone (wc ['pkgconfig' ])
861- self .assertEqual (
862- wc ['cpe' ]('5.9.1' ),
863- 'cpe:2.3:a:wolfssl:wolfcrypt:5.9.1:*:*:*:*:*:*:*' )
864+ self .assertIsNone (wc .get ('cpe' ))
864865 # Resolvable github PURL for the wolfssl release that ships it,
865866 # with a #wolfcrypt subpath so it does not collide with wolfssl.
866867 self .assertEqual (
@@ -907,12 +908,14 @@ def test_dep_constructors_strip_plus_build_metadata(self):
907908 dirty = '1.2.3+local'
908909 for key , meta in gs .DEP_META .items ():
909910 with self .subTest (dep = key ):
910- cpe = meta ['cpe' ](dirty )
911- self .assertNotIn ('+' , cpe , cpe )
912- self .assertIn (':1.2.3:' , cpe )
913911 purl = meta ['purl' ](dirty )
914912 self .assertNotIn ('+' , purl , purl )
915913 self .assertIn ('1.2.3' , purl )
914+ if not meta .get ('cpe' ):
915+ continue
916+ cpe = meta ['cpe' ](dirty )
917+ self .assertNotIn ('+' , cpe , cpe )
918+ self .assertIn (':1.2.3:' , cpe )
916919
917920 def test_openssl_dep_cpe_and_purl_drop_build_metadata (self ):
918921 # wolfProvider patches OpenSSL BUILD_METADATA, so openssl version
@@ -943,16 +946,19 @@ def test_openssl_dep_cpe_and_purl_drop_build_metadata(self):
943946 self .assertEqual (
944947 locators ['purl' ], 'pkg:github/openssl/openssl@openssl-3.5.4' )
945948
946- def test_every_dep_entry_carries_both_identifiers (self ):
947- # A dep with only one identifier is invisible to half the scanner
948- # population: PURL serves OSV / Trivy / Dependency-Track, CPE serves
949- # NVD, which is what a CRA vulnerability-monitoring process keys on .
949+ def test_every_dep_entry_carries_a_purl (self ):
950+ # PURL serves OSV / Trivy / Dependency-Track. CPE serves NVD.
951+ # wolfcrypt is the exception: matching rides on the parent
952+ # wolfssl CPE, so a nested wolfcrypt CPE is omitted on purpose .
950953 for key , meta in gs .DEP_META .items ():
951954 with self .subTest (dep = key ):
952955 purl = meta ['purl' ]('1.2.3' )
953- cpe = meta ['cpe' ]('1.2.3' )
954956 self .assertTrue (purl .startswith ('pkg:' ), purl )
955957 self .assertIn ('1.2.3' , purl )
958+ if key == 'wolfcrypt' :
959+ self .assertIsNone (meta .get ('cpe' ))
960+ continue
961+ cpe = meta ['cpe' ]('1.2.3' )
956962 self .assertTrue (cpe .startswith ('cpe:2.3:a:' ), cpe )
957963 self .assertEqual (len (cpe .split (':' )), 13 , cpe )
958964 self .assertIn (':1.2.3:' , cpe )
@@ -1955,13 +1961,12 @@ def test_wolfssl_dep_component_carries_nvd_cpe(self):
19551961 self .assertEqual (
19561962 comp ['purl' ], 'pkg:github/wolfssl/wolfssl@v5.9.1-stable' )
19571963
1958- def test_wolfcrypt_dep_component_carries_nvd_cpe (self ):
1964+ def test_wolfcrypt_dep_component_has_purl_and_no_cpe (self ):
19591965 _ , comp = gs .cdx_dep_component (
19601966 'wolfboot' , '2.9.0' , 'wolfcrypt' , {'wolfcrypt' : '5.9.1' })
19611967 self .assertEqual (comp ['name' ], 'wolfcrypt' )
19621968 self .assertEqual (comp ['version' ], '5.9.1' )
1963- self .assertEqual (
1964- comp ['cpe' ], 'cpe:2.3:a:wolfssl:wolfcrypt:5.9.1:*:*:*:*:*:*:*' )
1969+ self .assertNotIn ('cpe' , comp )
19651970 self .assertEqual (
19661971 comp ['purl' ],
19671972 'pkg:github/wolfssl/wolfssl@v5.9.1-stable#wolfcrypt' )
@@ -2067,6 +2072,12 @@ def test_cpe_externalref_present_when_version_known(self):
20672072 cpe_refs [0 ]['referenceLocator' ],
20682073 'cpe:2.3:a:wolfssl:wolfssl:5.9.1:*:*:*:*:*:*:*' )
20692074
2075+ def test_wolfcrypt_omits_cpe_externalref (self ):
2076+ _ , pkg = gs .spdx_dep_package ('wolfcrypt' , {'wolfcrypt' : '5.9.1' })
2077+ types = [r ['referenceType' ] for r in pkg .get ('externalRefs' , [])]
2078+ self .assertNotIn ('cpe23Type' , types )
2079+ self .assertIn ('purl' , types )
2080+
20702081
20712082class TestGenerateCdx (unittest .TestCase ):
20722083 """gen-sbom:624 generate_cdx assembles the full CycloneDX 1.6 doc."""
@@ -2996,9 +3007,11 @@ def test_cdx_nests_wolfcrypt_inside_wolfssl(self):
29963007
29973008 nested = {c ['name' ]: c for c in top ['wolfssl' ]['components' ]}
29983009 self .assertEqual (set (nested ), {'wolfcrypt' })
3010+ self .assertEqual (nested ['wolfcrypt' ]['version' ], '5.9.1' )
29993011 self .assertEqual (
3000- nested ['wolfcrypt' ]['cpe' ],
3001- 'cpe:2.3:a:wolfssl:wolfcrypt:5.9.1:*:*:*:*:*:*:*' )
3012+ nested ['wolfcrypt' ]['purl' ],
3013+ 'pkg:github/wolfssl/wolfssl@v5.9.1-stable#wolfcrypt' )
3014+ self .assertNotIn ('cpe' , nested ['wolfcrypt' ])
30023015
30033016 def test_cdx_dependency_edges_follow_the_nesting (self ):
30043017 doc = gs .generate_cdx (** self .BASE_KW )
@@ -3053,6 +3066,18 @@ def test_spdx_expresses_containment_not_a_second_dependency(self):
30533066 self .assertEqual (
30543067 rels [('SPDXRef-Package-wolfssl' , 'SPDXRef-Package-wolfcrypt' )],
30553068 'CONTAINS' )
3069+ pkgs = {p ['name' ]: p for p in doc ['packages' ]}
3070+ wc_refs = {r ['referenceType' ]: r ['referenceLocator' ]
3071+ for r in pkgs ['wolfcrypt' ]['externalRefs' ]}
3072+ self .assertNotIn ('cpe23Type' , wc_refs )
3073+ self .assertEqual (
3074+ wc_refs ['purl' ],
3075+ 'pkg:github/wolfssl/wolfssl@v5.9.1-stable#wolfcrypt' )
3076+ ssl_refs = {r ['referenceType' ]: r ['referenceLocator' ]
3077+ for r in pkgs ['wolfssl' ]['externalRefs' ]}
3078+ self .assertEqual (
3079+ ssl_refs ['cpe23Type' ],
3080+ 'cpe:2.3:a:wolfssl:wolfssl:5.9.1:*:*:*:*:*:*:*' )
30563081
30573082 def test_spdx_wolfssl_own_sbom_contains_its_wolfcrypt (self ):
30583083 # wolfSSL ships wolfCrypt; it does not depend on it.
@@ -3075,11 +3100,12 @@ def test_wolfssl_own_sbom_keeps_wolfcrypt_top_level(self):
30753100 self .BASE_KW , name = 'wolfssl' , version = '5.9.1' ,
30763101 enabled_deps = ['wolfcrypt' ], component_type = 'library' ))
30773102 self .assertEqual ([c ['name' ] for c in doc ['components' ]], ['wolfcrypt' ])
3103+ self .assertNotIn ('cpe' , doc ['components' ][0 ])
30783104
3079- def test_tool_version_is_1_8 (self ):
3105+ def test_tool_version_is_1_9 (self ):
30803106 doc = gs .generate_cdx (** self .BASE_KW )
30813107 tools = doc ['metadata' ]['tools' ]['components' ]
3082- self .assertEqual (tools [0 ]['version' ], '1.8 ' )
3108+ self .assertEqual (tools [0 ]['version' ], '1.9 ' )
30833109
30843110
30853111if __name__ == '__main__' :
@@ -3092,7 +3118,7 @@ class TestWolfcryptVersionInheritance(unittest.TestCase):
30923118 Regression: the inheritance ran BEFORE _resolve_dep_versions, so it only
30933119 ever saw versions passed explicitly via --dep-version. A downstream
30943120 embedder (wolfBoot) whose wolfssl version came from pkg-config got a
3095- wolfcrypt component with no version, no purl and no cpe , and exit 0.
3121+ wolfcrypt component with no version and no purl , and exit 0.
30963122 """
30973123
30983124 def test_inherits_wolfssl_version_resolved_by_pkgconfig (self ):
@@ -3121,17 +3147,20 @@ def test_noop_when_wolfcrypt_not_enabled(self):
31213147 ['wolfssl' ], overrides , 'wolfboot' , '2.9.0' )
31223148 self .assertNotIn ('wolfcrypt' , overrides )
31233149
3124- def test_inherited_version_yields_a_resolvable_cpe (self ):
3125- # End state that matters: the CPE 2.3 formatted string is well formed
3126- # (13 colon-separated fields) and carries the inherited version .
3150+ def test_inherited_version_yields_a_resolvable_purl_and_no_cpe (self ):
3151+ # End state that matters: the nested component is versioned and
3152+ # has a resolvable PURL. Matching stays on the wolfssl CPE .
31273153 overrides = {'wolfssl' : '5.9.1' , 'wolfcrypt' : None }
31283154 gs ._inherit_wolfcrypt_version (
31293155 ['wolfssl' , 'wolfcrypt' ], overrides , 'wolfboot' , '2.9.0' )
31303156 _ref , comp = gs .cdx_dep_component (
31313157 'wolfcrypt' , overrides ['wolfcrypt' ], 'wolfcrypt' , overrides )
31323158 self .assertEqual (
3133- comp ['cpe' ], 'cpe:2.3:a:wolfssl:wolfcrypt:5.9.1:*:*:*:*:*:*:*' )
3134- self .assertEqual (len (comp ['cpe' ].split (':' )), 13 )
3159+ comp ['purl' ],
3160+ 'pkg:github/wolfssl/wolfssl@v5.9.1-stable#wolfcrypt' )
3161+ self .assertNotIn ('cpe' , comp )
3162+
3163+
31353164class TestEnabledDepsValidation (unittest .TestCase ):
31363165 """--dep-* must be exactly yes or no.
31373166
0 commit comments