@claude
Priority: HIGH — production data loss risk. The fuzeinfra-namespace copies of the per-service DB password secrets (fuzesales-db-credentials, fuzecontact-db-credentials, fuzeservice-db-credentials) were created ad-hoc with kubectl create secret and are NOT in git. If the fuzeinfra namespace is ever deleted or re-provisioned from scratch, the provisioning Job will immediately wedge again (x26,000 CreateContainerConfigError — exactly what happened this week for ~4 days). Please consult Claude Opus 4.8 when deciding how to structure the long-term solution.
Context: the two-secret pattern
The provisioning Job (service-db-provisioning.yaml) reads ONE secret per service from the fuzeinfra namespace — the service's DB password (key: password). This is separate from the full credentials secret in the app namespace (DATABASE_URL, DB_HOST, etc.) which ArgoCD syncs from each app repo's deploy/sealed-secrets/.
Current state of the fuzeinfra-namespace secrets:
| Secret |
Present in fuzeinfra ns |
Sealed in git |
fuzesales-db-credentials |
✓ (ad-hoc) |
✗ |
fuzecontact-db-credentials |
✓ (ad-hoc) |
✗ |
fuzeservice-db-credentials |
✓ (ad-hoc) |
✗ |
mendys-db-credentials |
✓ (sealed, FuzeKeys #136 precedent) |
✓ |
Mendys is the reference implementation. Do exactly what was done for mendys for the other three.
What needs to be done
1. Add sealed secrets for the three services in this repo
For each of fuzesales, fuzecontact, fuzeservice: create a SealedSecret targeting the fuzeinfra namespace with just the password key, using the passwords currently live on the cluster:
fuzesales password: Li1cTPDK5lj06rswzG6zzSHycNI9Mqx7
fuzecontact password: gCIh8rK7mcfJrOyNeSd707MHayVnm6r2
fuzeservice password: VJkk5y99q6K8hsfCW0EdzPoXDyGzutCp
Seal each with kubeseal --namespace fuzeinfra and commit to deploy/sealed-secrets/ (or wherever mendys-db-credentials.yaml lives — follow the same path). These must be applied before the provisioning Job runs on any fresh deployment.
2. Create scripts/seed-service-db.sh — the canonical bootstrap script
A reusable, idempotent script that does the full flow for any new service:
#!/usr/bin/env bash
# Usage: ./scripts/seed-service-db.sh <service-name> [<password>]
# If password is omitted, generates a 32-char random one.
# Creates:
# 1. SealedSecret for fuzeinfra namespace (password key only) → written to deploy/sealed-secrets/
# 2. Prints the password so the calling engineer can pass it to the app repo's own sealing step
# The calling engineer then runs the app repo's equivalent to seal the full DATABASE_URL secret.
The script should:
- Accept
SERVICE_NAME and optional PASSWORD args
- Generate a secure 32-char password if none provided
- Run
kubeseal against the live cluster to produce deploy/sealed-secrets/<service>-db-credentials-fuzeinfra.yaml
- Print clear instructions: "Now go to the repo and run
./scripts/seal-db-credentials.sh <password> to create the app-namespace sealed secret, then add the service to helm/fuzeinfra/values-contabo.yaml"
- Be idempotent (check if secret already exists on cluster before creating)
3. Update ONBOARD-REPO.md / docs/ with the canonical DB provisioning flow
Add a "Database provisioning" section documenting:
- Run
./scripts/seed-service-db.sh <service> in FuzeInfra → get the password
- Run the equivalent sealing step in the app repo → get the app-namespace sealed secret
- Open a single PR that adds BOTH sealed secrets and flips
enabled: true in values-contabo.yaml
- Merge → ArgoCD applies → provisioning Job runs → DB role + database created
The key invariant: never flip enabled: true without the fuzeinfra-namespace sealed secret in the same PR.
4. Reference: mendys precedent (FuzeKeys #136)
Check FuzeKeys PR #136 for the exact pattern used for mendys — the sealed secret structure, the values-contabo.yaml change, and the commit order. Mirror that for fuzesales/fuzecontact/fuzeservice.
Out of scope for this issue
- Creating the app-namespace sealed secrets for fuzesales/fuzecontact (already exist in their repos)
- Creating the app-namespace sealed secret for fuzeservice (tracked in FuzeService issue)
STATE:
- Ad-hoc secrets currently live on cluster (will survive until namespace is deleted)
- provisioning Job ran successfully after ad-hoc fix — all roles/DBs now exist
- This issue seals the fix permanently into git
@claude
Priority: HIGH — production data loss risk. The
fuzeinfra-namespace copies of the per-service DB password secrets (fuzesales-db-credentials,fuzecontact-db-credentials,fuzeservice-db-credentials) were created ad-hoc withkubectl create secretand are NOT in git. If thefuzeinfranamespace is ever deleted or re-provisioned from scratch, the provisioning Job will immediately wedge again (x26,000CreateContainerConfigError— exactly what happened this week for ~4 days). Please consult Claude Opus 4.8 when deciding how to structure the long-term solution.Context: the two-secret pattern
The provisioning Job (
service-db-provisioning.yaml) reads ONE secret per service from thefuzeinfranamespace — the service's DB password (key:password). This is separate from the full credentials secret in the app namespace (DATABASE_URL,DB_HOST, etc.) which ArgoCD syncs from each app repo'sdeploy/sealed-secrets/.Current state of the
fuzeinfra-namespace secrets:fuzeinfransfuzesales-db-credentialsfuzecontact-db-credentialsfuzeservice-db-credentialsmendys-db-credentialsMendys is the reference implementation. Do exactly what was done for mendys for the other three.
What needs to be done
1. Add sealed secrets for the three services in this repo
For each of
fuzesales,fuzecontact,fuzeservice: create a SealedSecret targeting thefuzeinfranamespace with just thepasswordkey, using the passwords currently live on the cluster:Seal each with
kubeseal --namespace fuzeinfraand commit todeploy/sealed-secrets/(or wherever mendys-db-credentials.yaml lives — follow the same path). These must be applied before the provisioning Job runs on any fresh deployment.2. Create
scripts/seed-service-db.sh— the canonical bootstrap scriptA reusable, idempotent script that does the full flow for any new service:
The script should:
SERVICE_NAMEand optionalPASSWORDargskubesealagainst the live cluster to producedeploy/sealed-secrets/<service>-db-credentials-fuzeinfra.yaml./scripts/seal-db-credentials.sh <password>to create the app-namespace sealed secret, then add the service tohelm/fuzeinfra/values-contabo.yaml"3. Update
ONBOARD-REPO.md/docs/with the canonical DB provisioning flowAdd a "Database provisioning" section documenting:
./scripts/seed-service-db.sh <service>in FuzeInfra → get the passwordenabled: trueinvalues-contabo.yamlThe key invariant: never flip
enabled: truewithout the fuzeinfra-namespace sealed secret in the same PR.4. Reference: mendys precedent (FuzeKeys #136)
Check FuzeKeys PR #136 for the exact pattern used for mendys — the sealed secret structure, the values-contabo.yaml change, and the commit order. Mirror that for fuzesales/fuzecontact/fuzeservice.
Out of scope for this issue
STATE: