k8s Job: provision admin_app Postgres user + grants on basketball db #302
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
ldraney/pal-e-platform#302
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Type
Task
Lineage
Companion to westside-admin deploy. Independent — can start before app code exists. Blocks
forgejo_admin/westside-admin#1(Drizzle integration test needs to connect as admin_app) andforgejo_admin/pal-e-deployments#133(overlay's DATABASE_URL secret depends on this user existing).Scope-revision lineage: Original ticket offered three options (terraform via cyrilgdn provider, k8s Job, manual SOP) and asked dev agent to pick. Scope review (
review-1097-2026-04-25) discovered:cyrilgdn/postgresqlprovider is NOT registered in pal-e-platform (would require provider expansion)postgres:16-alpineDeployment inpal-e-deployments/overlays/basketball-api/prod/postgres.yaml, NOT CNPGpaledocs_db_urlinterraform/modules/database/main.tf) targets the CNPGpal-e-postgres-rwcluster — different infra, not applicableadmin_appor sub-user pattern exists anywhere — this is genuinely new groundDecision (path A — k8s Job in pal-e-deployments): provision via an idempotent k8s Job manifest that runs
psqlagainst the existing basketball-api Postgres pod. Lower scope expansion than adding a terraform provider. Job is idempotent (usesIF NOT EXISTSpatterns) so it can be re-run safely.Repo
forgejo_admin/pal-e-platform(this ticket's tracking repo). The actual k8s Job manifest lands inpal-e-deployments/overlays/basketball-api/prod/(or a sibling overlay) — that PR is part of this ticket's deliverable.Scope
Three deliverables, all must complete:
1. Generate admin_app password. A 32-character random hex string (e.g.,
openssl rand -hex 32). Store in pal-e-platform's secret pattern (or document where; existing pattern likely interraform/modules/database/for paledocs's CNPG cluster — replicate the shape).2. Create idempotent k8s Job manifest in
pal-e-deployments/overlays/basketball-api/prod/admin-app-user-job.yaml(or similar). The Job:postgres:16-alpineimagepsql:restartPolicy: OnFailurebackoffLimit: 4Add the Job to
kustomization.yamlresources so ArgoCD applies it. Job runs to completion on apply; safe to re-run on grant updates.3. Mirror the password Secret to
pal-e-deployments/overlays/westside-admin/prod/westside-admin-secrets.enc.yamlasDATABASE_URL=postgresql://admin_app:<password>@postgres.basketball-api.svc.cluster.local:5432/basketball. Coordinate withforgejo_admin/pal-e-deployments#133.After apply: verify the three connection tests below all behave as expected. Document the password rotation procedure as a brief SOP note in pal-e-docs (slug
sop-admin-app-password-rotation, tagsop,active).Acceptance Criteria
admin_appexists on basketball-api Postgres after Job runswestside-admin-secrets.enc.yamlin pal-e-deployments overlay (companion to #133)psql "$DATABASE_URL" -c "SELECT 1"succeeds (run from a debug pod)psql "$DATABASE_URL" -c "CREATE TABLE foo (id int)"FAILS with permission deniedsop-admin-app-password-rotationcreated in pal-e-docsTest Expectations
Constraints
IF NOT EXISTSpatterns in SQL, declarative resource definitionChecklist
review-1097-2026-04-25Related
project-westside-adminarch-deployment-westside-adminreview-1097-2026-04-25(scope investigation that drove path A)feedback_never_write_prod_db(this is the legitimized write user)forgejo_admin/westside-admin#1(Drizzle),forgejo_admin/pal-e-deployments#133(overlay secrets)Scope Review: NEEDS_REFINEMENT
Review note:
review-1097-2026-04-25Pre-investigation done:
cyrilgdn/postgresqlprovider is NOT registered in pal-e-platform, and basketball-api Postgres is a plainpostgres:16-alpineDeployment (NOT CNPG). The 3-option fork in the body should be replaced with a concrete chosen approach.Issues to refine:
[BODY]Pick one provisioning approach (recommend: one-shot Job/migration via kustomize, or terraformkubernetes_job_v1running psql) — drop the cyrilgdn option since adding a provider is out of scope.[BODY]Specify the secret-handoff contract: does this ticket create the consumer Secret inwestside-adminns directly (paledocs precedent), or does pal-e-deployments#133 own it via SealedSecret? The two tickets need a clear interface.[SCOPE]Missing backing arch notearch-deployment-westside-admin(referenced byproject-westside-adminbut not yet created). Optionallyarch-postgres-grantsas sub-component.Strengths: traceability story leg verified, 8 AC are sharp and testable, blast radius low, no decomposition needed.
Once body is tightened and arch stub exists, this is READY.
Postgres admin_app user + grants on basketball db (for westside-admin)to k8s Job: provision admin_app Postgres user + grants on basketball dbScope Re-Review: READY
Review note:
review-1097-2026-04-25-v2(supersedesreview-1097-2026-04-25)Rewritten body addresses all v1 [BODY] recommendations: 3-option fork removed, Path A (idempotent k8s Job) explicitly chosen with rationale, SQL spelled out inline, secret handoff to #1095/#133 explicit, cyrilgdn provider explicitly out of scope.
Verified:
CREATE ROLEwrapped inDO $$ ... IF NOT EXISTS;GRANTandALTER DEFAULT PRIVILEGESare idempotent by Postgres semantics.postgres.basketball-api.svc.cluster.local:5432/basketballmatchespal-e-deployments/overlays/basketball-api/prod/postgres.yaml(Servicepostgres, namespacebasketball-api, DBbasketball). Companion #1095 has unambiguous consumer contract.Non-blocking carryovers (optional polish, not blockers for READY):
[SCOPE](carryover from v1): createarch-deployment-westside-adminand stubarch-postgresbacking notes. Story:arch traceability is incomplete without them, but doesn't block ticket execution. Recommend Ava queue as a separate scoping ticket.[BODY]Optional: replace "superuser credentials" with "owner credentials" — the rolebasketballis DB owner, not formally SUPERUSER. SQL semantics are correct as written.[BODY]Optional: explicit note that admin_app's password Secret must be a NEW Secret (notbasketball-api-secrets) for blast-radius isolation. Implied but worth stating.Cleared to advance backlog → todo.