Merge pull request 'fix(sandbox-poc): regenerate api_key when the existing one is garbage + note platform backup gaps' (#35) from claude/poc-apikey-regen into main

This commit was merged in pull request #35.
This commit is contained in:
2026-06-30 22:45:06 +02:00
2 changed files with 27 additions and 14 deletions
+18 -12
View File
@@ -82,18 +82,24 @@ was reverted to the backup's value by `restore --db`.
The recurring form ships in the chart (`chart/templates/backup-cronjob.yaml`, The recurring form ships in the chart (`chart/templates/backup-cronjob.yaml`,
`backup.enabled=false` by default): a daily **CronJob** (ConfigMap-mounted `backup.enabled=false` by default): a daily **CronJob** (ConfigMap-mounted
`backup-job.sh`) with its **own** S3 creds via a `VaultStaticSecret` — no `backup-job.sh`) with its **own** S3 creds via a `VaultStaticSecret` — no
cross-namespace borrowing of the Longhorn secret. To activate: cross-namespace borrowing of the Longhorn secret.
1. store the GCS HMAC creds (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / **Status: LIVE (2026-06-30).** tools#5 granted the erp prod Vault policy read on
`AWS_ENDPOINTS`, same shape as `longhorn-gcs-backup-credentials`) at `kvv2/data/longhorn/gcs-backup` (via the module's `kv_read_paths`), and the chart
`kvv2/<backup.vaultS3Path>` (default `erp/backup`); sets `backup.enabled: true` + `vaultS3Path: longhorn/gcs-backup`. The CronJob runs
2. grant the erp `auth` Vault role read on that path (a `tools` change) if its daily at 03:00 UTC; a manual run was verified (db + docs → GCS). Sandbox keeps it off.
policy doesn't already cover it;
3. set `backup.enabled: true` (+ tune `schedule`).
Until then, run the orchestrator above on demand / from a host cron — it works ## Platform follow-ups — NOT erp (open; revisit when we look at ERP backups)
today by borrowing the Longhorn creds transiently.
> The generic Longhorn gap (the orphaned `default` group) should be fixed too, as a 1. **Longhorn `default` group is orphaned → other volumes have NO offsite backup.**
> platform concern — but this dedicated, offsite, 10-year-retention backup is the The cluster's only Longhorn recurring-backup job (`thrice-a-month-backup`) has
> one that matches Dolibarr's legal criticality. `groups=[]`, so it serves no group — yet volumes are enrolled in the `default`
group. Result found 2026-06-30: erp + most volumes had `lastBackupAt=never`. This
dedicated backup covers Dolibarr, but every OTHER cluster volume is still exposed.
Fix at the platform layer (factory): attach a recurring job to the `default` group
(or set the storageclass `recurringJobSelector`).
2. **Verify the factory `pg_dumpall` host cron actually runs.** `factory` ships
`ansible/.../playbooks/backup/postgres.yml` that `pg_dumpall`s daily on the
Postgres host (192.168.1.202) — unverified from the k8s side. Confirm it's live
and where it ships; it's the platform-level DB safety net beneath this app-level
one.
+9 -2
View File
@@ -228,9 +228,16 @@ async function generateApiKey(
); );
} }
// If a key is already set, reuse it. // Reuse the existing key ONLY if it is a clean plaintext key. After an iso-prod
// refresh the instance unique-id changes, so a key encrypted with the OLD id can
// no longer be decrypted — Dolibarr then renders non-UTF-8 bytes in the field.
// Reusing that (the old bug) wrote a corrupt key file. Treat anything that isn't
// a plausible key (≥24 url-safe chars) as garbage: clear it and regenerate.
const existing = (await apiKeyInput.first().inputValue()).trim(); const existing = (await apiKeyInput.first().inputValue()).trim();
if (existing.length > 0) return existing; if (/^[A-Za-z0-9_-]{24,}$/.test(existing)) return existing;
if (existing.length > 0) {
await apiKeyInput.first().fill(""); // drop the undecryptable/garbage value
}
// Trigger generation. GUESS: a generate control next to the field. We try a // Trigger generation. GUESS: a generate control next to the field. We try a
// few likely selectors in order and click the first that exists. // few likely selectors in order and click the first that exists.