Files
Unraid-AppOps-Gateway-Public/backend/tests/test_mcp_hub_deployment_reconciliation.py
T

283 lines
13 KiB
Python

from types import SimpleNamespace
from backend.app.services.mcp_hub_deployment_reconciliation import (
McpHubDeploymentReconciliation,
)
class FakeResponse:
def __init__(self, payload):
self.payload = payload
def json(self):
return self.payload
class FakePortainer:
def __init__(self, exit_code=0):
self.exit_code = exit_code
self.calls = []
def get_container_status(self, name):
assert name == "gitea-deploy-control"
return {
"status": "ok",
"container": {
"id": "controller-id",
"name": "gitea-deploy-control",
"state": "running",
},
}
def _config(self):
return SimpleNamespace(endpoint_id="3")
def _request(self, method, path, **kwargs):
self.calls.append((method, path, kwargs))
if path.endswith("/containers/controller-id/exec"):
return FakeResponse({"Id": "exec-1"})
if path.endswith("/exec/exec-1/start"):
return FakeResponse({})
if path.endswith("/exec/exec-1/json"):
return FakeResponse({"Running": False, "ExitCode": self.exit_code})
raise AssertionError(path)
def test_reconciliation_is_fixed_to_mcp_hub_and_reconciles_only_verified_failed_forward_state():
fake = FakePortainer()
result = McpHubDeploymentReconciliation(fake).run()
assert result == {
"status": "reconciled",
"repository": "jens/itworx_mcp_hub",
"composeProject": "itworx-mcp-hub",
}
create = fake.calls[0]
command = create[2]["json"]["Cmd"]
assert command[:2] == ["python3", "-c"]
assert command[3:] == ["jens/itworx_mcp_hub", "itworx-mcp-hub"]
assert create[2]["json"]["AttachStdout"] is False
assert create[2]["json"]["AttachStderr"] is False
script = command[2]
assert "/opt/gitea-deploy/projects.json" in script
assert "/mnt/cache/appdata/gitea-deploy-runners/controller/projects.json" in script
assert "os.path.samefile(registry_path, host_registry_path)" in script
assert "/mnt/cache/appdata/gitea-deploy-runners/state" in script
assert "/srv/example/appdata/gitea-deploy-runners/deploy.lock" not in script
assert "/mnt/cache/appdata/gitea-deploy-runners/deploy.lock" in script
assert 'project.get("branch") != "main"' in script
assert 'project.get("compose_project") != expected_compose_project' in script
assert 'recorded_status != "failed"' in script
assert 'recorded_live_status not in {"healthy", "unknown"}' in script
assert 'attempt_status != "failed"' in script
assert 'attempt_revision == recorded_live' in script
assert 'git_run("merge-base", "--is-ancestor", recorded_live, attempt_revision)' in script
assert 'git_run("merge-base", "--is-ancestor", attempt_revision, main_revision)' in script
def test_unknown_live_status_is_accepted_only_for_a_proven_snapshot_stage_failure_without_rollback_error():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert 'last_attempt_message = str(last_attempt.get("message") or "")' in script
assert "snapshot_failure_prefixes = (" in script
assert 'recorded_live_status == "unknown"' in script
assert 'last_attempt_message.startswith(snapshot_failure_prefixes)' in script
assert '"; rollback error:" in last_attempt_message' in script
assert '"; source rollback error:" in last_attempt_message' in script
assert "raise SystemExit(55)" in script
def test_reconciliation_proves_complete_live_compose_topology_and_preserves_actual_image_ids():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert 'expected_containers = project.get("containers")' in script
assert "set(project_names) != set(expected_containers)" in script
assert 'labels.get("com.docker.compose.project") != expected_compose_project' in script
assert 'not runtime_state.get("Running")' in script
assert 'health in {"starting", "unhealthy"}' in script
assert 'image_id = str(container.get("Image") or "")' in script
assert 'artifacts = {"containers": container_artifacts, "compose_sha256": ""}' in script
assert '"live_legacy_provenance": True' in script
assert '"live_artifacts": artifacts' in script
assert '"live_revision": recorded_live' in script
def test_reconciliation_recognizes_only_the_fixed_mcp_hub_oci_source_as_owned():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert 'owned_image_source = "https://gitea.example.com/jens/itworx-mcp-hub"' in script
assert "if image_source == owned_image_source:" in script
assert 'git_run("merge-base", "--is-ancestor", recorded_live, image_revision)' in script
assert 'git_run("merge-base", "--is-ancestor", image_revision, main_revision)' in script
assert 'image_source.startswith("https://gitea.example.com/")' not in script
assert 'image_source == repository' not in script
assert '"live_revision": main_revision' not in script
assert '"live_revision": attempt_revision' not in script
def test_owned_image_ancestry_can_fail_closed_to_the_canonical_gitea_store():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert 'canonical_repository_root = Path("/mnt/cache/appdata/gitea/git/repositories")' in script
assert 'canonical_bare_repo = canonical_repository_root / owner / f"{name}.git"' in script
assert "def canonical_git_run(*args):" in script
assert "def canonical_image_ancestry_is_proven(" in script
assert 'resolved_recorded = canonical_git_run("rev-parse", f"{recorded_revision}^{{commit}}")' in script
assert 'resolved_image = canonical_git_run("rev-parse", f"{image_revision}^{{commit}}")' in script
assert 'resolved_main = canonical_git_run("rev-parse", "refs/heads/main")' in script
assert 'resolved_main.stdout.strip() == expected_main' in script
assert '"merge-base", "--is-ancestor", recorded_revision, image_revision' in script
assert '"merge-base", "--is-ancestor", image_revision, expected_main' in script
assert "if not mounted_ancestry_proven and not canonical_image_ancestry_is_proven(" in script
assert "canonical_bare_repo.is_symlink()" in script
def test_unchanged_recorded_image_ids_do_not_reinterpret_historical_oci_revision_labels():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
change_probe = "image_changed = image_id != recorded_image_id"
provenance_gate = "if image_changed:"
compat_probe = "contextforge_compat_image = main_declares_contextforge_compat_image(name, image_ref)"
dataplane_probe = "main_declares_sessionless_dataplane_image(name, image_ref)"
owned_probe = "elif image_source == owned_image_source:"
external_probe = "elif not main_declares_external_image(image_ref):"
assert change_probe in script
assert provenance_gate in script
assert compat_probe in script
assert dataplane_probe in script
assert "not already_reconciled" in script
assert owned_probe in script
assert external_probe in script
assert script.index(change_probe) < script.index(provenance_gate)
assert script.index(provenance_gate) < script.index(compat_probe)
assert script.index(compat_probe) < script.index(dataplane_probe)
assert script.index(dataplane_probe) < script.index(owned_probe)
assert script.index(owned_probe) < script.index(external_probe)
assert "if image_id != recorded_image_id or container_id != recorded_container_id:" in script
def test_external_image_drift_requires_an_immutable_digest_declared_in_reviewed_main_compose():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert "def main_declares_external_image(image_ref):" in script
assert "@sha256:" in script
assert 'git_run("show", f"{main_revision}:{compose_path}")' in script
assert '"infrastructure/compose/docker-compose.yml"' in script
assert '"infrastructure/compose/docker-compose.prod.yml"' in script
assert 'line.strip() in {f"image: {image_ref}", f\'image: "{image_ref}"\', f"image: \'{image_ref}\'"}' in script
assert "main_declares_external_image(image_ref)" in script
assert "elif not main_declares_external_image(image_ref):" in script
def test_contextforge_compat_image_drift_requires_exact_reviewed_main_contract():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert 'container_name != "itworx-mcp-hub-contextforge-1"' in script
assert 'f"{main_revision}:infrastructure/images/contextforge/compat-image.env"' in script
assert 'f"{main_revision}:scripts/build_contextforge_compat_image.sh"' in script
assert '"CONTEXTFORGE_UPSTREAM_COMMIT"' in script
assert '"CONTEXTFORGE_ALEMBIC_HEAD"' in script
assert '"CONTEXTFORGE_MCP_SDK"' in script
assert '"CONTEXTFORGE_LOCAL_IMAGE"' in script
assert 're.fullmatch(r"[0-9a-f]{40}", upstream_commit)' in script
assert 're.fullmatch(r"[0-9a-f]{12}", alembic_head)' in script
assert 'local_image != f"itworx-mcp-hub/contextforge-schema:{alembic_head}"' in script
assert 'git -C "$SRC" fetch --depth 1 origin "$CONTEXTFORGE_UPSTREAM_COMMIT"' in script
assert 'git -C "$SRC" checkout --detach FETCH_HEAD' in script
assert 'MCP_REQUIREMENT="mcp==${CONTEXTFORGE_MCP_SDK}"' in script
assert 'alembic -c mcpgateway/alembic.ini heads' in script
assert 'docker tag "$STAGED_IMAGE" "$CONTEXTFORGE_LOCAL_IMAGE"' in script
assert 'image_ref.startswith("itworx-mcp-hub/contextforge-schema:")' not in script
compat_probe = "contextforge_compat_image = main_declares_contextforge_compat_image(name, image_ref)"
owned_probe = "elif image_source == owned_image_source:"
assert compat_probe in script
assert "if contextforge_compat_image or sessionless_dataplane_image:" in script
assert owned_probe in script
assert script.index(compat_probe) < script.index(owned_probe)
def test_sessionless_dataplane_baseline_is_one_time_and_commit_bound():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert 'container_name != "itworx-mcp-hub-dataplane-router-1"' in script
assert 'image_ref != "itworx-mcp-hub/dataplane:sessionless-final"' in script
assert 'sessionless_commit = "b519a8c4cf17cd9df00a575acfe096838aab7789"' in script
assert 'f"{sessionless_commit}:services/dataplane_router/router.py"' in script
assert 'f"{sessionless_commit}:tests/test_dataplane_session_headers.py"' in script
assert 'f"{main_revision}:evidence/mcp-session-boundary-20260916/SUMMARY.md"' in script
assert 'MCP_TRANSPORT_STATE_HEADERS = frozenset({b"mcp-session-id"})' in script
assert 'del response.headers["mcp-session-id"]' in script
assert '"2025-11-25"' in script
assert '"2026-07-28"' in script
assert '"permanently enforce stateless public transport"' in script
assert (
'git_run("merge-base", "--is-ancestor", sessionless_commit, main_revision)'
in script
)
assert "not already_reconciled" in script
def test_already_reconciled_state_is_reverified_before_idempotent_success():
fake = FakePortainer()
McpHubDeploymentReconciliation(fake).run()
script = fake.calls[0][2]["json"]["Cmd"][2]
assert "already_reconciled = (" in script
assert script.index("already_reconciled = (") < script.index("project_names =")
assert script.index("container_artifacts = {}") < script.index("if already_reconciled:")
assert 'print("already-reconciled", flush=True)' in script
assert "if drift_found:" in script
def test_reconciliation_refuses_unknown_runtime_topology():
result = McpHubDeploymentReconciliation(FakePortainer(exit_code=47)).run()
assert result == {
"status": "validation_failed",
"reason": "live MCP Hub Compose project differs from the controller target",
}
def test_reconciliation_refuses_unproven_runtime_revision_drift():
result = McpHubDeploymentReconciliation(FakePortainer(exit_code=51)).run()
assert result == {
"status": "validation_failed",
"reason": "live MCP Hub image revision or external immutable image is not proven by the recorded-live to main chain",
}
def test_reconciliation_refuses_state_that_is_not_the_known_failed_forward_shape():
result = McpHubDeploymentReconciliation(FakePortainer(exit_code=52)).run()
assert result == {
"status": "validation_failed",
"reason": "controller state drift is not the exact known recoverable MCP Hub state",
}
def test_reconciliation_refuses_unknown_state_without_snapshot_stage_proof():
result = McpHubDeploymentReconciliation(FakePortainer(exit_code=55)).run()
assert result == {
"status": "validation_failed",
"reason": "unknown MCP Hub live status was not produced by a proven recoverable snapshot-stage failure",
}