Docker install: both compose files still name the 0.2 image, so an install runs an old release and a pull can downgrade #403

Closed
opened 2026-10-01 10:46:26 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the compose files against the version, the release checklist and the wiki's install and upgrade instructions.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at CONTRIBUTING.md:333-361 (Making a release); the other locations have not moved.

Every Postulo service in both compose files names source.tiagoagueda.com/postulo/postulo:0.2, while the project is at 0.3.0 (pyproject.toml:3, ## [0.3.0] — 2026-09-16 in CHANGELOG.md); the v0.3.0 tag itself carries the same :0.2 pin. Nothing moves the pin when a release is cut. So the documented install runs the previous minor's image rather than the code, compose services and wiki beside it, without the 0.3.0 fixes, and an image built from a 0.3 checkout carries a tag that a later documented pull replaces with that older image.

Related to #251 (closed), which found that no 0.3 image had been published and made the release push and verify X.Y.Z, X.Y and latest. Publishing :0.3 does not help while the compose files still name :0.2; this issue adds the pin, the missing release step and the two upgrade paths that contradict each other.

  • Where:
    • docker/compose.yml:29, :50, :93 and docker/compose.postgres.yml:23, :51 (image: source.tiagoagueda.com/postulo/postulo:0.2), each under the comment that build: "tags the result with the same name" (docker/compose.yml:26-28).
    • Making a release in CONTRIBUTING.md:331-359, which sets the version in pyproject.toml, src/postulo/__init__.py and the changelog but never the image tag; check() in scripts/release_tools.py:146-156, which compares those three and nothing else.
    • tests/test_image_build.py, which reads compose.postgres.yml only for the database major (:157-158) and the scheduler service (:193-194).
    • The wiki repeats the pin: Installing-Postulo.md:141 and Writing-a-plugin.md:1529 (FROM source.tiagoagueda.com/postulo/postulo:0.2 for a plugin image), and Installing-Postulo.md:346 ("pinned to a minor, …/postulo:0.2").
  • What happens:
    1. Someone follows README.md:176-182 or the wiki's Installing-Postulo.md:9 (git clone, docker compose -f docker/compose.yml up -d). With both image: and build: and no pull_policy, Compose pulls the named image when it is not present locally and builds only if the pull fails, so they run the newest 0.2.x. Settings they configure from the wiki that 0.3 introduced do nothing.
    2. That build has none of the 0.3.0 security fixes, and its health probe cannot fail (the SSL-redirect fault fixed by #82 in 0.3.0).
    3. The scheduler service's healthcheck looks for /app/data/scheduler-heartbeat (docker/compose.yml:69), which the scheduler writes only from 0.3.0, so on a 0.2 image it is permanently unhealthy.
    4. With compose.postgres.yml, the 0.2 image has no psycopg (added by #219 in 0.3.0), so the entrypoint's migrate fails and the web container restarts in a loop: the documented PostgreSQL install does not start.
    5. An operator who upgrades as SECURITY.md:70-71 says ("Upgrading is a docker compose pull") stays on 0.2.x for good, though the same paragraph says only the latest release receives fixes.
    6. An operator who instead follows Upgrading in the wiki (Installing-Postulo.md:310-312: git pull, build --pull, up -d) gets a 0.3 build tagged :0.2, and the database is migrated to 0.3. Following Releases and upgrading later (Installing-Postulo.md:346-352, or SECURITY.md:70-71) replaces it with the registry's 0.2.x, which then runs against a schema newer than it knows.
  • Why it matters: the compose files are the supported install, and they silently hold every Docker user on an unsupported release with known, fixed security problems, with services that release cannot run. The two upgrade paths the documentation gives contradict each other, and combining them is a silent downgrade: old code writing to newer tables can fail on columns it does not fill, and fixes the operator believes they have are gone.
  • Fix:
    • Move every postulo image tag in both compose files, the two wiki FROM lines and Installing-Postulo.md:346 to :0.3.
    • Move the pin with the version from now on: add the step to Making a release in CONTRIBUTING.md (or have release_tools write the new minor into both compose files), and have scripts/release_tools.py check refuse a tag whose compose files name another minor.
    • Give the image built from a checkout a distinct local name (for example postulo:local, with pull_policy: build, in a separate override file) so that a pull can never replace it.
    • Say in Installing Postulo and in SECURITY.md which of the two upgrade paths applies to which install, and never both.
    • Main's compose files can already need unreleased code (the worker service at docker/compose.yml:88-106 runs manage.py work, which is still under Unreleased, #247), so point the install instructions at the latest release tag (git checkout vX.Y.Z) rather than at main, or attach the compose files to each release and link those.

Done when

  • A test in tests/test_image_build.py reads every services.*.image naming postulo/postulo in docker/compose.yml and docker/compose.postgres.yml and holds its tag to the major and minor of pyproject.toml's version; it fails today on :0.2.
  • A test in tests/test_release_tools.py gives check() a repository whose compose file names another minor than the tag and expects ReleaseError.
  • The wiki's install and upgrade sections and SECURITY.md name one upgrade path per kind of install, and no documented sequence ends with a pulled image older than the migrated database.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading the compose files against the version, the release checklist and the wiki's install and upgrade instructions. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `CONTRIBUTING.md:333-361` (*Making a release*); the other locations have not moved. Every Postulo service in both compose files names `source.tiagoagueda.com/postulo/postulo:0.2`, while the project is at 0.3.0 (`pyproject.toml:3`, `## [0.3.0] — 2026-09-16` in `CHANGELOG.md`); the `v0.3.0` tag itself carries the same `:0.2` pin. Nothing moves the pin when a release is cut. So the documented install runs the previous minor's image rather than the code, compose services and wiki beside it, without the 0.3.0 fixes, and an image built from a 0.3 checkout carries a tag that a later documented `pull` replaces with that older image. Related to #251 (closed), which found that no 0.3 image had been published and made the release push and verify `X.Y.Z`, `X.Y` and `latest`. Publishing `:0.3` does not help while the compose files still name `:0.2`; this issue adds the pin, the missing release step and the two upgrade paths that contradict each other. - **Where:** - `docker/compose.yml:29`, `:50`, `:93` and `docker/compose.postgres.yml:23`, `:51` (`image: source.tiagoagueda.com/postulo/postulo:0.2`), each under the comment that `build:` "tags the result with the same name" (`docker/compose.yml:26-28`). - *Making a release* in `CONTRIBUTING.md:331-359`, which sets the version in `pyproject.toml`, `src/postulo/__init__.py` and the changelog but never the image tag; `check()` in `scripts/release_tools.py:146-156`, which compares those three and nothing else. - `tests/test_image_build.py`, which reads `compose.postgres.yml` only for the database major (`:157-158`) and the scheduler service (`:193-194`). - The wiki repeats the pin: `Installing-Postulo.md:141` and `Writing-a-plugin.md:1529` (`FROM source.tiagoagueda.com/postulo/postulo:0.2` for a plugin image), and `Installing-Postulo.md:346` ("pinned to a minor, `…/postulo:0.2`"). - **What happens:** 1. Someone follows `README.md:176-182` or the wiki's `Installing-Postulo.md:9` (`git clone`, `docker compose -f docker/compose.yml up -d`). With both `image:` and `build:` and no `pull_policy`, Compose pulls the named image when it is not present locally and builds only if the pull fails, so they run the newest 0.2.x. Settings they configure from the wiki that 0.3 introduced do nothing. 2. That build has none of the 0.3.0 security fixes, and its health probe cannot fail (the SSL-redirect fault fixed by #82 in 0.3.0). 3. The `scheduler` service's healthcheck looks for `/app/data/scheduler-heartbeat` (`docker/compose.yml:69`), which the scheduler writes only from 0.3.0, so on a 0.2 image it is permanently unhealthy. 4. With `compose.postgres.yml`, the 0.2 image has no `psycopg` (added by #219 in 0.3.0), so the entrypoint's `migrate` fails and the web container restarts in a loop: the documented PostgreSQL install does not start. 5. An operator who upgrades as `SECURITY.md:70-71` says ("Upgrading is a `docker compose pull`") stays on 0.2.x for good, though the same paragraph says only the latest release receives fixes. 6. An operator who instead follows *Upgrading* in the wiki (`Installing-Postulo.md:310-312`: `git pull`, `build --pull`, `up -d`) gets a 0.3 build tagged `:0.2`, and the database is migrated to 0.3. Following *Releases and upgrading* later (`Installing-Postulo.md:346-352`, or `SECURITY.md:70-71`) replaces it with the registry's 0.2.x, which then runs against a schema newer than it knows. - **Why it matters:** the compose files are the supported install, and they silently hold every Docker user on an unsupported release with known, fixed security problems, with services that release cannot run. The two upgrade paths the documentation gives contradict each other, and combining them is a silent downgrade: old code writing to newer tables can fail on columns it does not fill, and fixes the operator believes they have are gone. - **Fix:** - Move every `postulo` image tag in both compose files, the two wiki `FROM` lines and `Installing-Postulo.md:346` to `:0.3`. - Move the pin with the version from now on: add the step to *Making a release* in `CONTRIBUTING.md` (or have `release_tools` write the new minor into both compose files), and have `scripts/release_tools.py check` refuse a tag whose compose files name another minor. - Give the image built from a checkout a distinct local name (for example `postulo:local`, with `pull_policy: build`, in a separate override file) so that a pull can never replace it. - Say in *Installing Postulo* and in `SECURITY.md` which of the two upgrade paths applies to which install, and never both. - Main's compose files can already need unreleased code (the `worker` service at `docker/compose.yml:88-106` runs `manage.py work`, which is still under *Unreleased*, #247), so point the install instructions at the latest release tag (`git checkout vX.Y.Z`) rather than at main, or attach the compose files to each release and link those. ## Done when - A test in `tests/test_image_build.py` reads every `services.*.image` naming `postulo/postulo` in `docker/compose.yml` and `docker/compose.postgres.yml` and holds its tag to the major and minor of `pyproject.toml`'s version; it fails today on `:0.2`. - A test in `tests/test_release_tools.py` gives `check()` a repository whose compose file names another minor than the tag and expects `ReleaseError`. - The wiki's install and upgrade sections and `SECURITY.md` name one upgrade path per kind of install, and no documented sequence ends with a pulled image older than the migrated database.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:46:26 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#403
No description provided.