From 81b19b90729a901e2100f4c255a084764217314c Mon Sep 17 00:00:00 2001 From: Barcode Betty Date: Fri, 5 Jun 2026 23:57:11 +0000 Subject: [PATCH 1/3] ci(deploy): never hard-fail on infra-PR merge outcome (CAR-1216) The in-job merge attempt against `cartsnitch/infra` main is a best-effort fast-path only. `infra` main requires a human approving review and the CI bot (`CI_GITEA_TOKEN`) can never self-approve, so the merge call structurally cannot succeed in the general case. Replace the special-cased `does not have enough approvals` branch and the final `else -> exit 1` branch in both `deploy-dev` and `deploy-uat` with a single non-failing outcome: surface the Gitea response as a `::notice::` and `exit 0`. The PR is already opened and `cs_savannah` is requested as reviewer above, so the GitOps hand-off is intact. The only hard-fail (`exit 1`) in this step remains the empty-`PR_NUM` check (PR could not be created at all). Related: CAR-1195 (PR-bump pattern), CAR-1194, CAR-1212. Co-Authored-By: Paperclip --- .gitea/workflows/ci.yml | 44 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 7efee44..f94d2fb 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -577,6 +577,16 @@ jobs: if [ "${REVIEW_HTTP}" -lt 200 ] || [ "${REVIEW_HTTP}" -ge 300 ]; then echo "::notice::Failed to request reviewers for cartsnitch/infra PR #${PR_NUM} (HTTP ${REVIEW_HTTP}); continuing" fi + # CAR-1216: the in-job merge attempt is a best-effort fast-path only. + # `cartsnitch/infra` main requires a human approving review (immutable + # branch protection); the CI bot (`CI_GITEA_TOKEN`) can never self- + # approve, so this merge call structurally cannot succeed in the + # general case. Any non-merged outcome (approvals pending, checks + # pending, any other Gitea message) is the GitOps approval gate, not + # a CI failure — the PR is already opened and `cs_savannah` is + # requested as reviewer above. Surface the response as a notice and + # exit success. The only hard-fail (`exit 1`) in this step remains + # the empty-`PR_NUM` check (PR could not be created at all). MERGE_RESP=$(curl -sS -X POST \ -H "Authorization: token ${CI_GITEA_TOKEN}" \ -H "Content-Type: application/json" \ @@ -585,17 +595,9 @@ jobs: MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false') if [ "$MERGED" = "true" ]; then echo "PR #${PR_NUM} merged into cartsnitch/infra main" - elif echo "$MERGE_RESP" | grep -qi 'does not have enough approvals'; then - # GitOps approval gate: the PR is correctly opened and surfaces in - # the CTO queue via the reviewers request above. Treat as success - # (exit 0) so the deploy job does not hard-fail on the approvals - # requirement that only a human maintainer can satisfy. - echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure" - exit 0 else - echo "::error::Auto-merge of cartsnitch/infra PR #${PR_NUM} failed: $MERGE_RESP" - echo "::error::Reassign to cs_savannah (authorized merger for cartsnitch/infra main) for backstop merge." - exit 1 + echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure: $MERGE_RESP" + exit 0 fi deploy-uat: @@ -721,6 +723,16 @@ jobs: if [ "${REVIEW_HTTP}" -lt 200 ] || [ "${REVIEW_HTTP}" -ge 300 ]; then echo "::notice::Failed to request reviewers for cartsnitch/infra PR #${PR_NUM} (HTTP ${REVIEW_HTTP}); continuing" fi + # CAR-1216: the in-job merge attempt is a best-effort fast-path only. + # `cartsnitch/infra` main requires a human approving review (immutable + # branch protection); the CI bot (`CI_GITEA_TOKEN`) can never self- + # approve, so this merge call structurally cannot succeed in the + # general case. Any non-merged outcome (approvals pending, checks + # pending, any other Gitea message) is the GitOps approval gate, not + # a CI failure — the PR is already opened and `cs_savannah` is + # requested as reviewer above. Surface the response as a notice and + # exit success. The only hard-fail (`exit 1`) in this step remains + # the empty-`PR_NUM` check (PR could not be created at all). MERGE_RESP=$(curl -sS -X POST \ -H "Authorization: token ${CI_GITEA_TOKEN}" \ -H "Content-Type: application/json" \ @@ -729,15 +741,7 @@ jobs: MERGED=$(echo "$MERGE_RESP" | jq -r '.merged // false') if [ "$MERGED" = "true" ]; then echo "PR #${PR_NUM} merged into cartsnitch/infra main" - elif echo "$MERGE_RESP" | grep -qi 'does not have enough approvals'; then - # GitOps approval gate: the PR is correctly opened and surfaces in - # the CTO queue via the reviewers request above. Treat as success - # (exit 0) so the deploy job does not hard-fail on the approvals - # requirement that only a human maintainer can satisfy. - echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure" - exit 0 else - echo "::error::Auto-merge of cartsnitch/infra PR #${PR_NUM} failed: $MERGE_RESP" - echo "::error::Reassign to cs_savannah (authorized merger for cartsnitch/infra main) for backstop merge." - exit 1 + echo "::notice::infra PR #${PR_NUM} opened and awaiting CTO (cs_savannah) approve+merge — GitOps approval gate, not a failure: $MERGE_RESP" + exit 0 fi From 7803d229eb9220dab735a65beaafc6772c9344dd Mon Sep 17 00:00:00 2001 From: Savannah Savings Date: Sat, 6 Jun 2026 02:26:54 +0000 Subject: [PATCH 2/3] fix(auth): pin base image to node 22.22.2 digest (CAR-1279 Phase 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pin both build and runtime stages of auth/Dockerfile to node:22-alpine@sha256:8ea2348b068a9544dae7317b4f3aafcdc032df1647bb7d768a05a5cad1a7683f — the Docker Hub manifest digest for node:22.22.2-alpine (verified against the registry by CTO). This is the digest pulled in by the previously-healthy ghcr auth image, which connects fine to the dev Postgres with the same pg 8.20.0 driver and byte-identical source. The Gitea-built image, which bundles node 22.22.3 (via the floating 'node:22-alpine' tag), deterministically resets the Postgres connection during the /health DB probe (read ECONNRESET → Connection terminated unexpectedly). Pinning both stages to the manifest digest restores the exact node runtime that the healthy ghcr image used and fixes the dev auth crashloop. The 'RUN apk update && apk upgrade --no-cache' lines are kept as-is per task spec. Refs CAR-1279, CAR-1276 (CAR-1287) --- auth/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth/Dockerfile b/auth/Dockerfile index 0b88089..388fd9d 100644 --- a/auth/Dockerfile +++ b/auth/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22-alpine AS builder +FROM node:22-alpine@sha256:8ea2348b068a9544dae7317b4f3aafcdc032df1647bb7d768a05a5cad1a7683f AS builder RUN apk update && apk upgrade --no-cache WORKDIR /app COPY package.json package-lock.json* ./ @@ -7,7 +7,7 @@ COPY tsconfig.json ./ COPY src/ src/ RUN npm run build -FROM node:22-alpine +FROM node:22-alpine@sha256:8ea2348b068a9544dae7317b4f3aafcdc032df1647bb7d768a05a5cad1a7683f RUN apk update && apk upgrade --no-cache WORKDIR /app ENV NODE_ENV=production From afe8f7b7f95a4a9f44f29ed922e71b9ee068d902 Mon Sep 17 00:00:00 2001 From: Barcode Betty Date: Sun, 7 Jun 2026 11:51:42 +0000 Subject: [PATCH 3/3] fix(ci): align deploy frontend image-bump to app entry name (CAR-1318) Co-authored-by: Barcode Betty Co-committed-by: Barcode Betty --- .gitea/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index f94d2fb..098af34 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -495,7 +495,7 @@ jobs: if: needs.build-and-push.result == 'success' run: | cd infra/apps/overlays/dev - kustomize edit set image ghcr.io/cartsnitch/cartsnitch=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }} + kustomize edit set image ghcr.io/cartsnitch/app=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }} - name: Determine image tag for receiptwitness id: receiptwitness_tag @@ -641,7 +641,7 @@ jobs: if: needs.build-and-push.result == 'success' run: | cd infra/apps/overlays/uat - kustomize edit set image ghcr.io/cartsnitch/cartsnitch=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }} + kustomize edit set image ghcr.io/cartsnitch/app=git.farh.net/cartsnitch/cartsnitch:${{ steps.frontend_tag.outputs.tag }} - name: Determine image tag for receiptwitness id: receiptwitness_tag