From 9874f50efedf2cb57d86cba948978dff67c06d64 Mon Sep 17 00:00:00 2001 From: Jake Bromberg Date: Tue, 8 Sep 2026 06:45:35 -0700 Subject: [PATCH] chore(ops): carry FLOWSHEET_TAKEOVER_ENABLED through the env-var allowlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flag has shipped dormant since BS#2233 and there is no supported way to light it up: `set-ec2-env-var.yml`'s resolve step hard-fails with "Unsupported secret_name" on any key missing from its env block, and this one was never added, so production has run the pre-BS#2233 silent co-host attachment the whole time. Turning it on today means a hand-edit of the EC2 host's `.env` over SSH, which leaves no record and no rollback path. Adds the key to the env block and the resolve `case`, matching STATION_SIGNUP_ENABLED: strict `=== 'true'` reader, so the secret holds lowercase `true` and rollback is `false` rather than an empty value. `restart_target=backend` is required and not incidental — unlike the cron-invoked station-signup keys, the backend is a long-running container that reads its env once at boot. --- .github/workflows/set-ec2-env-var.yml | 19 +++++++++++++++++++ docs/env-vars.md | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/set-ec2-env-var.yml b/.github/workflows/set-ec2-env-var.yml index e9f8b06f..0a44c803 100644 --- a/.github/workflows/set-ec2-env-var.yml +++ b/.github/workflows/set-ec2-env-var.yml @@ -270,6 +270,24 @@ jobs: # two keys above this one DOES need the restart: the auth service is a # long-running container, not a per-run cron invocation. STATION_SIGNUP_ENABLED: ${{ secrets.STATION_SIGNUP_ENABLED }} + # FLOWSHEET_TAKEOVER_ENABLED (BS#2233) gates POST /flowsheet/join's + # explicit start-vs-join decision. Off (the default), `intent` and + # `expected_show_id` are ignored and the route silently co-hosts a + # caller onto whatever show is still open; on, an undecided caller + # gets a 409 `show_already_open` and `intent: "takeover"` closes the + # open show and starts their own. Not sensitive, but carried through + # the allowlist for the same "Unsupported secret_name" reason as + # DONATE_* above. Strict `=== 'true'` comparison + # (apps/backend/config/flowsheetTakeover.ts), same + # lowercase/::add-mask::/rollback rules as STATION_SIGNUP_ENABLED + # above. Pass restart_target=backend (the default) — only + # apps/backend reads it, and the backend is a long-running container, + # so the flip does need the restart. + # + # The flag is also the rollback: 'false' here restores the pre-BS#2233 + # behavior with no redeploy. Every 409-aware client tolerates the flag + # in either position, so it can be flipped back mid-show. + FLOWSHEET_TAKEOVER_ENABLED: ${{ secrets.FLOWSHEET_TAKEOVER_ENABLED }} run: | set -euo pipefail KEY="${{ inputs.key }}" @@ -297,6 +315,7 @@ jobs: STATION_SIGNUP_ALERT_EMAIL) VALUE="$STATION_SIGNUP_ALERT_EMAIL" ;; STATION_SIGNUP_DOWNGRADE_ENABLED) VALUE="$STATION_SIGNUP_DOWNGRADE_ENABLED" ;; STATION_SIGNUP_ENABLED) VALUE="$STATION_SIGNUP_ENABLED" ;; + FLOWSHEET_TAKEOVER_ENABLED) VALUE="$FLOWSHEET_TAKEOVER_ENABLED" ;; *) echo "::error::Unsupported secret_name '$SECRET_NAME'. Add it to the resolve step's env block." exit 1 diff --git a/docs/env-vars.md b/docs/env-vars.md index 496d8e7d..b3a62bde 100644 --- a/docs/env-vars.md +++ b/docs/env-vars.md @@ -173,7 +173,7 @@ Runtime vars supplied at `docker run --env-file .env` (all four have historicall ## Flowsheet Go-Live Intent -- `FLOWSHEET_TAKEOVER_ENABLED` (default `false`, BS#2233) — Strict `=== 'true'` gate (via `apps/backend/config/flowsheetTakeover.ts`'s `createEnvFlagConfig`, the same factory `CRITIC_REVIEWS_ENABLED` and `DONATE_ENABLED` use) for `POST /flowsheet/join`'s explicit start-vs-join decision. ON: a caller going live while a show they are not an active member of is still open must send `intent: "join"` (co-host) or `intent: "takeover"` (close it, start their own, `expected_show_id` required); sending neither is a `409 show_already_open` carrying `{ id, dj_name, start_time }`. OFF: `intent` and `expected_show_id` are ignored entirely and the route co-hosts as it always has. +- `FLOWSHEET_TAKEOVER_ENABLED` (default `false`, BS#2233) — Strict `=== 'true'` gate (via `apps/backend/config/flowsheetTakeover.ts`'s `createEnvFlagConfig`, the same factory `CRITIC_REVIEWS_ENABLED` and `DONATE_ENABLED` use) for `POST /flowsheet/join`'s explicit start-vs-join decision. ON: a caller going live while a show they are not an active member of is still open must send `intent: "join"` (co-host) or `intent: "takeover"` (close it, start their own, `expected_show_id` required); sending neither is a `409 show_already_open` carrying `{ id, dj_name, start_time }`. OFF: `intent` and `expected_show_id` are ignored entirely and the route co-hosts as it always has. In the `set-ec2-env-var.yml` allowlist; like `STATION_SIGNUP_ENABLED` (and unlike the cron-invoked `STATION_SIGNUP_DOWNGRADE_ENABLED`), the backend is a long-running container, so light-up needs the restart `restart_target=backend` performs. Rollback is the same invocation with the secret set to `false` — never cleared, since the resolve step hard-fails on an empty value. **Flag-OFF must never 400 or 409, and that is load-bearing rather than cosmetic.** `auto-dj-orchestrator` ships `intent: "takeover"` before the flip, and its `join()` throws on any response body without a show id, so a 400 on the unrecognized field would crash that daemon at activation. It is also what lets the four repos in this chain deploy in any order: BS ships dormant, every client becomes 409-aware while nothing is emitting 409s, and the flip is one env var. The flag is the rollback too — no redeploy.