1import typing as t
2
3import typing_extensions as te
4from pydantic import model_validator
5
6from sigstore_models._core import Base
7from sigstore_models.common.v1 import (
8 MessageSignature,
9 PublicKeyIdentifier,
10 RFC3161SignedTimestamp,
11 X509Certificate,
12 X509CertificateChain,
13)
14from sigstore_models.intoto import Envelope
15from sigstore_models.rekor.v1 import TransparencyLogEntry
16
17
18class TimestampVerificationData(Base):
19 rfc3161_timestamps: list[RFC3161SignedTimestamp] = []
20
21
22class VerificationMaterial(Base):
23 public_key: t.Optional[PublicKeyIdentifier] = None
24 x509_certificate_chain: t.Optional[X509CertificateChain] = None
25 certificate: t.Optional[X509Certificate] = None
26
27 tlog_entries: list[TransparencyLogEntry] # TODO
28 timestamp_verification_data: t.Optional[TimestampVerificationData] = None
29
30 @model_validator(mode="after")
31 def check_content_oneof(self) -> te.Self:
32 fields = [self.public_key, self.x509_certificate_chain, self.certificate]
33 if sum(bool(f) for f in fields) != 1:
34 raise ValueError(
35 "Exactly one of publicKey, x509CertificateChain, or certificate must be set"
36 )
37 return self
38
39
40BUNDLE_MEDIA_TYPES = t.Literal[
41 "application/vnd.dev.sigstore.bundle+json;version=0.1",
42 "application/vnd.dev.sigstore.bundle+json;version=0.2",
43 "application/vnd.dev.sigstore.bundle+json;version=0.3",
44 "application/vnd.dev.sigstore.bundle.v0.3+json",
45]
46
47
48class Bundle(Base):
49 media_type: BUNDLE_MEDIA_TYPES
50 verification_material: VerificationMaterial
51
52 message_signature: t.Optional[MessageSignature] = None
53 dsse_envelope: t.Optional[Envelope] = None
54
55 @model_validator(mode="after")
56 def check_content_oneof(self) -> te.Self:
57 fields = [self.message_signature, self.dsse_envelope]
58 if sum(bool(f) for f in fields) != 1:
59 raise ValueError(
60 "Exactly one of messageSignature or dsseEnvelope must be set"
61 )
62 return self