74bf8c1723
feat(2w): W0.1 keycloak realm lifecycle primitives (WC1)
...
sso.py: list_realms, delete_keycloak_realm (idempotent, refuses master),
realms_to_reap (pure, concurrency-safe predicate), reap_orphaned_realms.
The per-run realm is the isolation unit on a shared live-warm keycloak;
orphans (crashed runs) reaped by hex not mapping to a live app stack.
+8 unit tests (tests/unit/test_warm_realm.py); 43 unit pass on cc-ci.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-05-28 23:16:48 +01:00
41ede13042
feat(2): refactor — SSO-dep plan refinement (deps AFTER generic + setup_custom_tests + failure isolation)
...
Per operator-2026-05-28 SSO-dep plan (plan-sso-dep-testing.md). Substantial orchestrator
restructuring:
NEW LIFECYCLE ORDER:
1. Recipe deploy ALONE (no deps).
2. install / upgrade / backup / restore — recipe-only generic tiers.
3. setup_custom_tests step (NEW):
a. Deploy each declared dep + provision realm/client/test-user via harness.sso.
b. Write $CCCI_DEPS_FILE in dict shape {dep_recipe: {domain, realm, client_id, client_secret,
admin_user, admin_password, discovery_url, token_url, ...}}.
c. Run tests/<recipe>/setup_custom_tests.sh hook (jq-readable; wires OIDC env via abra
secret insert + .env edits + in-place 'abra app deploy --force --chaos').
4. CUSTOM tier with deps-ready flag; @pytest.mark.requires_deps tests skip with
'deps-not-ready: <reason>' when setup_custom_tests fails. NON-deps custom tests still run
normally — FAILURE ISOLATION (a DoD item per plan).
5. Teardown: recipe first, deps in reverse declaration order.
Harness changes:
- runner/run_recipe_ci.py: deps deploy moves from BEFORE recipe deploy to AFTER restore tier.
Adds _enrich_deps_with_sso() + _run_setup_custom_tests_hook(). DG4.1 generalised to
'one abra app new per app' (recipe + each dep); in-place redeploys (\--force) don't count.
- runner/harness/deps.py: write_run_state + load_run_state accept dict OR list shape;
deps_as_dict() coerces either to a recipe→entry map.
- runner/harness/sso.py: admin_password_inside() public re-export.
- tests/conftest.py: deps_creds fixture (full creds dict); deps_apps fixture flattens to
recipe→domain string. pytest_collection_modifyitems hook skips
\@pytest.mark.requires_deps tests when CCCI_DEPS_READY=0.
pytest_configure registers the marker.
Recipe content:
- tests/lasuite-docs/setup_custom_tests.sh: NEW hook reads $CCCI_DEPS_FILE via jq;
inserts oidc_rpcs secret at BUMPED version (v1→v2) since abra app new -S generates v1 first
and Swarm forbids overwriting; updates SECRET_OIDC_RPCS_VERSION in .env; writes 9 OIDC env
vars (REALM/DISCOVERY/AUTH/TOKEN/USERINFO/LOGOUT/JWKS/CLIENT_ID/SCOPES); ensures trailing
newline on .env so writes don't concatenate (caught a 'TIMEOUT=900OIDC_REALM=...' bug);
triggers in-place 'abra app deploy --force --chaos --no-input'.
- tests/lasuite-docs/functional/test_oidc_with_keycloak.py: refactored to consume deps_creds
fixture (no longer calls setup_keycloak_realm itself — the orchestrator does it in
setup_custom_tests). Marked \@pytest.mark.requires_deps.
Cold-verifiable on cc-ci (log /root/ccci-refactor-lasuite-r5.log):
RECIPE=lasuite-docs STAGES=install,custom cc-ci-run runner/run_recipe_ci.py
install: PASS, custom: 3 PASS incl. test_oidc_password_grant_against_dep_keycloak.
deploy-count = 2 (expect 2) — DG4.1 generalised holds.
Smoke regression: RECIPE=custom-html STAGES=install,custom → 5 PASS, deploy-count=1.
Closes DEFERRED.md #5 (lasuite-docs OIDC parity ports via this plan).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-28 19:11:42 +01:00
4d6b040ba7
feat(2): Q2.3 — dep resolver + SSO-setup harness primitives
...
- runner/harness/deps.py: dep resolver primitive (Phase 2 §4.2 / Q2.3).
- declared_deps(recipe) reads DEPS list from tests/<recipe>/recipe_meta.py
- dep_domain(parent, pr, ref, dep) — per-run domain per (parent, dep) pair
so two recipes' deps of the same kind don't collide on a host
- deploy_deps / teardown_deps — sequential deploy + reverse-order teardown
- read/write of run-scoped $CCCI_DEPS_FILE
- runner/harness/sso.py: SSO-setup / OIDC-flow primitive (Phase 2 §4.2 / Q2.3).
- setup_keycloak_realm: idempotent realm + confidential OIDC client +
test user with generated 25-char alphanumeric password (class-B per §4.4-B);
returns SsoCreds dict with discovery_url, token_url, all identifiers.
- oidc_password_grant: exercises the password-grant OIDC flow; returns
access_token (a JWT) or raises.
- assert_discovery_endpoint: GET /.well-known/openid-configuration; asserts
issuer matches the per-run provider domain+realm.
- runner/run_recipe_ci.py: wired in dep deploy BEFORE recipe-under-test, dep
teardown LAST in finally (reverse order). DG4.1 deploy-count guard now
expects 1 + len(deps_state) — accommodates declared deps without breaking
the no-extra-deploys invariant.
- tests/conftest.py: deps_apps fixture reads $CCCI_DEPS_FILE -> dict mapping
dep_recipe -> dep_domain.
- tests/unit/test_deps.py: 7 unit tests covering declared_deps parsing,
per-(parent,dep) domain distinctness, run-state JSON write/load, env-var
no-op semantics. 28/28 unit tests PASS on cc-ci.
Smoke test confirmed deploy_count == expected (1) when no deps declared
(custom-html install run, log /root/ccci-q2-deps-smoke.log).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-28 07:41:56 +01:00