feat: complete dockerization (optional)
This commit is contained in:
1 parent
3e01c29657
commit
d275ba3c14
38 files changed
+1244
-20
No files matched your search
@@ -0,0 +1,87 @@
|
||||
Feature: Container-aware update guidance
|
||||
|
||||
As the owner of a RenewCMS site running in Docker
|
||||
I want Settings to say "update by pulling a new image" instead of "Not prepared"
|
||||
So that I never see a browser-update flow that cannot work in a container
|
||||
|
||||
Background:
|
||||
Given browser updates need Linux with systemd and the helper that "renewcms enable-browser-updates" configures
|
||||
And a binary replaced inside a container is lost when the container is recreated,
|
||||
so in a container the update is a new image: "docker compose pull && docker compose up -d"
|
||||
And config.Settings gains Container bool, read from the env var RENEWCMS_CONTAINER (default "false", set to "true" by the Dockerfile and docker-compose.yml)
|
||||
And RENEWCMS_CONTAINER is added to envDefaults in cmd/server/main.go, to .env.example and to docs/configuration.md; it is not in requiredEnvVars
|
||||
And only "true" (case-insensitive) enables container mode; any other value means false
|
||||
And the update status use case receives the bool through its constructor from api/dependecyInjection.go; internal/domain/update stays stdlib only
|
||||
And the update check, update-status.json and the release feed work unchanged in container mode
|
||||
And GET /v1/system/update gains a 13th key, container (bool), after started_at; the other 12 keys are unchanged
|
||||
And in container mode can_apply is false for everyone, even if update-helper.json exists in the data directory
|
||||
And POST /v1/system/update/download and /restart keep their guards and answer 409 because can_apply is false (existing behaviour, not re-specified)
|
||||
And errors stay plain text from http.Error
|
||||
And the user approved the copy below and the 13th key on 2026-10-05; docs/design is read-only for agents, so the design files are updated by the user, and the visual gate for container states stays PENDING until a board frame exists
|
||||
|
||||
Scenario Outline: The status carries the container flag
|
||||
Given RENEWCMS_CONTAINER is "<value>"
|
||||
When a verified user sends GET /v1/system/update
|
||||
Then the JSON key container is <flag>
|
||||
|
||||
Examples:
|
||||
| value | flag |
|
||||
| true | true |
|
||||
| TRUE | true |
|
||||
| false | false |
|
||||
| | false |
|
||||
| yes | false |
|
||||
|
||||
Scenario: Container mode disables apply even with a helper
|
||||
Given RENEWCMS_CONTAINER is "true" and HelperDetector reports the helper installed
|
||||
When the owner sends GET /v1/system/update
|
||||
Then can_apply is false and container is true
|
||||
And a newer stored result still reports available true, latest and notes
|
||||
|
||||
Scenario: The check still works in a container
|
||||
Given container mode and a feed that reports "v2.9.0-beta" newer than the running "v2.8.0-beta"
|
||||
When the owner sends POST /v1/system/update/check
|
||||
Then the status is 200 and available is true and the result is stored in update-status.json
|
||||
|
||||
Scenario Outline: Download and restart are refused in a container
|
||||
Given container mode and a stored newer release
|
||||
When the owner sends POST <path>
|
||||
Then the status is 409 and no job starts and the fetcher and the restart request writer are not called
|
||||
|
||||
Examples:
|
||||
| path |
|
||||
| /v1/system/update/download |
|
||||
| /v1/system/update/restart |
|
||||
|
||||
Scenario: Host installs are unchanged
|
||||
Given RENEWCMS_CONTAINER is unset
|
||||
Then container is false and can_apply follows the helper as before
|
||||
And "Not prepared" still shows its "renewcms enable-browser-updates" command
|
||||
|
||||
Scenario: Settings, owner, container, update available (route /settings)
|
||||
Given GET /v1/system/update resolves available true, container true, can_apply false, latest "v2.9.0-beta"
|
||||
Then the block uses the "Not prepared" frame's layout: icon info, tone info
|
||||
And the title reads "Version 2.9.0-beta is available"
|
||||
And the text reads "You have v2.8.0-beta. This site runs in Docker, so it updates by pulling a new image. Run the commands below on the server."
|
||||
And a server-command block reads "docker compose pull && docker compose up -d" with the Copy button ("Copied" with a check for 2 s, announced)
|
||||
And a link "How to update" with arrow-up-right points to docs/docker.md
|
||||
And no Update, Restart or "Check for updates" button is rendered
|
||||
And the "renewcms enable-browser-updates" command and its note are not rendered
|
||||
|
||||
Scenario: Settings, owner, container, up to date
|
||||
Given container true and available false
|
||||
Then "You're up to date" shows as in the existing Up to date state, the Restart button is not rendered and the container hint is not rendered
|
||||
And "Check for updates" is still offered
|
||||
|
||||
Scenario: Settings, admin, container
|
||||
Given the session role is "admin", container true and available true
|
||||
Then the existing Admin view shows unchanged ("Only the owner can update RenewCMS.") with no command block
|
||||
|
||||
Scenario: Settings, non-container, no helper
|
||||
Given container false and can_apply false
|
||||
Then the existing "Not prepared" state shows unchanged
|
||||
|
||||
Scenario: The shipped Docker setup turns container mode on
|
||||
Given the Dockerfile and docker-compose.yml
|
||||
Then both set RENEWCMS_CONTAINER=true
|
||||
And docs/docker.md and docs/configuration.md describe the variable
|
||||
@@ -0,0 +1,25 @@
|
||||
# QA: Container update guidance
|
||||
|
||||
## Automated (Go, test/, httptest)
|
||||
1. Fakes: in-memory update status store, fake FeedClient, fake HelperDetector, fake JobStore and restart writer, validator.InitValidator(). Mount NewSystemRouter on a fresh chi.NewRouter() with jwtauth.Verifier + Authenticator and a test jwtauth.New("HS256", ...).
|
||||
2. Parse RENEWCMS_CONTAINER through config.NewSettingsFromEnv with t.Setenv over the table in the feature (true, TRUE, false, empty, yes).
|
||||
3. GET status: container key present and equal to the table; the other 12 keys are unchanged.
|
||||
4. Container true with a helper present: can_apply false for the owner.
|
||||
5. POST check in container mode: 200, available true, stored.
|
||||
6. POST download and restart in container mode: 409, no fake called.
|
||||
7. Container false: the existing updates_* tests still pass.
|
||||
8. An admin receives can_apply false and container true.
|
||||
|
||||
## SPA (Vitest, mocked /v1)
|
||||
- Container + available: the block, command, Copy, "How to update", and no buttons. Reuse the "Not prepared" sample data from the board.
|
||||
- Container + up to date: no Restart.
|
||||
- Admin: the existing admin view.
|
||||
- Non-container "Not prepared": unchanged.
|
||||
- Visual: container states are PENDING until a board frame exists; report as PENDING, never as passing. Existing states must still pass `task visual:check -- settings`.
|
||||
|
||||
## Manual (real Docker, ./docker-compose.yml)
|
||||
1. `docker compose up -d --build`; confirm RENEWCMS_CONTAINER=true with `docker compose exec renewcms env`.
|
||||
2. Point UPDATE_FEED_URL at a feed with a newer release; log in as owner; /settings shows the container block, no Update or Restart.
|
||||
3. The Copy button puts the exact command on the clipboard.
|
||||
4. Run the shown command on a host that has a newer image; Settings shows the new version afterwards.
|
||||
5. Run the binary on the host without the variable: "Not prepared" shows the old command.
|
||||
@@ -0,0 +1,45 @@
|
||||
Feature: Docker deployment
|
||||
RenewCMS can run in a container built from the repository. The container
|
||||
reuses the existing configuration contract in cmd/server/main.go
|
||||
(requiredEnvVars, envDefaults); no new variables are introduced.
|
||||
|
||||
Background:
|
||||
Given the image is built with the default build, without the nofrontend tag
|
||||
And the container runs the binary directly as PID 1 under a non-root user
|
||||
And the environment sets DB_FILE and UPLOAD_DIR to paths on a named volume
|
||||
And the required variables PUBLIC_URL, JWT_SECRET, SMTP_LOGIN, SMTP_SENDER, SMTP_PASSWORD, SMTP_HOST and SMTP_PORT come from an env file at runtime
|
||||
|
||||
Scenario: Healthy start
|
||||
When the container starts with every required variable set
|
||||
Then it logs "RenewCMS <version> (production) listening on :8080"
|
||||
And GET /healthz on the published port returns 200 with the body "ok"
|
||||
|
||||
Scenario: Frontend and API are both served
|
||||
When the container is running
|
||||
Then GET / returns 200 with the SPA index.html
|
||||
And GET /v1/auth/registration returns 200 with a JSON body
|
||||
|
||||
Scenario Outline: A missing required variable stops the container
|
||||
When the container starts without <variable>
|
||||
Then the process exits with a non-zero status
|
||||
And the log contains "Environment variable <variable> is not set"
|
||||
|
||||
Examples:
|
||||
| variable |
|
||||
| PUBLIC_URL |
|
||||
| JWT_SECRET |
|
||||
| SMTP_LOGIN |
|
||||
| SMTP_SENDER |
|
||||
| SMTP_PASSWORD |
|
||||
| SMTP_HOST |
|
||||
| SMTP_PORT |
|
||||
|
||||
Scenario: Data survives container recreation
|
||||
Given an account was registered while the container was running
|
||||
When the container is removed and recreated on the same named volume
|
||||
Then the same account can log in
|
||||
|
||||
Scenario: Graceful shutdown on SIGTERM
|
||||
When the container receives SIGTERM
|
||||
Then the log contains "shutting down..."
|
||||
And the container exits with status 0 within 10 seconds
|
||||
@@ -0,0 +1,98 @@
|
||||
# QA: Docker deployment
|
||||
|
||||
Packaging and docs only. There is no Go test in test/ and no Vitest spec for this slice. All steps are manual command steps run from a clean checkout on a machine with Docker and Compose v2. Record results in the Notes table. Anything not run is reported NOT RUN, never PASS.
|
||||
|
||||
## Preconditions
|
||||
- Clean checkout, no bin/, tmp/, node_modules or internal/infrastructure/assets/dist present.
|
||||
- docker.env created from docker.env.example. JWT_SECRET is generated (openssl rand -hex 32) and SMTP values are real or placeholders. Nothing is committed.
|
||||
- For local HTTP trial, ENVIRONMENT=development (otherwise the Secure cookie is not stored over HTTP).
|
||||
|
||||
## Static checks (no Docker daemon needed)
|
||||
1. Dockerfile, .dockerignore and docker-compose.yml contain no comment lines (no line starting with `#`, no trailing ` #`).
|
||||
2. .dockerignore lists tmp/, bin/, node_modules (also web/node_modules), .git, internal/infrastructure/assets/dist, .env and docker.env.
|
||||
3. Dockerfile: three stages (bun, go, final). The Go build sets CGO_ENABLED=0, has no `-tags nofrontend`, and uses `-ldflags` containing `-X main.version=` from a build arg. The final stage has USER non-root, exec-form ENTRYPOINT (no `sh -c`), and no ENV, ARG or COPY holding JWT_SECRET or any SMTP_* value.
|
||||
4. docker-compose.yml: one service, a named volume mounted at the data directory, a `ports` entry, `env_file`, a healthcheck on /healthz, `stop_grace_period` >= 15s.
|
||||
5. git diff --stat shows no change under api/, internal/, web/src/, cmd/ and test/. Only Dockerfile, .dockerignore, docker-compose.yml, docker.env.example, Taskfile.yml, .gitignore, README.md and docs/ changed. No new env var appears in cmd/server/main.go.
|
||||
6. docs/docker.md exists and is linked from README.md and docs/deployment.md.
|
||||
7. `task --list` shows docker:build, docker:run, docker:up, docker:down and docker:logs.
|
||||
|
||||
## Build
|
||||
8. `task docker:build` succeeds from the clean checkout, with no pre-built SPA.
|
||||
9. `docker run --rm <image> --version` prints the version, which is not `dev`.
|
||||
10. `docker image ls` size recorded. Flag it if it is above roughly 40 MB.
|
||||
11. `docker image inspect` shows a non-root User, and `docker run --rm --entrypoint id <image>` shows uid not 0.
|
||||
12. `docker history --no-trunc <image>` contains none of the values in docker.env.
|
||||
|
||||
## Run
|
||||
13. `task docker:up` starts the service. `docker compose ps` shows it healthy within the healthcheck start period.
|
||||
14. `curl -i http://localhost:8080/healthz` returns 200 and body `ok`.
|
||||
15. `curl -i http://localhost:8080/` returns 200 text/html, and the SPA loads in a browser.
|
||||
16. `curl -i http://localhost:8080/v1/auth/registration` returns 200 with JSON.
|
||||
17. Logs show the listening line, and no permission error creating DB_FILE or UPLOAD_DIR on the volume.
|
||||
18. Register an account in the SPA, then upload an image, to confirm both the DB and UPLOAD_DIR are writable by the container user.
|
||||
|
||||
## Persistence
|
||||
19. `docker compose down` (no -v), then `task docker:up`. The account from step 18 can log in and the image is still served.
|
||||
20. `docker compose down -v` removes the volume, and the next start gives an empty instance. Documented in docs/docker.md.
|
||||
21. The backup procedure in docs/docker.md is followed once and restores into a fresh volume.
|
||||
|
||||
## Failure and shutdown
|
||||
22. For each required variable in turn, remove it from the env file and run `docker compose up`. The container exits non-zero and the log contains `Environment variable <NAME> is not set`.
|
||||
23. `docker compose stop` (timed) completes in under 10 s, the log contains `shutting down...`, and the exit code is 0. This proves PID 1 receives SIGTERM.
|
||||
24. Break the healthcheck (stop the app inside the container, or point it at the wrong port): the service becomes unhealthy.
|
||||
|
||||
## SMTP (manual, needs real SMTP)
|
||||
25. With an external SMTP host, trigger a registration or password-reset email and confirm delivery.
|
||||
26. With a host MTA via host.docker.internal, repeat. On Linux this needs the extra_hosts mapping documented.
|
||||
27. Confirm the failure mode is documented when SMTP is unreachable.
|
||||
|
||||
## Reverse proxy and TLS (manual)
|
||||
28. Put Caddy or nginx in front, per docs/docker.md, with ENVIRONMENT=production over HTTPS. Log in and confirm the Secure cookie is accepted.
|
||||
29. Set TRUSTED_PROXIES to the proxy address as seen by the container and confirm the login rate limiter uses X-Real-IP.
|
||||
|
||||
## Upgrade
|
||||
30. Follow docs/docker.md: back up, rebuild with `task docker:build`, `task docker:up`. Data is intact and `--version` shows the new version.
|
||||
31. Confirm docs state that browser-update Restart is unsupported in Docker (Settings shows "Not prepared").
|
||||
|
||||
## Notes to record
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Image size | |
|
||||
| Base images and tags used | |
|
||||
| Container uid | |
|
||||
| Build time (cold) | |
|
||||
| Docker and Compose versions | |
|
||||
| Steps 25-29 run? | |
|
||||
|
||||
Not run in this slice: CI, registry publishing, Kubernetes or Helm, multi-arch. SPA tests and visual checks are out of scope.
|
||||
|
||||
## Results
|
||||
Run on Windows 11, Docker 29.8.1, Compose 5.5.1, with a throwaway docker.env (fake secrets, ENVIRONMENT=development) that was deleted afterwards.
|
||||
|
||||
| Steps | Result |
|
||||
| --- | --- |
|
||||
| 1-7, 31 | PASS |
|
||||
| 8 | PASS after a fix: `bun run build` failed in the image because vue-tsc cannot resolve .vue modules under the Bun-only node fallback; the Dockerfile now runs `bun run build-only`. vue-tsc passes on the host and under real node 22 |
|
||||
| 9, 11, 12 | PASS (version v2.8.0-beta-dirty, uid 10001, entrypoint exec form, no secret names in history) |
|
||||
| 10 | 54.5 MB, above the 40 MB flag (binary 29.9 MB on alpine 3.22) |
|
||||
| 13-17 | PASS (healthy, /healthz 200 ok, / 200 text/html, /v1/auth/registration 200 JSON, no permission errors) |
|
||||
| 18-19 | PASS (register, verify, login, image upload to /data/uploads as uid 10001; all survive `down` and recreate; uploaded image still served) |
|
||||
| 20 | PASS (`down -v` removed the volume) |
|
||||
| 21 | PASS (tar backup, `down -v`, restore, login and media list intact) |
|
||||
| 22 | PASS for all 7 vars (exit 2, `Environment variable X is not set`) |
|
||||
| 23 | PASS (stop 0.4 s, exit 0, `shutting down...` logged) |
|
||||
| 24 | PASS (wrong-port healthcheck reports unhealthy) |
|
||||
| 25 | PARTIAL: mail delivered over STARTTLS to a Mailpit container on the compose network with the CA trusted via SSL_CERT_FILE; no real external host |
|
||||
| 26-29 | NOT RUN (host MTA, Caddy/nginx TLS, TRUSTED_PROXIES) |
|
||||
| 30 | NOT RUN as a before/after upgrade |
|
||||
| `task docker:run` | PASS (healthz 200, graceful stop, separate volume renewcms-data) |
|
||||
|
||||
Notes
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Image size | 54.5 MB |
|
||||
| Base images and tags used | oven/bun:1-alpine, golang:1.27.1-alpine, alpine:3.22 |
|
||||
| Container uid | 10001 |
|
||||
| Build time (cold) | not measured, layers were partly cached; about 18 s warm |
|
||||
| Docker and Compose versions | 29.8.1, 5.5.1 |
|
||||
| Steps 25-29 run? | 25 partial, 26-29 no |
|
||||
@@ -0,0 +1,71 @@
|
||||
Feature: Publish the RenewCMS image to a registry so an upgrade is "docker compose pull"
|
||||
|
||||
As a maintainer
|
||||
I want one task that builds and pushes a versioned multi-arch image
|
||||
So that site operators upgrade with "docker compose pull && docker compose up -d" and never build from source
|
||||
|
||||
Background:
|
||||
Given there is no CI pipeline on purpose; publishing is a maintainer-run task, like "task release"
|
||||
And the registry is the Gitea registry of git.floriansylvain.fr and REGISTRY_IMAGE defaults to "git.floriansylvain.fr/fsylvain/renewcms"
|
||||
And the Dockerfile and docker-compose.yml from docker-deployment exist and are unchanged except where stated here
|
||||
And Taskfile.yml gains "docker:publish", with variables REGISTRY_IMAGE and VERSION (default: git describe --tags)
|
||||
And "docker:publish" refuses to run, before building anything, when REGISTRY_IMAGE is empty, when VERSION is not an exact tag "vX.Y.Z" or "vX.Y.Z-<pre>", or when the work tree is dirty
|
||||
And the build is "docker buildx build --platform linux/amd64,linux/arm64 --build-arg VERSION=<tag>"; the tag is baked in through the existing version ldflags path, so the image's "renewcms --version" prints the tag
|
||||
And tags pushed for vX.Y.Z-<pre>: "vX.Y.Z-<pre>" and "X.Y.Z-<pre>" and the moving tag "<pre-name>" (for example "beta"); "latest" is NOT moved
|
||||
And tags pushed for vX.Y.Z: "vX.Y.Z", "X.Y.Z", "X.Y", and "latest"
|
||||
And the maintainer authenticates beforehand with "docker login git.floriansylvain.fr"; the task never reads, stores or echoes a password or token, and never passes credentials on a command line
|
||||
And no secret, .env, signing key or JWT_SECRET is copied into the image (already enforced by .dockerignore; checked again here)
|
||||
And no image signing or attestation is part of this slice; the Ed25519 key signs release binaries only
|
||||
And "task docker:publish -- --dry-run" builds for the host platform only with "--load", pushes nothing, needs no login and prints the tags it would push
|
||||
And docker-compose.yml uses "image: ${RENEWCMS_IMAGE:-git.floriansylvain.fr/fsylvain/renewcms:beta}" (the default tag is "beta" because "latest" does not exist until the first stable release; it is changed to "latest" then) and its "build:" block moves to docker-compose.build.yml, used as "docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build"
|
||||
And docs/docker.md, docs/deployment.md and README.md document pull-based upgrade, the build override, the tag scheme and the maintainer publish steps; no comments in any file
|
||||
And the real push is a manual item: it needs a registry account and network
|
||||
|
||||
Scenario Outline: Tags for a version
|
||||
Given VERSION is "<version>"
|
||||
When "task docker:publish -- --dry-run" runs
|
||||
Then it prints exactly these tags: <tags>
|
||||
|
||||
Examples:
|
||||
| version | tags |
|
||||
| v2.9.0 | v2.9.0, 2.9.0, 2.9, latest |
|
||||
| v2.9.0-beta | v2.9.0-beta, 2.9.0-beta, beta |
|
||||
| v2.9.0-rc.1 | v2.9.0-rc.1, 2.9.0-rc.1, rc |
|
||||
|
||||
Scenario Outline: Refusals before any build
|
||||
Given <condition>
|
||||
When "task docker:publish" runs
|
||||
Then it exits non-zero with a message naming the problem and docker is not invoked
|
||||
|
||||
Examples:
|
||||
| condition |
|
||||
| REGISTRY_IMAGE is empty |
|
||||
| VERSION is "dev" |
|
||||
| VERSION is "2.9.0" (no leading v) |
|
||||
| the work tree has uncommitted changes |
|
||||
|
||||
Scenario: Dry run builds and loads a working image
|
||||
When "task docker:publish -- --dry-run" runs with VERSION "v2.9.0-beta"
|
||||
Then an image is loaded locally for the host platform and no registry is contacted
|
||||
And running it prints "v2.9.0-beta" for --version
|
||||
And it serves GET /healthz as ok with the env from docker.env.example
|
||||
And it runs as the non-root user with the data volume as in docker-deployment
|
||||
|
||||
Scenario: No secrets in the image
|
||||
Given the dry-run image
|
||||
Then "docker history" and a file listing show no .env, no release.key, no JWT_SECRET value and no SMTP password
|
||||
|
||||
Scenario: Compose pulls by default
|
||||
Given docker-compose.yml with RENEWCMS_IMAGE unset
|
||||
Then "docker compose config" shows the image "git.floriansylvain.fr/fsylvain/renewcms:beta" and no build section
|
||||
And with RENEWCMS_IMAGE set to a tag, that tag is used
|
||||
And with docker-compose.build.yml added, the build section is present and the image builds from the local Dockerfile
|
||||
|
||||
Scenario: Upgrade is a pull
|
||||
Given a running stack on tag "v2.8.0-beta" with data in the volume
|
||||
When the operator runs "docker compose pull && docker compose up -d" after a newer tag is pushed
|
||||
Then the container is recreated on the new image and the articles, uploads and database in the volume are intact
|
||||
And GET /v1/settings reports the new version
|
||||
|
||||
Scenario: Docs say the same thing
|
||||
Then docs/docker.md, docs/deployment.md and README.md each show the pull upgrade, the tag scheme and the maintainer flow, and none claims CI exists
|
||||
@@ -0,0 +1,29 @@
|
||||
# QA: Docker image publishing
|
||||
|
||||
Everything runs on the real local Docker daemon, with no registry push. On Windows use MSYS_NO_PATHCONV=1 under Git Bash and put the Docker bin on PATH (memory: docker-windows-gotchas).
|
||||
|
||||
## Automated / scripted
|
||||
1. Refusals: run "task docker:publish" with REGISTRY_IMAGE empty, VERSION=dev, VERSION=2.9.0, and a dirty tree; assert non-zero exit and that no docker build started (compare "docker buildx ls" and the image list before and after).
|
||||
2. Tag table: run "task docker:publish -- --dry-run" with VERSION=v2.9.0, v2.9.0-beta and v2.9.0-rc.1 (the VERSION override is accepted only with --dry-run); compare the printed tags with the feature.
|
||||
3. Dry run: the image is loaded; "docker run --rm <image> --version" prints the tag; start the stack from docker.env.example and check GET /healthz is ok, and "docker exec <ctr> id -u" is not 0.
|
||||
4. Secrets: "docker history --no-trunc" and a file search for .env and release.key inside the image are clean; grep the layers for the sample JWT_SECRET value.
|
||||
5. Compose: "docker compose config" with and without RENEWCMS_IMAGE, and with the build override.
|
||||
6. Upgrade simulation: tag two local images v-old and v-new, run the stack on v-old, write an article, switch RENEWCMS_IMAGE to v-new, "docker compose up -d", and verify the article and the new version.
|
||||
7. Docs: grep the three docs for "docker compose pull", the tag scheme, and the absence of CI claims.
|
||||
8. No credentials: grep Taskfile.yml and docs for token or password literals; the task must not call "docker login".
|
||||
|
||||
## Manual (user performs; needs the registry)
|
||||
- `docker login git.floriansylvain.fr`; "task docker:publish" with a real tag; confirm "docker buildx imagetools inspect <image>:<tag>" lists linux/amd64 and linux/arm64.
|
||||
- On a clean machine, "docker compose pull && docker compose up -d" against the pushed image; confirm /settings shows the new version and the container guidance from container_update_guidance.
|
||||
- Confirm the moving "beta" tag points at the intended digest and that "latest" did not move for a prerelease.
|
||||
|
||||
## Results
|
||||
- 1 Refusals: PASS (coder and hardener runs).
|
||||
- 2 Tag table: PASS (v2.9.0, v2.9.0-beta, v2.9.0-rc.1; re-seen with v2.9.0-beta and v2.9.1-beta, tags "vX, X, beta").
|
||||
- 3 Dry run: PASS (--version prints the tag, /healthz ok, uid 10001).
|
||||
- 4 Secrets: PASS.
|
||||
- 5 Compose: PASS.
|
||||
- 6 Upgrade simulation: PASS. Local images v2.9.0-beta and v2.9.1-beta, stack on the old tag, register + verify (mail captured over TLS by Mailpit) + login, article created (201), RENEWCMS_IMAGE switched, "docker compose up -d" recreated the container on the same volume. Old cookie still accepted, login 200, article 1 intact, GET /v1/settings reports v2.9.1-beta (was v2.9.0-beta).
|
||||
- 7 Docs: PASS.
|
||||
- 8 No credentials: PASS.
|
||||
- Manual items: NOT RUN (need the registry): docker login, real multi-arch push and imagetools inspect, "docker compose pull" against the pushed image, moving beta/latest tag checks, builder failure paths of a real run.
|
||||
Reference in new issue
Block a user