Review: pal-e-deployments#135 — Cross-namespace admin-app-db-url surfacing (2026-04-25)

review-135-2026-04-25 Doc

active review

Scope

Ticket pal-e-deployments#135 — surface the admin-app-db-url Secret produced in the basketball-api namespace (PR pal-e-platform#304) into the westside-admin namespace so the westside-admin pod (PR pal-e-deployments#134) can mount DATABASE_URL via secretKeyRef.
Producer: pal-e-platform terraform module/database creates kubernetes_secret_v1.admin_app_db_url in basketball-api.
Consumer: westside-admin Deployment in westside-admin namespace expects a Secret named westside-admin-secrets with key DATABASE_URL.

Verdict

REQUEST_CHANGES — pre-decision required before dev dispatch.
The dev agent should not be asked to "decide during scoping" between four mechanisms (mittwald/kubernetes-replicator, External Secrets Operator, kustomize secretGenerator with duplicated SOPS payload, terraform-emitted second Secret). Each option has materially different blast radius and operational burden, and at least one (replicator / ESO) introduces a brand-new platform dependency that belongs to pal-e-platform, not to a deployments-overlay PR.

Verification

  • Read PR pal-e-deployments#134 body + diff — consumer expects Secret westside-admin-secrets in the westside-admin ns with DATABASE_URL. Currently the SOPS-encrypted westside-admin-secrets.enc.yaml in the overlay carries a placeholder DATABASE_URL.
  • Read PR pal-e-platform#304 body + diff — producer creates kubernetes_secret_v1.admin_app_db_url in basketball-api ns. The PR body explicitly defers cross-namespace surfacing to "Track B (#133/#135)" and even names the two leading candidates ("kustomize secretGenerator referencing the same value or a small replicator").
  • Issue pal-e-deployments#135 body could not be retrieved directly (no get_issue MCP tool, Tailscale-internal Forgejo not reachable from WebFetch). Review proceeds from the producer/consumer PR bodies, both of which are authoritative on the gap and the candidate set.
  • Repo precedent check: bases/standard/kustomization.yaml has no replicator hook. No kubernetes-replicator / external-secrets Helm release exists in the visible pal-e-platform/terraform/main.tf module wiring (storage, keycloak, database, ops, observability, etc.). No precedent for cross-namespace secret replication exists in the platform. This ticket is therefore introducing a new pattern, which raises the bar for pre-decision.
  • Story story:admin-row-crud and arch arch:k8s-deploy are the correct labels (consistent with #134 / #304).

Findings

1. Four-option deferral is the wrong shape for a brand-new pattern

Per feedback_review_before_dispatch and feedback_tickets_not_solution_specs, tickets carry user story + context + AC; dev agents pick implementation. That holds when there is precedent. Here there is none — picking between mittwald-replicator (cluster-wide controller, RBAC, ArgoCD app), ESO (CRDs, secret store, controller), kustomize secretGenerator + duplicated SOPS file, and a terraform-side second kubernetes_secret_v1 in the consumer ns is a platform architecture decision, not an implementation detail. The blast radii differ by orders of magnitude.

2. Three of the four options shouldn't even be on the table for this ticket

  • mittwald/kubernetes-replicator — adds a new cluster-wide controller. Belongs to pal-e-platform as its own ticket + tofu module, not to a deployments-overlay PR. Out of scope.
  • External Secrets Operator — same: new CRDs, controller, SecretStore. Out of scope for a single overlay.
  • kustomize secretGenerator with duplicated SOPS ciphertext — violates the spirit of feedback_never_alter_prod_directly's "single source of truth" thinking. Two encrypted blobs to rotate, two failure modes. Hard to keep in sync with the terraform-emitted producer.
  • Terraform emits a second kubernetes_secret_v1 in the westside-admin namespace — adds ~10 lines to module/database, no new dependency, no new controller, idempotent, single source of truth (the Salt pillar value). Already inside the producer module that owns the password lifecycle.
Recommend pre-deciding option 4 (terraform mirrors the Secret into westside-admin ns), and downscoping the ticket to either (a) a westside-admin-overlay-only fix that simply switches the env var secretKeyRef.name from westside-admin-secretsadmin-app-db-url and removes the placeholder DATABASE_URL from the SOPS file, or (b) a tiny pal-e-platform PR that adds the mirror Secret. The honest answer is the work largely belongs to pal-e-platform, not pal-e-deployments — that should be settled before dispatch.

3. File Targets ambiguity

The ticket reportedly lists services/westside-admin/overlays/prod/ + possibly services/_shared/. The actual repo layout is overlays/westside-admin/prod/ (no services/ prefix, no _shared/ dir). Per feedback_verify_repo_layout_before_ticketing, File Targets must match the live repo or the dev agent burns cycles. Fix before promoting to todo.

4. AC must include rotation propagation E2E

Producer Job already rotates via Salt-pillar bump → terraform re-apply. The consumer must observe the new password without manual pod-roll, OR the AC must explicitly state "rotation requires kubectl rollout restart of westside-admin Deployment." Either is fine; the unstated case is a foot-gun.

5. Constraints that must be in the ticket

  • No manual SOPS duplication of the encrypted DATABASE_URL.
  • No coupling of pal-e-platform module/database to westside-admin app internals (mirror Secret is fine; importing westside-admin config is not).
  • No new cluster-wide controllers added in this ticket — if a replicator is the right answer long-term, that is its own pal-e-platform ticket gated separately.

Recommendation

  • Pre-decide the mechanism with Lucas/Ava before dispatch. Recommended: terraform mirrors the Secret into westside-admin ns from the same module/database resource. Lowest blast radius, no new dependency, single source of truth.
  • Move the actual implementation work onto pal-e-platform as a small follow-up PR to #304 (or amend #304 if not yet merged), since terraform owns the password and the producer Secret. Then pal-e-deployments#135 becomes a tiny overlay-only change: rewire deployment-patch.yaml envs to source DATABASE_URL from the mirrored Secret name, drop DATABASE_URL from the SOPS-encrypted westside-admin-secrets.enc.yaml.
  • Fix File Targets to match real repo paths (overlays/westside-admin/prod/deployment-patch.yaml, overlays/westside-admin/prod/westside-admin-secrets.enc.yaml).
  • Add explicit rotation-propagation step to AC.
  • Add the three constraints in finding #5.
  • Once the above are in the ticket body, ticket can move backlogtodo per feedback_todo_means_reviewed.