Files
poimen-memory/tasks/M6.5-credentials-secret.md

4.9 KiB

M6.5 — Postgres credentials for the Mac client

Field Value
Phase M6 — agent-manager migration
Size S — <1 day
Status Not started
Flags homelab
Spec inlined below
Blocks M6.1

Goal

The agent-manager process running on the Mac gets a Postgres connection string/credentials, managed the same ksops way the rest of this homelab handles secrets — not a password pasted into a local config file or env var by hand.

Facts (inlined — no spec read needed)

Existing pattern to follow: ksops-managed secret, same as model-invoke-apikey elsewhere in this homelab. CNPG itself already generates an in-cluster Secret for the app user (agent-manager-db-app by its usual naming convention) — the work here is getting that credential (or a dedicated read-write user, if reusing the CNPG-generated superuser-adjacent app credential isn't desired) to a process running outside the cluster, on the Mac.

Two credentials touch two different trust boundaries:

  • Cluster-internal: CNPG's own generated Secret, already ksops-free (CNPG manages it, not this repo).
    • Mac client: needs that same username/password (or a separate, narrower-scoped user) delivered to ~/workplace/agent-manager's runtime config, via a ksops-encrypted file in git rather than a manually-copied value.

Steps

  1. Decide: reuse CNPG's auto-generated app user, or create a dedicated agent_manager_client role scoped to only the sessions/groups/ settings/review_* tables (narrower blast radius if the credential ever leaks from a Mac laptop, which is a meaningfully different threat model than a credential that only ever lives inside the cluster).
  2. If a dedicated role: add it via CNPG's declarative Database / postInitSQL (or a one-time migration in M6.2's schema setup) rather than a manual psql grant.
  3. Encrypt the resulting connection string (or user/password pair) with ksops, following the exact file layout model-invoke-apikey uses.
  4. Commit the encrypted secret to git (safe — that's the point of ksops), push to both remotes.
  5. Wire agent-manager's config loading (check cmd/ / existing config file handling on the add-headless-spawn branch) to read the decrypted value at runtime — decide whether decryption happens via a sops exec-env-style wrapper the Mac invokes, or a decrypted file materialized once locally and gitignored, matching whatever model-invoke-apikey's consumers already do.
  6. Verify agent-manager connects using only the ksops-sourced credential — no plaintext password anywhere in the repo or in shell history.

Acceptance

  • No Postgres password appears in plaintext in git, in ~/workplace/agent-manager's tracked config, or was typed directly into a kubectl/psql command during setup.
  • The credential is encrypted with ksops in the same repo location/ pattern as model-invoke-apikey.
  • agent-manager on the Mac successfully authenticates through M6.4's ingress route using this credential.

Verify

Harness: manual — this is a secret-handling task, not one to automate a fake credential through.

Checklist (no verify/*.sh, since scripting a real credential check means committing something that either leaks a real secret or asserts nothing):

  1. git grep -i "password" in both the homelab repo and ~/workplace/agent-manager shows only ksops-encrypted blobs or references to environment/config loading, never a literal value.
  2. The ksops secret file's structure matches model-invoke-apikey's (same encryption provider, same key layout) — a side-by-side diff of the YAML structure (not values) confirms this.
  3. psql from the Mac using the decrypted credential (via M6.4's route) succeeds.
  4. Revoking/rotating the credential (delete the CNPG Secret or drop the dedicated role, if one was created) and re-running step 3 fails cleanly — confirms the client isn't caching or falling back to something else.

False pass:

  • Confirming connectivity once with a credential typed in manually during setup, then wiring the ksops path afterward without re-testing that the ksops-sourced value is what actually authenticates. Checklist item 4 (rotate and confirm the old path is really gone) is the guard against "it worked, but only because of leftover state."

Traps

  • Granting the dedicated role (if created) superuser or database-owner-equivalent privileges "to avoid permission errors during setup" and never narrowing it afterward — defeats the reason to create a dedicated role at all.
  • Storing the decrypted credential in a file the Mac client reads that isn't gitignored, recreating the plaintext-secret problem one directory away from the ksops-encrypted source of truth.

Background: M6.1 · model-invoke-apikey (ksops pattern reference, this homelab)