fix(ci): restore buildx cache reads on PR builds via pod WI login

The PR-read-only hardening (1d5eb3bf4) gated the WIF auth step on
non-PR events, which also silently gated the Artifact Registry docker
login that step fed. The comment said "PRs read the cache via the pod's
GKE Workload Identity", but pod WI is not ambient for buildx: with no
login, cache-from does an anonymous pull against us-central1-docker.pkg.dev
and gets 403 Forbidden (visible as "failed to configure registry cache
importer" in every PR build since), so every PR built cache-cold
(~12-16 min instead of ~2-3).

Fix: on PR events, mint an access token from the pod's GKE metadata
server (the runner pod's KSA impersonates gha-buildx-cache-ro@, which
has only artifactregistry.reader) and feed it to the same docker login
step. The security boundary is unchanged — PR builds still cannot write
cache layers; cache-to remains gated on the WIF token that only exists
on trusted main-push/release contexts.
This commit is contained in:
ethernet 2026-07-31 12:09:55 -04:00
parent f81237cecd
commit f6bf871eb0

View file

@ -92,13 +92,36 @@ jobs:
service_account: gha-buildx-cache@hermes-agent-github-actions.iam.gserviceaccount.com
token_format: access_token
# PR builds mint a READ-ONLY registry token from the runner pod's GKE
# Workload Identity instead. The pod's KSA (arc-runners/buildx-cache-
# reader) impersonates gha-buildx-cache-ro@, which holds only
# artifactregistry.reader on the ci-cache repo — so this token cannot
# write cache layers, and the layer-poisoning boundary above holds.
#
# This step is what actually turns pod WI into a docker credential:
# buildx only forwards auth that's present in the docker cred store,
# and there is no ambient cred helper for *.pkg.dev in the runner
# image — without an explicit login, cache-from falls back to an
# anonymous pull, gets 403, and every PR build runs cache-cold
# (~15 min instead of ~3).
- name: Mint read-only cache token (pod Workload Identity)
id: wi-token
if: github.event_name == 'pull_request'
run: |
set -euo pipefail
token=$(curl -sSf -H "Metadata-Flavor: Google" \
"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" \
| jq -r .access_token)
echo "::add-mask::$token"
echo "token=$token" >> "$GITHUB_OUTPUT"
- name: Log in to Artifact Registry
if: steps.gcp-auth.outputs.access_token != ''
if: steps.gcp-auth.outputs.access_token != '' || steps.wi-token.outputs.token != ''
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: us-central1-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.gcp-auth.outputs.access_token }}
password: ${{ steps.gcp-auth.outputs.access_token || steps.wi-token.outputs.token }}
# Build once, load into the local daemon for testing. Cached
# per-arch; the push step below reuses every layer from this build.