2424from pydantic import Base64Bytes , BaseModel , ConfigDict , Field , field_validator
2525from pydantic .alias_generators import to_snake
2626from pydantic_core import ValidationError
27+ from rfc3161_client import decode_timestamp_response
2728from sigstore ._utils import _sha256_streaming
2829from sigstore .dsse import DigestSet , StatementBuilder , Subject , _Statement
2930from sigstore .dsse import Envelope as DsseEnvelope
@@ -136,6 +137,7 @@ def __init__(self: VerificationError, msg: str) -> None:
136137
137138
138139TransparencyLogEntry = NewType ("TransparencyLogEntry" , dict [str , Any ])
140+ Timestamp = NewType ("Timestamp" , bytes )
139141
140142
141143class VerificationMaterial (BaseModel ):
@@ -152,6 +154,11 @@ class VerificationMaterial(BaseModel):
152154 and certificate.
153155 """
154156
157+ timestamps : list [Timestamp ] = []
158+ """
159+ list of RFC3161 timestamps. List may be empty if all transparency entries are rekor v1.
160+ """
161+
155162
156163class Attestation (BaseModel ):
157164 """Attestation object as defined in PEP 740."""
@@ -347,10 +354,16 @@ def to_bundle(self) -> Bundle:
347354 except (ValidationError , sigstore .errors .Error ) as err :
348355 raise ConversionError ("invalid transparency log entry" ) from err
349356
357+ timestamps = [
358+ decode_timestamp_response (base64 .b64encode (t ))
359+ for t in self .verification_material .timestamps
360+ ]
361+
350362 return Bundle ._from_parts ( # noqa: SLF001
351363 cert = certificate ,
352364 content = evp ,
353365 log_entry = log_entry ,
366+ signed_timestamp = timestamps ,
354367 )
355368
356369 @classmethod
@@ -368,13 +381,19 @@ def from_bundle(cls, sigstore_bundle: Bundle) -> Attestation:
368381 if len (envelope .signatures ) != 1 :
369382 raise ConversionError (f"expected exactly one signature, got { len (envelope .signatures )} " )
370383
384+ timestamps = []
385+ if sigstore_bundle .verification_material .timestamp_verification_data :
386+ ts_data = sigstore_bundle .verification_material .timestamp_verification_data
387+ timestamps = [base64 .b64encode (ts .as_bytes ()) for ts in ts_data .rfc3161_timestamps ]
388+
371389 return cls (
372390 version = 1 ,
373391 verification_material = VerificationMaterial (
374392 certificate = base64 .b64encode (certificate ),
375393 transparency_entries = [
376394 sigstore_bundle .log_entry ._inner .to_dict () # noqa: SLF001
377395 ],
396+ timestamps = timestamps ,
378397 ),
379398 envelope = Envelope (
380399 statement = base64 .b64encode (envelope .payload ),
0 commit comments