Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,4 @@ jobs:
run: sudo apt-get install -y firejail

- name: run tests offline
run: |
make dev INSTALL_EXTRA=test
firejail --noprofile --net=none --env=TEST_OFFLINE=1 make test-nocoverage
run: make test-offline INSTALL_EXTRA=test
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ test-nocoverage: $(VENV)/pyvenv.cfg
. $(VENV_BIN)/activate && \
pytest $(T) $(TEST_ARGS)

# test-offline requires firejail
.PHONY: test-offline
test-offline: $(VENV)/pyvenv.cfg
# ensure trust root is updated, then run tests inside no-network firejail
. $(VENV_BIN)/activate && \
python -m sigstore plumbing update-trust-root && \
python -m sigstore --staging plumbing update-trust-root && \
firejail --noprofile --net=none --env=TEST_OFFLINE=1 pytest $(T) $(TEST_ARGS)

.PHONY: doc
doc: $(VENV)/pyvenv.cfg
. $(VENV_BIN)/activate && \
Expand Down
14 changes: 12 additions & 2 deletions src/pypi_attestations/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

import argparse
import base64
import json
import logging
import typing
Expand All @@ -20,6 +21,7 @@
parse_wheel_filename,
)
from pydantic import ValidationError
from rfc3161_client import decode_timestamp_response
from rfc3986 import exceptions, uri_reference, validators
from sigstore.models import Bundle, ClientTrustConfig, InvalidBundle
from sigstore.oidc import IdentityError, IdentityToken, Issuer
Expand Down Expand Up @@ -428,7 +430,7 @@ def _sign(args: argparse.Namespace) -> None:
_die(f"Failed to detect identity: {identity_error}")

trust_config = ClientTrustConfig.staging() if args.staging else ClientTrustConfig.production()
# Make sure we use rekor v1 until attestations are compatible with v2
# Make sure we choose the rekor version: currently v1
trust_config.force_tlog_version = 1

signing_ctx = SigningContext.from_trust_config(trust_config)
Expand Down Expand Up @@ -464,7 +466,7 @@ def _inspect(args: argparse.Namespace) -> None:

Warning: The information displayed from the attestations are not verified.
"""
attestation_files = [f for f in args.files if f.suffix == ".attestation"]
attestation_files = args.files
_validate_files(attestation_files, should_exist=True)
for file_path in attestation_files:
try:
Expand Down Expand Up @@ -513,6 +515,14 @@ def _inspect(args: argparse.Namespace) -> None:
)
for idx, entry in enumerate(verification_material.transparency_entries):
_logger.info(f"\tLog Index: {entry['logIndex']}")
kv = entry["kindVersion"]
_logger.info(f"\tEntry type: {kv['kind']} {kv['version']}")

# Timestamps
_logger.info(f"Timestamps ({len(verification_material.timestamps)}):")
for data in verification_material.timestamps:
ts = decode_timestamp_response(base64.b64decode(data))
_logger.info(f"\tTime: {ts.tst_info.gen_time}")


def _verify_attestation(args: argparse.Namespace) -> None:
Expand Down
19 changes: 19 additions & 0 deletions src/pypi_attestations/_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from pydantic import Base64Bytes, BaseModel, ConfigDict, Field, field_validator
from pydantic.alias_generators import to_snake
from pydantic_core import ValidationError
from rfc3161_client import decode_timestamp_response
from sigstore._utils import _sha256_streaming
from sigstore.dsse import DigestSet, StatementBuilder, Subject, _Statement
from sigstore.dsse import Envelope as DsseEnvelope
Expand Down Expand Up @@ -136,6 +137,7 @@ def __init__(self: VerificationError, msg: str) -> None:


TransparencyLogEntry = NewType("TransparencyLogEntry", dict[str, Any])
Timestamp = NewType("Timestamp", bytes)


class VerificationMaterial(BaseModel):
Expand All @@ -152,6 +154,11 @@ class VerificationMaterial(BaseModel):
and certificate.
"""

timestamps: list[Timestamp] = []
"""
list of RFC3161 timestamps. List may be empty if all transparency entries are rekor v1.
"""


class Attestation(BaseModel):
"""Attestation object as defined in PEP 740."""
Expand Down Expand Up @@ -347,10 +354,16 @@ def to_bundle(self) -> Bundle:
except (ValidationError, sigstore.errors.Error) as err:
raise ConversionError("invalid transparency log entry") from err

