infra: migration 048 — GRANT tournament tables to westside_streamlit_ro #515
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api!515
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "510-grant-tournament-tables-to-ro-role"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds migration
048extending thewestside_streamlit_roallowlist (created in044) to includetournamentsandtournament_products. Enables the upcoming Streamlit tournament section (forgejo_admin/westside-streamlit#15) to query tournament data joined through the already-grantedorderstable. ACL only — no schema changes.Closes #510
Changes
alembic/versions/048_grant_tournament_tables_to_ro_role.py— new migration.revision="048",down_revision="047".upgrade()GRANTs SELECT ontournamentsandtournament_productstowestside_streamlit_ro;downgrade()REVOKEs.Style mirrors migration
044: per-table loop withTABLE public.{table}qualifier,ROLE_NAME+GRANT_TABLESconstants.registrationsintentionally NOT included — tournament payments write toorders(already granted in 044), notregistrations.Test Plan
Round-trip verified locally against a Postgres DB stamped to
047with the role + tournament tables seeded:ruff check alembic/versions/048_grant_tournament_tables_to_ro_role.py— cleanruff format --check— cleanpytest tests/— 474 pass; 1 pre-existing failure (test_jersey_reminder.py::test_plain_text_has_deadline_copyasserts "March 30" but copy now reads "April 10") confirmed to also fail onmainand is unrelated to this migrationReview Checklist
"048", down_revision is exactly"047"(no slot collision)westside_streamlit_romatches migration 044upgrade()GRANTs SELECT ontournamentsandtournament_productsonly —registrationsintentionally excludeddowngrade()REVOKEs SELECT on the same two tablesTABLE public.{table}qualifier)src/basketball_api/models.pyruff checkcleanruff format --checkcleanupgrade head/downgrade 047/upgrade head) verified locallytest_jersey_reminderfailure onmain)Notes / Surprises
alembic upgrade headfrom an empty DB hits a pre-existing issue at migration029_add_schedule_tables(type "division" already existson the secondEnum(..., create_type=False)usage in the same migration with current SQLAlchemy 2.0.48). This is unrelated to migration 048 and is reproducible onmain. Round-trip for 048 was therefore validated against a DB stamped at047with the role and tournament tables seeded — verifying the actual SQL emitted by 048 works correctly. Worth filing a separate ticket for the 029 enum issue.Related Notes
review-1072-2026-04-22(APPROVED)project-westside-streamlit— consumer projectstory-westside-streamlit-tournament— user story this servesfeedback_migration_slot_coordination— slot-collision rulefeedback_basketball_hands_off— narrow-allowlist rationale044_add_westside_streamlit_ro_role— defines the role being extended045_add_tournament_tables— source of the tables being GRANTedforgejo_admin/westside-streamlit#15(C3 — Tournament section)PR #515 Review
DOMAIN REVIEW
Stack: Python / Alembic / Postgres ACL. ACL-only migration, no schema or model changes.
Migration slot coordination (
feedback_migration_slot_coordination)revision = "048",down_revision = "047"— slot correct.047at branch time, no contention. Single migration, no parallel-agent collision risk.048_grant_tournament_tables_to_ro_role.pymatches the{slot}_{snake_case}.pyconvention used by 044/045.Style match with migration 044
TABLE public.{table}qualifier — matches 044 exactly.ROLE_NAMEandGRANT_TABLESconstants — same pattern as 044.downgrade()usesREVOKE ALL PRIVILEGES(because it also drops the role); 048 uses targetedREVOKE SELECTbecause it must NOT touch the grants 044 owns. This is the correct narrowing — aREVOKE ALLhere would clobber 044's allowlist ontournaments/tournament_productsif those tables had been added to 044 retroactively. Targeted REVOKE is safer and idempotent.Allowlist correctness (deliberate
registrationsexclusion)GRANT_TABLES = ("tournaments", "tournament_products")— exactly whatwestside-streamlit#15needs for the join path.registrationsis NOT included: tournament checkout writes toorders(already granted in 044),registrationsis for tryouts/practices. Correct perfeedback_basketball_hands_offdefense-in-depth: extend allowlist deliberately and minimally.tournament_products.product_id->products.id(granted in 044),tournament_products.tournament_id->tournaments.id(granted here). Join path closes withoutregistrations.Round-trip evidence
upgrade head-> grants present,downgrade 047-> grants removed (0 rows),upgrade head-> grants re-applied. This is the right test for an ACL migration.information_schema.role_table_grantsis the correct source-of-truth view to verify GRANTs. Output shows exactly the two expected rows and nothing else.GRANT SELECTon an already-granted privilege is a no-op in Postgres (noIF NOT EXISTSgymnastics needed).Code quality (generic checklist)
{table}and{ROLE_NAME}into raw SQL — both are module-local constants under code review, not user input. No injection risk. Acceptable here for the same reason 044 does it.BLOCKERS
None.
NITS
None blocking. One observation for the record: the upgrade log message text (
"GRANT SELECT on tournament tables to westside_streamlit_ro.") is supplied by Alembic from the docstring's first line, which matches. No action.SOP COMPLIANCE
510-grant-tournament-tables-to-ro-role— matches{issue}-{kebab-case}conventionwestside-streamlit#15, conventions (feedback_migration_slot_coordination,feedback_basketball_hands_off), and predecessor migrations 044/045PROCESS OBSERVATIONS
DORA notes:
Discovered scope (do NOT block this PR — flag for separate tickets per
feedback_discovered_scope_always_tracked):alembic upgrade headfrom empty DB fails at029_add_schedule_tableswithtype "division" already exists. Reproducible onmain. Confirmed in source: lines 34 and 77 both referenceEnum("boys", "girls", name="division", create_type=False)without an explicitdivision.create()call, so SQLAlchemy 2.0.48 emits the type creation on the first hit and again on the second. Should be a separate Forgejo issue.tests/test_jersey_reminder.py::test_plain_text_has_deadline_copy— asserts "March 30" deadline copy, but template now reads "April 10". Pre-existing failure onmain, unrelated to this migration. Tracking ticket may already exist (#491 mentions "two pre-existing test failures keep CI red on main"); worth checking before filing a new one.Neither blocks #515. Both warrant their own board items.
VERDICT: APPROVED
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.