From d0397de84d0aa2e253a66baae88bb144cb5fc274 Mon Sep 17 00:00:00 2001 From: Facundo Tuesca Date: Tue, 14 Jan 2025 22:51:13 +0100 Subject: [PATCH 1/2] Add new test artifacts Signed-off-by: Facundo Tuesca --- test/assets/pypi_attestations-0.0.19.tar.gz | Bin 0 -> 29882 bytes ...stations-0.0.19.tar.gz.publish.attestation | 1 + test/test_cli.py | 37 ++++++++---------- 3 files changed, 18 insertions(+), 20 deletions(-) create mode 100644 test/assets/pypi_attestations-0.0.19.tar.gz create mode 100644 test/assets/pypi_attestations-0.0.19.tar.gz.publish.attestation diff --git a/test/assets/pypi_attestations-0.0.19.tar.gz b/test/assets/pypi_attestations-0.0.19.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..be9a1fb239b1948281546b6281320f8a6c2ed7d6 GIT binary patch literal 29882 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 str: @online def test_sign_command(tmp_path: Path) -> None: # Happy path - copied_artifact = tmp_path / artifact_path.with_suffix(".copy.whl").name + copied_artifact = tmp_path / artifact_path.name shutil.copy(artifact_path, copied_artifact) run_main_with_command( @@ -172,7 +173,7 @@ def test_sign_fail_to_sign( monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture, tmp_path: Path ) -> None: monkeypatch.setattr(pypi_attestations._cli, "Attestation", stub(sign=raiser(AttestationError))) - copied_artifact = tmp_path / artifact_path.with_suffix(".copy.whl").name + copied_artifact = tmp_path / artifact_path.name shutil.copy(artifact_path, copied_artifact) with pytest.raises(SystemExit): @@ -183,11 +184,11 @@ def test_sign_fail_to_sign( def test_inspect_command(caplog: pytest.LogCaptureFixture) -> None: # Happy path - run_main_with_command(["inspect", attestation_path.as_posix()]) - assert attestation_path.as_posix() in caplog.text + run_main_with_command(["inspect", publish_attestation_path.as_posix()]) + assert publish_attestation_path.as_posix() in caplog.text assert "CN=sigstore-intermediate,O=sigstore.dev" in caplog.text - run_main_with_command(["inspect", "--dump-bytes", attestation_path.as_posix()]) + run_main_with_command(["inspect", "--dump-bytes", publish_attestation_path.as_posix()]) assert "Signature:" in caplog.text # Failure paths @@ -217,13 +218,12 @@ def test_verify_attestation_command(caplog: pytest.LogCaptureFixture) -> None: [ "verify", "attestation", - "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, artifact_path.as_posix(), ] ) - assert f"OK: {attestation_path.as_posix()}" in caplog.text + assert f"OK: {publish_attestation_path.as_posix()}" in caplog.text caplog.clear() @@ -233,8 +233,9 @@ def test_verify_attestation_command(caplog: pytest.LogCaptureFixture) -> None: [ "verify", "attestation", + "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, artifact_path.as_posix(), ] ) @@ -256,9 +257,8 @@ def test_verify_attestation_invalid_attestation(caplog: pytest.LogCaptureFixture [ "verify", "attestation", - "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, fake_package_name.as_posix(), ] ) @@ -272,9 +272,8 @@ def test_verify_attestation_missing_artifact(caplog: pytest.LogCaptureFixture) - [ "verify", "attestation", - "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, "not_a_file.txt", ] ) @@ -290,9 +289,8 @@ def test_verify_attestation_missing_attestation(caplog: pytest.LogCaptureFixture [ "verify", "attestation", - "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, f.name, ] ) @@ -306,16 +304,15 @@ def test_verify_attestation_invalid_artifact( copied_artifact = tmp_path / artifact_path.with_suffix(".whl2").name shutil.copy(artifact_path, copied_artifact) copied_attestation = tmp_path / artifact_path.with_suffix(".whl2.publish.attestation").name - shutil.copy(attestation_path, copied_attestation) + shutil.copy(publish_attestation_path, copied_attestation) with pytest.raises(SystemExit): run_main_with_command( [ "verify", "attestation", - "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, copied_artifact.as_posix(), ] ) From 5e585e98541587592d09b3711f94b32c00c19484 Mon Sep 17 00:00:00 2001 From: Facundo Tuesca Date: Tue, 14 Jan 2025 22:53:40 +0100 Subject: [PATCH 2/2] cli: support verifying slsa attestations Signed-off-by: Facundo Tuesca --- CHANGELOG.md | 7 +++ README.md | 14 ++---- src/pypi_attestations/_cli.py | 50 ++++++++++--------- ...ttestations-0.0.19.tar.gz.slsa.attestation | 1 + test/test_cli.py | 4 +- 5 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 test/assets/pypi_attestations-0.0.19.tar.gz.slsa.attestation diff --git a/CHANGELOG.md b/CHANGELOG.md index af9600d..a8c194b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- The CLI subcommand `verify attestation` now supports `.slsa.attestation` + files. When verifying an artifact, both `.publish.attestation` and + `.slsa.attestation` files are used (if present). + ## [0.0.21] ### Changed @@ -18,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#82](https://github.com/trailofbits/pypi-attestations/pull/82)) ### Added + - The CLI has a new subcommand `verify pypi`, which takes a URL to a PyPI distribution (either a wheel or a source distribution) and a GitHub/GitLab repository. The command verifies the distribution by diff --git a/README.md b/README.md index 84a171f..432137a 100644 --- a/README.md +++ b/README.md @@ -134,20 +134,12 @@ pypi-attestations inspect dist/pypi_attestations-*.whl.publish.attestation ### Verifying a PEP 740 Attestation -> [!NOTE] -> The example below uses an email with `--identity`, but actual PyPI -> attestations will be signed with a machine identity corresponding to the -> workflow that generated the attestation. The format of that identity - ```bash -pypi-attestations verify attestation --staging \ - --identity william@yossarian.net \ - test/assets/rfc8785-0.1.2-py3-none-any.whl +pypi-attestations verify attestation \ + --identity https://github.com/trailofbits/pypi-attestations/.github/workflows/release.yml@refs/tags/v0.0.19 \ + test/assets/pypi_attestations-0.0.19.tar.gz ``` -The attestation present in the test has been generated using the staging -environment of Sigstore and signed by the identity `william@yossarian.net`. - ### Verifying a PyPI package > [!NOTE] > The URL must be a direct link to the distribution artifact hosted by PyPI. diff --git a/src/pypi_attestations/_cli.py b/src/pypi_attestations/_cli.py index ebc389b..dccb4a3 100644 --- a/src/pypi_attestations/_cli.py +++ b/src/pypi_attestations/_cli.py @@ -6,6 +6,7 @@ import json import logging import typing +from collections import defaultdict from pathlib import Path from tempfile import TemporaryDirectory @@ -385,35 +386,36 @@ def _verify_attestation(args: argparse.Namespace) -> None: """Verify the files passed as argument.""" pol = policy.Identity(identity=args.identity) - # Validate that both the attestations and files exist + # Validate that the files exist _validate_files(args.files, should_exist=True) - _validate_files( - (Path(f"{file_path}.publish.attestation") for file_path in args.files), - should_exist=True, - ) - - inputs: list[Path] = [] - for file_path in args.files: - inputs.append(file_path) - for input in inputs: - attestation_path = Path(f"{input}.publish.attestation") - try: - attestation = Attestation.model_validate_json(attestation_path.read_text()) - except ValidationError as validation_error: - _die(f"Invalid attestation ({attestation_path}): {validation_error}") + # artifact -> [attestation1, attestation2, ...] + files_with_attestations: dict[Path, list[Path]] = defaultdict(list) + for f in args.files: + for attestation_file in (Path(f"{f}.publish.attestation"), Path(f"{f}.slsa.attestation")): + if attestation_file.exists(): + files_with_attestations[f].append(attestation_file) + if not files_with_attestations[f]: + _die(f"Couldn't find attestations for file {f}") + + for file_path, attestations in files_with_attestations.items(): + for attestation_path in attestations: + try: + attestation = Attestation.model_validate_json(attestation_path.read_text()) + except ValidationError as validation_error: + _die(f"Invalid attestation ({attestation_path}): {validation_error}") - try: - dist = Distribution.from_file(input) - except ValidationError as e: - _die(f"Invalid Python package distribution: {e}") + try: + dist = Distribution.from_file(file_path) + except ValidationError as e: + _die(f"Invalid Python package distribution: {e}") - try: - attestation.verify(pol, dist, staging=args.staging) - except VerificationError as verification_error: - _die(f"Verification failed for {input}: {verification_error}") + try: + attestation.verify(pol, dist, staging=args.staging) + except VerificationError as verification_error: + _die(f"Verification failed for {file_path}: {verification_error}") - _logger.info(f"OK: {attestation_path}") + _logger.info(f"OK: {attestation_path}") def _verify_pypi(args: argparse.Namespace) -> None: diff --git a/test/assets/pypi_attestations-0.0.19.tar.gz.slsa.attestation b/test/assets/pypi_attestations-0.0.19.tar.gz.slsa.attestation new file mode 100644 index 0000000..a4a4b96 --- /dev/null +++ b/test/assets/pypi_attestations-0.0.19.tar.gz.slsa.attestation @@ -0,0 +1 @@ +{"version":1,"verification_material":{"certificate":"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","transparency_entries":[{"logIndex":"153454647","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"dsse","version":"0.0.1"},"integratedTime":"1733354026","inclusionPromise":{"signedEntryTimestamp":"MEQCIBZa0QFH2bQdHPVzDuXB3wD9xhD5+bSRkcnKwUJlvSimAiAnVBlHJ6C2kjCxlRaWEnRKFPnfT7bQdPOX4zlvin4qhg=="},"inclusionProof":{"logIndex":"31550385","rootHash":"n8apOsmrZJCWBvMSN7+1QZUx/1bAIyrkU1yA7ALI/OE=","treeSize":"31550386","hashes":["oRU9kC1iRU4CSImgvF5RGA5TrN/6o2RlJmwefuaHUL8=","lfWdMc8jC01GhVso+yFbpu0d/1vRWE7UTNm8eeYlHs8=","ilx1qUMsKu7l7vLXMVVej9m7N5HaZyyvWli0IVr1hfA=","PcaivMMXf/sp7holRDnainZ7CqkhfGbumRzqHBLORyo=","QmGjL5m3QfWxTeS1DSKdcZi1Cb/kXHez6zUQJFM+6No=","RzzP82vxkFlwbK42drRrLKdQO7cU4TutI9RH4GZWqmc=","T180VQg42xooybP3Nj9QuoOWlDWbbaQ4n4S2wWmwsSc=","hABDIJpRLjWOq3nQy0+WmZvudV2qvqHNysU41bEne1Q=","pDqPuFyZgsegAtT2zcnZSet9YAZExTulHeEunQ5/LRg=","Q+viUQ+8PPr3Ck1WOMcjETEmAMGVbNDvGlSy6G/aFAI=","R7hO1X+KgSw8Oojd8i2+G3BzBYztkRBE6LpYSXPg33U=","oOecFfN3YqDOkbijS/ej1WF5Da/Gt/AZNhbwE9uoOE8=","4lUF0YOu9XkIDXKXA0wMSzd6VeDY3TZAgmoOeWmS2+Y=","gf+9m552B3PnkWnO0o4KdVvjcT3WVHLrCbf1DoVYKFw="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n31550386\nn8apOsmrZJCWBvMSN7+1QZUx/1bAIyrkU1yA7ALI/OE=\n\n— rekor.sigstore.dev wNI9ajBGAiEAkx5uYofu324HAjvOQPiR2KIJIri6xssROT/uyvTut90CIQCMGpM2mVwa3U5+jYEXGE4uaCqaJ+nbWK4STjZAc//+kQ==\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiODJhZThhMDBlNjc1ZjE0ODk1MGNlZGNmODMyM2FiN2MzZjc3ZGU0NDMwNzZlZDdmODA4MDc1NzA3MDFhYWQzNiJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6Ijg3ZDgyOTQ4N2JjNjlhNzhlZDQxZWY0ZDY0Nzk4Y2U1NzI4YjQ1ZmY4MTI0Mzg0M2Y3ZjY1M2NiYTBmMjRhNWQifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVZQ0lRREhSNk1hY3hKY3JXL1NaQ0JqaXY0T1hsSEJDQWNyRG9SNWlqdXVDOXlVMFFJaEFNMFJwTXNDN29rbnd2UDU2MlYrTmtRVEJxQ0hVUjlGc3kwT0FPNSs5WlVpIiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjdmFrTkRRbTlYWjBGM1NVSkJaMGxWWVdSbGQxZHZkMUVyZFhwb2QyRjBlazU1VG5kMU5uTm1aMkZGZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwUmVFMXFRVEJOYWsxNFRYcFJNbGRvWTA1TmFsRjRUV3BCTUUxcVRYbE5lbEV5VjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVkNWRGQ2UjFSaVRXcHVNa1p2VlZCMGNVMXdUMVJVZDFNeVptTTFkSGczU21oNFZsTUtTVzFSV2k4elZqaERaM2hIV0VzM1ZXRlZXblJIT1c4d1dVRkRlbmQ0VEV0amRXVkZNSGRuY3poV1drZDRNbTAxYTJGUFEwSmhVWGRuWjFkblRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdSQ1owNVdTRkUwUlVablVWVXhOWFZxQ2tzNWNIbHVLM1pZVjI1M1JESmpOa3RsYW1STk5HdzRkMGgzV1VSV1VqQnFRa0puZDBadlFWVXpPVkJ3ZWpGWmEwVmFZalZ4VG1wd1MwWlhhWGhwTkZrS1drUTRkMkpuV1VSV1VqQlNRVkZJTDBKSFVYZFpiMXBuWVVoU01HTklUVFpNZVRsdVlWaFNiMlJYU1hWWk1qbDBURE5TZVZsWGJITmlNbHBwWVZoU2VncE1NMEkxWTBkcmRGbFlVakJhV0U0d1dWaFNjR0l5TlhwTWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhR015VlhWbFZ6RnpDbEZJU214YWJrMTJaRWRHYm1ONU9USk5RelIzVEdwRk5VMUVhMGREYVhOSFFWRlJRbWMzT0hkQlVVVkZTekpvTUdSSVFucFBhVGgyWkVjNWNscFhOSFVLV1ZkT01HRlhPWFZqZVRWdVlWaFNiMlJYU2pGak1sWjVXVEk1ZFdSSFZuVmtRelZxWWpJd2QwWlJXVXRMZDFsQ1FrRkhSSFo2UVVKQloxRklZMjFXY3dwYVYwWjZXbFJCTWtKbmIzSkNaMFZGUVZsUEwwMUJSVVJDUTJkM1QwUm5kMDF0Vm0xYVZFWnRUMGRWTVZwdFZtcE9SMFpyVDBSUmVWcEVXbWxQUjA1c0NrOVVZekpPVkZsM1QxUktiRnBVWTNsTlFsVkhRMmx6UjBGUlVVSm5OemgzUVZGUlJVSXpTbXhpUjFab1l6SlZkMHQzV1V0TGQxbENRa0ZIUkhaNlFVSUtRbEZSWkdSSVNtaGhWM2gyV20xS2NHUklUWFpqU0d4M1lWTXhhR1JJVW14ak0xSm9aRWRzZG1KdVRYZElkMWxMUzNkWlFrSkJSMFIyZWtGQ1FtZFJVZ3BqYlZadFkzazVNRmxYWkhwTU0xbDNUR3BCZFUxVWEzZFBkMWxMUzNkWlFrSkJSMFIyZWtGQ1EwRlJkRVJEZEc5a1NGSjNZM3B2ZGt3elVuWmhNbFoxQ2t4dFJtcGtSMngyWW01TmRWb3liREJoU0ZacFpGaE9iR050VG5aaWJsSnNZbTVSZFZreU9YUk5TRUZIUTJselIwRlJVVUpuTnpoM1FWRnJSVmxuZUdjS1lVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVEROU2VWbFhiSE5pTWxwcFlWaFNla3d6UWpWalIydDBXVmhTTUZwWVRqQlpXRkp3WWpJMWVncE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYVmxWekZ6VVVoS2JGcHVUWFprUjBadVkzazVNazFETkhkTWFrVTFDazFFWjBkRGFYTkhRVkZSUW1jM09IZEJVVzlGUzJkM2IwMUVaelJOUkVwc1dtMVZlRnBxYUd4T1YxcHNXWHBTYUZwRVp6Qk5iVkV5V1dwb2FscFVhek1LVG1wVk1rMUVhM2xhVjFVelRXcEJaRUpuYjNKQ1owVkZRVmxQTDAxQlJVeENRVGhOUkZka2NHUkhhREZaYVRGdllqTk9NRnBYVVhkUlFWbExTM2RaUWdwQ1FVZEVkbnBCUWtSQlVYbEVSRUp2WkVoU2QyTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJaRWhLYUdGWGVIWmFiVXB3WkVoTmRtTkliSGRoVXpGb0NtUklVbXhqTTFKb1pFZHNkbUp1VFhkUFFWbExTM2RaUWtKQlIwUjJla0ZDUkZGUmNVUkRaM2RQUkdkM1RXMVdiVnBVUm0xUFIxVXhXbTFXYWs1SFJtc0tUMFJSZVZwRVdtbFBSMDVzVDFSak1rNVVXWGRQVkVwc1dsUmplVTFEUlVkRGFYTkhRVkZSUW1jM09IZEJVVFJGUlhkM1VtTnRWbTFqZVRrd1dWZGtlZ3BNTTFsM1RHcEJkVTFVYTNkSFVWbExTM2RaUWtKQlIwUjJla0ZDUkhkUlRFUkJhek5PZWtsNVRrUmpNRTFxVFhkTVoxbExTM2RaUWtKQlIwUjJla0ZDQ2tWQlVXZEVRalZ2WkVoU2QyTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJaRWhLYUdGWGVIWmFiVXB3WkVoTmQwWjNXVXRMZDFsQ1FrRkhSSFo2UVVJS1JWRlJTa1JCWTNsTmVrVXdUa1JKZWsxSVFVZERhWE5IUVZGUlFtYzNPSGRCVWtsRldXZDRaMkZJVWpCalNFMDJUSGs1Ym1GWVVtOWtWMGwxV1RJNWRBcE1NMUo1V1Zkc2MySXlXbWxoV0ZKNlRETkNOV05IYTNSWldGSXdXbGhPTUZsWVVuQmlNalY2VEhrMWJtRllVbTlrVjBsMlpESTVlV0V5V25OaU0yUjZDa3d6U214aVIxWm9ZekpWZFdWWE1YTlJTRXBzV201TmRtUkhSbTVqZVRreVRVTTBkMHhxUlRWTlJHZEhRMmx6UjBGUlVVSm5OemgzUVZKTlJVdG5kMjhLVFVSbk5FMUVTbXhhYlZWNFdtcG9iRTVYV214WmVsSm9Xa1JuTUUxdFVUSlphbWhxV2xSck0wNXFWVEpOUkd0NVdsZFZNMDFxUVZoQ1oyOXlRbWRGUlFwQldVOHZUVUZGVlVKQmEwMUNNMHBzWWtkV2FHTXlWWGRhUVZsTFMzZFpRa0pCUjBSMmVrRkNSbEZTVjBSR1VtOWtTRkozWTNwdmRrd3laSEJrUjJneENsbHBOV3BpTWpCMlpFaEthR0ZYZUhaYWJVcHdaRWhOZG1OSWJIZGhVekZvWkVoU2JHTXpVbWhrUjJ4MlltNU5kbGxYVGpCaFZ6bDFZM2s1ZVdSWE5Yb0tUSHBGZVUxVVdUVlBWR2MxVG5wbk0wd3lSakJrUjFaMFkwaFNla3g2UlhkR1oxbExTM2RaUWtKQlIwUjJla0ZDUm1kUlNVUkJXbmRrVjBwellWZE5kd3BuV1hOSFEybHpSMEZSVVVJeGJtdERRa0ZKUldaUlVqZEJTR3RCWkhkRVpGQlVRbkY0YzJOU1RXMU5Xa2hvZVZwYWVtTkRiMnR3WlhWT05EaHlaaXRJQ21sdVMwRk1lVzUxYW1kQlFVRmFUMVE0TTFJclFVRkJSVUYzUWtsTlJWbERTVkZETUV0a01sUjRVWElyV0VGU1ZUbDRkVzE1V0V0WmFHRktTM0ZuUjI0S01sQndORWxtYVZkYVNrVTFla0ZKYUVGUU9WbEZUbGRUUlROSmIweEdiRzV3UTFsa1JYUnpPR0pTU0ZGNVprUmlTVWs0THpWYVNXRm1XRWszVFVGdlJ3cERRM0ZIVTAwME9VSkJUVVJCTW1OQlRVZFJRMDFITW1SVWJGZGhUbWxFYjBWNWFGYzVRMmRDV0dzNVZIYzJWVzlOVlV4cGJHd3liMGN3ZWpjclJ6Wk9DbGt3VGxaWlZEaHpSMEo0WTJwME1GZE9NRFJ3U2xGSmQxUm1USFlyVVRCMVJtVTFWbmhIYjAxdGVXRkpkWFpEWTFSck1FeGFSVzVQZURoeVltMDVkVmNLZURGdFFVOURjRzlITTBsVmJ6VnpieXR5T0VOcFFuWjNDaTB0TFMwdFJVNUVJRU5GVWxSSlJrbERRVlJGTFMwdExTMEsifV19fQ=="}]},"envelope":{"statement":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicHlwaV9hdHRlc3RhdGlvbnMtMC4wLjE5LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI5YmIxYWRkMDRiMWI0ZTE4MmJlNmIwYjgwOTMxNTkzZjdhMjkxZWI0OWQ2OWI0ZmQ3MjhhNWQ0Y2JjZGM0YmQzIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MSIsInByZWRpY2F0ZSI6eyJidWlsZERlZmluaXRpb24iOnsiYnVpbGRUeXBlIjoiaHR0cHM6Ly9hY3Rpb25zLmdpdGh1Yi5pby9idWlsZHR5cGVzL3dvcmtmbG93L3YxIiwiZXh0ZXJuYWxQYXJhbWV0ZXJzIjp7IndvcmtmbG93Ijp7InJlZiI6InJlZnMvdGFncy92MC4wLjE5IiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS90cmFpbG9mYml0cy9weXBpLWF0dGVzdGF0aW9ucyIsInBhdGgiOiIuZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoicmVsZWFzZSIsInJlcG9zaXRvcnlfaWQiOiI3NzIyNDc0MjMiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiMjMxNDQyMyIsInJ1bm5lcl9lbnZpcm9ubWVudCI6ImdpdGh1Yi1ob3N0ZWQifX0sInJlc29sdmVkRGVwZW5kZW5jaWVzIjpbeyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL3RyYWlsb2ZiaXRzL3B5cGktYXR0ZXN0YXRpb25zQHJlZnMvdGFncy92MC4wLjE5IiwiZGlnZXN0Ijp7ImdpdENvbW1pdCI6IjA4ODAyZWZlMWY4ZTVmZWM0YWQ4NDJkNmI4Y2U5NzY1NjA5MmVlNzIifX1dfSwicnVuRGV0YWlscyI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9naXRodWIuY29tL3RyYWlsb2ZiaXRzL3B5cGktYXR0ZXN0YXRpb25zLy5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvdGFncy92MC4wLjE5In0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS90cmFpbG9mYml0cy9weXBpLWF0dGVzdGF0aW9ucy9hY3Rpb25zL3J1bnMvMTIxNjk5ODk3ODcvYXR0ZW1wdHMvMSJ9fX19","signature":"MEYCIQDHR6MacxJcrW/SZCBjiv4OXlHBCAcrDoR5ijuuC9yU0QIhAM0RpMsC7oknwvP562V+NkQTBqCHUR9Fsy0OAO5+9ZUi"}} diff --git a/test/test_cli.py b/test/test_cli.py index a224fbe..1d361ad 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -33,6 +33,7 @@ artifact_path = _ASSETS / "pypi_attestations-0.0.19.tar.gz" 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" pypi_wheel_url = "https://files.pythonhosted.org/packages/70/f5/324edb6a802438e97e289992a41f81bb7a58a1cda2e49439e7e48896649e/sigstore-3.6.1-py3-none-any.whl" pypi_sdist_url = "https://files.pythonhosted.org/packages/db/89/b982115aabe1068fd581d83d2a0b26b78e1e7ce6184e75003d173e15c0b3/sigstore-3.6.1.tar.gz" @@ -224,6 +225,7 @@ def test_verify_attestation_command(caplog: pytest.LogCaptureFixture) -> None: ] ) assert f"OK: {publish_attestation_path.as_posix()}" in caplog.text + assert f"OK: {slsa_attestation_path.as_posix()}" in caplog.text caplog.clear() @@ -295,7 +297,7 @@ def test_verify_attestation_missing_attestation(caplog: pytest.LogCaptureFixture ] ) - assert "is not a file." in caplog.text + assert f"Couldn't find attestations for file {f.name}" in caplog.text def test_verify_attestation_invalid_artifact(