Server settings: \"Not set here\" in a three-state policy select is saved as \"No\ #493

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

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading PolicyField and cleaning an empty value with it.

Checked again on 2026-10-01 against main at 0a5cad587: still present.

PolicyField offers three states, "Not set here — the environment or the default applies", "Yes" and "No", and the model stores the first as NULL. The first state can never be saved: choosing it stores False, and the page shows "No" after saving.

  • Where: core/server_forms.py:19-36, PolicyField. The converter is a static method named _coerce, which shadows TypedChoiceField._coerce, the method TypedChoiceField.clean() calls to turn an empty value into empty_value before converting anything else.
  • What happens: with the base method replaced, clean("") runs the field's own converter on the empty string and returns "" == "true", which is False; empty_value=None is never used. Checked: PolicyField().clean("") and PolicyField().clean(None) both return False, and posting the Sign-in page with registration_open empty over a stored True leaves False in the row. It affects every PolicyField: registration_open, sso_is_second_factor and email_sign_in on Sign-in, and capture_ignore_robots, capture_keep_source and capture_keep_rendering on Capture.
  • Why it matters: an administrator who wants to hand a decision back to the environment or the default cannot; the row records an explicit No and the page says so. Every fallback is False today, so what the instance does is the same, but the stored state is wrong, and any policy whose fallback is True would be switched off by choosing "Not set here".
  • Fix: rename the converter (for example _to_bool) and pass coerce=self._to_bool, leaving TypedChoiceField._coerce in place, so an empty choice becomes None.

Done when

  • tests/test_server_settings.py has a test that stores registration_open = True, posts the Sign-in page with registration_open empty and finds None stored, and the page drawing "Not set here" as the selected option. It fails today.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading `PolicyField` and cleaning an empty value with it. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. `PolicyField` offers three states, "Not set here — the environment or the default applies", "Yes" and "No", and the model stores the first as `NULL`. The first state can never be saved: choosing it stores `False`, and the page shows "No" after saving. - **Where:** `core/server_forms.py:19-36`, `PolicyField`. The converter is a static method named `_coerce`, which shadows `TypedChoiceField._coerce`, the method `TypedChoiceField.clean()` calls to turn an empty value into `empty_value` before converting anything else. - **What happens:** with the base method replaced, `clean("")` runs the field's own converter on the empty string and returns `"" == "true"`, which is `False`; `empty_value=None` is never used. Checked: `PolicyField().clean("")` and `PolicyField().clean(None)` both return `False`, and posting the Sign-in page with `registration_open` empty over a stored `True` leaves `False` in the row. It affects every `PolicyField`: `registration_open`, `sso_is_second_factor` and `email_sign_in` on Sign-in, and `capture_ignore_robots`, `capture_keep_source` and `capture_keep_rendering` on Capture. - **Why it matters:** an administrator who wants to hand a decision back to the environment or the default cannot; the row records an explicit No and the page says so. Every fallback is `False` today, so what the instance does is the same, but the stored state is wrong, and any policy whose fallback is `True` would be switched off by choosing "Not set here". - **Fix:** rename the converter (for example `_to_bool`) and pass `coerce=self._to_bool`, leaving `TypedChoiceField._coerce` in place, so an empty choice becomes `None`. ## Done when - `tests/test_server_settings.py` has a test that stores `registration_open = True`, posts the Sign-in page with `registration_open` empty and finds `None` stored, and the page drawing "Not set here" as the selected option. It fails today.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:47:05 +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#493
No description provided.