Migrate to uv, update dependencies, harden login flow - #83
Merged
Merged
Conversation
Add an operator guide covering both PROPS data stores: the PostgreSQL database (pg_dump custom-format dumps or managed-Postgres snapshots, with cron automation and pg_restore recovery) and the object/media store (rclone offsite mirror, S3 versioning, or garage_data volume snapshot). The generic guidance is dependency-free for open-source/self-hosted deployments; ARK (rwts-backup) is documented separately as the operational, no-repo-dependency option for RWTS-managed deployments. Covers cadence, retention, restore drills, and the DB<->media consistency trade-off. Link the guide from the README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Users reported intermittent password failures with no clear cause. Four defects in the login flow explain them: - Rate limiting keyed on REMOTE_ADDR. Behind Traefik that is the proxy container, so all users shared one 5-per-minute bucket. Add a RATELIMIT_IP_META_KEY callable that reads the first X-Forwarded-For hop only when the proxy is trusted (SECURE_PROXY_SSL_HEADER is set). - The rate-limited response queued a message the login template never rendered, so the user saw an empty form and assumed a bad password. Render messages on the login page. - Username lookup was case-sensitive while usernames are generated in lowercase. Mobile keyboards capitalise the first letter of a text field. Fall back to a unique case-insensitive match and set autocapitalize="none" on the input. - The next parameter was followed without validation (open redirect). Accept only same-host URLs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
pyproject.toml now declares runtime dependencies and a dev group; uv.lock replaces requirements.txt. The image installs with uv sync --frozen into /usr/local on python:3.13-slim (no venv), and only includes dev tooling when INSTALL_DEV=true (dev compose profile and CI). CI checks the lockfile with uv lock --check and runs pip-audit. Dependabot now tracks the uv, GitHub Actions and Docker ecosystems. libgobject-2.0-0 no longer exists on Debian trixie; use libglib2.0-0t64. All dependencies were upgraded to their latest compatible releases within Django 5.2 LTS. pip-audit reports no known vulnerabilities. Spec §4.13 and §6.1.6 are updated on the spec branch spec/uv-dependency-management. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Node 22 to 24 LTS, Tailwind standalone CLI 4.1.18 to 4.3.3, and pin mjml to 5.4.1 so the email build is reproducible. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CACHE_URL was never documented in .env.example, and the fallback pointed at localhost. Inside a container that is unreachable, and because every page reads the site branding from the cache, each request failed with a 500. Fall back to the broker's Redis host on database 1 and document CACHE_URL. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Tests wrote media into src/media (2 GB locally). pytest walked that tree at collection, and through a Docker bind mount the suite appeared to hang. Root test media in a temporary directory and stop pytest recursing into generated directories. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The setup-uv action never started its jobs on this repository; the run failed within seconds with no annotation. pipx is preinstalled on GitHub-hosted runners. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PROPS_IMAGE selects the image repository for the prod profile. The default stays ghcr.io for self-hosters; RWTS-run deployments set it to the internal GHES registry. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GitHub Actions do not run for the organisation on github.com, so the workflows target github.realworld.net.au: self-hosted runners labelled ubuntu-latest (no ubuntu-latest-large), images published to containers.github.realworld.net.au, and uv pinned to 0.12.15 on the runner. github.com stays the public mirror. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The same workflows run on github.com (publishing to ghcr.io) and on the internal GHES (publishing to its registry), so either host can be the active CI home. The runner label comes from the RUNNER_LABEL repository variable, default ubuntu-latest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
pipx is not present on the GHES runner image. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GHES cannot resolve recent setup-uv tags through GitHub Connect, and the runner image has no pipx. The installer is pinned to 0.12.15. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GHES does not support upload-artifact v4, so the image no longer travels between jobs. The release workflow builds, tests and publishes in a single job. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pin the installer by SHA-256 and install into RUNNER_TEMP so nothing persists on a shared runner PATH. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Dockerfile and .env.example are excluded by .dockerignore, matching the existing docker-compose.yml skip. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
MJML 5 (released 2026-04-16) drops the header include, and with it the brand colour and logo template variables, from the compiled emails. The unpinned install has produced unbranded emails in every image built since then and broke the email template tests in CI. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The image carries only GIT_COMMIT. The release version reaches the app through the APP_VERSION environment variable, which compose fills from PROPS_VERSION, so one image per commit can be promoted from a pull request to develop and then to a release without a rebuild. Sentry keeps using APP_VERSION as the release. The `test` target layers the dev dependency group on the `base` stage for CI and the dev compose profile; the default `runtime` target is what gets published and contains no dev tooling. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A develop-to-main pull request has the develop merge commit as its head, which promote-develop already tagged. That image was tested when its pull request merged, so CI only records the existing image. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Maintenance pass after a few months without changes: move dependency management from pip-tools to uv, upgrade all Python and frontend build dependencies, and fix the login flow defects behind the reported "intermittent password failures".
Spec Alignment
Section 4.13 and 6.1.6 mandate pip-tools. The matching spec change is on the spec repo branch
spec/uv-dependency-managementand must be approved with this PR.Changes
nextparameter allowed an open redirect.pyproject.tomlanduv.lockreplacerequirements.in/.txt. Image ispython:3.13-slim, installs withuv sync --frozeninto/usr/local; dev tooling only withINSTALL_DEV=true. CI runsuv lock --checkandpip-audit. Dependabot config for uv, Actions and Docker.libgobject-2.0-0no longer exists on trixie; replaced withlibglib2.0-0t64.CACHE_URLwas undocumented and defaulted to localhost, which 500s every page in a container. It now follows the Celery broker host.Test Plan
pytest) — 2775 passed, 6 skipped, 83 xfaileddocker compose exec web pytest) — 2775 passedblack src/ && isort src/ && flake8 src/)Notes
.envshould gainCACHE_URL=redis://redis:6379/1for clarity, although the new fallback makes it optional.🤖 Generated with Claude Code