From c6a8a5e0048fb54dff232fba858efd2023a248b5 Mon Sep 17 00:00:00 2001 From: Mariano Macri Date: Sun, 26 Jul 2026 09:19:38 -0700 Subject: [PATCH 1/3] ci: build and push grid-wallet-prod image to ECR Triggers on pushes to main touching components/grid-wallet-prod/**, assumes github-actions-grid-wallet-prod via OIDC, and pushes an immutable sha- image to the ECR repo vended by tooling-infra. Builds linux/arm64 because the tooling-prod cluster is Graviton. No other workflow in this repo uses an ARM label yet, so if the first run sits in `queued`, GitHub-hosted ARM runners are not enabled for the org; the fallback is setup-qemu + setup-buildx on ubuntu-latest, noted inline. --build-arg NEXT_PUBLIC_GRID_SANDBOX=true is written literally rather than defaulted in the Dockerfile, so a future production image is a separate workflow against a separate repo and cannot inherit the sandbox affordance. The ECR repo is IMMUTABLE-tagged, so the build is guarded by a describe-images check: a re-run for an already-pushed SHA exits 0 instead of failing on the duplicate tag. No workflow_dispatch: the IAM trust policy pins the sub claim to refs/heads/main, so a dispatch from any other ref could not authenticate. Co-Authored-By: Claude Opus 5 --- .github/workflows/grid-wallet-prod-image.yml | 66 ++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/grid-wallet-prod-image.yml diff --git a/.github/workflows/grid-wallet-prod-image.yml b/.github/workflows/grid-wallet-prod-image.yml new file mode 100644 index 000000000..72510f81c --- /dev/null +++ b/.github/workflows/grid-wallet-prod-image.yml @@ -0,0 +1,66 @@ +name: grid-wallet-prod image + +on: + push: + branches: [main] + paths: + - 'components/grid-wallet-prod/**' + - '.github/workflows/grid-wallet-prod-image.yml' + +permissions: + id-token: write + contents: read + +concurrency: + group: grid-wallet-prod-image + cancel-in-progress: false + +jobs: + build: + # The tooling-prod cluster is Graviton (m8g), so the image must be + # linux/arm64. A native ARM runner avoids QEMU emulation, which makes a + # Next.js build painfully slow. NOTE: no other workflow in this repo uses + # an ARM label yet — if this job sits in `queued`, GitHub-hosted ARM + # runners are not enabled for the org and the fallback is + # docker/setup-qemu-action + docker/setup-buildx-action on ubuntu-latest. + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v4 + + - uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::405785876631:role/github-actions-grid-wallet-prod + aws-region: us-west-2 + + - id: ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Build and push + working-directory: components/grid-wallet-prod + env: + REGISTRY: ${{ steps.ecr.outputs.registry }} + run: | + set -euo pipefail + TAG="sha-${GITHUB_SHA}" + IMAGE="${REGISTRY}/grid-wallet-prod:${TAG}" + + # The ECR repo is IMMUTABLE-tagged, so re-pushing an existing tag is + # a hard failure. A re-run (manual retry, cancelled-then-resumed job) + # must be a no-op rather than a red build. + if aws ecr describe-images --repository-name grid-wallet-prod \ + --image-ids imageTag="$TAG" --region us-west-2 >/dev/null 2>&1; then + echo "$IMAGE already present — nothing to do." + exit 0 + fi + + # NEXT_PUBLIC_* is inlined by Next at BUILD time, so the sandbox flag + # is a build arg, not a runtime var. It is written literally here and + # has NO default in the Dockerfile: a production image would be a + # separate workflow and a separate ECR repo, so this flag cannot leak + # by inheritance. + docker build \ + --platform linux/arm64 \ + --build-arg NEXT_PUBLIC_GRID_SANDBOX=true \ + -t "$IMAGE" . + docker push "$IMAGE" + echo "Pushed $IMAGE" From 6a45f19a7841d61d6482ad49f8dd9014582f1d13 Mon Sep 17 00:00:00 2001 From: Mariano Macri Date: Sun, 26 Jul 2026 09:54:13 -0700 Subject: [PATCH 2/3] ci: don't treat a failed describe-images as a missing tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The idempotency guard was `if aws ecr describe-images ... >/dev/null 2>&1`. Commands used as an `if` condition are exempt from `set -e`, so an IAM error, a throttle, or a network blip was indistinguishable from "the tag isn't there" — the job would fall through, build, and then die on the immutable push with a misleading duplicate-tag error. Now the exit code and stderr are captured separately: rc 0 means the image exists and the job exits clean, ImageNotFoundException means build, and anything else fails loudly with the underlying AWS error. Co-Authored-By: Claude Opus 5 --- .github/workflows/grid-wallet-prod-image.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/grid-wallet-prod-image.yml b/.github/workflows/grid-wallet-prod-image.yml index 72510f81c..c33c9de17 100644 --- a/.github/workflows/grid-wallet-prod-image.yml +++ b/.github/workflows/grid-wallet-prod-image.yml @@ -47,11 +47,26 @@ jobs: # The ECR repo is IMMUTABLE-tagged, so re-pushing an existing tag is # a hard failure. A re-run (manual retry, cancelled-then-resumed job) # must be a no-op rather than a red build. - if aws ecr describe-images --repository-name grid-wallet-prod \ - --image-ids imageTag="$TAG" --region us-west-2 >/dev/null 2>&1; then + # + # Distinguish "tag absent" from "the call failed". A bare + # `if aws ... >/dev/null 2>&1` is exempt from set -e and treats an + # IAM/network error identically to a missing image, so a transient + # failure would fall through to a build and then die on the immutable + # push. Only ImageNotFoundException means "go build". + set +e + describe_err=$(aws ecr describe-images --repository-name grid-wallet-prod \ + --image-ids imageTag="$TAG" --region us-west-2 2>&1 >/dev/null) + describe_rc=$? + set -e + if [ "$describe_rc" -eq 0 ]; then echo "$IMAGE already present — nothing to do." exit 0 + elif ! grep -q 'ImageNotFoundException' <<<"$describe_err"; then + echo "::error::describe-images failed for a reason other than a missing tag:" + echo "$describe_err" + exit 1 fi + echo "$TAG not present — building." # NEXT_PUBLIC_* is inlined by Next at BUILD time, so the sandbox flag # is a build arg, not a runtime var. It is written literally here and From 61bf04b1176f3046fb183f0908e509cbfcc6b49a Mon Sep 17 00:00:00 2001 From: Mariano Macri Date: Mon, 27 Jul 2026 11:33:22 -0700 Subject: [PATCH 3/3] ci: pin grid-wallet-prod image actions to commit SHAs This job holds id-token: write and assumes a role that can push to ECR, so an upstream tag move would silently change code running with cloud write access. It is the first workflow in this repo to hold cloud write credentials, which is why it deviates from the repo-wide major-tag convention. actions/checkout @11d5960 # v4.4.0 aws-actions/configure-aws-credentials @7474bc4 # v4.3.1 aws-actions/amazon-ecr-login @d539f09 # v2.1.6 Caveat recorded inline: this repo has no dependabot.yml, so these pins will not update themselves and will go stale. A github-actions ecosystem entry would fix that repo-wide and is worth doing separately. Co-Authored-By: Claude --- .github/workflows/grid-wallet-prod-image.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/grid-wallet-prod-image.yml b/.github/workflows/grid-wallet-prod-image.yml index c33c9de17..8a1465ab7 100644 --- a/.github/workflows/grid-wallet-prod-image.yml +++ b/.github/workflows/grid-wallet-prod-image.yml @@ -24,16 +24,22 @@ jobs: # runners are not enabled for the org and the fallback is # docker/setup-qemu-action + docker/setup-buildx-action on ubuntu-latest. runs-on: ubuntu-24.04-arm + # Actions are pinned to full commit SHAs, not major tags. This job holds + # id-token: write and assumes a role that can push to ECR, so an upstream + # tag move would silently change code running with cloud write access. + # NOTE: this repo has no Dependabot config, so these pins do not update + # themselves — re-resolve them when bumping, or add a dependabot.yml with + # a github-actions ecosystem entry so they stay current. steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - - uses: aws-actions/configure-aws-credentials@v4 + - uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 with: role-to-assume: arn:aws:iam::405785876631:role/github-actions-grid-wallet-prod aws-region: us-west-2 - id: ecr - uses: aws-actions/amazon-ecr-login@v2 + uses: aws-actions/amazon-ecr-login@d539f0932e70871a027e9d5a9d8fc38589180a64 # v2.1.6 - name: Build and push working-directory: components/grid-wallet-prod