feat(ops): erp-sandbox iso-prod seed + documents sync tooling (ADR-0003 E2) #15

Merged
arcodange merged 1 commits from claude/e2-sandbox-lifecycle into main 2026-06-29 07:43:45 +02:00
Owner

Summary

Productionizes the erp-sandbox state-lifecycle mechanisms from ADR-0003, validated live against the running sandbox. Adds ops/sandbox/sandbox-lifecycle.sh + README.

  • refresh-from-prod — read-only pg_dump of prod erpDROP OWNED BY erp_sandbox_role CASCADEpg_restore into erp-sandbox, with the sandbox's own membership creds (no DROP/CREATE DATABASE, no CREATEDB, no superuser). Dumps the full public schema (so app helper functions + triggers like update_modified_column_tms() come over) and filters the provisioner-owned pgbouncer user_lookup from the restore TOC. Scales the pod to 0 for exclusive access; prod creds are copied into a transient secret deleted on exit.
  • sync-documents — tar-pipes documents/mycompany (company logo + uploads) prod → sandbox, since files live on the PVC not the DB.

Proven live

I ran both against erp-sandbox: it now carries prod's 295 llx_* tables, real data (societe/facture rows), company config (Arcodange, fr_FR, theme), MAIN_MODULE_API=1, all owned by erp_sandbox_role; the login renders identically to prod and the company logo returns HTTP 200. Prod was read-only throughout (default_transaction_read_only=on), and the restore credential is structurally unable to touch prod erp (owns only erp-sandbox).

Caveats documented (ADR-0003)

Encryption (API keys are instance-uuid-bound → ai_agent_sandbox key must be generated in-sandbox) and the PVC/file fidelity (logo image needs sync-documents). README also lists the hardening backlog: a dedicated read-only dump role + a golden-cache PVC for fast BDD resets.

🤖 Generated with Claude Code

## Summary Productionizes the `erp-sandbox` state-lifecycle mechanisms from [ADR-0003](https://gitea.arcodange.lab/arcodange-org/factory/src/branch/main/vibe/ADR/0003-sandbox-state-lifecycle.md), **validated live** against the running sandbox. Adds `ops/sandbox/sandbox-lifecycle.sh` + README. - **`refresh-from-prod`** — read-only `pg_dump` of prod `erp` → `DROP OWNED BY erp_sandbox_role CASCADE` → `pg_restore` into `erp-sandbox`, with the sandbox's own membership creds (no `DROP/CREATE DATABASE`, no `CREATEDB`, no superuser). Dumps the **full** `public` schema (so app helper functions + triggers like `update_modified_column_tms()` come over) and filters the provisioner-owned pgbouncer `user_lookup` from the restore TOC. Scales the pod to 0 for exclusive access; prod creds are copied into a transient secret deleted on exit. - **`sync-documents`** — tar-pipes `documents/mycompany` (company logo + uploads) prod → sandbox, since files live on the PVC not the DB. ### Proven live I ran both against `erp-sandbox`: it now carries prod's 295 `llx_*` tables, real data (societe/facture rows), company config (Arcodange, `fr_FR`, theme), `MAIN_MODULE_API=1`, all owned by `erp_sandbox_role`; the login renders identically to prod and the company logo returns HTTP 200. Prod was read-only throughout (`default_transaction_read_only=on`), and the restore credential is structurally unable to touch prod `erp` (owns only `erp-sandbox`). ### Caveats documented (ADR-0003) Encryption (API keys are instance-uuid-bound → `ai_agent_sandbox` key must be generated in-sandbox) and the PVC/file fidelity (logo image needs `sync-documents`). README also lists the hardening backlog: a dedicated read-only dump role + a golden-cache PVC for fast BDD resets. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
arcodange added 1 commit 2026-06-29 07:42:46 +02:00
Productionizes the sandbox state-lifecycle mechanisms validated live against
erp-sandbox. `ops/sandbox/sandbox-lifecycle.sh`:
  - refresh-from-prod: read-only pg_dump of prod erp (default_transaction_read_only)
    -> DROP OWNED BY erp_sandbox_role CASCADE -> pg_restore into erp-sandbox, using
    the sandbox's own membership creds (no DROP/CREATE DATABASE, no CREATEDB, no
    superuser). Dumps the full public schema (so app helper functions + triggers
    come over) and filters the provisioner-owned pgbouncer user_lookup function
    from the restore TOC. Scales the pod to 0 for exclusive access; copies prod
    creds into a transient secret that is deleted on exit.
  - sync-documents: tar-pipe the documents/mycompany tree (company logo + uploads)
    prod -> sandbox, since uploaded files live on the PVC, not the DB.

Prod integrity is structural: prod is read-only during dump; the restore can only
write erp-sandbox (erp_sandbox_role owns only the sandbox DB and cannot drop prod
erp/erp_role); the platform's only prod-capable superuser stays behind the
human-gated postgres.yaml CI and is never used here.

README documents the integrity guarantee, the encryption + PVC fidelity caveats,
the BDD reset loop, and the hardening backlog (dedicated read-only dump role,
golden-cache PVC).

Refs ADR-0003 (factory#19). Chart owner-role fix = erp#13.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
arcodange merged commit 4cc5ca39ce into main 2026-06-29 07:43:45 +02:00
arcodange deleted branch claude/e2-sandbox-lifecycle 2026-06-29 07:43:45 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: arcodange-org/erp#15