Metadata-Version: 2.4
Name: gcp-attest
Version: 0.3.1.post2.dev0
Summary: Digital Attestations and Trusted Publishing via Google Cloud IAM
Project-URL: Source, https://codeberg.org/kytta/gcp-attest
Author-email: Nikita Karamov <me@kytta.dev>
License-Expression: ISC
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development
Requires-Python: >=3.9
Requires-Dist: google-auth[requests]>=2.16.1
Requires-Dist: pypi-attestations>=0.0.28
Requires-Dist: sigstore>=4
Description-Content-Type: text/markdown

# gcp-attest

Produce Digital Attestations and use PyPI Trusted Publishing using Google Cloud service accounts.

## Setup

First, follow the [setup guide](https://codeberg.org/kytta/gcp-attest#setup).

```sh
# Build your package; e.g. with `python -m build`

# Sign files
gcp-attest sign dist/*

# Upload to PyPI incl. attestations
TWINE_USERNAME=__token__ \
TWINE_PASSWORD="$(gcp-attest exchange)" \
twine upload --attestations dist/*
```

### Digital attestations

Run `gcp-attest sign <FILES...>` (alias: `attest`) in the same way you would run `pypi-attestations sign`. This will create attestations for all valid Python package files.

```
usage: gcp-attest attest [-h] [--staging] FILE [FILE ...]

positional arguments:
  FILE        file(s) to sign

options:
  -h, --help  show this help message and exit
  --staging   use the staging environment
```

### PyPI uploading

Run `gcp-attest exchange` (alias: `mint`) to exchange a Google OIDC token for a PyPI upload token.

You can use `--repository` to specify a different repository (e.g. TestPyPI)

```
usage: gcp-attest exchange [-h] [--repository REPOSITORY]

options:
  -h, --help            show this help message and exit
  --repository, -r REPOSITORY
                        the repository (package index) to mint the token for
```

## Why

PyPI encourages Trusted Publishing, but their supported platforms do not include Codeberg. This is understandable: Supporting a new platform means trusting it, and for a long time neither of Codeberg's CI options even had an option to issue OIDC tokens.

PyPI trusts Google's OIDC, though. All OIDC tokens issued by Google Cloud IAM can be exchanged against valid PyPI publishing tokens. The same applies to Sigstore and digital attestations.

Google Cloud OIDC tokens usually represent a service account.  There are multiple ways to "log in" as said account to issue tokens:

1. Inside a Google Cloud workflow. This is the expected way and already supported by [di/id][id] and [pypi-attestations].
2. Using a long-lived credentials key file.
3. Using [Workload Identity Federation](https://docs.cloud.google.com/iam/docs/workload-identity-federation-with-other-providers)

The last one is interesting, as it allows us to exchange OIDC tokens from any valid identity provider for Google Cloud tokens. This way, Google Cloud acts like a proxy between PyPI and not (yet) supported OIDC providers.

This project aims to simplify publishing process by offering APIs to create attestations and exchange tokens.

## Licence

© 2026 [Nikita Karamov]\
Licensed under the [ISC License][ISC]

[gcloud]: https://console.cloud.google.com/
[id]: https://github.com/di/id
[ISC]: https://spdx.org/licenses/ISC.html
[Nikita Karamov]: https://www.kytta.dev/
[pypi-attestations]: https://github.com/pypi/pypi-attestations
