from __future__ import annotations from types import SimpleNamespace import pytest from test_deploy_broker import deploy_module as _deploy_fixture from test_hub_component_transport import controller as _controller_fixture @pytest.fixture def deploy_module(): return _deploy_fixture.__wrapped__() @pytest.fixture def controller(monkeypatch): return _controller_fixture.__wrapped__(monkeypatch) @pytest.mark.parametrize("mode", ["deploy", "rollback"]) def test_original_git_objects_are_bound_before_identity_reads(deploy_module, monkeypatch, mode): monkeypatch.delenv("APPOPS_REGISTERED_LEGACY_REQUEST_ID", raising=False) monkeypatch.delenv("GIT_NO_REPLACE_OBJECTS", raising=False) assert deploy_module.bind_registered_legacy_request({}, mode) == "" assert deploy_module.os.environ["GIT_NO_REPLACE_OBJECTS"] == "1" def test_known_registered_restore_keeps_verified_revision_and_fresh_runtime_ids(deploy_module): prior_revision = "a" * 40 restored_artifacts = { "containers": { "quiz-monitor-quiz-server-1": { "container_id": "b" * 64, "image_id": "sha256:" + "c" * 64, } }, "registered_legacy": {"requestId": "restored-request", "revision": prior_revision}, } restored_receipt = {"revision": prior_revision, "containers": restored_artifacts["containers"]} project = { "_registered_legacy_restored": True, "_registered_legacy_restored_revision": prior_revision, "_registered_legacy_restored_artifacts": restored_artifacts, "_registered_legacy_restored_receipt": restored_receipt, } result = deploy_module.resolve_failed_live_state( {"live_revision": prior_revision, "live_status": "healthy"}, {"revision": prior_revision, "legacy_provenance": False, "registered_legacy": {}}, project, production_started=True, failure_stage="verification", restore_error=None, ) assert result["live_revision"] == prior_revision assert result["live_status"] == "healthy" assert result["live_legacy_provenance"] is False assert result["live_artifacts"] == restored_artifacts assert result["live_receipt"] == restored_receipt def test_failed_known_registered_restore_keeps_provenance_unknown(deploy_module): prior_revision = "a" * 40 result = deploy_module.resolve_failed_live_state( {"live_revision": prior_revision, "live_status": "healthy"}, {"revision": prior_revision, "legacy_provenance": False, "registered_legacy": {}}, {}, production_started=True, failure_stage="verification", restore_error=RuntimeError("restore failed"), ) assert result["live_status"] == "unknown" assert result["live_artifacts"] == {} assert result["live_receipt"] == {} def test_known_restore_source_callback_precedes_verification_and_state_binding( deploy_module, monkeypatch ): previous_revision = "a" * 40 failed_revision = "d" * 40 image_ids = {"quiz-monitor-quiz-server-1": "sha256:" + "c" * 64} restored_receipt = {"revision": previous_revision, "build": {"revision": previous_revision}} artifacts = {"containers": {}, "registered_legacy": {"revision": previous_revision}} events = [] project = {} def core_restore(_repository, _project, _snapshot, _failed, **kwargs): events.append("signed-preimage-verified") restore_source = kwargs.get("restore_source") assert callable(restore_source), "known restore requires a source callback after signed validation" restore_source(previous_revision) events.append("restored-runtime-signed") return {"revision": previous_revision, "artifacts": artifacts, "imageIDs": image_ids, "liveReceipt": restored_receipt} def source_restore(_project, _repository, revision): assert revision == previous_revision events.append("prior-source-restored") def verify(_project, metadata, *, expected_image_ids): assert metadata["revision"] == previous_revision assert expected_image_ids == image_ids events.append("health-and-provenance-verified") return restored_receipt monkeypatch.setattr(deploy_module, "read_state", lambda _project: {}) monkeypatch.setattr(deploy_module, "_registered_legacy_receipt_key", lambda: b"k" * 32) monkeypatch.setattr(deploy_module, "_load_registered_legacy_adoption", lambda: SimpleNamespace( restore_deployment_snapshot=core_restore )) monkeypatch.setattr(deploy_module, "restore_live_source", source_restore) monkeypatch.setattr(deploy_module, "validate_recorded_receipt", lambda *_args: restored_receipt["build"]) monkeypatch.setattr(deploy_module, "verify_deployment", verify) deploy_module.restore_compose_snapshot( project, {"revision": previous_revision, "legacy_provenance": False, "registered_legacy": {}}, "jens/quiz-monitor", failed_revision, ) assert events == ["signed-preimage-verified", "prior-source-restored", "restored-runtime-signed", "health-and-provenance-verified"] assert project["_registered_legacy_restored"] is True assert project["_registered_legacy_restored_revision"] == previous_revision assert project["_registered_legacy_restored_receipt"] == restored_receipt @pytest.mark.parametrize("receipt_matches", [True, False]) def test_typed_rollback_worker_supplies_fixed_source_and_provenance_verifiers( controller, monkeypatch, receipt_matches ): import sys module, projects = controller repository = "jens/quiz-monitor" previous_revision = "a" * 40 receipt = {"revision": previous_revision, "build": {"revision": previous_revision}} project = {"slug": "quiz-monitor", "source_dir": "/fixed/source"} projects[repository] = project calls = [] def rollback(_payload, **kwargs): kwargs["restore_source"](previous_revision) kwargs["verify_restored"]({"revision": previous_revision, "liveReceipt": receipt, "imageIDs": {"quiz": "immutable-image"}}) calls.append("state-cas") monkeypatch.setitem(sys.modules, "registered_legacy_adoption", SimpleNamespace( rollback=rollback, read_registered_state=lambda *_a: ({}, None), RegisteredLegacyAdoptionError=ValueError, record_worker_failure=lambda *_a, **_k: calls.append("failed"), )) monkeypatch.setitem(sys.modules, "deploy", SimpleNamespace( restore_live_source=lambda selected, repo, revision: calls.append( ("source", selected, repo, revision)), validate_recorded_receipt=lambda selected, raw, repo, revision: receipt["build"], verify_deployment=lambda selected, build, **kwargs: calls.append("verified") or ( receipt if receipt_matches else {**receipt, "revision": "f" * 40} ), )) module._run_registered_legacy_rollback({ "repository": repository, "requestId": "11111111-1111-4111-8111-111111111111", }, b"k" * 32) assert calls == [("source", project, repository, previous_revision), "verified", "state-cas" if receipt_matches else "failed"]