@@ -43,8 +43,11 @@ def extract_repo_and_commit_from_provenance(payload: InTotoPayload) -> tuple[str
4343 If the extraction process fails for any reason.
4444 """
4545 predicate_type = payload .statement .get ("predicateType" )
46- if isinstance (payload , InTotoV1Payload ) and predicate_type == "https://slsa.dev/provenance/v1" :
47- return _extract_from_slsa_v1 (payload )
46+ if isinstance (payload , InTotoV1Payload ):
47+ if predicate_type == "https://slsa.dev/provenance/v1" :
48+ return _extract_from_slsa_v1 (payload )
49+ if predicate_type == "https://docs.pypi.org/attestations/publish/v1" :
50+ return _extract_from_pypi_v1 (payload )
4851
4952 if isinstance (payload , InTotoV01Payload ):
5053 if predicate_type == "https://slsa.dev/provenance/v0.2" :
@@ -195,6 +198,32 @@ def _extract_from_slsa_v1(payload: InTotoV1Payload) -> tuple[str | None, str | N
195198 return repo , commit or None
196199
197200
201+ def _extract_from_pypi_v1 (payload : InTotoV1Payload ) -> tuple [str | None , str | None ]:
202+ """Extract the repository and commit metadata from the pypi provenance file found at the passed path.
203+
204+ This payload represents a custom predicate created from the certificate of a PyPI v1 attestation file.
205+ By design, these attestations come without a predicate.
206+
207+ Parameters
208+ ----------
209+ payload: InTotoPayload
210+ The payload to extract from.
211+
212+ Returns
213+ -------
214+ tuple[str, str]
215+ The repository URL and commit hash if found, a pair of empty strings otherwise.
216+ """
217+ predicate : dict [str , JsonType ] | None = payload .statement .get ("predicate" )
218+ if not predicate :
219+ logger .debug ("No predicate in payload statement." )
220+ return None , None
221+
222+ repo = json_extract (predicate , ["sourceUri" ], str )
223+ digest = json_extract (predicate , ["sourceDigest" ], str )
224+ return repo , digest
225+
226+
198227def _extract_from_witness_provenance (payload : InTotoV01Payload ) -> tuple [str | None , str | None ]:
199228 """Extract the repository and commit metadata from the witness provenance file found at the passed path.
200229
@@ -300,7 +329,7 @@ def check_if_input_purl_provenance_conflict(
300329 provenance_repo_url : str | None ,
301330 purl : PackageURL ,
302331) -> bool :
303- """Test if the input repository type PURL's repo and commit match the contents of the provenance.
332+ """Test if the input repository type PURL's repo matches the contents of the provenance.
304333
305334 Parameters
306335 ----------
@@ -620,6 +649,41 @@ def get_build_invocation(self, statement: InTotoV01Statement | InTotoV1Statement
620649 return gl_workflow , gl_job_url
621650
622651
652+ class PyPICertificateDefinition (ProvenanceBuildDefinition ):
653+ """Class representing the derived PyPI certificate build definition.
654+
655+ This class implements the abstract methods from the `ProvenanceBuildDefinition`
656+ to extract build invocation details specific to the GitHub Actions build type.
657+ """
658+
659+ #: Determines the expected ``buildType`` field in the provenance predicate.
660+ expected_build_type = "pypi_certificate"
661+
662+ def get_build_invocation (self , statement : InTotoV01Statement | InTotoV1Statement ) -> tuple [str | None , str | None ]:
663+ """Retrieve the build invocation information from the given statement.
664+
665+ Parameters
666+ ----------
667+ statement : InTotoV1Statement | InTotoV01Statement
668+ The provenance statement from which to extract the build invocation
669+ details. This statement contains the metadata about the build process
670+ and its associated artifacts.
671+
672+ Returns
673+ -------
674+ tuple[str | None, str | None]
675+ A tuple containing two elements:
676+ - The first element is the build invocation entry point (e.g., workflow name), or None if not found.
677+ - The second element is the invocation URL or identifier (e.g., job URL), or None if not found.
678+ """
679+ if statement ["predicate" ] is None :
680+ return None , None
681+
682+ gha_workflow = json_extract (statement ["predicate" ], ["workflow" ], str )
683+ invocation_url = json_extract (statement ["predicate" ], ["invocationUrl" ], str )
684+ return gha_workflow , invocation_url
685+
686+
623687class ProvenancePredicate :
624688 """Class providing utility methods for handling provenance predicates.
625689
@@ -685,6 +749,7 @@ def find_build_def(statement: InTotoV01Statement | InTotoV1Statement) -> Provena
685749 SLSAGCBBuildDefinitionV1 (),
686750 SLSAOCIBuildDefinitionV1 (),
687751 WitnessGitLabBuildDefinitionV01 (),
752+ PyPICertificateDefinition (),
688753 ]
689754
690755 for build_def in build_defs :
0 commit comments