@@ -82,6 +82,14 @@ def spdx_id(value: str) -> str:
8282 return re .sub (r"[^a-zA-Z0-9.\-]+" , "-" , value )
8383
8484
85+ def error_if (value : bool , error_message : str ) -> None :
86+ """Prints an error if a comparison fails along with a link to the devguide"""
87+ if value :
88+ print (error_message )
89+ print ("See 'https://devguide.python.org/developer-workflow/sbom' for more information." )
90+ sys .exit (1 )
91+
92+
8593def filter_gitignored_paths (paths : list [str ]) -> list [str ]:
8694 """
8795 Filter out paths excluded by the gitignore file.
@@ -206,22 +214,47 @@ def main() -> None:
206214 discover_pip_sbom_package (sbom_data )
207215
208216 # Ensure all packages in this tool are represented also in the SBOM file.
209- assert {package ["name" ] for package in sbom_data ["packages" ]} == set (PACKAGE_TO_FILES )
217+ error_if (
218+ {package ["name" ] for package in sbom_data ["packages" ]} != set (PACKAGE_TO_FILES ),
219+ "Packages defined in SBOM tool don't match those defined in SBOM file." ,
220+ )
210221
211222 # Make a bunch of assertions about the SBOM data to ensure it's consistent.
212223 for package in sbom_data ["packages" ]:
213-
214224 # Properties and ID must be properly formed.
215- assert set (package .keys ()) == REQUIRED_PROPERTIES_PACKAGE
216- assert package ["SPDXID" ] == spdx_id (f"SPDXRef-PACKAGE-{ package ['name' ]} " )
225+ error_if (
226+ "name" not in package ,
227+ "Package is missing the 'name' field"
228+ )
229+ error_if (
230+ set (package .keys ()) != REQUIRED_PROPERTIES_PACKAGE ,
231+ f"Package '{ package ['name' ]} ' is missing required fields" ,
232+ )
233+ error_if (
234+ package ["SPDXID" ] != spdx_id (f"SPDXRef-PACKAGE-{ package ['name' ]} " ),
235+ f"Package '{ package ['name' ]} ' has a malformed SPDXID" ,
236+ )
217237
218238 # Version must be in the download and external references.
219239 version = package ["versionInfo" ]
220- assert version in package ["downloadLocation" ]
221- assert all (version in ref ["referenceLocator" ] for ref in package ["externalRefs" ])
240+ error_if (
241+ version not in package ["downloadLocation" ],
242+ f"Version '{ version } ' for package '{ package ['name' ]} not in 'downloadLocation' field" ,
243+ )
244+ error_if (
245+ any (version not in ref ["referenceLocator" ] for ref in package ["externalRefs" ]),
246+ (
247+ f"Version '{ version } ' for package '{ package ['name' ]} not in "
248+ f"all 'externalRefs[].referenceLocator' fields"
249+ ),
250+ )
222251
223252 # License must be on the approved list for SPDX.
224- assert package ["licenseConcluded" ] in ALLOWED_LICENSE_EXPRESSIONS , package ["licenseConcluded" ]
253+ license_concluded = package ["licenseConcluded" ]
254+ error_if (
255+ license_concluded not in ALLOWED_LICENSE_EXPRESSIONS ,
256+ f"License identifier '{ license_concluded } ' not in SBOM tool allowlist"
257+ )
225258
226259 # Regenerate file information from current data.
227260 sbom_files = []
@@ -232,11 +265,13 @@ def main() -> None:
232265 package_spdx_id = spdx_id (f"SPDXRef-PACKAGE-{ name } " )
233266 exclude = files .exclude or ()
234267 for include in sorted (files .include ):
235-
236268 # Find all the paths and then filter them through .gitignore.
237269 paths = glob .glob (include , root_dir = CPYTHON_ROOT_DIR , recursive = True )
238270 paths = filter_gitignored_paths (paths )
239- assert paths , include # Make sure that every value returns something!
271+ error_if (
272+ len (paths ) == 0 ,
273+ f"No valid paths found at path '{ include } ' for package '{ name } " ,
274+ )
240275
241276 for path in paths :
242277 # Skip directories and excluded files
0 commit comments