diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index b4b6d19..7cf5dd4 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -115,27 +115,14 @@ jobs: # Update compose files + mosquitto config git pull origin main - # server-26#51: Firestore rules + composite indexes had no deploy - # path and regressed silently after every fix (the alert_events and - # calls(org_id,started_at) indexes among them). The VM runs as the - # project service account, so firebase-tools authenticates via ADC - # with no key file, and infra/firestore/firebase.json pins database - # c2-server. Indexes go on additively -- no --force -- so a stray - # edit to firestore.indexes.json can never delete a live index; - # rules are a full replace, which is the intent. --non-interactive - # means the FIRST run after a drift still needs a one-time manual - # `firebase deploy` on the VM to clear pending deletions (it aborts - # rather than guess). A failure here warns but does NOT fail the - # deploy: a transient Firebase API error must not roll back a good - # app build. - if command -v firebase >/dev/null 2>&1; then - ( cd /opt/drb/infra/firestore \ - && firebase deploy --only firestore:rules,firestore:indexes \ - --project ${{ secrets.FIREBASE_PROJECT_ID }} --non-interactive ) \ - || echo "WARNING: firestore deploy failed (server-26#51) -- rules/indexes may be stale" - else - echo "WARNING: firebase CLI not on the VM -- skipped firestore deploy (server-26#51); install once with: npm i -g firebase-tools" - fi + # server-26#51: Firestore rules/indexes deploy used to be attempted + # HERE, over SSH, gated on the VM having firebase-tools installed. + # It never did (no node on the VM), so this silently warned and + # skipped on every deploy for weeks -- PR #124 even auto-closed + # #13/#51 as if it were fixed. Moved to a standalone + # deploy-firestore-rules job below that runs on the Gitea runner + # itself (which always has node), so it no longer depends on + # anything being pre-installed on this VM. # server-26#65: capture what is actually live BEFORE switching, so # a bad deploy has something concrete to fall back to. This reads @@ -291,9 +278,48 @@ jobs: echo "status=success" >> "$GITHUB_OUTPUT" echo "rolled_back_to=$PREV_TAG" >> "$GITHUB_OUTPUT" + deploy-firestore-rules: + name: Deploy Firestore rules & indexes + needs: build + runs-on: ubuntu-latest + # Deliberately independent of the `deploy` job (app containers) and its + # health-check/rollback chain above: a rules/indexes deploy failure has + # nothing to roll back (there is no previous "build" of a ruleset to + # revert to via this pipeline) and must never be conflated with an app + # deploy failure by triggering that job's rollback logic. This job + # failing is its own, separate red run -- picked up by notify-failure + # below -- not a signal to touch the running containers. + steps: + - uses: actions/checkout@v4 + + - name: Deploy firestore rules and indexes + env: + FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} + run: | + set -e + # server-26#51: this used to run over SSH on the deploy VM, gated + # on the VM having firebase-tools installed. It never did, so it + # silently warned-and-skipped on every single deploy for weeks. + # Running it here instead means the only prerequisite is a secret + # -- FIREBASE_TOKEN, from `firebase login:ci` -- rather than + # something installed by hand on a machine this pipeline doesn't + # otherwise touch. A missing token now fails this job LOUDLY + # (picked up by notify-failure) instead of a buried warning line + # nobody reads in the app deploy's logs. + if [ -z "$FIREBASE_TOKEN" ]; then + echo "FIREBASE_TOKEN secret is not set -- cannot deploy Firestore rules/indexes." >&2 + echo "Generate one with 'firebase login:ci' and add it as a Gitea Actions secret." >&2 + exit 1 + fi + npm install -g firebase-tools + cd infra/firestore + firebase deploy --only firestore:rules,firestore:indexes \ + --project ${{ secrets.FIREBASE_PROJECT_ID }} \ + --token "$FIREBASE_TOKEN" --non-interactive + notify-failure: name: Report a failed deploy - needs: [build, deploy] + needs: [build, deploy, deploy-firestore-rules] if: failure() runs-on: ubuntu-latest @@ -310,6 +336,8 @@ jobs: SHA: ${{ gitea.sha }} ROLLBACK_STATUS: ${{ needs.deploy.outputs.rollback_status }} ROLLBACK_SHA: ${{ needs.deploy.outputs.rollback_sha }} + DEPLOY_RESULT: ${{ needs.deploy.result }} + RULES_RESULT: ${{ needs.deploy-firestore-rules.result }} run: | if [ -z "$WEBHOOK" ]; then echo "DEPLOY_ALERT_WEBHOOK is not set - skipping notification." @@ -321,6 +349,16 @@ jobs: run_url = os.environ["RUN_URL"] status = os.environ.get("ROLLBACK_STATUS", "") rollback_sha = os.environ.get("ROLLBACK_SHA", "") + deploy_result = os.environ.get("DEPLOY_RESULT", "") + rules_result = os.environ.get("RULES_RESULT", "") + + # deploy-firestore-rules runs independent of the app deploy/rollback + # chain (see its own job comment), so its failure needs its own + # branch here -- otherwise this fell through to the generic "Build + # failed before any deploy was attempted" text even when the app + # deployed fine and only the Firestore rules/indexes push failed. + if deploy_result != "failure" and rules_result == "failure": + detail = "App deploy succeeded; Firestore rules/indexes deploy FAILED (server-26#51). Rules may be stale — check FIREBASE_TOKEN and the job log." # server-26#65: the old text here unconditionally claimed # "production is still running the previous build" -- true only @@ -329,7 +367,7 @@ jobs: # class of bug the correlator instrumentation exists to catch), or # once the deploy job's own rollback path has run. Say what # actually happened instead. - if status == "success": + elif status == "success": detail = "Automatic rollback to `%s` succeeded. Production is back on the previous good build." % rollback_sha[:8] elif status == "failed": detail = ("Automatic rollback to `%s` FAILED. Production state is UNKNOWN -- "