From 1adfbd70cb0f12efe8e75f061e1dc471b785fee2 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Thu, 11 Jun 2026 21:37:45 +0000 Subject: [PATCH] fix(drone-dep): correct gitea admin create flag + dep deploy counter Two issues found during first manual harness run: 1. gitea `--must-change-password false` (space form) leaves a pending password-change for the ci_admin user, blocking the OAuth2 API call. Fix: use `--must-change-password=false` (equals form, required by gitea's BoolFlag with default=true). 2. dep deploy_app() calls incremented the DG4.1 "one deploy per run" counter, causing a false violation when gitea dep + drone both deploy. Fix: lifecycle.deploy_app gains _count_deploy=True param (default backward-compat); deps_mod.deploy_deps passes _count_deploy=False so only the recipe-under-test counts toward DG4.1. Co-Authored-By: Claude Sonnet 4.6 --- runner/harness/deps.py | 8 +++++--- runner/harness/lifecycle.py | 9 +++++++-- runner/harness/sso.py | 3 +-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/runner/harness/deps.py b/runner/harness/deps.py index f0fc97e..b73e7b7 100644 --- a/runner/harness/deps.py +++ b/runner/harness/deps.py @@ -80,9 +80,10 @@ def deploy_deps( for dep in deps: domain = dep_domain(parent_recipe, pr, ref, dep) print(f" dep: deploying {dep} -> {domain}", flush=True) - # NB: each dep_app gets a fresh deploy_count entry only on `_record_deploy` which fires - # inside `lifecycle.deploy_app`. For Phase 2 the deploy-count guard (DG4.1) counts the - # parent + its deps as distinct install events — by design, since each is a separate app. + # Dep deploys do NOT count toward the DG4.1 "one deploy per run" invariant — that + # contract covers the recipe-under-test only; each dep is a supporting service, not the + # subject of the test. Pass _count_deploy=False so the main recipe's single-deploy + # assertion isn't distorted by the number of deps declared. dm = meta_for.get(dep) or meta_mod.load(dep) lifecycle.deploy_app( dep, @@ -90,6 +91,7 @@ def deploy_deps( secrets=True, deploy_timeout=int(dm.DEPLOY_TIMEOUT), meta=dm, + _count_deploy=False, ) try: lifecycle.wait_healthy( diff --git a/runner/harness/lifecycle.py b/runner/harness/lifecycle.py index d14162b..98f8000 100644 --- a/runner/harness/lifecycle.py +++ b/runner/harness/lifecycle.py @@ -238,6 +238,7 @@ def deploy_app( install_steps_hook: tuple[str, str] | None = None, deploy_timeout: int = 900, meta=None, + _count_deploy: bool = True, ) -> None: """Create + configure + deploy an app. Forces LETS_ENCRYPT_ENV='' so traefik serves the wildcard cert via the file provider and NEVER attempts ACME (adversary finding A1). Applies any @@ -251,10 +252,14 @@ def deploy_app( `deploy_timeout` is the subprocess timeout for `abra app deploy`. Caller (orchestrator) passes `recipe_meta.DEPLOY_TIMEOUT` so heavy recipes (ghost, matrix-synapse, lasuite-meet) can extend past the 900s default. abra's INTERNAL TIMEOUT (recipe's TIMEOUT env, default 300s) is set via - EXTRA_ENV; this is the Python subprocess wrapper's timeout so abra doesn't get SIGKILLed mid-deploy.""" + EXTRA_ENV; this is the Python subprocess wrapper's timeout so abra doesn't get SIGKILLed mid-deploy. + + `_count_deploy`: set False for dep deployments — the DG4.1 "one deploy per run" invariant + counts ONLY the recipe-under-test, not its install-time deps (deps_mod.deploy_deps).""" if meta is None: meta = meta_mod.load(recipe) - _record_deploy() + if _count_deploy: + _record_deploy() # Lock BEFORE the app exists: a concurrent run's janitor must never see this app without a # held app lock (it would probe it as an orphan and reap an in-flight deploy). Also the # double-!testme serialisation point: a second run of the same domain blocks here. diff --git a/runner/harness/sso.py b/runner/harness/sso.py index 0cb2a94..e02f2df 100644 --- a/runner/harness/sso.py +++ b/runner/harness/sso.py @@ -444,8 +444,7 @@ def setup_gitea_oauth(provider_domain: str, parent_domain: str) -> dict: admin_password, "--email", admin_email, - "--must-change-password", - "false", + "--must-change-password=false", # equals-form required; gitea BoolFlag default=true ], timeout=120, )