Start-up checks: a mistyped POSTULO_EMAIL_OAUTH_PROVIDER or POSTULO_EMAIL_OAUTH_GRANT passes and mail fails later #487

Closed
opened 2026-10-01 10:47:02 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the system checks against the settings they guard and running them with mistyped values.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at core/mail_auth.py:163-206 (instance_token; the refusal for an unknown provider at :188, the comparison with MailGrant.APPLICATION at :206), and MailGrant is defined in core/mail_choices.py:42 and re-exported from mail_auth; core/checks.py and the settings are where they were.

core/checks.py exists (#233) so that a setting with a fixed vocabulary is refused at start-up rather than surfacing at the first send. It checks POSTULO_EMAIL_AUTH, but not the two variables beside it that also have a fixed vocabulary: POSTULO_EMAIL_OAUTH_PROVIDER (google or microsoft, the keys of mail_auth.PROVIDERS) and POSTULO_EMAIL_OAUTH_GRANT (blank, mailbox or application), both documented with those words in the wiki's Configuration.md:599-600. A variable pins its field over the Email page, so a typo there cannot be corrected from the interface.

  • Where: core/checks.py:28-33 (CHOICES) and :61, choices; the settings at config/settings/base.py:729-730; their use in core/mail_auth.py:188-231, instance_token.
  • What happens:
    • With POSTULO_EMAIL_AUTH=xoauth2 and POSTULO_EMAIL_OAUTH_PROVIDER=microsft, the postulo checks return nothing (run against the snapshot with those settings), the entrypoint starts, and every message, password resets included, fails with "No identity provider is chosen for mail." (mail_auth.py:212).
    • With POSTULO_EMAIL_OAUTH_GRANT=aplication, instance_token compares the word with MailGrant.APPLICATION, finds it different and quietly takes the signed-in-once route (mail_auth.py:230), which on an instance set up for the application grant fails with "Nobody has signed in to the mail provider yet".
    • google with application is refused on the Email page by _refuse_a_grant_the_provider_lacks (core/server_forms.py:470), but the same pair from the environment is checked nowhere and fails on every send.
  • Why it matters: the failure lands where the module's docstring says it should not, at the first password reset, on an instance whose operator ran check --deploy and saw it pass.
  • Fix: add a check (the next free id, postulo.E008) that, when POSTULO_EMAIL_AUTH is xoauth2, requires POSTULO_EMAIL_OAUTH_PROVIDER to be a key of mail_auth.PROVIDERS; that requires POSTULO_EMAIL_OAUTH_GRANT to be blank or a MailGrant value; and that refuses application for a provider whose application_grant is false. Take the words from mail_auth rather than adding a second list to CHOICES, so the check and the code that acts on them cannot drift.

Done when

  • Tests in tests/test_checks.py set each of the three combinations above and expect an error; they fail today because the checks return nothing.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the system checks against the settings they guard and running them with mistyped values. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `core/mail_auth.py:163-206` (`instance_token`; the refusal for an unknown provider at `:188`, the comparison with `MailGrant.APPLICATION` at `:206`), and `MailGrant` is defined in `core/mail_choices.py:42` and re-exported from `mail_auth`; `core/checks.py` and the settings are where they were. `core/checks.py` exists (#233) so that a setting with a fixed vocabulary is refused at start-up rather than surfacing at the first send. It checks `POSTULO_EMAIL_AUTH`, but not the two variables beside it that also have a fixed vocabulary: `POSTULO_EMAIL_OAUTH_PROVIDER` (`google` or `microsoft`, the keys of `mail_auth.PROVIDERS`) and `POSTULO_EMAIL_OAUTH_GRANT` (blank, `mailbox` or `application`), both documented with those words in the wiki's `Configuration.md:599-600`. A variable pins its field over the Email page, so a typo there cannot be corrected from the interface. - **Where:** `core/checks.py:28-33` (`CHOICES`) and `:61`, `choices`; the settings at `config/settings/base.py:729-730`; their use in `core/mail_auth.py:188-231`, `instance_token`. - **What happens:** - With `POSTULO_EMAIL_AUTH=xoauth2` and `POSTULO_EMAIL_OAUTH_PROVIDER=microsft`, the `postulo` checks return nothing (run against the snapshot with those settings), the entrypoint starts, and every message, password resets included, fails with "No identity provider is chosen for mail." (`mail_auth.py:212`). - With `POSTULO_EMAIL_OAUTH_GRANT=aplication`, `instance_token` compares the word with `MailGrant.APPLICATION`, finds it different and quietly takes the signed-in-once route (`mail_auth.py:230`), which on an instance set up for the application grant fails with "Nobody has signed in to the mail provider yet". - `google` with `application` is refused on the Email page by `_refuse_a_grant_the_provider_lacks` (`core/server_forms.py:470`), but the same pair from the environment is checked nowhere and fails on every send. - **Why it matters:** the failure lands where the module's docstring says it should not, at the first password reset, on an instance whose operator ran `check --deploy` and saw it pass. - **Fix:** add a check (the next free id, `postulo.E008`) that, when `POSTULO_EMAIL_AUTH` is `xoauth2`, requires `POSTULO_EMAIL_OAUTH_PROVIDER` to be a key of `mail_auth.PROVIDERS`; that requires `POSTULO_EMAIL_OAUTH_GRANT` to be blank or a `MailGrant` value; and that refuses `application` for a provider whose `application_grant` is false. Take the words from `mail_auth` rather than adding a second list to `CHOICES`, so the check and the code that acts on them cannot drift. ## Done when - Tests in `tests/test_checks.py` set each of the three combinations above and expect an error; they fail today because the checks return nothing.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:47:02 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#487
No description provided.