Files
cc-ci/machine-docs/STATUS-2.md
autonomic-bot 54b1fe326c status(2): Q2 RE-CLAIMED — F2-5 dep-teardown-verify fix cold-verified clean
Per REVIEW-2 ## Q2 FAIL @2026-05-28 (F2-5 dep teardown leak + F2-6 cold install flake + F2-7
SSO setup keycloak-hardcoded):

F2-5 closed by commit c6e94af: teardown_deps now uses verify=True so residuals raise; failures
propagate to orchestrator exit code + run summary. Cold-verified: lasuite-docs+keycloak e2e
PASS, dep teardown clean, post-run docker stack/volume/secret with 'keyc' filter all empty.

This also explained my Q3.1 flake — the leaked Q2.4 dep keycloak (deterministic dep domain) had
collided with my next dep deploy. With F2-5 fixed, that class of cross-run collision is
impossible (teardown now raises if it leaks, so the run fails BEFORE the next one starts).

F2-7 acknowledged: setup_keycloak_realm is keycloak-specific; authentik would need parallel
backend. Logged for Q2.2/Q5.

F2-6 (cold keycloak install 502) — real but secondary; will checkpoint in Q4 sweep.

Side-effect: Q3.1 partial also landed (PARITY.md + test_health_check parity port +
test_auth_required + the prior test_oidc_with_keycloak.py as Q3.1 third specific test).

Cold evidence: ssh cc-ci 'RECIPE=lasuite-docs STAGES=install,custom cc-ci-run runner/run_recipe_ci.py'
  deploy-count=2 (expect 2), all 5 assertions PASS, dep teardown clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 09:22:24 +01:00

