Harness change (small, surgical):
- runner/harness/lifecycle.deploy_app gains a deploy_timeout param (default 900s); passes
through to abra.deploy(timeout=...). For heavy recipes (ghost, matrix-synapse, lasuite-meet),
the orchestrator + dep resolver now read recipe_meta.DEPLOY_TIMEOUT and pass it so the Python
subprocess wrapping abra deploy doesn't SIGKILL it before the recipe's INTERNAL TIMEOUT
(via EXTRA_ENV) finishes swarm convergence.
- runner/run_recipe_ci.py + runner/harness/deps.py: thread recipe_meta.DEPLOY_TIMEOUT into
the per-recipe deploy_app call.
Q4.4 ghost enrollment:
- recipe_meta.py: HEALTH_PATH=/, DEPLOY_TIMEOUT=1200 (subprocess), EXTRA_ENV={TIMEOUT: 1200}
(recipe internal). Ghost cold-start with theme + DB migration runs ~12-15min on cc-ci.
- functional/test_health_check.py: GET / returns 200 (themed site).
- functional/test_content_api.py: GET /ghost/api/content/settings/ returns 200 (settings JSON)
or 401/403 (Ghost error envelope) — distinguishes ghost-server up + JSON API working from
static fallback.
- functional/test_admin_redirect.py: GET /ghost/ returns 200 or 302 + Ghost branding;
proves admin route is wired through nginx proxy.
- PARITY.md: recipe-maintainer corpus has no ghost tests/, Phase-2 health_check is the
parity baseline; create-a-post deeper test deferred (DEFERRED.md, --extra-tests linked).
Cold-verifiable (log /root/ccci-q44-ghost-r3.log):
RECIPE=ghost STAGES=install,custom cc-ci-run runner/run_recipe_ci.py
install + 3 functional tests PASS, deploy-count=1. 28/28 unit tests still PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2.1 KiB
Parity — ghost
The recipe-maintainer corpus has no recipe-info/ghost/tests/ directory — ghost was not in
their parity suite. This PARITY.md documents the Phase-2 health_check (parity-aligned baseline)
- recipe-specific tests beyond.
Recipe-specific tests (Phase-2 P3, ≥2 beyond parity)
Ghost is a publishing platform with a public themed site at /, an admin UI at /ghost/,
and a JSON Content/Admin API at /ghost/api/*. Defining behaviors exercised:
| cc-ci file | what's verified | rationale |
|---|---|---|
tests/ghost/functional/test_content_api.py |
GETs /ghost/api/content/settings/; asserts 200 with {"settings": {...}} envelope OR 401/403 with a Ghost error envelope. |
Distinguishes "the ghost-server JS process is up + emitting its API" from "a static themed page is served at /." A wedged Ghost backend → 5xx; misrouted nginx → 404. |
tests/ghost/functional/test_admin_redirect.py |
GETs /ghost/; asserts 200 or 302 + Ghost branding/SPA references in the response (or a redirect to /ghost/#/setup on fresh deploy). |
Proves the admin route is wired through the nginx proxy. Distinguishes "admin SPA bound" from "404 (route missing)" or "5xx (broken)." |
Two specific tests + parity health_check = ≥2 floor met.
Plan §4.3 prescribed deeper test (deferred to Q4 follow-up)
§4.3 named "create-a-post round-trip" for ghost. That requires:
- Setup the Ghost owner (POST
/ghost/api/v3/admin/authentication/setup/) with a per-run admin email+password. - Login → JWT bearer token.
- POST
/ghost/api/v3/admin/posts/to create a post. - GET
/ghost/api/v3/admin/posts/<id>/to read it back.
Doable; adds a per-run setup secret + token-management. Tracked for Q4 follow-up.
Backup data-integrity (P4)
Lifecycle overlays not authored. The base recipe stores state in SQLite + a content volume; backup-capable is auto-detected from compose. Q5 catch-up if backup data-integrity proves needed for this recipe.
Playwright (P6)
Not yet authored. Ghost's admin UI is an Ember SPA; a Playwright flow would exercise the setup wizard + post creation. Q4 follow-up.