mirror of https://github.com/astral-sh/uv
Sign docker images using cosign (#8685)
cosign uses the GitHub action ID token to retrieve an ephemeral code signing certificate from Fulcio, and store the signature in the Rekor transparency log. Once an image has been successfully signed, you should be able to verify the signature with: ```sh cosign verify ghcr.io/astral-sh/uv:latest --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ``` Closes #8670
This commit is contained in:
parent
c6713f5751
commit
47f80a62c4
|
|
@ -39,6 +39,8 @@ jobs:
|
||||||
|
|
||||||
# Login to DockerHub first, to avoid rate-limiting
|
# Login to DockerHub first, to avoid rate-limiting
|
||||||
- uses: docker/login-action@v3
|
- uses: docker/login-action@v3
|
||||||
|
# PRs from forks don't have access to secrets, disable this step in that case.
|
||||||
|
if: ${{ github.event.pull_request.head.repo.full_name == 'astral-sh/uv' }}
|
||||||
with:
|
with:
|
||||||
username: astralshbot
|
username: astralshbot
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN_RO }}
|
password: ${{ secrets.DOCKERHUB_TOKEN_RO }}
|
||||||
|
|
@ -164,6 +166,10 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- docker-publish
|
- docker-publish
|
||||||
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
|
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
attestations: write # needed to push image attestations to the Github attestation store
|
||||||
|
id-token: write # needed for signing the images with GitHub OIDC Token
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -260,6 +266,7 @@ jobs:
|
||||||
${{ env.TAG_PATTERNS }}
|
${{ env.TAG_PATTERNS }}
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
|
id: build-and-push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
|
|
@ -272,6 +279,13 @@ jobs:
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
annotations: ${{ steps.meta.outputs.annotations }}
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
|
||||||
|
- name: Generate artifact attestation
|
||||||
|
uses: actions/attest-build-provenance@v2
|
||||||
|
with:
|
||||||
|
subject-name: ${{ env.UV_BASE_IMG }}
|
||||||
|
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||||
|
# push-to-registry is explicitly not enabled to maintain full control over the top image
|
||||||
|
|
||||||
# This is effectively a duplicate of `docker-publish` to make https://github.com/astral-sh/uv/pkgs/container/uv
|
# This is effectively a duplicate of `docker-publish` to make https://github.com/astral-sh/uv/pkgs/container/uv
|
||||||
# show the uv base image first since GitHub always shows the last updated image digests
|
# show the uv base image first since GitHub always shows the last updated image digests
|
||||||
# This works by annotating the original digests (previously non-annotated) which triggers an update to ghcr.io
|
# This works by annotating the original digests (previously non-annotated) which triggers an update to ghcr.io
|
||||||
|
|
@ -283,6 +297,10 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- docker-publish-extra
|
- docker-publish-extra
|
||||||
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
|
if: ${{ inputs.plan != '' && !fromJson(inputs.plan).announcement_tag_is_implicit }}
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
attestations: write # needed to push image attestations to the Github attestation store
|
||||||
|
id-token: write # needed for signing the images with GitHub OIDC Token
|
||||||
steps:
|
steps:
|
||||||
# Login to DockerHub first, to avoid rate-limiting
|
# Login to DockerHub first, to avoid rate-limiting
|
||||||
- uses: docker/login-action@v3
|
- uses: docker/login-action@v3
|
||||||
|
|
@ -330,3 +348,29 @@ jobs:
|
||||||
"${annotations[@]}" \
|
"${annotations[@]}" \
|
||||||
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||||
$(printf '${{ env.UV_BASE_IMG }}@sha256:%s ' *)
|
$(printf '${{ env.UV_BASE_IMG }}@sha256:%s ' *)
|
||||||
|
|
||||||
|
- name: Share manifest digest
|
||||||
|
id: manifest-digest
|
||||||
|
# To sign the manifest, we need it's digest. Unfortunately "docker
|
||||||
|
# buildx imagetools create" does not (yet) have a clean way of sharing
|
||||||
|
# the digest of the manifest it creates (see docker/buildx#2407), so
|
||||||
|
# we use a separate command to retrieve it.
|
||||||
|
# imagetools inspect [TAG] --format '{{json .Manifest}}' gives us
|
||||||
|
# the machine readable JSON description of the manifest, and the
|
||||||
|
# jq command extracts the digest from this. The digest is then
|
||||||
|
# sent to the Github step output file for sharing with other steps.
|
||||||
|
run: |
|
||||||
|
digest="$(
|
||||||
|
docker buildx imagetools inspect \
|
||||||
|
"${UV_BASE_IMG}:${DOCKER_METADATA_OUTPUT_VERSION}" \
|
||||||
|
--format '{{json .Manifest}}' \
|
||||||
|
| jq -r '.digest'
|
||||||
|
)"
|
||||||
|
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Generate artifact attestation
|
||||||
|
uses: actions/attest-build-provenance@v2
|
||||||
|
with:
|
||||||
|
subject-name: ${{ env.UV_BASE_IMG }}
|
||||||
|
subject-digest: ${{ steps.manifest-digest.outputs.digest }}
|
||||||
|
# push-to-registry is explicitly not enabled to maintain full control over the top image
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,9 @@ jobs:
|
||||||
plan: ${{ needs.plan.outputs.val }}
|
plan: ${{ needs.plan.outputs.val }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
permissions:
|
permissions:
|
||||||
|
"attestations": "write"
|
||||||
"contents": "read"
|
"contents": "read"
|
||||||
|
"id-token": "write"
|
||||||
"packages": "write"
|
"packages": "write"
|
||||||
|
|
||||||
# Build and package all the platform-agnostic(ish) things
|
# Build and package all the platform-agnostic(ish) things
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ publish-jobs = ["./publish-pypi"]
|
||||||
# Post-announce jobs to run in CI
|
# Post-announce jobs to run in CI
|
||||||
post-announce-jobs = ["./publish-docs"]
|
post-announce-jobs = ["./publish-docs"]
|
||||||
# Custom permissions for GitHub Jobs
|
# Custom permissions for GitHub Jobs
|
||||||
github-custom-job-permissions = { "build-docker" = { packages = "write", contents = "read" } }
|
github-custom-job-permissions = { "build-docker" = { packages = "write", contents = "read", id-token = "write", attestations = "write" } }
|
||||||
# Whether to install an updater program
|
# Whether to install an updater program
|
||||||
install-updater = false
|
install-updater = false
|
||||||
# Path that installers should place binaries in
|
# Path that installers should place binaries in
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue