Skip to content

Commit 28d055e

Browse files
authored
cli: Support verifing *.slsa.attestation attestation files (#86)
1 parent 41584d9 commit 28d055e

File tree

7 files changed

+58
-56
lines changed

7 files changed

+58
-56
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- The CLI subcommand `verify attestation` now supports `.slsa.attestation`
13+
files. When verifying an artifact, both `.publish.attestation` and
14+
`.slsa.attestation` files are used (if present).
15+
1016
## [0.0.21]
1117

1218
### Changed
@@ -18,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1824
([#82](https://github.com/trailofbits/pypi-attestations/pull/82))
1925

2026
### Added
27+
2128
- The CLI has a new subcommand `verify pypi`, which takes a URL to a
2229
PyPI distribution (either a wheel or a source distribution) and a
2330
GitHub/GitLab repository. The command verifies the distribution by

README.md

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,20 +134,12 @@ pypi-attestations inspect dist/pypi_attestations-*.whl.publish.attestation
134134
135135
### Verifying a PEP 740 Attestation
136136
137-
> [!NOTE]
138-
> The example below uses an email with `--identity`, but actual PyPI
139-
> attestations will be signed with a machine identity corresponding to the
140-
> workflow that generated the attestation. The format of that identity
141-
142137
```bash
143-
pypi-attestations verify attestation --staging \
144-
--identity william@yossarian.net \
145-
test/assets/rfc8785-0.1.2-py3-none-any.whl
138+
pypi-attestations verify attestation \
139+
--identity https://github.com/trailofbits/pypi-attestations/.github/workflows/release.yml@refs/tags/v0.0.19 \
140+
test/assets/pypi_attestations-0.0.19.tar.gz
146141
```
147142
148-
The attestation present in the test has been generated using the staging
149-
environment of Sigstore and signed by the identity `william@yossarian.net`.
150-
151143
### Verifying a PyPI package
152144
> [!NOTE]
153145
> The URL must be a direct link to the distribution artifact hosted by PyPI.

src/pypi_attestations/_cli.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import json
77
import logging
88
import typing
9+
from collections import defaultdict
910
from pathlib import Path
1011
from tempfile import TemporaryDirectory
1112

@@ -385,35 +386,36 @@ def _verify_attestation(args: argparse.Namespace) -> None:
385386
"""Verify the files passed as argument."""
386387
pol = policy.Identity(identity=args.identity)
387388

388-
# Validate that both the attestations and files exist
389+
# Validate that the files exist
389390
_validate_files(args.files, should_exist=True)
390-
_validate_files(
391-
(Path(f"{file_path}.publish.attestation") for file_path in args.files),
392-
should_exist=True,
393-
)
394-
395-
inputs: list[Path] = []
396-
for file_path in args.files:
397-
inputs.append(file_path)
398391

399-
for input in inputs:
400-
attestation_path = Path(f"{input}.publish.attestation")
401-
try:
402-
attestation = Attestation.model_validate_json(attestation_path.read_text())
403-
except ValidationError as validation_error:
404-
_die(f"Invalid attestation ({attestation_path}): {validation_error}")
392+
# artifact -> [attestation1, attestation2, ...]
393+
files_with_attestations: dict[Path, list[Path]] = defaultdict(list)
394+
for f in args.files:
395+
for attestation_file in (Path(f"{f}.publish.attestation"), Path(f"{f}.slsa.attestation")):
396+
if attestation_file.exists():
397+
files_with_attestations[f].append(attestation_file)
398+
if not files_with_attestations[f]:
399+
_die(f"Couldn't find attestations for file {f}")
400+
401+
for file_path, attestations in files_with_attestations.items():
402+
for attestation_path in attestations:
403+
try:
404+
attestation = Attestation.model_validate_json(attestation_path.read_text())
405+
except ValidationError as validation_error:
406+
_die(f"Invalid attestation ({attestation_path}): {validation_error}")
405407

406-
try:
407-
dist = Distribution.from_file(input)
408-
except ValidationError as e:
409-
_die(f"Invalid Python package distribution: {e}")
408+
try:
409+
dist = Distribution.from_file(file_path)
410+
except ValidationError as e:
411+
_die(f"Invalid Python package distribution: {e}")
410412

411-
try:
412-
attestation.verify(pol, dist, staging=args.staging)
413-
except VerificationError as verification_error:
414-
_die(f"Verification failed for {input}: {verification_error}")
413+
try:
414+
attestation.verify(pol, dist, staging=args.staging)
415+
except VerificationError as verification_error:
416+
_die(f"Verification failed for {file_path}: {verification_error}")
415417

416-
_logger.info(f"OK: {attestation_path}")
418+
_logger.info(f"OK: {attestation_path}")
417419

418420

419421
def _verify_pypi(args: argparse.Namespace) -> None:
29.2 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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}

0 commit comments

Comments
 (0)