Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
# The GitHub release is created as a *draft* on purpose: the release notes want
# a human. Publishing the draft is a single click in the GitHub UI.
#
# The sdist gets a build provenance attestation, which says that this workflow
# built it from this repository at this commit. GitHub serves it via the
# attestations API, and the attestation bundle is attached to the release as a
# .jsonl file as well, so that the sdist can also be verified against a file.
#
# The upload to PyPI is a separate job only so that the "pypi" environment gate
# applies to the upload alone - that is the last chance to stop a release before
# the irreversible step.
Expand Down Expand Up @@ -42,7 +47,9 @@ jobs:
timeout-minutes: 30

permissions:
contents: write # to create the release
contents: write # to create the release
id-token: write # to attest the sdist
attestations: write

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down Expand Up @@ -97,6 +104,27 @@ jobs:
"$RUNNER_TEMP/venv-sdist/bin/pytest" -v -rs tests/
"$RUNNER_TEMP/venv-sdist/bin/borghash-demo"

- name: Attest the sdist provenance
# Only after the checks above: an attestation for a sdist that does not
# install would be a signed statement about a broken release.
id: attest
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: 'dist/*.tar.gz'

- name: Keep the attestation bundle as a release asset
# "gh attestation verify" fetches the attestation from the GitHub API by
# default, but the bundle is tiny, so attach it to the release, too: then
# the sdist can also be verified against that file, via "--bundle".
env:
BUNDLE: ${{ steps.attest.outputs.bundle-path }}
TAG: ${{ github.ref_name }}
run: |
set -euxo pipefail
# ".jsonl" is how "gh attestation download" names such a file.
cp "$BUNDLE" "dist/borghash-$TAG.tar.gz.jsonl"
ls -l dist/

- name: Create the draft release
env:
GH_TOKEN: ${{ github.token }}
Expand All @@ -115,17 +143,28 @@ jobs:

borghash is a Cython extension: installing the source distribution below
needs a C compiler, but no Cython - the generated C files are included.

### Verification

The sdist has a [build provenance attestation](https://github.com/borgbackup/borghash/attestations):

\`gh attestation verify --owner borgbackup borghash-$TAG.tar.gz\`

The attestation bundle is attached as \`borghash-$TAG.tar.gz.jsonl\`, too, for
verifying against that file instead of the GitHub API:

\`gh attestation verify --owner borgbackup --bundle borghash-$TAG.tar.gz.jsonl borghash-$TAG.tar.gz\`
EOF
if gh release view "$TAG" > /dev/null 2>&1; then
# a re-run of this job: keep the (possibly already edited) release and
# just replace its assets.
gh release upload "$TAG" --clobber dist/*.tar.gz
gh release upload "$TAG" --clobber dist/*.tar.gz dist/*.jsonl
else
gh release create "$TAG" \
--draft $prerelease \
--title "borghash $TAG" \
--notes-file release-notes.md \
dist/*.tar.gz
dist/*.tar.gz dist/*.jsonl
fi
gh release view "$TAG" --json isDraft,isPrerelease,assets

Expand Down
14 changes: 10 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,16 @@ an annotated, signed tag named like the version (no ``v`` prefix) onto the
git push origin 0.3.0

Pushing the tag runs ``.github/workflows/release.yml``, which builds the sdist,
checks that it is complete and installable, and creates a *draft* GitHub
release with it. The upload to PyPI happens in the ``pypi`` job, which uses
trusted publishing (no API token) and waits for an approval if the ``pypi``
environment has required reviewers configured.
checks that it is complete and installable, attests its build provenance and
creates a *draft* GitHub release with the sdist and the attestation bundle
(``borghash-0.3.0.tar.gz.jsonl``). The upload to PyPI happens in the ``pypi``
job, which uses trusted publishing (no API token) and waits for an approval if
the ``pypi`` environment has required reviewers configured.

The attestation says that this workflow built this sdist from this repository,
and is checked with::

gh attestation verify --owner borgbackup borghash-0.3.0.tar.gz

Finally, write the release notes and publish the draft release.

Expand Down