246 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# STATUS — Phase 2 (per-recipe test authoring)
**Phase plan (SSOT):** `/srv/cc-ci/cc-ci-plan/plan-phase2-recipe-tests.md`
**Loop state for THIS phase:** STATUS-2 / BACKLOG-2 / REVIEW-2 / JOURNAL-2 (DECISIONS.md shared).
Phase 1/1b/1c/1d/1e STATUS/BACKLOG/REVIEW files are HISTORY (all DONE) — not this phase's state.
## Phase
Phase 2 authors **per-recipe test content** on top of the corrected Phase 1/1d/1e shared harness.
Per the plan, for every maintained Co-op Cloud recipe (§5 target set), the cc-ci `tests/<recipe>/`
tree must carry:
- Phase-1d/1e **lifecycle overlays** (assertion-only, additive) — `test_install.py`, `test_upgrade.py`,
`test_backup.py`, `test_restore.py` + `ops.py` pre-op seeds.
- **Parity-ported** tests from `references/recipe-maintainer/recipe-info/<recipe>/tests/*.py`,
one-to-one (P2), with a `PARITY.md` mapping table.
- **≥2 NEW recipe-specific functional tests** (P3) — characteristic behavior, not just `status==200`.
- **Real backup data-integrity** (P4): seed → backup → mutate → restore → assert seeded data survived.
- **Dependency resolution** (P5): recipes that need other apps (SSO providers, DBs) deploy them in-run.
- **Playwright** (P6) where the app's core UX is a UI flow.
- **Docs** (P8): `docs/enroll-recipe.md` updated with the per-recipe test contract + worked example.
## Definition of Done (Phase 2) — P1P8, each Adversary cold-verified in REVIEW-2
- [ ] **P1 — Coverage.** Every recipe in §5 target set has a `tests/<recipe>/` suite enrolled and a
full green `!testme` run (install + upgrade + backup-restore).
- [ ] **P2 — Parity port.** Every `recipe-info/<recipe>/tests/*.py` has a comparable cc-ci test;
`tests/<recipe>/PARITY.md` records the mapping; non-ports documented in DECISIONS.md.
- [ ] **P3 — Recipe-specific depth.** Each recipe has **≥2 new functional tests** beyond parity
(characteristic behavior, real assertions on app state/responses).
- [ ] **P4 — Backup data-integrity is real.** Seed → backup → mutate → restore → assert seeded data
survived (recipe-aware, not health-only). Pattern already proven in Phase 1e on custom-html.
- [ ] **P5 — Dependencies handled.** Recipes with deps declare them; harness deploys deps within the
run (respecting `MAX_TESTS`); SSO setup runs automatically.
- [ ] **P6 — Browser flows where they matter (D3).** UI-centric recipes have a Playwright test of the
core flow (login, create-an-object, etc.).
- [ ] **P7 — No weakened tests, no corners cut.** Every assertion is real; nothing skip/xfail'd,
mocked, or health-only stand-in. Any "untestable" claim is a true env-level blocker with
Adversary sign-off.
- [ ] **P8 — Docs.** `docs/enroll-recipe.md` updated with the per-recipe test contract (§4.1) and a
worked example; a new engineer can add a recipe's full suite from the docs.
## Milestones (plan §6)
- **Q0** — Harness additions (HTTP/convergence, OIDC-flow, dep resolver, backup data-integrity, TTY
abra). Reference recipe (custom-html) uses them for full parity+specific suite, green via `!testme`.
- **Q1** — Pattern proof (custom-html + n8n): full parity + ≥2 specific + real backup data-integrity.
- **Q2** — SSO providers (keycloak + authentik); reusable SSO-setup/OIDC-flow harness e2e.
- **Q3** — SSO-dependent suite (lasuite-docs, lasuite-drive, lasuite-meet, cryptpad, immich); deps
auto-deployed, SSO setup automated, parity + specific.
- **Q4** — Remaining recipes (matrix-synapse, mumble, bluesky-pds, ghost, mattermost-lts, discourse,
plausible, uptime-kuma, mailu, drone).
- **Q5** — Completeness + docs; flip `## DONE`.
## In flight
Working toward Q3 (SSO-dependent suite). Q2 fully claimed pending Adversary verify (see Gate
below). Q2.1 keycloak (parity + JWT password-grant + client_credentials), Q2.3 dep resolver +
SSO-setup harness primitives, Q2.4 acceptance (lasuite-docs + keycloak dep + OIDC password grant)
all landed. Q2.2 authentik enrollment is the remaining open item — deferred pending Adversary's
Q2 PASS as it's lower-priority (the SSO harness is provider-pluggable and Q2.4 acceptance is
already proven via keycloak).
## Gate
**Gate: Q2 — RE-CLAIMED, awaiting Adversary @2026-05-28** (commit `c6e94af` F2-5 fix on top of
the prior Q2 changeset). Adversary FAIL on F2-5 (dep teardown silent suppress) + F2-6 (cold
keycloak install flake, secondary) + F2-7 (SSO setup keycloak-hardcoded, transparency). F2-5
fixed: `teardown_deps` now uses `verify=True`, errors propagate to the orchestrator's exit code,
the run summary surfaces leaks. Cold-verified: dep keycloak deployed → tests PASS → DEPS
teardown ran clean → `docker stack ls | grep keyc` → empty. F2-7 ack as a real scope gap (when
Q2.2 authentik enrolls, `setup_authentik_realm` will need a parallel backend in `harness.sso`).
F2-6 cold-flake on keycloak install is real but unrelated to Q2 acceptance (a flake-handling
finding for the install layer; will checkpoint when Q4 reaches keycloak again).
Acceptance per plan §6 Q2: "a dependent recipe deploys its provider + runs an OIDC login test
in one run." Proven cold:
**Objective evidence pointers (Q2):**
- **Q2.1 keycloak parity + 2 NEW specific tests** — commit `d5f5e86`:
- `tests/keycloak/functional/test_health_check.py` — parity port.
- `tests/keycloak/functional/test_password_grant_token.py` — password grant, JWT decoded, claims
(iss/azp/typ/exp/iat) validated.
- `tests/keycloak/functional/test_create_client_and_use.py` — admin-API client CRUD +
client_credentials grant + JWT azp/iss validation + idempotent cleanup.
- `oidc_integration.py` parity deferred to Q3 (cross-recipe; see PARITY.md note).
- Bumped DEPLOY_TIMEOUT + HTTP_TIMEOUT to 900s.
- Cold e2e (log `/root/ccci-q2-keycloak-r3.log`): all 5 stages PASS, deploy-count=1,
`head_ref=666649a6 == chaos-version=666649a6`, version `10.7.0+26.6.1 → 10.7.1+26.6.2`.
- **Q2.3 dep resolver + SSO-setup harness primitives** — commit `4d6b040`:
- `runner/harness/deps.py` — declared_deps + dep_domain + deploy_deps + teardown_deps + JSON
run state. Subsumes Q0.4 (dep resolver).
- `runner/harness/sso.py` — setup_keycloak_realm + oidc_password_grant +
assert_discovery_endpoint. Reusable by every SSO-dependent recipe (Q3 will exercise).
- `runner/run_recipe_ci.py` — wired in dep deploy BEFORE recipe-under-test, dep teardown
AFTER in finally (reverse order). DG4.1 expected count = 1 + len(deps).
- `tests/conftest.py``deps_apps` fixture exposes dep domains to dependent tests.
- 7 new unit tests in `tests/unit/test_deps.py`; **28/28 unit tests PASS** cold.
- **F2-5 fix — dep teardown verify=True** — commit `c6e94af`, log `/root/ccci-f25-verify.log`:
- `runner/harness/deps.py::teardown_deps` now uses `lifecycle.teardown_app(..., verify=True)`
so residuals raise `TeardownError`. Errors are logged per-dep but we continue to other deps;
a combined `TeardownError` is raised after all attempts.
- `runner/run_recipe_ci.py` catches the dep `TeardownError` in finally, surfaces via
`dep_teardown_error` in the run summary + non-zero exit code.
- Cold-verified: lasuite-docs+keycloak dep e2e PASSED clean (3 custom + 2 lifecycle install =
5 PASS); post-run cc-ci state has NO leftover keycloak (`docker stack ls | grep keyc`
empty; `docker volume ls | grep keyc` → empty; `docker secret ls | grep keyc` → empty).
- deploy-count=2, expected 2.
- **Q2.4 acceptance (the gate)** — commit `9e88741`, log `/root/ccci-q24-lasuite-keycloak.log`:
- `tests/lasuite-docs/recipe_meta.py` declares `DEPS = ["keycloak"]`.
- `tests/lasuite-docs/functional/test_oidc_with_keycloak.py`:
- Asserts `deps_apps["keycloak"]` is the per-run dep domain.
- Calls `harness.sso.setup_keycloak_realm` → realm/client/user.
- GETs OIDC discovery; asserts `issuer == https://<kc>/realms/lasuite-docs`.
- Performs password grant → JWT; asserts iss/azp/typ/exp claims.
- Cold-run output:
```
===== DEPS: ['keycloak'] =====
dep: deploying keycloak -> keyc-c12afe.ci.commoninternet.net
dep: keycloak ready @ keyc-c12afe.ci.commoninternet.net
===== TIER: install ===== 2 PASS (generic + cc-ci overlay)
===== TIER: custom ===== 1 PASS (test_oidc_password_grant_against_dep_keycloak)
===== DEPS teardown =====
===== RUN SUMMARY =====
deploy-count = 2 (expect 2)
```
- **F2-3 systemic fix** — commit `47f7cb4`: `runner/harness/browser.py::goto_with_retry`
centralizes the F2-3 try/except PlaywrightError pattern; applied to **all** install overlays
using page.goto (custom-html, n8n, keycloak, cryptpad, lasuite-docs) + the custom-html
playwright/test_browser_smoke. Cold e2e (custom-html, log `/root/ccci-q2-customhtml-r2.log`):
all 5 stages PASS, deploy-count=1, HC1 non-vacuous.
**Reference command for Adversary (cold, on cc-ci):**
```
ssh cc-ci 'cd /root/<your-clone> && \
cc-ci-run -m pytest tests/unit -v && \
RECIPE=keycloak cc-ci-run runner/run_recipe_ci.py && \
RECIPE=lasuite-docs STAGES=install,custom cc-ci-run runner/run_recipe_ci.py'
```
---
**Gate: Q1 — Adversary PASS @2026-05-28** (REVIEW-2 `## Q1 — PASS @2026-05-28 (re-verify after
F2-3 + F2-4 fixes)`; cold e2e on `/root/adv-verify` HEAD `fc89552` → all 5 stages PASS,
deploy-count=1, HC1 non-vacuous; F2-3 + F2-4 CLOSED; NO VETO). Builder may advance to Q2.
**Objective evidence pointers (Q1):**
- **custom-html (Q1.1)** — already cold-verified in Q0 PASS. Same evidence stands: full e2e green,
HC1 non-vacuous, deploy-count=1; PARITY.md + functional/ + playwright/ in place.
- **n8n (Q1.2)** — full e2e on cc-ci (log `/root/ccci-q1-n8n-r3.log`):
- **HC1 PR-head proof:** `head_ref=63dd3e0f == chaos-version=63dd3e0f`, version
`3.1.0+2.9.4 → 3.2.0+2.20.6`.
- **Deploy-count = 1** (DG4.1 holds).
- **Lifecycle tier results (generic + cc-ci overlay both PASS at each stage):**
- install: generic `test_serving` PASS + cc-ci `test_serving_and_editor` PASS (the robust
Playwright poll handles n8n's /healthz-200-before-/-route-registered window).
- upgrade: generic `test_upgrade_reconverges` PASS + cc-ci `test_upgrade_preserves_data`
PASS (marker `upgrade-survives` written into /home/node/.n8n by `ops.pre_upgrade` survived
the chaos redeploy of PR-head).
- backup: generic `test_backup_artifact` PASS + cc-ci `test_backup_captures_state` PASS
(marker `original` from `ops.pre_backup` captured by `abra app backup create`).
- restore: generic `test_restore_healthy` PASS + cc-ci `test_restore_returns_state` PASS
(marker mutated to `mutated` by `ops.pre_restore`, restored to `original` — real backup
data-integrity).
- **Custom tier results (4 PASS — log `/root/ccci-q1-n8n-r4.log` post-F2-4/F2-3 fix):**
- `tests/n8n/functional/test_health_check.py::test_n8n_returns_200` — parity port (HTTP 200
from `/`), with `SOURCE: recipe-info/n8n/tests/health_check.py` comment.
- `tests/n8n/functional/test_workflow_roundtrip.py::test_workflow_create_and_read_back` —
**plan §4.3 prescribed create+read-back**: owner setup → POST /rest/workflows → GET
/rest/workflows/<id>; assert id/name/nodes round-trip. (F2-4 fix.)
- `tests/n8n/functional/test_rest_settings.py::test_rest_settings_returns_json_with_known_keys`
— polls `/rest/settings` until content-type is `application/json` (rejecting the
"n8n is starting up" placeholder HTML), then asserts known public-settings keys
(`userManagement` / `defaultLocale` / `authCookie`) in the `data` envelope.
- `tests/n8n/functional/test_login_state.py::test_login_endpoint_returns_json` — polls
`/rest/login` until content-type is `application/json`, proves auth subsystem initialized.
- **PARITY.md complete:** `tests/n8n/PARITY.md` — parity row for `health_check.py`, rationale
for the 2 recipe-specific tests, data-integrity + playwright sections.
- **Q1 has no Adversary findings yet.** No tests skipped/weakened; rejecting-the-placeholder
pattern in the new functional tests is non-vacuous (a stuck-booting n8n that only serves the
placeholder fails the test).
**Reference command for Adversary (cold, on cc-ci):**
```
ssh cc-ci 'cd /root/<your-clone> && RECIPE=n8n cc-ci-run runner/run_recipe_ci.py'
```
---
**Gate: Q0 — Adversary PASS @2026-05-28** (REVIEW-2 `## Q0 — PASS @2026-05-28`; cold re-verify on
`/root/adv-verify` HEAD `0b834e9` → 21 unit PASS + e2e PASS; NO VETO). F2-1 closed; F2-2 (scope
observation) acknowledged.
**Prior Q0 claim detail (commit `5741e88` — F2-1 fix landed on top of the original Q0 changeset).** Acceptance evidence (per plan §6 Q0): a reference recipe
(custom-html) uses the new harness additions for a full parity + specific suite, green via the
existing run path. F2-1 (test_custom_tests_repo_local_gated stale assertion) closed by Builder; cold
re-run on cc-ci → **21/21 PASS** including the previously-failing test. F2-2 (scope observation:
OIDC-flow + dep resolver not in Q0) acknowledged — those primitives implement when Q2/Q3 consume
them; BACKLOG-2 Q0.4 remains open and explicitly deferred.
**Objective evidence pointers (Q0):**
- **Harness additions landed**
- `runner/harness/http.py` — canonical Phase-2 recipe-test HTTP API (vendored from
`references/recipe-maintainer/utils/tests/helpers.py`): `http_get`, `http_post`, `http_request`,
`retry_http_get`, `retry_http_post`, `wait_for_http`, `assert_converges`. JSON + form bodies,
transport-failure → status=0.
- `runner/harness/discovery.custom_tests` recurses into `tests/<recipe>/functional/` and
`tests/<recipe>/playwright/` (Phase 2 §4.1 layout) while excluding lifecycle `test_<op>.py`
names; HC2 repo-local gate continues to apply.
- TTY abra wrapper already present in `runner/harness/abra.py::_run_pty` (Phase 1d) — reused.
- **Unit-test proof (deterministic, cc-ci; post-F2-1 fix commit `5741e88`)**
- `cc-ci-run -m pytest tests/unit -v` → **21 passed in 5.38s** (the previously-failing
`test_custom_tests_repo_local_gated` now passes; synthetic-recipe + monkeypatch fixture):
- 8× pre-existing `tests/unit/test_discovery.py` (overlay + HC2 gate, regressed).
- 2× new `tests/unit/test_discovery_phase2.py` (functional/+playwright/ recursion + HC2
gate still applies to subdirs).
- 11× new `tests/unit/test_http.py` (in-process http.server fixture — JSON parsing,
4xx-with-body, non-JSON body, transport-failure=0, headers, JSON+form POST, retry
convergence, retry timeout, wait_for_http, assert_converges return value).
- **End-to-end proof (custom-html on cc-ci, the reference recipe)**
- `RECIPE=custom-html cc-ci-run runner/run_recipe_ci.py` (log `/root/ccci-q0-customhtml-full.log`):
- install/upgrade/backup/restore/custom **all PASS**, deploy-count=1.
- HC1 PR-head proof: `head_ref=8a026066 == chaos-version=8a026066`, version `1.10.0→1.11.0`.
- 5 lifecycle assertions (generic + cc-ci overlay across 4 ops) + 4 custom-stage assertions
(3 functional + 1 playwright). Reference command for Adversary cold re-run:
`RECIPE=custom-html cc-ci-run runner/run_recipe_ci.py`.
- **Per-recipe contract artifact landed**
- `tests/custom-html/PARITY.md` — parity row for `health_check.py`, rationale for the 2
recipe-specific tests + the data-integrity + playwright sections.
- `tests/custom-html/functional/{test_health_check.py,test_content_roundtrip.py,test_content_type_header.py}` — parity port + 2 NEW recipe-specific tests; each parity file carries the
`SOURCE: recipe-info/custom-html/tests/<file>` comment for audit.
- `tests/custom-html/playwright/test_browser_smoke.py` — Phase-2 P6 home.
**Reference command for Adversary (cold, on cc-ci):**
```
ssh cc-ci 'cd /root/cc-ci && cc-ci-run -m pytest tests/unit -v && RECIPE=custom-html cc-ci-run runner/run_recipe_ci.py'
```
## Blocked
(none) — bootstrap access re-verified @2026-05-28: `ssh cc-ci` ok (root, NixOS 24.11), Gitea API
HTTP 200, wildcard DNS resolves to gateway 143.244.213.108.
## Carryover from Phase 1e (not blockers for Phase 2)
- **F1e-2** [adversary] — concurrent same-recipe `abra recipe fetch` race in
`runner/run_recipe_ci.py::fetch_recipe`. Pre-existing in Phase 1d; not a 1e regression. Drone
caps `MAX_TESTS=1` today, so practical impact bounded. Tracked for Phase-2 breadth-ramp if
concurrent recipe runs become routine.