From dbb03095341737cf1441e00ef89d17167d36435c Mon Sep 17 00:00:00 2001 From: nourshoreibah Date: Sun, 23 Aug 2026 01:18:12 -0400 Subject: [PATCH] fix(preview): reconcile preview lambda config on every push A preview stack kept whatever environment it was born with. Both the step that resolves the env from prod and the `terraform apply` that delivers it were gated on `create == 'true'`, so a labelled PR only ever redeployed lambda *code* on subsequent pushes -- the config was never revisited. That went unnoticed until the RDS instance was given an explicit identifier. Its endpoint changed from `terraform-20251009192006341800000001...` to `branch-rds...`, prod picked the new value up on its next apply, and every preview stack created before that kept the old hostname. The old name no longer resolves, so all six preview lambdas threw getaddrinfo ENOTFOUND terraform-20251009192006341800000001... on any request that reached the database. Public routes still worked, which made it look like an auth bug: POST /auth/login and /auth/respond-challenge answered normally while GET /auth/me -- the first route to resolve a caller -- returned `{"message":"Internal Server Error"}` from dispatch's catch-all. Both steps now run on every event. Terraform is declarative, so an apply where the resolved config already matches is an empty plan. With the apply no longer conditional, the API URL comes from `terraform output` in both modes. That retires the fallback that looked the API up by name and told the reader to re-add the label when it was missing or had no stage -- the apply either repairs the stack or fails and stops the job. `LABEL` went with those two messages, its only consumers. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/preview-env.yml | 39 ++++++++++++------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index a5e37da9..563b02cc 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -32,7 +32,6 @@ on: # DynamoDB state lock (which serializes any overlapping terraform) keep cleanup # reliable regardless of event ordering. env: - LABEL: test-environment AWS_REGION: us-east-2 ROLE_ARN: arn:aws:iam::489881683177:role/branch-ci-preview TF_VERSION: 1.13.0 @@ -126,9 +125,14 @@ jobs: # Prod config is the single source of truth, DB_HOST included. Never re-derive # it from `DBInstances[0]` -- this account hosts other C4C databases and that # picked an unreachable one. Reserved / credential keys are dropped; the module - # adds NODE_ENV. Only needed when creating the stack. + # adds NODE_ENV. + # + # Runs on every event, not just label-add. Gating this on create meant a + # stack kept whatever env it was born with: when the RDS instance was given + # an explicit identifier its endpoint changed, and every existing preview + # kept the old `terraform-*` hostname, so all six lambdas 500'd on any + # request that touched the database while prod was fine. - name: Resolve preview lambda env - if: steps.mode.outputs.create == 'true' run: | set -euo pipefail AUTH_ENV=$(aws lambda get-function-configuration --function-name branch-auth --query 'Environment.Variables' --output json) @@ -149,8 +153,9 @@ jobs: # Stash for the terraform step (multiline-safe). printf 'LAMBDA_ENV<> "$GITHUB_ENV" - - name: Terraform apply (create/ensure preview stack) - if: steps.mode.outputs.create == 'true' + # Also every run: an apply is how the resolved env above actually reaches + # the functions. Cheap when nothing changed -- the plan is empty. + - name: Terraform apply (create/reconcile preview stack) working-directory: infrastructure/preview run: | cat > preview.auto.tfvars.json </dev/null 2>&1; then - echo "::error::Preview API ${API_ID} for PR #${PR} has no 'prod' stage — the stack is incomplete. Remove and re-add the ${LABEL} label to rebuild it." - exit 1 - fi - API_URL="https://${API_ID}.execute-api.${AWS_REGION}.amazonaws.com/prod" - fi + # Straight from the apply above, in both modes. The old else-branch + # looked the API up by name and told the reader to re-add the label if + # it was missing or half-built; the apply now repairs that itself, or + # fails loudly and stops the job before this step. + API_URL=$(terraform output -raw api_gateway_url) echo "api_url=$API_URL" >> "$GITHUB_OUTPUT" # On create → all lambdas + frontend. On update → only what changed in the PR.