Skip to the content.

Supply-Chain Attestations

coding-ethos publishes trust evidence in layers. The goal is not to claim that an attested artifact is automatically safe; the goal is to make the source, workflow, identity, digest, and release path verifiable.

Current Policy

Why These Controls

GitHub artifact attestations bind a subject path or checksum to an in-toto statement signed through Sigstore using the workflow’s OIDC identity. That gives consumers a verifiable link from an artifact digest back to the repository, workflow, commit, and event that produced it.

PyPI Trusted Publishing removes long-lived upload credentials from GitHub secrets. PyPI digital attestations then bind the uploaded release files to the Trusted Publisher identity that performed the upload.

OpenSSF Scorecard is a public, repeatable health signal. The project publishes Scorecard results so the badge and API reflect a current repository-owned run instead of waiting for external ecosystem scans.

SBOMs complement provenance. Provenance says where and how an artifact was built; the SBOM records the component inventory used for dependency review, license review, vulnerability matching, and downstream audit.

Verification Commands

Verify GitHub artifact attestations for release artifacts:

gh attestation verify dist/coding_ethos-*.tar.gz \
  --repo paudley/coding-ethos
gh attestation verify dist/coding_ethos-*.whl \
  --repo paudley/coding-ethos
gh attestation verify dist-checksums/SHA256SUMS \
  --repo paudley/coding-ethos

Verify the SBOM attestation bound to the release artifact checksums:

gh attestation verify dist/coding_ethos-*.whl \
  --repo paudley/coding-ethos \
  --predicate-type https://spdx.dev/Document

Download offline attestation bundles from a release and verify them with the artifact they describe:

gh release download v0.1.1 \
  --repo paudley/coding-ethos \
  --pattern '*.intoto.jsonl'
gh attestation verify dist/coding_ethos-*.whl \
  --repo paudley/coding-ethos \
  --bundle coding_ethos-*.whl.intoto.jsonl

Verify checksums:

sha256sum --check dist-checksums/SHA256SUMS

Verify PyPI publish attestations after a release with a concrete distribution file URL from PyPI:

uvx pypi-attestations verify pypi \
  --repository https://github.com/paudley/coding-ethos \
  https://files.pythonhosted.org/.../coding_ethos-0.1.0-py3-none-any.whl

Inspect the public Scorecard result:

curl -fsS https://api.scorecard.dev/projects/github.com/paudley/coding-ethos

Release Workflow Contract

The release workflow is intentionally split:

Keep these responsibilities separate. The PyPI publishing job should stay small, run on GitHub-hosted Ubuntu, use OIDC, and avoid unrelated build or mutation steps. The GitHub release job must attach assets before publication so immutable releases contain the distributions, checksums, SBOM, and offline attestation bundles from the start.

The same workflow also supports manual workflow_dispatch dry runs. A manual dry run executes the build job, package metadata validation, checksum generation, SBOM generation, GitHub provenance attestations, SBOM attestation, and artifact uploads. It intentionally skips GitHub release creation and PyPI publication so the release identity can be tested before creating or publishing a real release.

First-Release Setup

Before the first PyPI release, run the local release dry run:

make release-dry-run

Then run the GitHub release workflow manually with dry_run enabled. Download the dist, dist-checksums, and dist-sbom artifacts from that run and verify the generated attestations before publishing the first release.

Then configure a PyPI Trusted Publisher:

Configure the GitHub pypi environment before the first public release. If the project has multiple maintainers, use environment reviewers to keep release publication as a deliberate approval step even though the credential exchange is automated.

The environment can be created from the CLI:

gh api repos/paudley/coding-ethos/environments/pypi \
  --method PUT \
  --field wait_timer=0

Add required reviewers through the GitHub environment settings or with the GitHub API after resolving the maintainer or team reviewer IDs.