timestamps = [
decode_timestamp_response(base64.b64decode(t))
for t in self.verification_material.timestamps
]

return Bundle._from_parts( # noqa: SLF001
cert=certificate,
content=evp,
log_entry=log_entry,
signed_timestamp=timestamps,
)

@classmethod
Expand All @@ -368,13 +381,19 @@ def from_bundle(cls, sigstore_bundle: Bundle) -> Attestation:
if len(envelope.signatures) != 1:
raise ConversionError(f"expected exactly one signature, got {len(envelope.signatures)}")

timestamps = []
if sigstore_bundle.verification_material.timestamp_verification_data:
ts_data = sigstore_bundle.verification_material.timestamp_verification_data
timestamps = [base64.b64encode(ts.as_bytes()) for ts in ts_data.rfc3161_timestamps]
Copy link
Contributor Author

@jku jku Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this is the main decision in this PR: A timestamp in the attestations serialization format is the base64 encoded timestamp response as defined in RFC3161.

For reference the timestamp use is defined in sigstore client spec, but it's basically the same as the use of integrated time in rekor1: timestamped data is the signature bytes, at least one timestamp time must be within lifetime of the signing certificate (and its chain) to prove the time of signing.


return cls(
version=1,
verification_material=VerificationMaterial(
certificate=base64.b64encode(certificate),
transparency_entries=[
sigstore_bundle.log_entry._inner.to_dict() # noqa: SLF001
],
timestamps=timestamps,
),
envelope=Envelope(
statement=base64.b64encode(envelope.payload),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":1,"verification_material":{"certificate":"MIICyjCCAlGgAwIBAgIUCwSld2TPMfzGf7dWDCWJ/usimb0wCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjUxMDEwMDgyMzQxWhcNMjUxMDEwMDgzMzQxWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEpxjPe0rDTmkfNdf3BYfERviPS1HwIraC9anAY6nvb50XOV3UdRaOuhrcqK7eKEfDX5CIfuTbla7V4sNHo3b3W6OCAXAwggFsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUi7a3nCqG5XXtGAudLFN0kH2Rc8gwHwYDVR0jBBgwFoAUcYYwphR8Ym/599b0BRp/X//rb6wwGQYDVR0RAQH/BA8wDYELamt1QGdvdG8uZmkwLAYKKwYBBAGDvzABAQQeaHR0cHM6Ly9naXRodWIuY29tL2xvZ2luL29hdXRoMC4GCisGAQQBg78wAQgEIAweaHR0cHM6Ly9naXRodWIuY29tL2xvZ2luL29hdXRoMIGLBgorBgEEAdZ5AgQCBH0EewB5AHcAKzC83GiIyeLh2CYpXnQfSDkxlgLynDPLXkNA/rKshnoAAAGZzTf3nwAABAMASDBGAiEAqwr4LJOIaxM8Bc0kcNEPNCxlDzZpos/f1rS7BK76nv0CIQCLIb2V/2i4FqvOGqHvuz3fF0nAKAEtW6VNiH+LnPOm0zAKBggqhkjOPQQDAwNnADBkAjBwVJpXj7XmjRSi7+KbiPoFUlyWX2N5DYvWFOLLKruvOqSYYYDVCqg/8doBMT99v4gCMHFSLEA0E9vSM03a5zkjO8vgY1ZP8LsJ/CJH1Z/MOYjJ9owPGLAt87WaN1QA76hKsg==","transparency_entries":[{"logIndex":"27301","logId":{"keyId":"09OnDKEw7/hpZiYVPoTRzRbglHk0sylsUovegnRUlJY="},"kindVersion":{"kind":"dsse","version":"0.0.2"},"integratedTime":"0","inclusionProof":{"logIndex":"27301","rootHash":"d+mZtqsmI19pROxvjpvI49MvCN3K+OQz+eU7kMYIf7I=","treeSize":"27302","hashes":["5PW4MIHqlleW+qI0c7/S3Y5mGSUBtShnVY6MNrxy+Z8=","AErw4uGrtK1FSaK0K6kdEHDyEbSBepPyZn3M/V0kjPc=","mPEssHL3To5i1DwEbUH7A30Ncl0+tvJKqprgM5KdsmE=","3Z1CsJikTA+Jxb5U90HaRQ6szln3OgKZGfo0GtC8NHI=","LpmrDMP/j7qB/x+7ZpcsyNWjCEFpW4r89LOgxXe4Si4=","3po/6lFr3EfEwUGBEcW8VrwzTFYiozZdE+fqrjQYcQ0=","X9zV3aAQKYVKUMZNhpSw5DeU9UGYo8IgrRbL7YPss40=","/F5BrQjoXk4Ob9cWhsK690rvVXNd/UwynjOz51kuYSM="],"checkpoint":{"envelope":"log2025-alpha3.rekor.sigstage.dev\n27302\nd+mZtqsmI19pROxvjpvI49MvCN3K+OQz+eU7kMYIf7I=\n\n— log2025-alpha3.rekor.sigstage.dev 09OnDBORH0Cui/+phd++9rIxf12lCq+ueOqrzKdUiyWHbJQzcg8IGLmE2vor7d5rC3EHGMjCY3aQht9n1Abp74Xjjgk=\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjIiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZHNzZVYwMDIiOnsicGF5bG9hZEhhc2giOnsiYWxnb3JpdGhtIjoiU0hBMl8yNTYiLCJkaWdlc3QiOiIrWGtPaW9mUUdKalFEU3poeW16a0sveHM1Witxb3h1cUNyWkFaS2FXZ0FBPSJ9LCJzaWduYXR1cmVzIjpbeyJjb250ZW50IjoiTUVRQ0lBOWszWTRYZ3gyWFYwajVXVTZIYjFiZXNOYURzQ0FNdktPQjFGak5hdEF1QWlBQjY2cWtSQW1mQmhPdXdQUHhNVnJ4Rm16VjBGSkl2NldLblQvdEdrZUJxUT09IiwidmVyaWZpZXIiOnsia2V5RGV0YWlscyI6IlBLSVhfRUNEU0FfUDI1Nl9TSEFfMjU2IiwieDUwOUNlcnRpZmljYXRlIjp7InJhd0J5dGVzIjoiTUlJQ3lqQ0NBbEdnQXdJQkFnSVVDd1NsZDJUUE1mekdmN2RXRENXSi91c2ltYjB3Q2dZSUtvWkl6ajBFQXdNd056RVZNQk1HQTFVRUNoTU1jMmxuYzNSdmNtVXVaR1YyTVI0d0hBWURWUVFERXhWemFXZHpkRzl5WlMxcGJuUmxjbTFsWkdsaGRHVXdIaGNOTWpVeE1ERXdNRGd5TXpReFdoY05NalV4TURFd01EZ3pNelF4V2pBQU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRXB4alBlMHJEVG1rZk5kZjNCWWZFUnZpUFMxSHdJcmFDOWFuQVk2bnZiNTBYT1YzVWRSYU91aHJjcUs3ZUtFZkRYNUNJZnVUYmxhN1Y0c05IbzNiM1c2T0NBWEF3Z2dGc01BNEdBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVpN2EzbkNxRzVYWHRHQXVkTEZOMGtIMlJjOGd3SHdZRFZSMGpCQmd3Rm9BVWNZWXdwaFI4WW0vNTk5YjBCUnAvWC8vcmI2d3dHUVlEVlIwUkFRSC9CQTh3RFlFTGFtdDFRR2R2ZEc4dVpta3dMQVlLS3dZQkJBR0R2ekFCQVFRZWFIUjBjSE02THk5bmFYUm9kV0l1WTI5dEwyeHZaMmx1TDI5aGRYUm9NQzRHQ2lzR0FRUUJnNzh3QVFnRUlBd2VhSFIwY0hNNkx5OW5hWFJvZFdJdVkyOXRMMnh2WjJsdUwyOWhkWFJvTUlHTEJnb3JCZ0VFQWRaNUFnUUNCSDBFZXdCNUFIY0FLekM4M0dpSXllTGgyQ1lwWG5RZlNEa3hsZ0x5bkRQTFhrTkEvcktzaG5vQUFBR1p6VGYzbndBQUJBTUFTREJHQWlFQXF3cjRMSk9JYXhNOEJjMGtjTkVQTkN4bER6WnBvcy9mMXJTN0JLNzZudjBDSVFDTEliMlYvMmk0RnF2T0dxSHZ1ejNmRjBuQUtBRXRXNlZOaUgrTG5QT20wekFLQmdncWhrak9QUVFEQXdObkFEQmtBakJ3VkpwWGo3WG1qUlNpNytLYmlQb0ZVbHlXWDJONURZdldGT0xMS3J1dk9xU1lZWURWQ3FnLzhkb0JNVDk5djRnQ01IRlNMRUEwRTl2U00wM2E1emtqTzh2Z1kxWlA4THNKL0NKSDFaL01PWWpKOW93UEdMQXQ4N1dhTjFRQTc2aEtzZz09In19fV19fX0="}],"timestamps":["MIIE6jADAgEAMIIE4QYJKoZIhvcNAQcCoIIE0jCCBM4CAQMxDTALBglghkgBZQMEAgEwgcMGCyqGSIb3DQEJEAEEoIGzBIGwMIGtAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgfC4NT5HwVGPGQCO/haHFdiCiQMSQ/fyL6nOLil48PyYCFQDR+SzWjCiB32Mq1s4ntWsFmx3uXxgPMjAyNTEwMTAwODIzNDFaMAMCAQECCQD5vCCFKUu0uqAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgggITMIICDzCCAZagAwIBAgIUCjWhBmHV4kFzxomWp/J98n4DfKcwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTAzMjgwOTE0MDZaFw0zNTAzMjYwODE0MDZaMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx1v5F3HpD9egHuknpBFlRz7QBRDJu4aeVzt9zJLRY0lvmx1lF7WBM2c9AN8ZGPQsmDqHlJN2R/7+RxLkvlLzkc19IOx38t7mGGEcB7agUDdCF/Ky3RTLSK0Xo/0AgHQdo2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKj8ZPYo3i7mO3NPVIxSxOGc3VOlMB8GA1UdIwQYMBaAFDsgRlletTJNRzDObmPuc3RH8gR9MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMDA2cAMGQCMESvVS6GGtF33+J19TfwENWJXjRv4i0/HQFwLUSkX6TfV7g0nG8VnqNHJLvEpAtOjQIwUD3uywTXorQP1DgbV09rF9Yen+CEqs/iEpieJWPst280SSOZ5Na+dyPVk9/8SFk6MYIB2zCCAdcCAQEwUTA5MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxIDAeBgNVBAMTF3NpZ3N0b3JlLXRzYS1zZWxmc2lnbmVkAhQKNaEGYdXiQXPGiZan8n3yfgN8pzALBglghkgBZQMEAgGggfwwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTEwMTAwODIzNDFaMC8GCSqGSIb3DQEJBDEiBCDDNLfOiDbENhYGQNGrMwLkPKhAPwxEnmIPJuPgx/7mYjCBjgYLKoZIhvcNAQkQAi8xfzB9MHsweQQgBvT/4Ef+s1mZtzOw16MjUBz8GOTAM2aoRdd1NudLJ0QwVTA9pDswOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUCjWhBmHV4kFzxomWp/J98n4DfKcwCgYIKoZIzj0EAwIEZzBlAjEAnEXFAwkb8GHuC6Id7lxA9W6gUzV+6PmrgCtz5KHs/ud0QVtGvzDxA3uBJHZm7t1JAjANQFBCyGWdOINu2/cfLwpVjJ0TvXr8M+dFAOSf/JeQbK0gD93OMtZ7F7jH3lES3zY="]},"envelope":{"statement":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicHlwaV9hdHRlc3RhdGlvbnMtMC4wLjE5LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI5YmIxYWRkMDRiMWI0ZTE4MmJlNmIwYjgwOTMxNTkzZjdhMjkxZWI0OWQ2OWI0ZmQ3MjhhNWQ0Y2JjZGM0YmQzIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vZG9jcy5weXBpLm9yZy9hdHRlc3RhdGlvbnMvcHVibGlzaC92MSIsInByZWRpY2F0ZSI6bnVsbH0=","signature":"MEQCIA9k3Y4Xgx2XV0j5WU6Hb1besNaDsCAMvKOB1FjNatAuAiAB66qkRAmfBhOuwPPxMVrxFmzV0FJIv6WKnT/tGkeBqQ=="}}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":1,"verification_material":{"certificate":"MIICyjCCAlGgAwIBAgIUCsKmvvvMOxljmIrNu7XsdHuxA1UwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjUxMDEwMDgyMjI4WhcNMjUxMDEwMDgzMjI4WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEQL/FHnzx8tbzUWNgJNCiOmqZ+PFNYjECUklO9kcwK0FylPr8WLqxnxJIyu4CAq6BHMdXApib/t1LZCBpiCkKW6OCAXAwggFsMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUPrNp830jURXObbZcz0De5AXtZfwwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wGQYDVR0RAQH/BA8wDYELamt1QGdvdG8uZmkwLAYKKwYBBAGDvzABAQQeaHR0cHM6Ly9naXRodWIuY29tL2xvZ2luL29hdXRoMC4GCisGAQQBg78wAQgEIAweaHR0cHM6Ly9naXRodWIuY29tL2xvZ2luL29hdXRoMIGLBgorBgEEAdZ5AgQCBH0EewB5AHcA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGZzTbZ2AAABAMASDBGAiEA6iKnHAj/opQOry1f9GcEE1Kmhk4eHjsR7lypmeG9Me0CIQCub0pTY/XBfHjahPr8C1R26HFfmEGa+DPunjHW1ZZurjAKBggqhkjOPQQDAwNnADBkAjAru0NtGlCsjwOOCnH/beIFl0jXYuZ6NS2DzpD5OV3kNpMEJp8wsBeCxFtuSMePF30CMBqySI7MrueB7/2SUur3DJv7A/OLUslnfN0WAjPzMGsoJrMpwqVD4cady2mXwhK/eQ==","transparency_entries":[{"logIndex":"598461431","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"dsse","version":"0.0.1"},"integratedTime":"1760084548","inclusionPromise":{"signedEntryTimestamp":"MEUCIQCx6X6FZCepxmGbNtzw3+ttHWCvslmkUSHdSjGoc6A8CgIgLzJrx4K0XP+nPChNIgM8R2e2OX+nQ49bn5dbsjsDKcE="},"inclusionProof":{"logIndex":"476557169","rootHash":"5rmfI5fg+GLgW1u9vyFGa5CGRWCuWfqD9KN9ChB8mB0=","treeSize":"476557170","hashes":["Z4U0ToAixBcbhfvBzcFZ0aP7CxhW7Ql4zjDkU/UcXZI=","IMm3BxjyrXKFqCUjNVImFffyzp9lGd85VywPwPpOkYk=","XQl2LB3lN5KPbizzBG/FSu/PzUXjB8/9CJ7Emxf5CfE=","OSXATwZmQbaIxVOkMhKJhHruKbXPyw23sE0vPAf4LTU=","5F0HtxEvz9wzVBJDJicASVB1EQVwyT02M3EyBZCjsN4=","pGA1v60Ji6EbUgbRVHoTQ/r5fhlMetBrO6XM5F5ZCJU=","ePisi8uUsxle18YHgyMhOSB6feLySmaFVzmDHNTGIzQ=","VOdGKmbb9n2TrE3xEQ/QehtkLm4+7UQgycAIDwL7tOM=","pTOZwpCP0yDqia4ethoqTejq6XusxsbezkyHrZ9wim0=","1ph/oLtygbE0j91MF5D3qGzpB7t5+wmEvheP9AJwN1k=","6V8DhhxWbMfN9pfeP/KTwoCvgbJlDiesecM5nYGTONs=","a2ac6t7rl39TPjIcwg8cvKVHuwE1SIkI7M5kC6iA7UA=","oRq5SAm/9ovZ2TYAsT6iBMkqWElTdvMY6PBVze65E8g=","mxhgKnbFidkcY9Sspg3POkzMS3zMgeWy033i8AHVyWQ=","EGaD/cNavzxGYLx1Gl0uNNWBZvyXlSHSdlIeH7m+63A=","2Wv4GiithwNukRKV06clevnQQYCzXmSS/+/OJtXgsXQ=","1mfy94KpcItqshH9+gwqV6jccupcaMpVsF28New8zDY=","vS7O4ozHIQZJWBiov+mkpI27GE8zAmVCEkRcP3NDyNE="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n476557170\n5rmfI5fg+GLgW1u9vyFGa5CGRWCuWfqD9KN9ChB8mB0=\n\n— rekor.sigstore.dev wNI9ajBFAiAJ5EzPNjtvhuhuueWp4MstQItoEcdtX3+LbBPJg8RllQIhALDctcPGO1VzCP2FTbfvCo16X8MuVjHdigS1m2f5LAjC\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiOTg5NmEzNDljYTFlZWYzNWIwNjFkOWQ0ZjM3Mzc2NzE3MWJmZjVlMjUwMmY2ZjNjNDVhYTYzMzU4MzA5NWVkMSJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImY5NzkwZThhODdkMDE4OThkMDBkMmNlMWNhNmNlNDJiZmM2Y2U1OWZhYWEzMWJhYTBhYjY0MDY0YTY5NjgwMDAifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVVQ0lRRGJiUWpQR1h5YmZZeU5nRk9hRmRqamlEMi80K1VRWUJSTjZwamJ5SytTaHdJZ0NnZ1ljeHZ1RWF2NnZTeFFJaTFlckhMc1M4dmh1bFIvYmNVNlhxYVRSbG89IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VONWFrTkRRV3hIWjBGM1NVSkJaMGxWUTNOTGJYWjJkazFQZUd4cWJVbHlUblUzV0hOa1NIVjRRVEZWZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwVmVFMUVSWGROUkdkNVRXcEpORmRvWTA1TmFsVjRUVVJGZDAxRVozcE5ha2swVjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVlJUQzlHU0c1NmVEaDBZbnBWVjA1blNrNURhVTl0Y1ZvclVFWk9XV3BGUTFWcmJFOEtPV3RqZDBzd1JubHNVSEk0VjB4eGVHNTRTa2w1ZFRSRFFYRTJRa2hOWkZoQmNHbGlMM1F4VEZwRFFuQnBRMnRMVnpaUFEwRllRWGRuWjBaelRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdSQ1owNVdTRkUwUlVablVWVlFjazV3Q2pnek1HcFZVbGhQWW1KYVkzb3dSR1UxUVZoMFdtWjNkMGgzV1VSV1VqQnFRa0puZDBadlFWVXpPVkJ3ZWpGWmEwVmFZalZ4VG1wd1MwWlhhWGhwTkZrS1drUTRkMGRSV1VSV1VqQlNRVkZJTDBKQk9IZEVXVVZNWVcxME1WRkhaSFprUnpoMVdtMXJkMHhCV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZsWVVoU01BcGpTRTAyVEhrNWJtRllVbTlrVjBsMVdUSTVkRXd5ZUhaYU1teDFUREk1YUdSWVVtOU5RelJIUTJselIwRlJVVUpuTnpoM1FWRm5SVWxCZDJWaFNGSXdDbU5JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVERKNGRsb3liSFZNTWpsb1pGaFNiMDFKUjB4Q1oyOXlRbWRGUlVGa1dqVkJaMUZEUWtnd1JXVjNRalVLUVVoalFUTlVNSGRoYzJKSVJWUktha2RTTkdOdFYyTXpRWEZLUzFoeWFtVlFTek12YURSd2VXZERPSEEzYnpSQlFVRkhXbnBVWWxveVFVRkJRa0ZOUVFwVFJFSkhRV2xGUVRacFMyNUlRV292YjNCUlQzSjVNV1k1UjJORlJURkxiV2hyTkdWSWFuTlNOMng1Y0cxbFJ6bE5aVEJEU1ZGRGRXSXdjRlJaTDFoQ0NtWklhbUZvVUhJNFF6RlNNalpJUm1adFJVZGhLMFJRZFc1cVNGY3hXbHAxY21wQlMwSm5aM0ZvYTJwUFVGRlJSRUYzVG01QlJFSnJRV3BCY25Vd1RuUUtSMnhEYzJwM1QwOURia2d2WW1WSlJtd3dhbGhaZFZvMlRsTXlSSHB3UkRWUFZqTnJUbkJOUlVwd09IZHpRbVZEZUVaMGRWTk5aVkJHTXpCRFRVSnhlUXBUU1RkTmNuVmxRamN2TWxOVmRYSXpSRXAyTjBFdlQweFZjMnh1Wms0d1YwRnFVSHBOUjNOdlNuSk5jSGR4VmtRMFkyRmtlVEp0V0hkb1N5OWxVVDA5Q2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn1dfX0="}],"timestamps":["MIIE7DADAgEAMIIE4wYJKoZIhvcNAQcCoIIE1DCCBNACAQMxDTALBglghkgBZQMEAgEwgcMGCyqGSIb3DQEJEAEEoIGzBIGwMIGtAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQg8KlV7NgkK/FnHgIWxUJXSXwkp5vWaelxfxdGgVBszw4CFQCqAXNo5MneAMM9Roy7KoYTJxYFkBgPMjAyNTEwMTAwODIyMjhaMAMCAQECCQCxPnBshVVTnKAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgggIUMIICEDCCAZagAwIBAgIUOhNULwyQYe68wUMvy4qOiyojiwwwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTA0MDgwNjU5NDNaFw0zNTA0MDYwNjU5NDNaMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ra2Z8hKNig2T9kFjCAToGG30jky+WQv3BzL+mKvh1SKNR/UwuwsfNCg4sryoYAd8E6isovVA3M4aoNdm9QDi50Z8nTEyvqgfDPtTIwXItfiW/AFf1V7uwkbkAoj0xxco2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFIn9eUOHz9BlRsMCRscsc1t9tOsDMB8GA1UdIwQYMBaAFJjsAe9/u1H/1JUeb4qImFMHic6/MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMDA2gAMGUCMDtpsV/6KaO0qyF/UMsX2aSUXKQFdoGTptQGc0ftq1csulHPGG6dsmyMNd3JB+G3EQIxAOajvBcjpJmKb4Nv+2Taoj8Uc5+b6ih6FXCCKraSqupe07zqswMcXJTe1cExvHvvlzGCAdwwggHYAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjUxMDEwMDgyMjI4WjAvBgkqhkiG9w0BCQQxIgQgLjDQB0fviWQEUJvQcAa3MLNvzeZAawcvopv+4ZsHWzIwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGgwZgIxANkYjeM8aGQ3d9IB5INg1wnvcH6zn8whwSiQKDK6I+3Xy3EydisbDPs+ygpoRw55MAIxAJIb7+HPPc6TJmKB8vSfTwrOonRSw6YVWckJbLeUWO4SIrO26ASszUuXNzaA24Rd3A=="]},"envelope":{"statement":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicHlwaV9hdHRlc3RhdGlvbnMtMC4wLjE5LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI5YmIxYWRkMDRiMWI0ZTE4MmJlNmIwYjgwOTMxNTkzZjdhMjkxZWI0OWQ2OWI0ZmQ3MjhhNWQ0Y2JjZGM0YmQzIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vZG9jcy5weXBpLm9yZy9hdHRlc3RhdGlvbnMvcHVibGlzaC92MSIsInByZWRpY2F0ZSI6bnVsbH0=","signature":"MEUCIQDbbQjPGXybfYyNgFOaFdjjiD2/4+UQYBRN6pjbyK+ShwIgCggYcxvuEav6vSxQIi1erHLsS8vhulR/bcU6XqaTRlo="}}
9 changes: 9 additions & 0 deletions test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
publish_attestation_identity = "https://github.com/trailofbits/pypi-attestations/.github/workflows/release.yml@refs/tags/v0.0.19"
publish_attestation_path = _ASSETS / "pypi_attestations-0.0.19.tar.gz.publish.attestation"
slsa_attestation_path = _ASSETS / "pypi_attestations-0.0.19.tar.gz.slsa.attestation"
rekor2_attestation_path = (
_ASSETS / "pypi_attestations-0.0.19.tar.gz.publish.attestation.with_rekor2_timestamp"
)


pypi_wheel_url = "https://files.pythonhosted.org/packages/fb/f2/3e026065773b84c5b2345e2548a08b10105d324b9b95c72643f57a25fcbb/pypi_attestations-0.0.19-py3-none-any.whl"
pypi_sdist_url = "https://files.pythonhosted.org/packages/c5/4d/a114bdd186903426bd9c1e9c3700761ec5eaac260fa3dfdef14bf84b751b/pypi_attestations-0.0.19.tar.gz"
Expand Down Expand Up @@ -229,6 +233,11 @@ def test_inspect_command(caplog: pytest.LogCaptureFixture) -> None:
run_main_with_command(["inspect", "--dump-bytes", publish_attestation_path.as_posix()])
assert "Signature:" in caplog.text

# Happy path with annotation that contains rekor2 entry and a timestamp
run_main_with_command(["inspect", rekor2_attestation_path.as_posix()])
assert "Entry type: dsse 0.0.2" in caplog.text
assert "Timestamps (1):" in caplog.text

# Failure paths
caplog.clear()

Expand Down
Loading