@@ -82,6 +82,14 @@ def spdx_id(value: str) -> str:
82
82
return re .sub (r"[^a-zA-Z0-9.\-]+" , "-" , value )
83
83
84
84
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
+
85
93
def filter_gitignored_paths (paths : list [str ]) -> list [str ]:
86
94
"""
87
95
Filter out paths excluded by the gitignore file.
@@ -206,22 +214,47 @@ def main() -> None:
206
214
discover_pip_sbom_package (sbom_data )
207
215
208
216
# 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
+ )
210
221
211
222
# Make a bunch of assertions about the SBOM data to ensure it's consistent.
212
223
for package in sbom_data ["packages" ]:
213
-
214
224
# 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
+ )
217
237
218
238
# Version must be in the download and external references.
219
239
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
+ )
222
251
223
252
# 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
+ )
225
258
226
259
# Regenerate file information from current data.
227
260
sbom_files = []
@@ -232,11 +265,13 @@ def main() -> None:
232
265
package_spdx_id = spdx_id (f"SPDXRef-PACKAGE-{ name } " )
233
266
exclude = files .exclude or ()
234
267
for include in sorted (files .include ):
235
-
236
268
# Find all the paths and then filter them through .gitignore.
237
269
paths = glob .glob (include , root_dir = CPYTHON_ROOT_DIR , recursive = True )
238
270
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
+ )
240
275
241
276
for path in paths :
242
277
# Skip directories and excluded files
0 commit comments