Skip to content

v0.10.0

Choose a tag to compare

@dholbach dholbach released this 30 Oct 07:46
· 44 commits to main since this release
90dd67e

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.py and docker-compose.prod.yml first (./prod.py update prints the curl commands), 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_backups is removed; ./prod.py backup prunes 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_KEY is unset. ./prod.py always generates one, so only a hand-built .env is 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, CSP frame-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_duplicates never deletes bank-linked records or records with receipts.
    • seed_sample_data --clear only touches its own demo data.

Fixes

  • GDPR erasure now also removes the client's converted inquiry and imported calendar events.
  • clearbanktransactions --with-financials deletes only the records the selected transactions link to.

Backups, restore and 2FA

  • ./prod.py update backs up before migrating (--skip-backup to 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_inquiries runs 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