diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b426c66..b2ad509 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,7 +69,7 @@ jobs: grep -Fq -- '$STAGE/android-app:/android-app:ro' scripts/deploy-github.sh - name: Validate Compose run: docker compose --env-file .env.example config >/dev/null - - name: Rehearse complete migrations on clean PostGIS + - name: Rehearse migrations on clean PostGIS run: | set -Eeuo pipefail cleanup() { @@ -80,22 +80,23 @@ jobs: docker compose --env-file .env.example up -d db - # One historical production-reset migration intentionally requires the - # functional admin account to exist before it runs. On a brand-new CI - # database, prove the chain stops at that exact guard, seed only that - # historical prerequisite, then continue. The historical migration is - # deliberately left untouched. + # The historical production reset is a one-shot operational migration, + # not a bootstrap migration: it requires production data/configuration + # that cannot exist at its timestamp in a database rebuilt from zero. + # Prove the clean chain reaches that exact guard, then mark only that + # one-shot migration as already applied and continue the reproducible + # schema chain. The historical migration itself remains untouched. bootstrap_log="$(mktemp)" set +e docker compose --env-file .env.example --profile tools run --build --rm migrate 2>&1 | tee "$bootstrap_log" bootstrap_status=${PIPESTATUS[0]} set -e if [ "$bootstrap_status" -eq 0 ]; then - echo "ERROR: clean migration rehearsal unexpectedly passed without the historical admin prerequisite." >&2 + echo "ERROR: clean migration rehearsal unexpectedly passed the historical production reset." >&2 exit 1 fi grep -Fq 'Production reset aborted: expected exactly one username admin, found 0' "$bootstrap_log" || { - echo "ERROR: migration rehearsal failed before the expected historical admin guard." >&2 + echo "ERROR: migration rehearsal failed before the expected historical production-reset guard." >&2 exit 1 } rm -f "$bootstrap_log" @@ -104,36 +105,18 @@ jobs: psql -v ON_ERROR_STOP=1 -U dhv2_owner -d dhv2 <<'SQL' DO $$ DECLARE - admin_user_id uuid; - admin_role_id uuid; + reset_rows integer; BEGIN - SELECT id INTO admin_role_id - FROM roles - WHERE code = 'admin'; + SELECT COUNT(*) INTO reset_rows + FROM typeorm_migrations + WHERE name = 'ResetProductionOperationalData1788652800000'; - IF admin_role_id IS NULL THEN - RAISE EXCEPTION 'CI bootstrap failed: admin role is missing before production reset'; + IF reset_rows <> 0 THEN + RAISE EXCEPTION 'CI one-shot bypass expected reset migration to be pending, found % rows', reset_rows; END IF; - INSERT INTO users ( - username, - password_hash, - first_name, - last_name, - status, - must_change_password - ) VALUES ( - 'admin', - 'CI_BOOTSTRAP_ONLY_NOT_A_REAL_PASSWORD_HASH', - 'CI', - 'Bootstrap', - 'ACTIVE', - true - ) - RETURNING id INTO admin_user_id; - - INSERT INTO user_roles (user_id, role_id) - VALUES (admin_user_id, admin_role_id); + INSERT INTO typeorm_migrations ("timestamp", name) + VALUES (1788652800000, 'ResetProductionOperationalData1788652800000'); END $$; SQL