fix(chart): template Postgres owner role in update_ownership.sql for multi-env #13

Merged
arcodange merged 1 commits from claude/fix-chart-owner-role into main 2026-06-28 22:30:55 +02:00
Owner

The bug

chart/scripts/update_ownership.sql (a Dolibarr before-start step, embedded into a ConfigMap by chart/templates/scripts-config.yaml) hardcoded the Postgres owner role erp_role. After install it reassigns ownership of all public-schema objects to that role.

For any non-prod environment the owner role differs. By the multi-env elision rule (ADR-0002 / ADR-0003) it is snake-case <app>_role for prod and <app>_<env>_role for non-prod — so the sandbox owner role is erp_sandbox_role.

With the literal erp_role, once Dolibarr installs in erp-sandbox the script would reassign sandbox tables to prod's erp_role, which:

  • (a) breaks the sandbox runtime — its dynamic DB creds are a member of erp_sandbox_role, not erp_role; and
  • (b) breaks the ADR-0003 reset, which does DROP OWNED BY erp_sandbox_role.

The fix — make the owner role env-aware via a chart value

A new chart value db.ownerRole carries the per-env role:

  • chart/values.yaml — default ownerRole: erp_role (prod) in the existing db: block.
  • chart/values-sandbox.yaml — override ownerRole: erp_sandbox_role.
  • chart/scripts/update_ownership.sql — all 'erp_role' literals → '{{ .Values.db.ownerRole }}' (single quotes preserved so the rendered output is still a quoted SQL string literal). All four occurrences replaced, so the comment + RAISE NOTICE lines render the real role too.
  • chart/templates/scripts-config.yaml — render that one SQL file through tpl so the value is substituted: {{- tpl (.Files.Get "scripts/update_ownership.sql") . | nindent 4 }}. The other script (update_conf_db_credentials.sh, no template vars) stays on plain .Files.Get. The SQL's $$, %I, format(...), RAISE NOTICE are not Go-template syntax, so tpl only substitutes the added {{ .Values.db.ownerRole }}.

Proof: prod renders byte-identical

ConfigMap rendered from origin/main vs this branch, both with only chart/values.yaml:

$ helm template erp ./chart --show-only templates/scripts-config.yaml   # origin/main → A
$ helm template erp ./chart --show-only templates/scripts-config.yaml   # this branch → B
$ diff A B
<<< EMPTY DIFF — PROD IS BYTE-IDENTICAL >>>

Both still contain erp_role. helm lint ./chart passes, no worse than origin/main (same single [INFO] icon is recommended).

Proof: sandbox renders the right role

$ helm template erp ./chart --show-only templates/scripts-config.yaml \
    -f chart/values.yaml -f chart/values-sandbox.yaml
...
  update_table_ownership.sql: |
    ...
        -- Si le propriétaire actuel est différent de erp_sandbox_role
        IF current_schema_owner <> 'erp_sandbox_role' THEN
            EXECUTE format('REASSIGN OWNED BY %I TO %I', current_schema_owner, 'erp_sandbox_role');
            RAISE NOTICE 'Ownership of all objects in schema "public" has been reassigned from % to %', current_schema_owner, 'erp_sandbox_role';
        ELSE
            RAISE NOTICE 'No change needed; the owner of schema "public" is already %', 'erp_sandbox_role';
        END IF;
    END $$;

erp_sandbox_role appears 5× in the rendered SQL; bare 'erp_role' appears 0×.

Scope / follow-up

Full end-to-end validation — that sandbox tables actually end up owned by erp_sandbox_role after a real Dolibarr install — is deferred to Phase E1, when Dolibarr is installed into erp-sandbox. This PR is chart text only (no secrets introduced).

Cross-links: [factory vibe/ADR/0003-sandbox-state-lifecycle.md] — the sandbox state-lifecycle ADR that defines the DROP OWNED BY <app>_<env>_role reset this fix unblocks (also relevant: ADR-0002 per-application-environments / the elision rule).

🤖 Generated with Claude Code

