# Configuration reference All configuration lives in `config.toml` (copy from `config.example.toml`). The file is **round-tripped by the admin panel** — comments and formatting are preserved on save, so keep comments meaningful. The file is written `0600`; a `config.toml.bak` is kept from the previous save. **Zones:** `(S)` server-only — edit the file directly, never shown/written by the panel. `(A)` admin-editable in the panel. `(W)` write-only secret — never returned by any API. `live` — applies immediately; otherwise a restart is required. ## `[pps]` — connection to Proofpoint (A, live) | Key | Type | Notes | |-----|------|-------| | `base_url` | str | `https://host:10000`. `http://` requires `PPSQ_ALLOW_INSECURE=1`. | | `username` | str | API user with the Quarantine module role. | | `password` | str (W) | Never returned; blank on save = unchanged. | | `verify_tls` | bool \| path | `false` skips verification; or a CA-bundle path. | | `timeout` | int | Seconds per call, 5..600. | | `client_cert` | path | Mutual-TLS client cert (combined PEM, or cert with `client_key`). | | `client_key` | path | Private key, if `client_cert` is cert-only. | ## `[quarantine]` (A, live) | Key | Type | Notes | |-----|------|-------| | `default_folder` | str | Must be in `folders`. Per-user overridable. | | `folders` | list[str] | Source of truth (API can't enumerate). Exact names, no commas. | | `deleted_folder` | str | Target of Delete. Must be in `folders`. | | `default_limit` | int | UI row cap 1..1000. Per-user overridable. | | `list_query` | str | Search filter; `from=*` = match-all (API rejects folder-only). | | `default_days_back` | int | How far back sync reaches (API alone gives 24h). | | `chunk_size` | int | localguids per PPS POST, 1..500. | | `default_sort_field` | str | `subject`\|`date`\|`from`\|`rcpt`. Per-user overridable. | | `default_sort_dir` | str | `asc`\|`desc`. Per-user overridable. | ### `[quarantine.report_release]` (A, live) | Key | Type | Notes | |-----|------|-------| | `steps` | list[str] | Subsequence of `["move","release"]`, run in that fixed order. | | `move_target` | str | Required if `move` in steps; must be in `folders`. | | `step_delay_seconds` | int | 0..3600 (default 60). Wait between steps, then re-read locations. | Outcomes: `["release"]` delivers in place; `["move","release"]` files the mail in `move_target` and delivers it from there. Report & Release never deletes — Delete is a separate action; a `delete` step in an old config is dropped on load. Between two steps the worker waits `step_delay_seconds` for PPS's eventually-consistent backend to settle and then **re-reads** each message's current `localguid` by its stable `guid` — handles captured before the move are never reused. `0` disables both the wait and the re-read. The waiting job is parked back on the queue, so other jobs keep running. A `steps` list in the old `release`-before-`move` order is migrated to the current order on load (and a `delete` entry is removed). ## `[app]` (S, restart — except `log_level`) | Key | Notes | |-----|-------| | `secret_key` | Session signing key, ≥32 chars. Rotating it logs everyone out. | | `listen`, `port` | Bind address. Keep loopback unless behind a reverse proxy. | | `db_path` | SQLite file (jobs + prefs). | | `log_level` | `(A, live)` INFO/DEBUG/… | | `worker_log`, `app_log` | Rotating log file paths (5 MB × 5). | | `cookie_secure` | `true` in production; `false` only for plain-http localhost. | ## `[auth]` | Key | Zone | Notes | |-----|------|-------| | `mode` | (S) | `oidc` (production) or `static` (dev). Not admin-editable. | | `denied_message` | (A, live) | Shown to authenticated-but-unlisted users. | | `users` | (A, live) | `[[auth.users]]` entries `{email, role}`; role `admin`\|`user`. | | `[auth.static]` | (S) | Dev shared account (`username`/`password`/`email`/`role`). Ignored under oidc. | ## `[okta]` (S, restart — never admin-editable) | Key | Notes | |-----|-------| | `issuer` | e.g. `https://TENANT.okta.com/oauth2/default`. | | `client_id` | Okta app client id. | | `client_secret` | (W) Okta app secret. | | `redirect_uri` | Must EXACTLY match the Okta app registration. Ends in `/authorize`. | ## Environment variables | Var | Purpose | |-----|---------| | `PPSQ_CONFIG` | Path to the config file (default: `./config.toml`). | | `PPSQ_ALLOW_INSECURE` | Allow an `http://` PPS base_url (dev only). | | `PPSQ_ALLOW_INSECURE_AUTH` | Allow static auth on a non-loopback interface (dev only). | ## Live vs restart Live: `pps.*`, `quarantine.*`, `auth.users`, `auth.denied_message`, `app.log_level`. Restart: `app.secret_key/listen/port/db_path/worker_log/app_log/cookie_secure`, `auth.mode`, all `okta.*`. The panel reports `restart_required` after a save.