-
Notifications
You must be signed in to change notification settings - Fork 0
1.7 Step | CreateDbRole
Creates the PostgreSQL role for Odoo (
db_user), reversibly. It lives insrc/steps/create_db_role.rs. A port ofcreate_db_userfromlib/postgres.sh.
| Phase | Behaviour |
|---|---|
| snapshot | does the role already exist? (SELECT 1 FROM pg_roles WHERE rolname = ...) → Preexisting/Untracked
|
| run |
Preexisting → skip. Absent → CREATE ROLE "<user>" WITH LOGIN CREATEDB [PASSWORD '…'], then CreatedByUs. dry_run → log only |
| undo |
CreatedByUs only: DROP ROLE IF EXISTS "<user>". Idempotent, best-effort |
With a password (from the .env DB_PASSWORD) → ... PASSWORD '<escaped>'; without one → peer
authentication, the safe local default where the OS user and the PG role share a name.
DROP ROLE fails if the role owns objects — and the role owns the database created by
1.8 CreateDatabase. It is the same pattern as the home coordination in
1.2 CreateOdooUser: every step owns the removal of what it created,
and the reverse order guarantees the right sequence.
production: CreateDbRole → CreateDatabase
rollback: undo CreateDatabase (drop DB) → undo CreateDbRole (drop role)
The database goes before the role that owns it. A test verifies this by running the engine with a
shared log and asserting that DROP DATABASE precedes DROP ROLE.
The password arrives as a Secret (redacted Debug).
The plaintext value is extracted only at the call site of the SystemOps boundary
(pg_create_role), and it is never logged: the log carries at most with_password = true/false.
Inside the boundary, where all the risk is:
- the identifier (role name) is validated as an identifier during resolution and double-quoted anyway;
- the password is an SQL literal with single quotes doubled (
escape_sql_literal); - the SQL travels through stdin, not in
argv, so it does not show up in the process command line; - on error the stderr is suppressed: psql echoes the failing line, which would contain the password. We give up diagnostic detail rather than risk a leak.
The mock in the tests records only has_password: bool, never the value.
- No aggression towards pre-existing things: a role that was already there is neither created nor dropped.
- Best-effort, idempotent undo (
DROP ROLE IF EXISTS). - Tests: role absent (create/drop with the expected arguments), password containing a single quote
(correct escaping, value not recorded),
Preexistingrole (never touched), pure escaping'→''.
Start here
Key concepts
References
For developers
Technical detail — how it works inside
Steps:
- 1.1 PrepareOptRoot
- 1.2 CreateOdooUser
- 1.3 SetupLogDir
- 1.3b SetupCacheDir
- 1.4 AptPackages (delta)
- 1.5 InstallWkhtmltopdf
- 1.6 SetupPostgres
- 1.7 CreateDbRole
- 1.8 CreateDatabase
- 1.9 CloneOdooRepo
- 1.10 CreateVirtualenv
- 1.11 InstallPythonRequirements
- 1.12 GenerateConfig
- 1.12b SetupDataDir
- 1.13 InitializeOdooDatabase
- 1.14 SetupSystemd
- 1.15 Nginx (6 sub-steps)
- 1.16 WriteControlScript + PatchBashrc
Cross-cutting: