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 b/test/assets/pypi_attestations-0.0.19.tar.gz new file mode 100644 index 0000000..be9a1fb Binary files /dev/null and b/test/assets/pypi_attestations-0.0.19.tar.gz differ diff --git a/test/assets/pypi_attestations-0.0.19.tar.gz.publish.attestation b/test/assets/pypi_attestations-0.0.19.tar.gz.publish.attestation new file mode 100644 index 0000000..3d7e1e6 --- /dev/null +++ b/test/assets/pypi_attestations-0.0.19.tar.gz.publish.attestation @@ -0,0 +1 @@ +{"envelope":{"signature":"MEYCIQC+Yjc/GP2HATHRmlyN85BGBJdDgOWm/GVMDuoU6ESX/gIhAIyakdnRMW84PJVQJxpPp3zxwA9IdP64teBnkeFl71OH","statement":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicHlwaV9hdHRlc3RhdGlvbnMtMC4wLjE5LnRhci5neiIsImRpZ2VzdCI6eyJzaGEyNTYiOiI5YmIxYWRkMDRiMWI0ZTE4MmJlNmIwYjgwOTMxNTkzZjdhMjkxZWI0OWQ2OWI0ZmQ3MjhhNWQ0Y2JjZGM0YmQzIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vZG9jcy5weXBpLm9yZy9hdHRlc3RhdGlvbnMvcHVibGlzaC92MSIsInByZWRpY2F0ZSI6bnVsbH0="},"verification_material":{"certificate":"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","transparency_entries":[{"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiZWFjNTY1OWQ4NDZhMTYxMzdhNDFiMzQxM2E5MTE4ZjFiODYxNDFhNmJiMWIxNTRhYWZhNWZhNGY2NTJjYWM0NCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImY5NzkwZThhODdkMDE4OThkMDBkMmNlMWNhNmNlNDJiZmM2Y2U1OWZhYWEzMWJhYTBhYjY0MDY0YTY5NjgwMDAifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVZQ0lRQytZamMvR1AySEFUSFJtbHlOODVCR0JKZERnT1dtL0dWTUR1b1U2RVNYL2dJaEFJeWFrZG5STVc4NFBKVlFKeHBQcDN6eHdBOUlkUDY0dGVCbmtlRmw3MU9IIiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjdmFrTkRRbTlUWjBGM1NVSkJaMGxWUWprclYySndlRkZTSzI5V2RXZFdiRkl5VVhBd01XOTNablpGZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwUmVFMXFRVEJOYWsxNFRrUkJlRmRvWTA1TmFsRjRUV3BCTUUxcVRYbE9SRUY0VjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVm5ZU3RNV1ZneWRsUkVOMk16WmxreGRDOXdjR05XVjI1WmMzVTBaRXB0VEZwblIyd0tTRlJvTTJka1VERXdVRWRUZUhWUGNXWmlUVzVYTkZCbmEwcE9iR0oxYWtjMlJEVlliazU1VmtKcGFXaFljQzlUUldGUFEwSmhUWGRuWjFkbVRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdSQ1owNVdTRkUwUlVablVWVktWVmczQ21scWJYSkZTalJhWjA1NFYxWnZTbE5wTWtwWFMwOWpkMGgzV1VSV1VqQnFRa0puZDBadlFWVXpPVkJ3ZWpGWmEwVmFZalZ4VG1wd1MwWlhhWGhwTkZrS1drUTRkMkpuV1VSV1VqQlNRVkZJTDBKSFVYZFpiMXBuWVVoU01HTklUVFpNZVRsdVlWaFNiMlJYU1hWWk1qbDBURE5TZVZsWGJITmlNbHBwWVZoU2VncE1NMEkxWTBkcmRGbFlVakJhV0U0d1dWaFNjR0l5TlhwTWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhR015VlhWbFZ6RnpDbEZJU214YWJrMTJaRWRHYm1ONU9USk5RelIzVEdwRk5VMUVhMGREYVhOSFFWRlJRbWMzT0hkQlVVVkZTekpvTUdSSVFucFBhVGgyWkVjNWNscFhOSFVLV1ZkT01HRlhPWFZqZVRWdVlWaFNiMlJYU2pGak1sWjVXVEk1ZFdSSFZuVmtRelZxWWpJd2QwWlJXVXRMZDFsQ1FrRkhSSFo2UVVKQloxRklZMjFXY3dwYVYwWjZXbFJCTWtKbmIzSkNaMFZGUVZsUEwwMUJSVVJDUTJkM1QwUm5kMDF0Vm0xYVZFWnRUMGRWTVZwdFZtcE9SMFpyVDBSUmVWcEVXbWxQUjA1c0NrOVVZekpPVkZsM1QxUktiRnBVWTNsTlFsVkhRMmx6UjBGUlVVSm5OemgzUVZGUlJVSXpTbXhpUjFab1l6SlZkMHQzV1V0TGQxbENRa0ZIUkhaNlFVSUtRbEZSWkdSSVNtaGhWM2gyV20xS2NHUklUWFpqU0d4M1lWTXhhR1JJVW14ak0xSm9aRWRzZG1KdVRYZElkMWxMUzNkWlFrSkJSMFIyZWtGQ1FtZFJVZ3BqYlZadFkzazVNRmxYWkhwTU0xbDNUR3BCZFUxVWEzZFBkMWxMUzNkWlFrSkJSMFIyZWtGQ1EwRlJkRVJEZEc5a1NGSjNZM3B2ZGt3elVuWmhNbFoxQ2t4dFJtcGtSMngyWW01TmRWb3liREJoU0ZacFpGaE9iR050VG5aaWJsSnNZbTVSZFZreU9YUk5TRUZIUTJselIwRlJVVUpuTnpoM1FWRnJSVmxuZUdjS1lVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVEROU2VWbFhiSE5pTWxwcFlWaFNla3d6UWpWalIydDBXVmhTTUZwWVRqQlpXRkp3WWpJMWVncE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYVmxWekZ6VVVoS2JGcHVUWFprUjBadVkzazVNazFETkhkTWFrVTFDazFFWjBkRGFYTkhRVkZSUW1jM09IZEJVVzlGUzJkM2IwMUVaelJOUkVwc1dtMVZlRnBxYUd4T1YxcHNXWHBTYUZwRVp6Qk5iVkV5V1dwb2FscFVhek1LVG1wVk1rMUVhM2xhVjFVelRXcEJaRUpuYjNKQ1owVkZRVmxQTDAxQlJVeENRVGhOUkZka2NHUkhhREZaYVRGdllqTk9NRnBYVVhkUlFWbExTM2RaUWdwQ1FVZEVkbnBCUWtSQlVYbEVSRUp2WkVoU2QyTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJaRWhLYUdGWGVIWmFiVXB3WkVoTmRtTkliSGRoVXpGb0NtUklVbXhqTTFKb1pFZHNkbUp1VFhkUFFWbExTM2RaUWtKQlIwUjJla0ZDUkZGUmNVUkRaM2RQUkdkM1RXMVdiVnBVUm0xUFIxVXhXbTFXYWs1SFJtc0tUMFJSZVZwRVdtbFBSMDVzVDFSak1rNVVXWGRQVkVwc1dsUmplVTFEUlVkRGFYTkhRVkZSUW1jM09IZEJVVFJGUlhkM1VtTnRWbTFqZVRrd1dWZGtlZ3BNTTFsM1RHcEJkVTFVYTNkSFVWbExTM2RaUWtKQlIwUjJla0ZDUkhkUlRFUkJhek5PZWtsNVRrUmpNRTFxVFhkTVoxbExTM2RaUWtKQlIwUjJla0ZDQ2tWQlVXZEVRalZ2WkVoU2QyTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJaRWhLYUdGWGVIWmFiVXB3WkVoTmQwWjNXVXRMZDFsQ1FrRkhSSFo2UVVJS1JWRlJTa1JCWTNsTmVrVXdUa1JKZWsxSVFVZERhWE5IUVZGUlFtYzNPSGRCVWtsRldXZDRaMkZJVWpCalNFMDJUSGs1Ym1GWVVtOWtWMGwxV1RJNWRBcE1NMUo1V1Zkc2MySXlXbWxoV0ZKNlRETkNOV05IYTNSWldGSXdXbGhPTUZsWVVuQmlNalY2VEhrMWJtRllVbTlrVjBsMlpESTVlV0V5V25OaU0yUjZDa3d6U214aVIxWm9ZekpWZFdWWE1YTlJTRXBzV201TmRtUkhSbTVqZVRreVRVTTBkMHhxUlRWTlJHZEhRMmx6UjBGUlVVSm5OemgzUVZKTlJVdG5kMjhLVFVSbk5FMUVTbXhhYlZWNFdtcG9iRTVYV214WmVsSm9Xa1JuTUUxdFVUSlphbWhxV2xSck0wNXFWVEpOUkd0NVdsZFZNMDFxUVZoQ1oyOXlRbWRGUlFwQldVOHZUVUZGVlVKQmEwMUNNMHBzWWtkV2FHTXlWWGRhUVZsTFMzZFpRa0pCUjBSMmVrRkNSbEZTVjBSR1VtOWtTRkozWTNwdmRrd3laSEJrUjJneENsbHBOV3BpTWpCMlpFaEthR0ZYZUhaYWJVcHdaRWhOZG1OSWJIZGhVekZvWkVoU2JHTXpVbWhrUjJ4MlltNU5kbGxYVGpCaFZ6bDFZM2s1ZVdSWE5Yb0tUSHBGZVUxVVdUVlBWR2MxVG5wbk0wd3lSakJrUjFaMFkwaFNla3g2UlhkR1oxbExTM2RaUWtKQlIwUjJla0ZDUm1kUlNVUkJXbmRrVjBwellWZE5kd3BuV1c5SFEybHpSMEZSVVVJeGJtdERRa0ZKUldaQlVqWkJTR2RCWkdkRVpGQlVRbkY0YzJOU1RXMU5Xa2hvZVZwYWVtTkRiMnR3WlhWT05EaHlaaXRJQ21sdVMwRk1lVzUxYW1kQlFVRmFUMVE0TjBWbFFVRkJSVUYzUWtoTlJWVkRTVkZFVkRWWVEzQTFXbXN5V1V4blNGTjNTMmczVkRFemJrSmpjR0ZGYTNFS1UwRTVSa1ZPWkd4ak56bFNWMmRKWjB0b1FrY3JWM2g1YWk5S01WazROekZrVDNWMVIwWnNLeXRNYUZCeVdsQmhNMU5XYms5VFoxZHVNVEIzUTJkWlNRcExiMXBKZW1vd1JVRjNUVVJoUVVGM1dsRkplRUZLUzJWVVoyb3JaMmhqTTNCbFJEQXhRVkprT1dGSlZuTkZjRVJIWkdKUFlYcExRVEoxWVZGT2RsTk1DazkxWkhWNVNtdE1iRTVWVGt0T09GRmhUbmR3YzFGSmQxUndXalkwZG5ScWQwTXlVMXBCY1dJeU1VSnVOSEZXTjNSTVFrcHRTVmQ0TVd4VlpUQlJiRllLZVdsNE1URTRNRlJyUTFvd1FsWmpabTlFTkhoSlEwdEpDaTB0TFMwdFJVNUVJRU5GVWxSSlJrbERRVlJGTFMwdExTMEsifV19fQ==","inclusionPromise":{"signedEntryTimestamp":"MEQCIBCltBioLJc+JvwwmgQ1BYgIOE5RTG+4e7X3zQRGa6ZHAiA46xAH8obqC29dw2T8gwyllNzqr2tfG8iMWLnFKuIORQ=="},"inclusionProof":{"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n31550402\ny0mvJokg0K9X78/zSkzLfaoYE1EUnA0l4CTQQXV1g4o=\n\n— rekor.sigstore.dev wNI9ajBFAiBegciq2ELY5ENvqNVWFm9cEfG5dKBwBegOEaoDVWLdVwIhAJAOwu2VWIQojdyGzsV/t4MRCOkduH9SVKL8yoK9qMc2\n"},"hashes":["Ys0Xl1UkpNskWt6zZj4IF0V4C0hQnG2rcYT7yITCgxs=","SZr1mNOrcyCB9fdcJOMiVFgh1vv3F1JOn4Iro9CbeI0=","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="],"logIndex":"31550401","rootHash":"y0mvJokg0K9X78/zSkzLfaoYE1EUnA0l4CTQQXV1g4o=","treeSize":"31550402"},"integratedTime":"1733354041","kindVersion":{"kind":"dsse","version":"0.0.1"},"logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"logIndex":"153454663"}]},"version":1} 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 d7a84d4..1d361ad 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -30,8 +30,10 @@ _HERE = Path(__file__).parent _ASSETS = _HERE / "assets" -artifact_path = _ASSETS / "rfc8785-0.1.2-py3-none-any.whl" -attestation_path = _ASSETS / "rfc8785-0.1.2-py3-none-any.whl.publish.attestation" +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" @@ -83,7 +85,7 @@ def return_invalid_token() -> 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 +174,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 +185,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 +219,13 @@ 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 + assert f"OK: {slsa_attestation_path.as_posix()}" in caplog.text caplog.clear() @@ -233,8 +235,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 +259,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 +274,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,14 +291,13 @@ def test_verify_attestation_missing_attestation(caplog: pytest.LogCaptureFixture [ "verify", "attestation", - "--staging", "--identity", - "william@yossarian.net", + publish_attestation_identity, f.name, ] ) - 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( @@ -306,16 +306,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(), ] )