Skip to content

Commit 0c44fa5

Browse files
Merge pull request #56 from borgbackup/attest-provenance
release: attest the sdist provenance, attach the bundle to the release
2 parents a9eef2e + 631f457 commit 0c44fa5

2 files changed

Lines changed: 52 additions & 7 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
# The GitHub release is created as a *draft* on purpose: the release notes want
99
# a human. Publishing the draft is a single click in the GitHub UI.
1010
#
11+
# The sdist gets a build provenance attestation, which says that this workflow
12+
# built it from this repository at this commit. GitHub serves it via the
13+
# attestations API, and the attestation bundle is attached to the release as a
14+
# .jsonl file as well, so that the sdist can also be verified against a file.
15+
#
1116
# The upload to PyPI is a separate job only so that the "pypi" environment gate
1217
# applies to the upload alone - that is the last chance to stop a release before
1318
# the irreversible step.
@@ -42,7 +47,9 @@ jobs:
4247
timeout-minutes: 30
4348

4449
permissions:
45-
contents: write # to create the release
50+
contents: write # to create the release
51+
id-token: write # to attest the sdist
52+
attestations: write
4653

4754
steps:
4855
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -97,6 +104,27 @@ jobs:
97104
"$RUNNER_TEMP/venv-sdist/bin/pytest" -v -rs tests/
98105
"$RUNNER_TEMP/venv-sdist/bin/borghash-demo"
99106
107+
- name: Attest the sdist provenance
108+
# Only after the checks above: an attestation for a sdist that does not
109+
# install would be a signed statement about a broken release.
110+
id: attest
111+
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
112+
with:
113+
subject-path: 'dist/*.tar.gz'
114+
115+
- name: Keep the attestation bundle as a release asset
116+
# "gh attestation verify" fetches the attestation from the GitHub API by
117+
# default, but the bundle is tiny, so attach it to the release, too: then
118+
# the sdist can also be verified against that file, via "--bundle".
119+
env:
120+
BUNDLE: ${{ steps.attest.outputs.bundle-path }}
121+
TAG: ${{ github.ref_name }}
122+
run: |
123+
set -euxo pipefail
124+
# ".jsonl" is how "gh attestation download" names such a file.
125+
cp "$BUNDLE" "dist/borghash-$TAG.tar.gz.jsonl"
126+
ls -l dist/
127+
100128
- name: Create the draft release
101129
env:
102130
GH_TOKEN: ${{ github.token }}
@@ -115,17 +143,28 @@ jobs:
115143
116144
borghash is a Cython extension: installing the source distribution below
117145
needs a C compiler, but no Cython - the generated C files are included.
146+
147+
### Verification
148+
149+
The sdist has a [build provenance attestation](https://github.com/borgbackup/borghash/attestations):
150+
151+
\`gh attestation verify --owner borgbackup borghash-$TAG.tar.gz\`
152+
153+
The attestation bundle is attached as \`borghash-$TAG.tar.gz.jsonl\`, too, for
154+
verifying against that file instead of the GitHub API:
155+
156+
\`gh attestation verify --owner borgbackup --bundle borghash-$TAG.tar.gz.jsonl borghash-$TAG.tar.gz\`
118157
EOF
119158
if gh release view "$TAG" > /dev/null 2>&1; then
120159
# a re-run of this job: keep the (possibly already edited) release and
121160
# just replace its assets.
122-
gh release upload "$TAG" --clobber dist/*.tar.gz
161+
gh release upload "$TAG" --clobber dist/*.tar.gz dist/*.jsonl
123162
else
124163
gh release create "$TAG" \
125164
--draft $prerelease \
126165
--title "borghash $TAG" \
127166
--notes-file release-notes.md \
128-
dist/*.tar.gz
167+
dist/*.tar.gz dist/*.jsonl
129168
fi
130169
gh release view "$TAG" --json isDraft,isPrerelease,assets
131170

‎README.rst‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,16 @@ an annotated, signed tag named like the version (no ``v`` prefix) onto the
186186
git push origin 0.3.0
187187

188188
Pushing the tag runs ``.github/workflows/release.yml``, which builds the sdist,
189-
checks that it is complete and installable, and creates a *draft* GitHub
190-
release with it. The upload to PyPI happens in the ``pypi`` job, which uses
191-
trusted publishing (no API token) and waits for an approval if the ``pypi``
192-
environment has required reviewers configured.
189+
checks that it is complete and installable, attests its build provenance and
190+
creates a *draft* GitHub release with the sdist and the attestation bundle
191+
(``borghash-0.3.0.tar.gz.jsonl``). The upload to PyPI happens in the ``pypi``
192+
job, which uses trusted publishing (no API token) and waits for an approval if
193+
the ``pypi`` environment has required reviewers configured.
194+
195+
The attestation says that this workflow built this sdist from this repository,
196+
and is checked with::
197+
198+
gh attestation verify --owner borgbackup borghash-0.3.0.tar.gz
193199

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

0 commit comments

Comments
 (0)