From b944eca41d0fbfea20a1b61ce0df268c5f45c6e8 Mon Sep 17 00:00:00 2001 From: autonomic-bot <64+autonomic-bot@noreply.git.autonomic.zone> Date: Mon, 26 Oct 2026 17:34:56 +0000 Subject: [PATCH] fix(runner): allow version-guarded base repair overlays --- runner/harness/lifecycle.py | 4 ++++ tests/unit/test_previous.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/runner/harness/lifecycle.py b/runner/harness/lifecycle.py index e6e332b..1240b8d 100644 --- a/runner/harness/lifecycle.py +++ b/runner/harness/lifecycle.py @@ -487,6 +487,10 @@ def deploy_app( # may already include the environmental compose.ccci.yml). Stripped before the head redeploy # (generic.perform_upgrade) so the PR head runs unmodified. if apply_previous: + # This untracked overlay also trips abra's pinned-deploy clean-tree gate. + # The exact version was checked out above; chaos deploys that base plus + # its repair, just as for compose.ccci.yml, without fetching latest. + chaos = True cf = compose_file_add(extra.get("COMPOSE_FILE", "compose.yml"), PREVIOUS_COMPOSE) abra.env_set(domain, "COMPOSE_FILE", cf) provide_previous_overlay(recipe) diff --git a/tests/unit/test_previous.py b/tests/unit/test_previous.py index 1203aeb..859db76 100644 --- a/tests/unit/test_previous.py +++ b/tests/unit/test_previous.py @@ -116,3 +116,37 @@ def test_previous_status_stale_without_marker(monkeypatch): monkeypatch.setattr(lifecycle, "previous_target_version", lambda r: None) st = lifecycle.previous_status("rx", "version", "0.7.0+3.3.1") assert st["apply"] is False and st["stale"] is True and "marker" in st["reason"] + + +def test_previous_overlay_deploys_checked_out_base_without_clean_tree_gate(monkeypatch): + events = [] + for name in ( + "acquire_app_lock", + "provide_ccci_overlay", + "provide_previous_overlay", + "prepull_images", + ): + monkeypatch.setattr(lifecycle, name, lambda *a, **kw: None) + for name in ("app_config_remove", "app_new", "env_set", "secret_generate"): + monkeypatch.setattr(lifecycle.abra, name, lambda *a, **kw: None) + monkeypatch.setattr(lifecycle.meta_mod, "extra_env", lambda *a: {}) + monkeypatch.setattr(lifecycle.meta_mod, "hook_ctx", lambda *a: None) + monkeypatch.setattr(lifecycle.abra, "has_lightweight_version_tags", lambda r: False) + monkeypatch.setattr(lifecycle, "has_ccci_overlay", lambda r: False) + monkeypatch.setattr( + lifecycle.abra, "recipe_checkout", lambda r, v: events.append(("checkout", v)) + ) + monkeypatch.setattr( + lifecycle.abra, "deploy", lambda d, **kw: events.append(("deploy", kw["chaos"])) + ) + for apply_previous in (False, True): + events.clear() + lifecycle.deploy_app( + "example", + "example.invalid", + version="1.0.0", + apply_previous=apply_previous, + meta=object(), + _count_deploy=False, + ) + assert events == [("checkout", "1.0.0"), ("deploy", apply_previous)]