55import logging
66import os
77import tempfile
8+ from dataclasses import dataclass
89from functools import partial
910
1011from packageurl import PackageURL
2829logger : logging .Logger = logging .getLogger (__name__ )
2930
3031
32+ @dataclass (frozen = True )
33+ class ProvenanceAsset :
34+ """This class exists to hold a provenance payload with the original asset's name and URL."""
35+
36+ payload : InTotoPayload
37+ name : str
38+ url : str
39+
40+
3141class ProvenanceFinder :
3242 """This class is used to find and retrieve provenance files from supported registries."""
3343
@@ -42,7 +52,7 @@ def __init__(self) -> None:
4252 elif isinstance (registry , JFrogMavenRegistry ):
4353 self .jfrog_registry = registry
4454
45- def find_provenance (self , purl : PackageURL ) -> list [InTotoPayload ]:
55+ def find_provenance (self , purl : PackageURL ) -> list [ProvenanceAsset ]:
4656 """Find the provenance file(s) of the passed PURL.
4757
4858 Parameters
@@ -52,8 +62,8 @@ def find_provenance(self, purl: PackageURL) -> list[InTotoPayload]:
5262
5363 Returns
5464 -------
55- list[InTotoPayload ]
56- The provenance payload , or an empty list if not found.
65+ list[ProvenanceAsset ]
66+ The provenance asset , or an empty list if not found.
5767 """
5868 logger .debug ("Seeking provenance of: %s" , purl )
5969
@@ -82,7 +92,7 @@ def find_provenance(self, purl: PackageURL) -> list[InTotoPayload]:
8292 logger .debug ("Provenance finding not supported for PURL type: %s" , purl .type )
8393 return []
8494
85- def _find_provenance (self , discovery_functions : list [partial [list [InTotoPayload ]]]) -> list [InTotoPayload ]:
95+ def _find_provenance (self , discovery_functions : list [partial [list [ProvenanceAsset ]]]) -> list [ProvenanceAsset ]:
8696 """Find the provenance file(s) using the passed discovery functions.
8797
8898 Parameters
@@ -93,7 +103,7 @@ def _find_provenance(self, discovery_functions: list[partial[list[InTotoPayload]
93103 Returns
94104 -------
95105 list[InTotoPayload]
96- The provenance payload (s) from the first successful function, or an empty list if none were.
106+ The provenance asset (s) from the first successful function, or an empty list if none were.
97107 """
98108 if not discovery_functions :
99109 return []
@@ -108,7 +118,7 @@ def _find_provenance(self, discovery_functions: list[partial[list[InTotoPayload]
108118 return []
109119
110120
111- def find_npm_provenance (purl : PackageURL , registry : NPMRegistry ) -> list [InTotoPayload ]:
121+ def find_npm_provenance (purl : PackageURL , registry : NPMRegistry ) -> list [ProvenanceAsset ]:
112122 """Find and download the NPM based provenance for the passed PURL.
113123
114124 Two kinds of attestation can be retrieved from npm: "Provenance" and "Publish". The "Provenance" attestation
@@ -125,8 +135,8 @@ def find_npm_provenance(purl: PackageURL, registry: NPMRegistry) -> list[InTotoP
125135
126136 Returns
127137 -------
128- list[InTotoPayload ]
129- The provenance payload (s), or an empty list if not found.
138+ list[ProvenanceAsset ]
139+ The provenance asset (s), or an empty list if not found.
130140 """
131141 if not registry .enabled :
132142 logger .debug ("The npm registry is not enabled." )
@@ -172,16 +182,19 @@ def find_npm_provenance(purl: PackageURL, registry: NPMRegistry) -> list[InTotoP
172182 publish_payload = load_provenance_payload (signed_download_path )
173183 except LoadIntotoAttestationError as error :
174184 logger .error ("Error while loading publish attestation: %s" , error )
175- return [provenance_payload ]
185+ return [ProvenanceAsset ( provenance_payload , npm_provenance_asset . name , npm_provenance_asset . url ) ]
176186
177- return [provenance_payload , publish_payload ]
187+ return [
188+ ProvenanceAsset (provenance_payload , npm_provenance_asset .name , npm_provenance_asset .url ),
189+ ProvenanceAsset (publish_payload , npm_provenance_asset .name , npm_provenance_asset .url ),
190+ ]
178191
179192 except OSError as error :
180193 logger .error ("Error while storing provenance in the temporary directory: %s" , error )
181194 return []
182195
183196
184- def find_gav_provenance (purl : PackageURL , registry : JFrogMavenRegistry ) -> list [InTotoPayload ]:
197+ def find_gav_provenance (purl : PackageURL , registry : JFrogMavenRegistry ) -> list [ProvenanceAsset ]:
185198 """Find and download the GAV based provenance for the passed PURL.
186199
187200 Parameters
@@ -193,8 +206,8 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[
193206
194207 Returns
195208 -------
196- list[InTotoPayload ] | None
197- The provenance payload if found, or an empty list otherwise.
209+ list[ProvenanceAsset ] | None
210+ The provenance asset if found, or an empty list otherwise.
198211
199212 Raises
200213 ------
@@ -263,7 +276,7 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[
263276 if not is_witness_provenance_payload (provenance_payload , witness_verifier_config .predicate_types ):
264277 continue
265278
266- provenances .append (provenance_payload )
279+ provenances .append (ProvenanceAsset ( provenance_payload , provenance_asset . name , provenance_asset . url ) )
267280 except OSError as error :
268281 logger .error ("Error while storing provenance in the temporary directory: %s" , error )
269282
@@ -277,7 +290,7 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[
277290
278291def find_provenance_from_ci (
279292 analyze_ctx : AnalyzeContext , git_obj : Git | None , download_path : str
280- ) -> InTotoPayload | None :
293+ ) -> ProvenanceAsset | None :
281294 """Try to find provenance from CI services of the repository.
282295
283296 Note that we stop going through the CI services once we encounter a CI service
@@ -372,7 +385,10 @@ def find_provenance_from_ci(
372385 download_provenances_from_ci_service (ci_info , download_path )
373386
374387 # TODO consider how to handle multiple payloads here.
375- return ci_info ["provenances" ][0 ].payload if ci_info ["provenances" ] else None
388+ if ci_info ["provenances" ]:
389+ provenance = ci_info ["provenances" ][0 ]
390+ return ProvenanceAsset (provenance .payload , provenance .asset .name , provenance .asset .url )
391+ return None
376392
377393 else :
378394 logger .debug ("CI service not supported for provenance finding: %s" , ci_service .name )
0 commit comments