diff --git a/test/client.py b/test/client.py index d8a61b5..1584d48 100644 --- a/test/client.py +++ b/test/client.py @@ -159,8 +159,13 @@ def raises(self): ) raise ClientUnexpectedSuccess(msg) + def set_staging(self, args): + args.append("--staging") + @singledispatchmethod - def sign(self, materials: VerificationMaterials, artifact: os.PathLike) -> None: + def sign( + self, materials: VerificationMaterials, artifact: os.PathLike, staging: bool = False + ) -> None: """ Sign an artifact with the Sigstore client. Dispatches to `_sign_for_sigcrt` when given `SignatureCertificateMaterials`, or `_sign_for_bundle` when given @@ -174,7 +179,7 @@ def sign(self, materials: VerificationMaterials, artifact: os.PathLike) -> None: @sign.register def _sign_for_sigcrt( - self, materials: SignatureCertificateMaterials, artifact: os.PathLike + self, materials: SignatureCertificateMaterials, artifact: os.PathLike, staging: bool = False ) -> None: """ Sign an artifact with the Sigstore client, producing a signature and certificate. @@ -182,8 +187,7 @@ def _sign_for_sigcrt( This is an overload of `sign` for the signature/certificate flow and should not be called directly. """ - - self.run( + args = [ "sign", "--identity-token", self.identity_token, @@ -192,30 +196,39 @@ def _sign_for_sigcrt( "--certificate", materials.certificate, artifact, - ) + ] + + if staging: + self.set_staging(args) + self.run(*args) @sign.register - def _sign_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) -> None: + def _sign_for_bundle( + self, materials: BundleMaterials, artifact: os.PathLike, staging: bool = False + ) -> None: """ Sign an artifact with the Sigstore client, producing a bundle. This is an overload of `sign` for the bundle flow and should not be called directly. """ - self.run( + args = [ "sign-bundle", "--identity-token", self.identity_token, "--bundle", materials.bundle, artifact, - ) + ] + + if staging: + self.set_staging(args) + + self.run(*args) @singledispatchmethod def verify( - self, - materials: VerificationMaterials, - artifact: os.PathLike, + self, materials: VerificationMaterials, artifact: os.PathLike, staging: bool = False ) -> None: """ Verify an artifact with the Sigstore client. Dispatches to `_verify_for_sigcrt` @@ -230,9 +243,7 @@ def verify( @verify.register def _verify_for_sigcrt( - self, - materials: SignatureCertificateMaterials, - artifact: os.PathLike, + self, materials: SignatureCertificateMaterials, artifact: os.PathLike, staging: bool = False ) -> None: """ Verify an artifact given a signature and certificate with the Sigstore client. @@ -256,12 +267,17 @@ def _verify_for_sigcrt( if getattr(materials, "trusted_root", None) is not None: args.extend(["--trusted-root", materials.trusted_root]) + if staging: + args.append("--staging") + # The identity and OIDC issuer cannot be specified by the test since they remain constant # across the GitHub Actions job. self.run(*args, artifact) @verify.register - def _verify_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) -> None: + def _verify_for_bundle( + self, materials: BundleMaterials, artifact: os.PathLike, staging: bool = False + ) -> None: """ Verify an artifact given a bundle with the Sigstore client. @@ -282,4 +298,7 @@ def _verify_for_bundle(self, materials: BundleMaterials, artifact: os.PathLike) if getattr(materials, "trusted_root", None) is not None: args.extend(["--trusted-root", materials.trusted_root]) + if staging: + args.append("--staging") + self.run(*args, artifact) diff --git a/test/test_bundle.py b/test/test_bundle.py index 3b64444..6912250 100644 --- a/test/test_bundle.py +++ b/test/test_bundle.py @@ -19,7 +19,9 @@ def test_verify(client: SigstoreClient, make_materials_by_type: _MakeMaterialsBy client.verify(materials, input_path) -def test_verify_dsse_bundle_with_trust_root(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None: +def test_verify_dsse_bundle_with_trust_root( + client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType +) -> None: """ Test the happy path of verification for DSSE bundle w/ custom trust root """ @@ -170,7 +172,9 @@ def test_verify_rejects_different_materials( client.verify(materials, input_path) -def test_verify_rejects_expired_certificate(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None: +def test_verify_rejects_expired_certificate( + client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType +) -> None: """ Check that the client rejects a bundle if the certificate was issued outside the validity window of the trusted root @@ -184,7 +188,9 @@ def test_verify_rejects_expired_certificate(client: SigstoreClient, make_materia client.verify(materials, input_path) -def test_verify_rejects_missing_inclusion_proof(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None: +def test_verify_rejects_missing_inclusion_proof( + client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType +) -> None: """ Check that the client rejects a v0.2 bundle if the TLog entry does NOT contain an inclusion proof @@ -198,7 +204,9 @@ def test_verify_rejects_missing_inclusion_proof(client: SigstoreClient, make_mat client.verify(materials, input_path) -def test_verify_rejects_bad_tlog_timestamp(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None: +def test_verify_rejects_bad_tlog_timestamp( + client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType +) -> None: """ Check that the client rejects a bundle if the TLog entry contains a timestamp that falls outside the validity window of the signing @@ -213,7 +221,9 @@ def test_verify_rejects_bad_tlog_timestamp(client: SigstoreClient, make_material client.verify(materials, input_path) -def test_verify_rejects_bad_tlog_entry(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None: +def test_verify_rejects_bad_tlog_entry( + client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType +) -> None: """ Check that the client rejects a bundle if the body of the TLog entry does not match the signed artifact. @@ -226,7 +236,10 @@ def test_verify_rejects_bad_tlog_entry(client: SigstoreClient, make_materials_by with client.raises(): client.verify(materials, input_path) -def test_verify_rejects_bad_tsa_timestamp(client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType) -> None: + +def test_verify_rejects_bad_tsa_timestamp( + client: SigstoreClient, make_materials_by_type: _MakeMaterialsByType +) -> None: """ Check that the client rejects a bundle if the TSA timestamp falls outside the validity window of the signing certificate. diff --git a/test/test_simple_staging.py b/test/test_simple_staging.py new file mode 100644 index 0000000..d122bd9 --- /dev/null +++ b/test/test_simple_staging.py @@ -0,0 +1,24 @@ +from test.conftest import _MakeMaterials + +import pytest # type: ignore + +from .client import SigstoreClient + + +@pytest.mark.signing_staging +def test_simple_staging(client: SigstoreClient, make_materials: _MakeMaterials) -> None: + """ + A simple test that signs and verifies an artifact for a given Sigstore + client against staging. + """ + + staging = True + input_path, materials = make_materials("b.txt") + assert not materials.exists() + + # Sign the artifact. + client.sign(materials, input_path, staging) + assert materials.exists() + + # Verify the artifact signature. + client.verify(materials, input_path, staging)