chore(ci): address lint findings in build-docker.yml (#15245)

## Summary

This re-creates #15145, with fixes following the revert in #15174.

The overall approach is the same, except that I've added an explicit
permissions block to `docker-annotate-base` that should cover the needed
permissions in that job.

(One confusion is around how that wasn't failing before -- FWICT it was
receiving the default `GITHUB_TOKEN`, which doesn't include `id-token:
write` or `packages: write`. So it _should_ have been failing even
before I explicitly did `permissions: {}`...)

Edit: Oh, I see why -- the actual release process does a
`workflow_call`, so this inherits its `GITHUB_TOKEN` from
`release.yml:custom-build-docker`, which in turn has the right
permissions granted to it.

## Test Plan

See what happens in CI. Plus maybe we could do a release dry-run?

Signed-off-by: William Woodruff <william@astral.sh>
This commit is contained in:
William Woodruff 2025-08-12 14:59:27 -04:00 committed by GitHub
parent 959c9521c8
commit 65b4dbc47e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 20 additions and 8 deletions

View File

@ -40,6 +40,8 @@ env:
UV_GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/uv UV_GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/uv
UV_DOCKERHUB_IMAGE: docker.io/astral/uv UV_DOCKERHUB_IMAGE: docker.io/astral/uv
permissions: {}
jobs: jobs:
docker-plan: docker-plan:
name: plan name: plan
@ -57,13 +59,13 @@ jobs:
IS_LOCAL_PR: ${{ github.event.pull_request.head.repo.full_name == 'astral-sh/uv' }} IS_LOCAL_PR: ${{ github.event.pull_request.head.repo.full_name == 'astral-sh/uv' }}
id: plan id: plan
run: | run: |
if [ "${{ env.DRY_RUN }}" == "false" ]; then if [ "${DRY_RUN}" == "false" ]; then
echo "login=true" >> "$GITHUB_OUTPUT" echo "login=true" >> "$GITHUB_OUTPUT"
echo "push=true" >> "$GITHUB_OUTPUT" echo "push=true" >> "$GITHUB_OUTPUT"
echo "tag=${{ env.TAG }}" >> "$GITHUB_OUTPUT" echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "action=build and publish" >> "$GITHUB_OUTPUT" echo "action=build and publish" >> "$GITHUB_OUTPUT"
else else
echo "login=${{ env.IS_LOCAL_PR }}" >> "$GITHUB_OUTPUT" echo "login=${IS_LOCAL_PR}" >> "$GITHUB_OUTPUT"
echo "push=false" >> "$GITHUB_OUTPUT" echo "push=false" >> "$GITHUB_OUTPUT"
echo "tag=dry-run" >> "$GITHUB_OUTPUT" echo "tag=dry-run" >> "$GITHUB_OUTPUT"
echo "action=build" >> "$GITHUB_OUTPUT" echo "action=build" >> "$GITHUB_OUTPUT"
@ -91,6 +93,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with: with:
submodules: recursive submodules: recursive
persist-credentials: false
# Login to DockerHub (when not pushing, it's to avoid rate-limiting) # Login to DockerHub (when not pushing, it's to avoid rate-limiting)
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
@ -111,14 +114,16 @@ jobs:
if: ${{ needs.docker-plan.outputs.push == 'true' }} if: ${{ needs.docker-plan.outputs.push == 'true' }}
run: | run: |
version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g') version=$(grep "version = " pyproject.toml | sed -e 's/version = "\(.*\)"/\1/g')
if [ "${{ needs.docker-plan.outputs.tag }}" != "${version}" ]; then if [ "${TAG}" != "${version}" ]; then
echo "The input tag does not match the version from pyproject.toml:" >&2 echo "The input tag does not match the version from pyproject.toml:" >&2
echo "${{ needs.docker-plan.outputs.tag }}" >&2 echo "${TAG}" >&2
echo "${version}" >&2 echo "${version}" >&2
exit 1 exit 1
else else
echo "Releasing ${version}" echo "Releasing ${version}"
fi fi
env:
TAG: ${{ needs.docker-plan.outputs.tag }}
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
@ -224,7 +229,7 @@ jobs:
# Generate Dockerfile content # Generate Dockerfile content
cat <<EOF > Dockerfile cat <<EOF > Dockerfile
FROM ${BASE_IMAGE} FROM ${BASE_IMAGE}
COPY --from=${{ env.UV_GHCR_IMAGE }}:latest /uv /uvx /usr/local/bin/ COPY --from=${UV_GHCR_IMAGE}:latest /uv /uvx /usr/local/bin/
ENV UV_TOOL_BIN_DIR="/usr/local/bin" ENV UV_TOOL_BIN_DIR="/usr/local/bin"
ENTRYPOINT [] ENTRYPOINT []
CMD ["/usr/local/bin/uv"] CMD ["/usr/local/bin/uv"]
@ -236,8 +241,8 @@ jobs:
# Loop through all base tags and append its docker metadata pattern to the list # Loop through all base tags and append its docker metadata pattern to the list
# Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version # Order is on purpose such that the label org.opencontainers.image.version has the first pattern with the full version
IFS=','; for TAG in ${BASE_TAGS}; do IFS=','; for TAG in ${BASE_TAGS}; do
TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ version }},suffix=-${TAG},value=${{ needs.docker-plan.outputs.tag }}\n" TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ version }},suffix=-${TAG},value=${TAG}\n"
TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ major }}.{{ minor }},suffix=-${TAG},value=${{ needs.docker-plan.outputs.tag }}\n" TAG_PATTERNS="${TAG_PATTERNS}type=pep440,pattern={{ major }}.{{ minor }},suffix=-${TAG},value=${TAG}\n"
TAG_PATTERNS="${TAG_PATTERNS}type=raw,value=${TAG}\n" TAG_PATTERNS="${TAG_PATTERNS}type=raw,value=${TAG}\n"
done done
@ -250,6 +255,8 @@ jobs:
echo -e "${TAG_PATTERNS}" echo -e "${TAG_PATTERNS}"
echo EOF echo EOF
} >> $GITHUB_ENV } >> $GITHUB_ENV
env:
TAG: ${{ needs.docker-plan.outputs.tag }}
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
@ -334,6 +341,11 @@ jobs:
docker-annotate-base: docker-annotate-base:
name: annotate uv name: annotate uv
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # for GHCR signing
packages: write # for GHCR image pushes
attestations: write # for GHCR attestations
environment: environment:
name: ${{ needs.docker-plan.outputs.push == 'true' && 'release' || '' }} name: ${{ needs.docker-plan.outputs.push == 'true' && 'release' || '' }}
needs: needs: