Commit af823d5
committed
feat(container): compose split + bring-up fixes (ADR-T-009 Phase 8)
Phase 8 of ADR-T-009. Splits the single development-only
`compose.yaml` into a production-shaped baseline plus a
dev-sandbox override, wires both behind a top-level
`Makefile`, and folds in five latent bugs surfaced by the
end-to-end `make up-dev` / `make up-prod` bring-up against
`podman-compose 1.5.0` / `podman 5.8.2`.
Compose split
-------------
- `compose.yaml`: production-shaped baseline. Drops the
`mailcatcher` sidecar and the `tty: true` allocations.
Credentials and the environment-coupled mail SMTP
server are referenced as bare `${VAR}` (no default, no
`:?required`); validation is deferred to the wrapper
and the in-container config probe (defence in depth,
per ADR-T-009 §8.1). Operator selectors with a sensible
cross-environment default (`TORRUST_INDEX_DATABASE`,
`TORRUST_INDEX_DATABASE_DRIVER`, …) keep their
`${VAR:-default}` form. Switches `depends_on` on `index`
and `tracker` to long-form so an override can additively
re-attach `mailcatcher` rather than silently replace
the dependency list.
- `compose.override.yaml` (new): dev sandbox extras —
`mailcatcher` sidecar (re-attached to `index` via
long-form `depends_on`), `tty: true` on `index` and
`tracker`, and permissive `${VAR:-default}` credential
defaults so a plain `docker compose up` works with no
operator intervention. Auto-loaded by Compose v2 and by
`make up-dev`; excluded by `make up-prod` via explicit
`--file compose.yaml`.
- `Makefile` (new): two targets, `up-dev` (plain
`docker compose up`) and `up-prod` (validates required
env vars via POSIX `sh -uc ': "${VAR:?required}"'`,
then `docker compose --file compose.yaml up -d --wait`).
`COMPOSE_FILE` is overridable for acceptance tests.
The MySQL credential check is gated behind a
`grep mysql:` of the compose file so a baseline without
a local mysql sidecar does not require `MYSQL_ROOT_PASSWORD`.
Bring-up fixes (folded in rather than deferred)
-----------------------------------------------
1. **`addgroup` missing from the curated busybox surface.**
Distroless `cc-debian13` ships `/etc/passwd` and
`/etc/group`, but busybox `adduser -D -u UID NAME` only
writes `/etc/passwd`; `getgrnam("torrust")` then fails
and the entry script's `install -g torrust …` step dies
with `unknown group torrust`. Add `addgroup` to the
curated symlink loop in the release runtime base (and
to the preflight gate's symlink loop, kept in sync per
ADR-T-009 §4.4). Entry script now does
`addgroup -g "$USER_ID" torrust` followed by
`adduser -D -s /bin/sh -u "$USER_ID" -G torrust torrust`,
both guarded with idempotent `grep` checks of
`/etc/{group,passwd}` so a container restart is a no-op
under `set -e`.
2. **`jq` shipped without its shared libs.** The
`jq_donor` stage installed jq via `apt-get` but the
runtime stages copied only `/usr/bin/jq`; the binary
then aborted with `libjq.so.1: cannot open shared
object file` inside the lean `cc-debian13` runtime.
Copy `libjq.so.1` and `libonig.so.5` from the donor
alongside the binary into both runtime stages. Add an
`ldd`-based allow-list assertion to the `jq_donor`
stage (`libc.so.6 libjq.so.1 libm.so.6 libonig.so.5
ld-linux-x86-64.so.2 linux-vdso.so.1`) so a future
donor-base upgrade that drags in a new transitive dep
fails the build instead of silently producing a broken
image. The parser strips path prefixes from `ldd`'s
first column so absolute paths and bare sonames are
treated identically.
3. **Empty-string env vars treated as inline config TOML.**
`Info::from_env` called `env::var(…).ok()` directly,
which returns `Some("")` for an exported-but-unset
variable. The previous compose baseline's
`TORRUST_INDEX_CONFIG_TOML=${TORRUST_INDEX_CONFIG_TOML}`
propagated an empty string into the container, which
the loader treated as a zero-byte TOML and rejected
with `Missing mandatory option: logging.threshold`.
`Info::from_env` now filters empty strings out of both
`TORRUST_INDEX_CONFIG_TOML` and
`TORRUST_INDEX_CONFIG_TOML_PATH`. `compose.yaml` uses
Compose's bare-name pass-through form
(`- TORRUST_INDEX_CONFIG_TOML`, no `=`) for those two
optional inline-TOML envs so an unset host var is
omitted entirely rather than forwarded as empty.
4. **Test binaries baking compile-time paths.**
`packages/index-config-probe/tests/binary.rs` and
`packages/index-entry-script/tests/seed_sqlite.rs`
resolved their subjects via `env!("CARGO_BIN_EXE_…")`
and `CARGO_MANIFEST_DIR`; both bake the build-time
path into the test binary and break under
cargo-nextest's archive → `--extract-to` →
`--target-dir-remap` flow used by the container `test`
stage. `binary.rs` is rewritten to drive the contracts
through the library API (same model as
`packages/index-config/tests/shipped_samples.rs`):
exit-3 / 4 / 5 are pinned by exercising
`load_settings` / `probe`, and exit-2 is pinned by
handing clap a mirror of the binary's `Args` and
asserting `Err::exit_code() == 2`. The entry-script
test crate embeds `entry_script_lib_sh` at compile
time via `include_str!` and materialises it to a
`tempfile` per `run_sh` call; `tempfile` accordingly
moves from `[dev-dependencies]` to `[dependencies]`
since `run_sh` / `run_sh_with_args` are
`#[doc(hidden)] pub` library items.
5. **Unqualified Docker Hub image names.**
`mysql:8.0.45`, `dockage/mailcatcher:0.8.2`, and
`torrust/tracker:develop` all relied on a
short-name-resolution prompt that podman cannot honour
without a TTY (and that operators should not be relying
on regardless). Fully qualify all three as
`docker.io/...` in `compose.yaml` and
`compose.override.yaml`. Portable across docker and
podman; immune to per-host
`unqualified-search-registries` configuration.
6. **`USER_ID` missing from `_validate-prod-env`.**
`compose.yaml` references `${USER_ID}` with no default
(it is an operator-supplied numeric selector, neither
a credential nor environment-coupled). Without
wrapper-side validation, an unset `USER_ID` propagated
to the entry script's `adduser -u ""` call and failed
deep inside container start. Add `USER_ID` to the
`_validate-prod-env` required list.
Test fixtures
-------------
- The three `contrib/dev-tools/container/e2e/.../e2e-env-up.sh`
scripts now export `TORRUST_INDEX_CONFIG_OVERRIDE_DATABASE__CONNECT_URL`
alongside the existing `..._TRACKER__TOKEN` override, so
the e2e suite satisfies the §D2 mandatory-fields contract
the same way `make up-prod` does.
Docs
----
- `adr/009-implementation-plan.md`: mark Phase 8 Done; add
§8.6 documenting the six bring-up fixes and §9.1.3
scheduling the `mailcatcher`-on-`compose.yaml` CI lint
prescribed by §8.1; align the §4.4 / §9 prose and the
curated-applets table with the new `addgroup` symlink
and the §8.1 `USER_ID` validation.
- `docs/containers.md`: new "Compose Split" section
walking through the baseline / override split, the
`make up-dev` / `make up-prod` invocation paths, the
required env vars, and the defence-in-depth contract
with the in-container config probe. Update the curated
busybox applet list to include `addgroup` and refresh
the auth-key bootstrap pointer to the new override
file.1 parent 839450b commit af823d5
13 files changed
Lines changed: 396 additions & 49 deletions
File tree
- adr
- contrib/dev-tools/container/e2e
- mysql
- sqlite/mode
- private
- public
- docs
- packages
- index-config/src
- index-entry-script
- src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
39 | | - | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
40 | 63 | | |
41 | 64 | | |
42 | 65 | | |
| |||
227 | 250 | | |
228 | 251 | | |
229 | 252 | | |
230 | | - | |
| 253 | + | |
231 | 254 | | |
232 | 255 | | |
233 | 256 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
698 | 698 | | |
699 | 699 | | |
700 | 700 | | |
701 | | - | |
| 701 | + | |
702 | 702 | | |
703 | 703 | | |
704 | 704 | | |
| |||
951 | 951 | | |
952 | 952 | | |
953 | 953 | | |
| 954 | + | |
954 | 955 | | |
955 | 956 | | |
956 | 957 | | |
| |||
2307 | 2308 | | |
2308 | 2309 | | |
2309 | 2310 | | |
| 2311 | + | |
2310 | 2312 | | |
2311 | 2313 | | |
2312 | 2314 | | |
| |||
2318 | 2320 | | |
2319 | 2321 | | |
2320 | 2322 | | |
| 2323 | + | |
| 2324 | + | |
| 2325 | + | |
| 2326 | + | |
| 2327 | + | |
| 2328 | + | |
| 2329 | + | |
| 2330 | + | |
| 2331 | + | |
2321 | 2332 | | |
2322 | 2333 | | |
2323 | 2334 | | |
| |||
2355 | 2366 | | |
2356 | 2367 | | |
2357 | 2368 | | |
| 2369 | + | |
| 2370 | + | |
| 2371 | + | |
| 2372 | + | |
| 2373 | + | |
| 2374 | + | |
| 2375 | + | |
| 2376 | + | |
| 2377 | + | |
| 2378 | + | |
| 2379 | + | |
| 2380 | + | |
| 2381 | + | |
| 2382 | + | |
| 2383 | + | |
| 2384 | + | |
| 2385 | + | |
| 2386 | + | |
| 2387 | + | |
| 2388 | + | |
| 2389 | + | |
| 2390 | + | |
| 2391 | + | |
| 2392 | + | |
| 2393 | + | |
| 2394 | + | |
| 2395 | + | |
| 2396 | + | |
| 2397 | + | |
| 2398 | + | |
| 2399 | + | |
| 2400 | + | |
| 2401 | + | |
| 2402 | + | |
| 2403 | + | |
| 2404 | + | |
| 2405 | + | |
| 2406 | + | |
| 2407 | + | |
| 2408 | + | |
| 2409 | + | |
| 2410 | + | |
| 2411 | + | |
| 2412 | + | |
| 2413 | + | |
| 2414 | + | |
| 2415 | + | |
| 2416 | + | |
| 2417 | + | |
| 2418 | + | |
| 2419 | + | |
| 2420 | + | |
| 2421 | + | |
| 2422 | + | |
| 2423 | + | |
| 2424 | + | |
| 2425 | + | |
| 2426 | + | |
| 2427 | + | |
| 2428 | + | |
| 2429 | + | |
| 2430 | + | |
| 2431 | + | |
| 2432 | + | |
| 2433 | + | |
| 2434 | + | |
| 2435 | + | |
| 2436 | + | |
| 2437 | + | |
| 2438 | + | |
| 2439 | + | |
| 2440 | + | |
| 2441 | + | |
| 2442 | + | |
| 2443 | + | |
| 2444 | + | |
| 2445 | + | |
| 2446 | + | |
| 2447 | + | |
| 2448 | + | |
| 2449 | + | |
| 2450 | + | |
| 2451 | + | |
| 2452 | + | |
| 2453 | + | |
| 2454 | + | |
| 2455 | + | |
| 2456 | + | |
| 2457 | + | |
| 2458 | + | |
| 2459 | + | |
| 2460 | + | |
| 2461 | + | |
| 2462 | + | |
| 2463 | + | |
| 2464 | + | |
| 2465 | + | |
| 2466 | + | |
| 2467 | + | |
2358 | 2468 | | |
2359 | 2469 | | |
2360 | 2470 | | |
| |||
2394 | 2504 | | |
2395 | 2505 | | |
2396 | 2506 | | |
| 2507 | + | |
| 2508 | + | |
| 2509 | + | |
| 2510 | + | |
| 2511 | + | |
| 2512 | + | |
| 2513 | + | |
| 2514 | + | |
| 2515 | + | |
| 2516 | + | |
| 2517 | + | |
| 2518 | + | |
| 2519 | + | |
2397 | 2520 | | |
2398 | 2521 | | |
2399 | 2522 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
0 commit comments