diff --git a/tests/discourse/custom/_discourse.py b/tests/discourse/custom/_discourse.py index d548bd0..81494e2 100644 --- a/tests/discourse/custom/_discourse.py +++ b/tests/discourse/custom/_discourse.py @@ -1,12 +1,19 @@ """Shared discourse test helpers — admin user + API key + JSON HTTP. -The bitnamilegacy/discourse recipe (compose app env) sets ONLY the DB + SMTP vars — it does NOT seed -an admin user, and Discourse's Admin API requires `Api-Key` + `Api-Username` headers (there is no -auto-created API key). So the functional tests bootstrap their own admin by running Rails inside the -`app` container (Discourse ships its Rails env at /opt/bitnami/discourse): find-or-create an admin -user, then create an ApiKey and print its plaintext `.key` (Discourse returns the plaintext only at -create time; it's stored hashed). Both the admin user and the key are class-B run-scoped — they live -only in the per-run app and are destroyed at teardown. +The discourse recipe (compose app env) sets ONLY the DB + SMTP vars — it does NOT seed an admin user, +and Discourse's Admin API requires `Api-Key` + `Api-Username` headers (there is no auto-created API +key). So the functional tests bootstrap their own admin by running Rails inside the `app` container: +find-or-create an admin user, then create an ApiKey and print its plaintext `.key` (Discourse returns +the plaintext only at create time; it's stored hashed). Both the admin user and the key are class-B +run-scoped — they live only in the per-run app and are destroyed at teardown. + +The custom tier runs on the PR HEAD. Phase prevb made the head genuinely the OFFICIAL +`discourse/discourse` image (no longer reverted to bitnamilegacy by a leaky overlay), so the Rails env +location is image-dependent — `mint_admin` detects it: OFFICIAL ships discourse at `/var/www/discourse` +(ruby/bundle on PATH) and reads the DB password from `$DISCOURSE_DB_PASSWORD`, which the recipe's +entrypoint exports from `/run/secrets/db_password` only for the BOOT process — a fresh `docker exec` +must re-export it. The legacy `bitnamilegacy/discourse` ships at `/opt/bitnami/discourse` (ruby at +`/opt/bitnami/ruby/bin`, DB password injected via env). The probe tries official first, bitnami second. `mint_admin(domain)` returns (api_key, api_username). Each call creates a fresh ApiKey (cheap; idempotent enough — the shared deployment's functional tests each mint their own), reusing the same @@ -45,15 +52,26 @@ _BOOTSTRAP_RB = ( def mint_admin(domain: str) -> tuple[str, str]: - """Bootstrap an admin + fresh API key via Rails in the app container. Returns (api_key, username).""" - # `bin/rails` is `#!/usr/bin/env ruby`; the bitnami discourse image keeps ruby at - # /opt/bitnami/ruby/bin, which is NOT on a login shell's PATH (`bash -lc` resets PATH from - # /etc/profile → `env: 'ruby': No such file or directory`, rc=127). Use a non-login shell, discover - # ruby (image-ENV PATH first, bitnami fallback), and invoke it explicitly so the shebang is moot. + """Bootstrap an admin + fresh API key via Rails in the app container. Returns (api_key, username). + + Image-agnostic (phase prevb): detects the OFFICIAL `discourse/discourse` layout + (`/var/www/discourse`, ruby on PATH) vs the legacy `bitnamilegacy/discourse` + (`/opt/bitnami/discourse`, ruby at `/opt/bitnami/ruby/bin`). On the OFFICIAL image a fresh + `docker exec` lacks `DISCOURSE_DB_PASSWORD` (the entrypoint exports it only for the boot process), + so re-export it from `/run/secrets/db_password` before Rails connects.""" cmd = ( - "cd /opt/bitnami/discourse && " - "RUBY=$(command -v ruby || echo /opt/bitnami/ruby/bin/ruby) && " - f'RAILS_ENV=production "$RUBY" bin/rails runner "{_BOOTSTRAP_RB}"' + "set -e; " + "if [ -d /var/www/discourse ]; then " # official discourse/discourse + " cd /var/www/discourse; " + ' export DISCOURSE_DB_PASSWORD="$(cat /run/secrets/db_password 2>/dev/null)"; ' + f' RAILS_ENV=production bin/rails runner "{_BOOTSTRAP_RB}"; ' + "elif [ -d /opt/bitnami/discourse ]; then " # legacy bitnamilegacy/discourse + " cd /opt/bitnami/discourse; " + " RUBY=$(command -v ruby || echo /opt/bitnami/ruby/bin/ruby); " + f' RAILS_ENV=production "$RUBY" bin/rails runner "{_BOOTSTRAP_RB}"; ' + "else " + ' echo "no discourse app dir (/var/www/discourse|/opt/bitnami/discourse)" >&2; exit 3; ' + "fi" ) out = lifecycle.exec_in_app(domain, ["bash", "-c", cmd], service="app", timeout=240) key = user = None