Repository navigation
Install the Cloud SQL migration and household mirror-event workflows from uv.lock - #4080
Merged
Merged
Conversation
Remove the migrate-v1-cloud-sql.yml exception from api.dependencies.install-from-lock, and change the workflow tests to require that the job installs with uv sync --frozen on Python 3.12, with the pinned uv version, and that migrate_v1_cloud_sql.sh runs each v1_database_migration.py command through uv run --frozen. The migration script tests now put a fake uv on PATH. It fails unless it receives the passwords fetched from Secret Manager and none of the job-level database URLs the script unsets. These tests and the locked-installs guard fail until the workflow and script change in the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The migrate job sets up uv 0.13.4 (the version the Cloud Run image and the release job use) with astral-sh/setup-uv, sets UV_PYTHON to 3.12, and installs the runtime dependencies with uv sync --frozen, replacing the unlocked pip install -e ".[dev]". migrate_v1_cloud_sql.sh runs each v1_database_migration.py command through uv run --frozen. uv run passes the job and script environment to the command unchanged, so the passwords the script fetches and exports still reach the migration commands, and the unset job-level database URLs stay unset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove the process-v1-household-mirror-event.yml exception from api.dependencies.install-from-lock, the last operational job registered as installing unlocked, and apply the locked install, Python version and uv version checks to that job too. Add behaviour tests for run_household_mirror_event_operator.sh, which had only text checks. Fake gcloud and uv commands record their calls and the environment uv receives. The success test requires the command to run through uv run --frozen with the fetched migration password, the proxy port and every job-level variable the event command reads. The other tests cover an unauthorized operator, a staging run that targets the production Cloud SQL instance, and an empty password. The success test, the job checks and the locked-installs guard fail until the workflow and script change in the next commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The process-event job sets up uv 0.13.4 with astral-sh/setup-uv, sets UV_PYTHON to 3.12, and installs the runtime dependencies with uv sync --frozen, replacing the unlocked pip install -e ".[dev]". run_household_mirror_event_operator.sh runs process_v1_household_mirror_event.py through uv run --frozen, with the same POLICYENGINE_DB_PROXY_PORT and POLICYENGINE_DB_PASSWORD prefix; uv run passes them and the job environment to the command unchanged. The household migration guide says a local run of the operator script now needs uv. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4080 +/- ##
===========================================
+ Coverage 52.87% 88.22% +35.34%
===========================================
Files 273 285 +12
Lines 15647 16843 +1196
Branches 2505 2741 +236
===========================================
+ Hits 8274 14859 +6585
+ Misses 6680 1302 -5378
+ Partials 693 682 -11 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4079
Summary
The Public API's two operational database workflows now install from
uv.lockinstead of an unlockedpip install -e ".[dev]", and their exceptions toapi.dependencies.install-from-lockare removed.migrate-v1-cloud-sql.yml(jobmigrate, also called bypush.ymlbefore each staging and production deployment): sets up uv 0.13.4 withastral-sh/setup-uv@v6(the version the Cloud Run image, thequality-guardsjob and theversioningjob use), setsUV_PYTHON: "3.12", and installs withuv sync --frozen.migrate_v1_cloud_sql.shruns its threev1_database_migration.pycommands (--mode state,--mode upgrade,--mode verify-head) throughuv run --frozen.process-v1-household-mirror-event.yml(jobprocess-event): the same setup-uv step,UV_PYTHONanduv sync --frozen.run_household_mirror_event_operator.shrunsprocess_v1_household_mirror_event.pythroughuv run --frozen, with the samePOLICYENGINE_DB_PROXY_PORTandPOLICYENGINE_DB_PASSWORDprefix.devextra, as the Cloud Run image (uv sync --frozen --no-dev) andseed-v2-database.ymldo. Both scripts, the Alembic v1 environment and the v2 household writer they load import in a fresh environment built withuv sync --frozenand no extras.rules/registry.toml: the two[[rule.exception]]entries for these workflows are removed, so the exception list only shrinks;docs/generated/rules.mdis regenerated.docs/migration/stage-11-v2-households.mdsays a local run of the operator script now needs uv.This changes
rules/registry.toml, so it needs approval from a core developer other than the author (api.process.rule-machinery-code-owned). No inline suppressions (# noqa) are added.Environment variables
uv runpasses its whole environment to the command it runs, and reads no.envfile unless asked to. Everything the barepythonreceived before still reaches the scripts. The new tests check this with a fakeuvonPATHthat records the environment it receives.DEPLOYMENT_ENVIRONMENTdeployment_environmentenv:validate_database_environment.sh; the event commandPOLICYENGINE_DB_INSTANCE_CONNECTION_NAMEstaging-database,production-database,stagingandproductionenv:fromvarsPRODUCTION_POLICYENGINE_DB_INSTANCE_CONNECTION_NAMEenv:fromvarsPOLICYENGINE_DB_READONLY_PASSWORD_SECRET,POLICYENGINE_DB_MIGRATION_PASSWORD_SECRETenv:fromvarsgcloud secrets versions access; validationPRODUCTION_POLICYENGINE_DB_READONLY_PASSWORD_SECRET,PRODUCTION_POLICYENGINE_DB_MIGRATION_PASSWORD_SECRETenv:fromvarsPOLICYENGINE_DB_READONLY_PASSWORD,POLICYENGINE_DB_MIGRATION_PASSWORDmigrate_v1_cloud_sql.shuv runv1_database_migration.pySTAGE7_EXISTING_DATABASE_URL,ALEMBIC_DATABASE_URLmigrate_v1_cloud_sql.shbeforeuv runv1_database_migration.py,migrations/v1/env.py(only when set)V2_SUPABASE_PROJECT_REFstagingandproductionenv:fromvarsPRODUCTION_V2_SUPABASE_PROJECT_REFenv:fromvarsV2_SUPABASE_ENVIRONMENTdeployment_environmentenv:V2_RUNTIME_DATABASE_URLV2_DATA_WRITE_DATABASE_URLinstagingandproductionenv:fromsecretsHOUSEHOLD_MIRROR_OPERATOR_IDENTITYGCP_DB_MIGRATION_SERVICE_ACCOUNTenv:fromvarsALLOWED_HOUSEHOLD_MIRROR_OPERATOR_IDENTITYHOUSEHOLD_MIRROR_OPERATOR_IDENTITYinstagingandproductionenv:fromvarsPOLICYENGINE_DB_PROXY_PORT,POLICYENGINE_DB_PASSWORDuv run, inherited by the commandUV_PYTHON(new)"3.12"env:uv syncand the scripts'uv runGCP_WORKLOAD_IDENTITY_PROVIDERwith:ongoogle-github-actions/auth;push.ymlpassessecrets: inheritGCP_DB_MIGRATION_SERVICE_ACCOUNTwith:ongoogle-github-actions/authGOOGLE_APPLICATION_CREDENTIALSand the other credential variablesgoogle-github-actions/auth, written toGITHUB_ENVgcloud, the Cloud SQL Auth ProxyRUNNER_TEMP,GITHUB_ACTIONS,GITHUB_SHA,GITHUB_RUN_ID,GITHUB_RUN_ATTEMPTEvery secret and variable name above exists in the named place (checked with
gh api). The staging variable values meet the validation scripts' conditions: the staging instance, password secrets and Supabase project differ from production, andHOUSEHOLD_MIRROR_OPERATOR_IDENTITYequalsGCP_DB_MIGRATION_SERVICE_ACCOUNT. Secret values cannot be read through the API, so whetherV2_DATA_WRITE_DATABASE_URLmeets the v2 runtime loader's requirements (for example, not the transaction pooler port 6543) is unverified. The household workflow's first GitHub Actions run is described below.Staging runs before merge
Both workflows were dispatched from this branch at f29abfa (with master merged in) on 2026-11-03.
migrate-v1-cloud-sql.yml, run 41713976356,deployment_environment=staging,github_environment=staging-database: passed. uv used CPython 3.12.15 and installed 169 packages fromuv.lock.Upgrade and verify v1 databaseloggedDetected v1 database state: head, so the run took no backup and made no upgrade, and--mode verify-headpassed. It ran after release run 41713013425 had finished its own staging v1 migration, since the workflow has no concurrency group.process-v1-household-mirror-event.yml, run 41714851692,deployment_environment=staging,country_id=us,legacy_household_id=0: exited 1, as expected for an ID with no retained event. Staging has no pending event: its logs for the last 60 days show 26 immediate copies, all"outcome": "ok", and the copy records don't include household IDs. This was the workflow's first GitHub Actions run."failure_category": "integrity"(no retained event) rather than"database", and the operator record names the staging instancepolicyengine-api:us-central1:policyengine-api-data-staging.HouseholdMirrorUnavailableError, which wraps theHouseholdMirrorEventIntegrityError, notHouseholdMirrorEventIntegrityErroritself as this description first said.V2_DATA_WRITE_DATABASE_URL. Only a pending event reaches them, so they're first used when a pending staging or production event is processed.Testing
Written test-first, as two pairs of commits:
aca85c597uv run --frozenlocked-installsfailedded8e4ec4locked-installspassed873fba8felocked-installsfailed2ada2957clocked-installspassed(Tests run:
tests/unit/test_alembic_workflows.py,tests/unit/test_locked_test_environments.py,tests/unit/test_cloud_run_workflow_configuration.pyand, from873fba8fe,tests/unit/test_household_mirror_event_operator_script.py, throughuv run --frozen --extra dev pytest.)At the final commit:
ruff format --check .andruff check .: passedpython scripts/run_quality_guards.py: every guard passed, includinglocked-installsandci-scriptspython -m scripts.rules guard --base-ref origin/master: passedpython -m scripts.rules render: no diffuv lock --check: passedshellcheckon both changed scripts: passedpython -m unittest discover -s scripts/rules/tests -t .: 142 tests passed.github/workflowsor.github/scripts, plustests/unit/test_household_event_command.py: 223 passed.tests/unit/telemetry_error_issues/test_workflow_and_wrapper.pyneeds thetelemetry-error-issuesgroup, asmake testadds it; with it, 22 passed.🤖 Generated with Claude Code