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.
- Mac client: needs that same username/password (or a separate,
narrower-scoped user) delivered to
Steps
- Decide: reuse CNPG's auto-generated
appuser, or create a dedicatedagent_manager_clientrole scoped to only thesessions/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). - 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 manualpsqlgrant. - Encrypt the resulting connection string (or user/password pair) with
ksops, following the exact file layout
model-invoke-apikeyuses. - Commit the encrypted secret to git (safe — that's the point of ksops), push to both remotes.
- Wire agent-manager's config loading (check
cmd// existing config file handling on theadd-headless-spawnbranch) to read the decrypted value at runtime — decide whether decryption happens via asops exec-env-style wrapper the Mac invokes, or a decrypted file materialized once locally and gitignored, matching whatevermodel-invoke-apikey's consumers already do. - 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 akubectl/psqlcommand 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):
git grep -i "password"in both the homelab repo and~/workplace/agent-managershows only ksops-encrypted blobs or references to environment/config loading, never a literal value.- 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. psqlfrom the Mac using the decrypted credential (via M6.4's route) succeeds.- 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)