feat(harness): P2 — delete legacy customization keys & paths (rcust)
All checks were successful
continuous-integration/drone/push Build is passing

a) compose.ccci.yml is FIRST-CLASS: the harness auto-copies tests/<recipe>/
   compose.ccci.yml into the run's recipe checkout (ABRA_DIR-aware, lifecycle.
   provide_ccci_overlay) and auto-chaoses the pinned base deploy on its presence
   (kills the R7 implicit coupling). ghost/discourse install_steps.sh (copy-only
   boilerplate) deleted; CHAOS_BASE_DEPLOY removed from both metas + the registry.

b) install-time deps wiring is the ONLY mode: deps with DEPS provision BEFORE the
   single deploy; legacy post-deploy provisioning + the setup_custom_tests.sh
   invocation machinery deleted. lasuite-docs migrated to install_steps.sh OIDC
   wiring (same env names/values as the old hook — only the timing moved);
   lasuite-drive's remaining post-deploy MinIO bucket one-shot moved to ops.py
   pre_install; both setup_custom_tests.sh files deleted; OIDC_AT_INSTALL removed
   from drive/meet metas + the registry.

c) SKIP_GENERIC meta key deleted (zero users). Env form CCCI_SKIP_GENERIC* stays
   as the documented dev-only escape hatch; when active in a drone CI run the
   orchestrator prints a loud !! warning (manifest embedding lands in P5).

d) conftest cleanup: dead pre-deploy-once fixtures deployed/deployed_app deleted
   (zero users), app_domain + _short + _wait_healthy dropped (only users were the
   deleted fixtures); deps_apps+deps_creds consolidated into ONE deps fixture
   (entries expose .domain etc. as attributes; dict access intact); the 6 lasuite
   test files renamed deps_creds->deps (fixture name only — assertions and flows
   byte-identical). requires_deps marker + F2-11 skip-report plumbing unchanged.

Registry is now exactly the 14 final keys; docs §4 table regenerated. Stale
setup_custom_tests/OIDC_AT_INSTALL prose in docstrings/comments/assert MESSAGES
updated (no assert logic or expected value touched).

Verified on cc-ci: cc-ci-run -m pytest tests/unit -q -> 175 passed; scripts/lint.sh -> PASS.
This commit is contained in:
autonomic-bot
2026-06-10 17:01:33 +00:00
parent 472a68b32c
commit 8cd72fd78d
26 changed files with 316 additions and 472 deletions

View File

