mirror of https://github.com/astral-sh/uv
Restore Docker image annotations and fix attestations (#14165)
More follow-up to #13459 - Depot doesn't support annotations, so we push those manually - Docker push for the re-tag was breaking the manifest, since we need to annotate manually, we just do that instead - We attest after the annotation A bit of an aside - We test building the extra images, it's very fast and I don't see why it's better to gate it I tested this on my fork then cleaned it up a bit for a commit here. You can see the images at - https://github.com/zanieb/uv/pkgs/container/uv - https://hub.docker.com/r/astral/uv/tags --------- Co-authored-by: samypr100 <3933065+samypr100@users.noreply.github.com>
This commit is contained in:
parent
8352560b98
commit
b18f45db14
|
|
@ -80,7 +80,9 @@ jobs:
|
||||||
name: release
|
name: release
|
||||||
outputs:
|
outputs:
|
||||||
image-tags: ${{ steps.meta.outputs.tags }}
|
image-tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
image-annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
image-digest: ${{ steps.build.outputs.digest }}
|
image-digest: ${{ steps.build.outputs.digest }}
|
||||||
|
image-version: ${{ steps.meta.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
|
|
@ -117,6 +119,8 @@ jobs:
|
||||||
- name: Extract metadata (tags, labels) for Docker
|
- name: Extract metadata (tags, labels) for Docker
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
|
||||||
|
env:
|
||||||
|
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ env.UV_GHCR_IMAGE }}
|
${{ env.UV_GHCR_IMAGE }}
|
||||||
|
|
@ -137,10 +141,12 @@ jobs:
|
||||||
push: ${{ needs.docker-plan.outputs.push }}
|
push: ${{ needs.docker-plan.outputs.push }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
# TODO(zanieb): Annotations are not supported by Depot yet and are ignored
|
||||||
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
|
||||||
- name: Generate artifact attestation for base image
|
- name: Generate artifact attestation for base image
|
||||||
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
||||||
uses: actions/attest-build-provenance@c074443f1aee8d4aeeae555aebba3282517141b2 # v2.2.3
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
with:
|
with:
|
||||||
subject-name: ${{ env.UV_GHCR_IMAGE }}
|
subject-name: ${{ env.UV_GHCR_IMAGE }}
|
||||||
subject-digest: ${{ steps.build.outputs.digest }}
|
subject-digest: ${{ steps.build.outputs.digest }}
|
||||||
|
|
@ -153,7 +159,6 @@ jobs:
|
||||||
needs:
|
needs:
|
||||||
- docker-plan
|
- docker-plan
|
||||||
- docker-publish-base
|
- docker-publish-base
|
||||||
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # for Depot OIDC and GHCR signing
|
id-token: write # for Depot OIDC and GHCR signing
|
||||||
packages: write # for GHCR image pushes
|
packages: write # for GHCR image pushes
|
||||||
|
|
@ -263,20 +268,66 @@ jobs:
|
||||||
context: .
|
context: .
|
||||||
project: 7hd4vdzmw5 # astral-sh/uv
|
project: 7hd4vdzmw5 # astral-sh/uv
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: ${{ needs.docker-plan.outputs.push }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
# TODO(zanieb): Annotations are not supported by Depot yet and are ignored
|
||||||
annotations: ${{ steps.meta.outputs.annotations }}
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
|
|
||||||
- name: Generate artifact attestation
|
- name: Generate artifact attestation
|
||||||
|
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
||||||
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
with:
|
with:
|
||||||
subject-name: ${{ env.UV_GHCR_IMAGE }}
|
subject-name: ${{ env.UV_GHCR_IMAGE }}
|
||||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||||
|
|
||||||
# Re-tag the base image, to ensure it's shown as the newest on the registry UI
|
# Push annotations manually.
|
||||||
docker-retag-base:
|
# See `docker-annotate-base` for details.
|
||||||
name: retag uv
|
- name: Add annotations to images
|
||||||
|
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
||||||
|
env:
|
||||||
|
IMAGES: "${{ env.UV_GHCR_IMAGE }} ${{ env.UV_DOCKERHUB_IMAGE }}"
|
||||||
|
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||||
|
TAGS: ${{ steps.meta.outputs.tags }}
|
||||||
|
ANNOTATIONS: ${{ steps.meta.outputs.annotations }}
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
readarray -t lines <<< "$ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done
|
||||||
|
for image in $IMAGES; do
|
||||||
|
readarray -t lines < <(grep "^${image}:" <<< "$TAGS"); tags=(); for line in "${lines[@]}"; do tags+=(-t "$line"); done
|
||||||
|
docker buildx imagetools create \
|
||||||
|
"${annotations[@]}" \
|
||||||
|
"${tags[@]}" \
|
||||||
|
"${image}@${DIGEST}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# See `docker-annotate-base` for details.
|
||||||
|
- name: Export manifest digest
|
||||||
|
id: manifest-digest
|
||||||
|
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
||||||
|
env:
|
||||||
|
IMAGE: ${{ env.UV_GHCR_IMAGE }}
|
||||||
|
VERSION: ${{ steps.meta.outputs.version }}
|
||||||
|
run: |
|
||||||
|
digest="$(
|
||||||
|
docker buildx imagetools inspect \
|
||||||
|
"${IMAGE}:${VERSION}" \
|
||||||
|
--format '{{json .Manifest}}' \
|
||||||
|
| jq -r '.digest'
|
||||||
|
)"
|
||||||
|
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# See `docker-annotate-base` for details.
|
||||||
|
- name: Generate artifact attestation
|
||||||
|
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
||||||
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
|
with:
|
||||||
|
subject-name: ${{ env.UV_GHCR_IMAGE }}
|
||||||
|
subject-digest: ${{ steps.manifest-digest.outputs.digest }}
|
||||||
|
|
||||||
|
# Annotate the base image
|
||||||
|
docker-annotate-base:
|
||||||
|
name: annotate uv
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment:
|
environment:
|
||||||
name: release
|
name: release
|
||||||
|
|
@ -286,24 +337,67 @@ jobs:
|
||||||
- docker-publish-extra
|
- docker-publish-extra
|
||||||
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
if: ${{ needs.docker-plan.outputs.push == 'true' }}
|
||||||
steps:
|
steps:
|
||||||
|
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
|
with:
|
||||||
|
username: astral
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN_RW }}
|
||||||
|
|
||||||
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Push tags
|
# Depot doesn't support annotating images, so we need to do so manually
|
||||||
|
# afterwards. Mutating the manifest is desirable regardless, because we
|
||||||
|
# want to bump the base image to appear at the top of the list on GHCR.
|
||||||
|
# However, once annotation support is added to Depot, this step can be
|
||||||
|
# minimized to just touch the GHCR manifest.
|
||||||
|
- name: Add annotations to images
|
||||||
env:
|
env:
|
||||||
IMAGE: ${{ env.UV_GHCR_IMAGE }}
|
IMAGES: "${{ env.UV_GHCR_IMAGE }} ${{ env.UV_DOCKERHUB_IMAGE }}"
|
||||||
DIGEST: ${{ needs.docker-publish-base.outputs.image-digest }}
|
DIGEST: ${{ needs.docker-publish-base.outputs.image-digest }}
|
||||||
TAGS: ${{ needs.docker-publish-base.outputs.image-tags }}
|
TAGS: ${{ needs.docker-publish-base.outputs.image-tags }}
|
||||||
|
ANNOTATIONS: ${{ needs.docker-publish-base.outputs.image-annotations }}
|
||||||
|
# The readarray part is used to make sure the quoting and special characters are preserved on expansion (e.g. spaces)
|
||||||
|
# The final command becomes `docker buildx imagetools create --annotation 'index:foo=1' --annotation 'index:bar=2' ... -t tag1 -t tag2 ... <IMG>@sha256:<sha256>`
|
||||||
run: |
|
run: |
|
||||||
docker pull "${IMAGE}@${DIGEST}"
|
set -x
|
||||||
for tag in $TAGS; do
|
readarray -t lines <<< "$ANNOTATIONS"; annotations=(); for line in "${lines[@]}"; do annotations+=(--annotation "$line"); done
|
||||||
# Skip re-tag for DockerHub
|
for image in $IMAGES; do
|
||||||
if [[ "$tag" == "${{ env.UV_DOCKERHUB_IMAGE }}"* ]]; then
|
readarray -t lines < <(grep "^${image}:" <<< "$TAGS"); tags=(); for line in "${lines[@]}"; do tags+=(-t "$line"); done
|
||||||
continue
|
docker buildx imagetools create \
|
||||||
fi
|
"${annotations[@]}" \
|
||||||
docker tag "${IMAGE}@${DIGEST}" "${tag}"
|
"${tags[@]}" \
|
||||||
docker push "${tag}"
|
"${image}@${DIGEST}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Now that we've modified the manifest, we need to attest it again.
|
||||||
|
# Note we only generate an attestation for GHCR.
|
||||||
|
- name: Export manifest digest
|
||||||
|
id: manifest-digest
|
||||||
|
env:
|
||||||
|
IMAGE: ${{ env.UV_GHCR_IMAGE }}
|
||||||
|
VERSION: ${{ needs.docker-publish-base.outputs.image-version }}
|
||||||
|
# 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 \
|
||||||
|
"${IMAGE}:${VERSION}" \
|
||||||
|
--format '{{json .Manifest}}' \
|
||||||
|
| jq -r '.digest'
|
||||||
|
)"
|
||||||
|
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Generate artifact attestation
|
||||||
|
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2.4.0
|
||||||
|
with:
|
||||||
|
subject-name: ${{ env.UV_GHCR_IMAGE }}
|
||||||
|
subject-digest: ${{ steps.manifest-digest.outputs.digest }}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue