Repository navigation
v0.10.0
A security release from four source reviews (views and settings, bank import, practice scoping, admin and operator tooling), plus safer backups, restores and updates.
Upgrading
- Download the new
prod.pyanddocker-compose.prod.ymlfirst (./prod.py updateprints thecurlcommands), then run./prod.py update. It now takes a backup before restarting. - Three migrations run on start (
0009–0011). All are validation or key-widening only; existing rows already satisfy them. - The backup directory is mounted read-only into the app container.
manage.py prune_old_backupsis removed;./prod.py backupprunes after every verified run. - The hourly scheduled jobs now run the inquiry retention pass. Preview what the first run will change with
./prod.py manage tidy_inquiries. - With DEBUG off, the app refuses to start if
DJANGO_SECRET_KEYis unset../prod.pyalways generates one, so only a hand-built.envis affected.
Highlights
Security
- The dev stack no longer listens on the local network.
- Spelling a username with lookalike characters no longer gets around the login lockout.
- POST-only state changes,
?next=same-host checks, CSPframe-ancestors 'none', Ghostscript-dSAFER, an upload extension allowlist on the model fields. - Bank import:
- A sender-written payment reference can no longer abort a CSV import.
- Imports are atomic, and a failing row is isolated from the rest.
- Review actions are re-checked on the server.
- A second payment from a different payer with the same reference is no longer dropped as a duplicate.
- Practice isolation: fixes several latent cross-practice leaks in aggregates, revenue helpers and calendar suggestions. A new guardrail test flags unbound queries.
- Calendar: the hourly sync no longer books sessions from invitations someone else sent.
- Operator commands:
remove_financial_duplicatesnever deletes bank-linked records or records with receipts.seed_sample_data --clearonly touches its own demo data.
Fixes
- GDPR erasure now also removes the client's converted inquiry and imported calendar events.
clearbanktransactions --with-financialsdeletes only the records the selected transactions link to.
Backups, restore and 2FA
./prod.py updatebacks up before migrating (--skip-backupto opt out).- Restore is all-or-nothing:
- both archives are verified first;
- the database is restored in a single transaction;
- media is staged and swapped only after unpacking succeeds;
- all sessions are signed out afterwards.
- The backup directory is kept at 0700. The encrypted-backup self-check no longer writes a plaintext copy.
- Turning two-factor sign-in on or off, or running
two_factor_reset, signs the user out of their other sessions.
Inquiries
tidy_inquiriesruns hourly. Inquiries with no step for 60 days lapse, and closed non-client inquiries are anonymised 180 days after the last contact.
Full changelog: docs/CHANGELOG.md