@ -14,12 +14,7 @@ import pytest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "runner"))
from harness import deps as deps_mod # noqa: E402
from harness import lifecycle, naming
from harness import meta as meta_mod
def _short(s: str, n: int = 8) -> str:
return "".join(c for c in s if c.isalnum())[:n] or "local"
from harness import meta as meta_mod # noqa: E402
@pytest.fixture(scope="session")
@ -27,16 +22,6 @@ def recipe() -> str:
return os.environ.get("RECIPE", "custom-html")
@pytest.fixture(scope="session")
def app_domain(recipe) -> str:
# Docker swarm config/secret names = <stackname>_<res>_<ver> must be <= 64 chars, and
# stackname is the sanitized domain. ".ci.commoninternet.net" alone is 22 chars, so the
# subdomain label must stay short. Use <recipe[:4]>-<6hex(recipe|pr|ref)> — unique per run,
# collision-safe across recipes (full recipe in the hash), readable context lives in the
# Drone build params + PR comment. (Deviation from plan §4.0 long name; see DECISIONS.md.)
return naming.app_domain(recipe, os.environ.get("PR", "0"), os.environ.get("REF"))
@pytest.fixture(scope="session")
def meta(recipe):
"""The recipe's FULL validated customization (RecipeMeta, attribute access) via the single
@ -55,32 +40,33 @@ def live_app() -> str:
return domain
@pytest.fixture(scope="session")
def deps_apps() -> dict[str, str]:
"""Phase 2 Q2.3 dependency-resolver contract (refined operator-2026-05-28 SSO-dep plan §1):
when a recipe declares `DEPS = [...]` in its `recipe_meta.py`, the orchestrator deploys each
dep AFTER the generic tiers (between RESTORE and CUSTOM) and persists their per-run identity
+ SSO creds to `$CCCI_DEPS_FILE`. Tests access the dep's per-run domain via this fixture.
For full SSO creds (realm/client/secret/admin) use the `deps_creds` fixture instead.
class _DepEntry(dict):
"""One provisioned dep (full creds dict) with attribute sugar: `entry.domain`, `entry.realm`,
`entry.client_secret`, ... — dict-style access works too (rcust P2d)."""
Returns `{dep_recipe: domain}` (str→str). Empty when no deps declared OR deps-not-ready."""
def __getattr__(self, name):
try:
return self[name]
except KeyError as e:
raise AttributeError(name) from e
@pytest.fixture(scope="session")
def deps() -> dict[str, _DepEntry]:
"""The recipe's provisioned deps (rcust P2d — consolidates the old `deps_apps`+`deps_creds`
pair). When a recipe declares `DEPS = [...]` in its `recipe_meta.py`, the orchestrator
provisions each dep BEFORE the single deploy and persists per-run identity + SSO creds to
`$CCCI_DEPS_FILE`. `deps["keycloak"]` carries domain/realm/client_id/client_secret/user/
password/email/admin_user/admin_password/discovery_url/token_url/... (`.domain` etc. work as
attributes). Empty when no deps declared OR deps-not-ready — pair with
`@pytest.mark.requires_deps` so the F2-11 skip-report keeps the green signal honest."""
state = deps_mod.deps_as_dict(deps_mod.load_run_state())
return {r: e["domain"] for r, e in state.items() if e.get("domain")}
@pytest.fixture(scope="session")
def deps_creds() -> dict[str, dict]:
"""Full SSO-creds dict for each declared dep (operator-2026-05-28 SSO-dep plan §1).
`deps_creds["keycloak"]` returns the entry written by setup_custom_tests with keys
domain/realm/client_id/client_secret/user/password/email/admin_user/admin_password/
discovery_url/token_url/.... Use this in `@pytest.mark.requires_deps` tests that need to
authenticate via OIDC."""
return deps_mod.deps_as_dict(deps_mod.load_run_state())
return {r: _DepEntry(e) for r, e in state.items()}
def pytest_collection_modifyitems(config, items):
"""SSO-dep plan §4: tests marked `@pytest.mark.requires_deps` are skipped with reason
`deps-not-ready: <captured-err>` when the orchestrator's setup_custom_tests step failed
`deps-not-ready: <captured-err>` when the orchestrator's dep provisioning failed
(orchestrator sets CCCI_DEPS_READY=0 in env). Non-deps custom tests are unaffected.
This is failure-isolation per plan §1 — generic tiers cannot break the SSO-marked tests'
@ -113,40 +99,5 @@ def pytest_configure(config):
"""Register the `requires_deps` marker so pytest doesn't warn about it."""
config.addinivalue_line(
"markers",
"requires_deps: test requires DEPS-declared services + setup_custom_tests success.",
"requires_deps: test requires DEPS-declared services + dep provisioning success.",
)
def _wait_healthy(domain, meta):
lifecycle.wait_healthy(
domain,
ok_codes=tuple(meta.HEALTH_OK),
path=meta.HEALTH_PATH,
deploy_timeout=meta.DEPLOY_TIMEOUT,
http_timeout=meta.HTTP_TIMEOUT,
)
@pytest.fixture
def deployed(recipe, app_domain, meta, request):
"""Function-scoped: deploy the current/$REF version healthy, guaranteed teardown after.
Used by stages that start from current (install/backup)."""
version = os.environ.get("VERSION") or None
lifecycle.janitor()
request.addfinalizer(lambda: lifecycle.teardown_app(app_domain))
lifecycle.deploy_app(recipe, app_domain, version=version)
_wait_healthy(app_domain, meta)
return app_domain
@pytest.fixture(scope="session")
def deployed_app(recipe, app_domain, meta):
"""Install stage: deploy the recipe and wait until healthy; tear down at session end."""
version = os.environ.get("VERSION") or None
lifecycle.janitor() # sweep orphans from crashed runs first
try:
lifecycle.deploy_app(recipe, app_domain, version=version, secrets=True)
_wait_healthy(app_domain, meta)
yield app_domain
finally:
lifecycle.teardown_app(app_domain)