diff --git a/sigstore/verify/verifier.py b/sigstore/verify/verifier.py index 6d4f56d42..efe8e2ecf 100644 --- a/sigstore/verify/verifier.py +++ b/sigstore/verify/verifier.py @@ -59,7 +59,7 @@ from sigstore._internal.timestamp import TimestampSource, TimestampVerificationResult from sigstore._internal.trust import KeyringPurpose from sigstore._utils import base64_encode_pem_cert, sha256_digest -from sigstore.errors import CertValidationError, VerificationError +from sigstore.errors import CertValidationError, MetadataError, VerificationError from sigstore.hashes import Hashed from sigstore.models import Bundle, ClientTrustConfig, TrustedRoot from sigstore.verify.policy import VerificationPolicy @@ -92,6 +92,8 @@ def __init__(self, *, trusted_root: TrustedRoot): # this is an ugly hack needed for verifying "detached" materials # In reality we should be choosing the rekor instance based on the logid + if not trusted_root._inner.tlogs: + raise MetadataError("No transparency logs found in trusted root") url = trusted_root._inner.tlogs[0].base_url self._rekor = RekorClient(url) diff --git a/test/unit/verify/test_verifier.py b/test/unit/verify/test_verifier.py index 81287e7f6..673564533 100644 --- a/test/unit/verify/test_verifier.py +++ b/test/unit/verify/test_verifier.py @@ -24,12 +24,43 @@ from sigstore._internal.trust import CertificateAuthority from sigstore.dsse import StatementBuilder, Subject -from sigstore.errors import CertValidationError, VerificationError +from sigstore.errors import CertValidationError, MetadataError, VerificationError from sigstore.models import Bundle from sigstore.verify import policy from sigstore.verify.verifier import Verifier +def test_verifier_init_no_transparency_logs(): + """ + `Verifier.__init__` raises a structured `MetadataError` (rather than an + unhandled `IndexError`) when given a `trusted_root` with no + transparency logs. See #1822. + """ + trusted_root = pretend.stub( + get_fulcio_certs=pretend.call_recorder(lambda: []), + _inner=pretend.stub(tlogs=[]), + ) + + with pytest.raises(MetadataError, match="No transparency logs"): + Verifier(trusted_root=trusted_root) + + +def test_verifier_init_with_transparency_logs(): + """ + `Verifier.__init__` succeeds and picks the first transparency log's + `base_url` when `trusted_root` has at least one, proving the new + `MetadataError` guard doesn't affect the happy path. + """ + tlog = pretend.stub(base_url="https://rekor.example.com") + trusted_root = pretend.stub( + get_fulcio_certs=pretend.call_recorder(lambda: []), + _inner=pretend.stub(tlogs=[tlog]), + ) + + verifier = Verifier(trusted_root=trusted_root) + assert verifier._rekor.url == "https://rekor.example.com/api/v1" + + @pytest.mark.production def test_verifier_production(): verifier = Verifier.production()