CI has tested nothing for a fortnight: a collection error only a developer's .env hides #117
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Postulo/postulo#117
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observation
Every CI run since run 128 has failed, on
main, on every push — fourteen consecutive commits. The failure is intest (3.12),test (3.13),test (3.14)andbrowser;stylesandsecuritypass throughout.Why it went unnoticed for a fortnight
It passes on a developer's machine.
config/settings/prod.pyrefuses to import withoutPOSTULO_SECRET_KEY, which is correct of it. The repository's.env— gitignored, and belonging to whoever is developing here — supplies one, so the module imports locally and the suite is green. CI has no.env, so the import raises.It is a collection error, so it aborts the whole run. Not one failing test: no tests run at all.
testfell from ~100s to ~35s andbrowserfrom 172s to ~64s, which is the shape of a suite that never started.And the two jobs that pass are the two that never run pytest.
stylesbuilds the stylesheet,securityaudits dependencies. So the signal was "CI is red" without any indication that nothing was being tested.The same class of bug was found and fixed during #84 —
tests/security/test_health_redirect.pyalso depended on the developer's.envsupplyingPOSTULO_TIME_ZONE— and an autouse fixture now clears theENV_OVERRIDESvariables for every test. It could not have caught this one:POSTULO_SECRET_KEYis not one of those variables, and a collection error happens before any fixture runs.The irony worth recording
tests/security/test_requests.py, in the same directory, had already solved this exactly right, and says so in a comment:It reads the production settings in a subprocess with every
POSTULO_*variable stripped. The file next to it imported the module directly.The fix
One way to read production, in
tests/security/conftest.py, used by both files: a session-scoped fixture running that subprocess.test_health_redirect.pytakes the exemption list from the fixture instead of importingprodat module scope, which keeps the property it wanted — the list is read from what ships, never retyped — without needing a secret key to collect.Reproduced by moving
.envaside: collection aborts with CI's exact error before the change, and 1595 unit tests and 33 browser tests pass after it.Worth doing separately
Nothing in CI says "the suite did not run" differently from "the suite failed". A collection error and a failing assertion look the same from the outside, and this one hid for a fortnight behind a red mark that everybody had stopped reading.
Classification
Bug. Tier 2: no user-visible defect, and the project's stated assurance — a suite that runs on every push — was not true for a fortnight.