Super-linter ran from the unpinned :latest image and, because of
branches-ignore: [master], never on pull requests to master. Ruff now
checks syntax errors and pyflakes rules (E9, F) on every push and PR.
Fixes the existing findings: unused imports and variables, an unused
duplicate import in instances/tests.py, and the star import in
accounts/views.py. settings-dev.py keeps its star import of the base
settings.
The forced change of the generated admin password was a session flag
set at login when the password still matched data/admin_password. A
new session after the file was gone bypassed it.
- UserAttributes.must_change_password (migration 0007) holds it; the
admin created with a generated password gets it, and a password
change clears it. ForcePasswordChangeMiddleware reads it.
- A system check (accounts.E001) stops the server unless the middleware
follows AuthenticationMiddleware; the README has the settings change.
- If the generated password cannot be stored privately, provisioning
stops without printing it and without creating the admin (one
transaction for the user and its attributes).
- The admin is provisioned on any real migrate run while no user
exists, so running migrate again after a failure creates it; flush
(plan=None) and rollbacks of accounts are skipped.
- The post_migrate receivers check the migration state for the models
they use, so a targeted migrate on a fresh database (e.g. migrate
appsettings) no longer fails with 'no such table'.
- user_block, user_unblock and admin_email_otp changed state on GET, so an
<img> tag could lock a user out or trigger OTP emails through an
admin's session. They now require POST; the buttons are CSRF forms.
- The console token cookie is set with httponly, SameSite=Lax and, on
HTTPS, secure. Only novncd reads it; the page gets the token directly.