## The bug `chart/scripts/update_ownership.sql` (a Dolibarr before-start step, embedded into a ConfigMap by `chart/templates/scripts-config.yaml`) hardcoded the Postgres owner role `erp_role`. After install it reassigns ownership of **all** `public`-schema objects to that role. For any non-prod environment the owner role differs. By the multi-env elision rule (ADR-0002 / ADR-0003) it is snake-case `<app>_role` for prod and `<app>_<env>_role` for non-prod — so the sandbox owner role is **`erp_sandbox_role`**. With the literal `erp_role`, once Dolibarr installs in `erp-sandbox` the script would reassign sandbox tables to **prod's** `erp_role`, which: - **(a)** breaks the sandbox runtime — its dynamic DB creds are a member of `erp_sandbox_role`, not `erp_role`; and - **(b)** breaks the ADR-0003 reset, which does `DROP OWNED BY erp_sandbox_role`. ## The fix — make the owner role env-aware via a chart value A new chart value `db.ownerRole` carries the per-env role: - **`chart/values.yaml`** — default `ownerRole: erp_role` (prod) in the existing `db:` block. - **`chart/values-sandbox.yaml`** — override `ownerRole: erp_sandbox_role`. - **`chart/scripts/update_ownership.sql`** — all `'erp_role'` literals → `'{{ .Values.db.ownerRole }}'` (single quotes preserved so the rendered output is still a quoted SQL string literal). All four occurrences replaced, so the comment + `RAISE NOTICE` lines render the real role too. - **`chart/templates/scripts-config.yaml`** — render that one SQL file through `tpl` so the value is substituted: `{{- tpl (.Files.Get "scripts/update_ownership.sql") . | nindent 4 }}`. The other script (`update_conf_db_credentials.sh`, no template vars) stays on plain `.Files.Get`. The SQL's `$$`, `%I`, `format(...)`, `RAISE NOTICE` are not Go-template syntax, so `tpl` only substitutes the added `{{ .Values.db.ownerRole }}`. ## Proof: prod renders byte-identical ConfigMap rendered from `origin/main` vs this branch, both with only `chart/values.yaml`: ``` $ helm template erp ./chart --show-only templates/scripts-config.yaml # origin/main → A $ helm template erp ./chart --show-only templates/scripts-config.yaml # this branch → B $ diff A B <<< EMPTY DIFF — PROD IS BYTE-IDENTICAL >>> ``` Both still contain `erp_role`. `helm lint ./chart` passes, no worse than origin/main (same single `[INFO] icon is recommended`). ## Proof: sandbox renders the right role ``` $ helm template erp ./chart --show-only templates/scripts-config.yaml \ -f chart/values.yaml -f chart/values-sandbox.yaml ... update_table_ownership.sql: | ... -- Si le propriétaire actuel est différent de erp_sandbox_role IF current_schema_owner <> 'erp_sandbox_role' THEN EXECUTE format('REASSIGN OWNED BY %I TO %I', current_schema_owner, 'erp_sandbox_role'); RAISE NOTICE 'Ownership of all objects in schema "public" has been reassigned from % to %', current_schema_owner, 'erp_sandbox_role'; ELSE RAISE NOTICE 'No change needed; the owner of schema "public" is already %', 'erp_sandbox_role'; END IF; END $$; ``` `erp_sandbox_role` appears 5× in the rendered SQL; bare `'erp_role'` appears 0×. ## Scope / follow-up Full end-to-end validation — that sandbox tables actually end up owned by `erp_sandbox_role` after a real Dolibarr install — is **deferred to Phase E1**, when Dolibarr is installed into `erp-sandbox`. This PR is chart text only (no secrets introduced). Cross-links: [`factory vibe/ADR/0003-sandbox-state-lifecycle.md`] — the sandbox state-lifecycle ADR that defines the `DROP OWNED BY <app>_<env>_role` reset this fix unblocks (also relevant: ADR-0002 per-application-environments / the elision rule). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
arcodange added 1 commit 2026-06-28 22:30:04 +02:00
The Dolibarr before-start step `chart/scripts/update_ownership.sql` (embedded
into a ConfigMap by `chart/templates/scripts-config.yaml`) hardcoded the
Postgres owner role `erp_role`. It reassigns ownership of all public-schema
objects to that role after install. For any non-prod environment the owner
role differs — by the multi-env elision rule (ADR-0002/0003) it is snake-case
`<app>_role` for prod and `<app>_<env>_role` for non-prod, so the sandbox owner
role is `erp_sandbox_role`. With the literal `erp_role`, installing Dolibarr in
`erp-sandbox` would reassign sandbox tables to prod's `erp_role`, which (a)
breaks the sandbox runtime (its dynamic DB creds are a member of
`erp_sandbox_role`, not `erp_role`) and (b) breaks the ADR-0003 reset
(`DROP OWNED BY erp_sandbox_role`).

Fix: make the owner role env-aware via a new chart value `db.ownerRole`.
- values.yaml: default `ownerRole: erp_role` (prod).
- values-sandbox.yaml: override `ownerRole: erp_sandbox_role`.
- update_ownership.sql: all `'erp_role'` literals → `'{{ .Values.db.ownerRole }}'`.
- scripts-config.yaml: render that one SQL file through `tpl` so the value is
  substituted (the other script has no template vars and stays on `.Files.Get`).
  The SQL's `$$`, `%I`, `format(...)`, `RAISE NOTICE` are not Go-template syntax,
  so `tpl` only substitutes the added `{{ .Values.db.ownerRole }}`.

Verified: the prod ConfigMap render (values.yaml only) is byte-identical to
origin/main (empty diff, still `erp_role`); the sandbox render
(-f values.yaml -f values-sandbox.yaml) now contains `erp_sandbox_role` and no
bare `erp_role`; `helm lint` passes (no worse than origin/main).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
arcodange merged commit cb17332314 into main 2026-06-28 22:30:55 +02:00
arcodange deleted branch claude/fix-chart-owner-role 2026-06-28 22:30:55 +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#13