Initial curated Unraid-AppOps-Gateway source from 3bd6f6fee310125bfbb4d4650389a817f498724d
This commit is contained in:
commit
1dfbca08a1
528 files changed
+131054
No files matched your search
@@ -0,0 +1,156 @@
|
||||
from backend.app.services.action_execution import approval_execution_supported
|
||||
from backend.app.services.action_registry import ACTION_RISK, ACTIONS, action_default_target
|
||||
from backend.app.services.portfolio_deployment_enrollment import (
|
||||
_ENROLL_SCRIPT,
|
||||
_INSPECT_SCRIPT,
|
||||
_LEGACY_REVISION,
|
||||
_LEGACY_SINGLE_PROJECT,
|
||||
_PROJECT,
|
||||
_RECOVERY_FAILED_REVISION,
|
||||
_RECOVERY_FAILURE_MESSAGE,
|
||||
_RECOVERY_LIVE_REVISION,
|
||||
_REPOSITORY,
|
||||
PortfolioDeploymentEnrollment,
|
||||
)
|
||||
|
||||
|
||||
class _Response:
|
||||
def __init__(self, *, payload=None, text=""):
|
||||
self._payload = payload
|
||||
self.text = text
|
||||
|
||||
def json(self):
|
||||
return self._payload
|
||||
|
||||
|
||||
class _InspectPortainer:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
def _request(self, method, path, **kwargs):
|
||||
self.calls.append((method, path, kwargs))
|
||||
if path.endswith("/exec"):
|
||||
return _Response(payload={"Id": "exec-safe-inspect"})
|
||||
if path.endswith("/start"):
|
||||
return _Response(
|
||||
text='{"branch":"main","compose_files":["docker-compose.yml"],"containers":["Portfolio","Portfolio-api"],"present":true}'
|
||||
)
|
||||
raise AssertionError(f"Unexpected Portainer path: {path}")
|
||||
|
||||
|
||||
def test_portfolio_enrollment_contract_is_fixed_and_paired():
|
||||
assert _REPOSITORY == "jens/portfolio"
|
||||
assert _LEGACY_REVISION == "e59bfb3484531883e5486ee9e10b663ed0f6764f"
|
||||
assert _PROJECT["branch"] == "main"
|
||||
assert _PROJECT["exact_source"] is True
|
||||
assert _PROJECT["env_source"] == "/srv/example/appdata/Portfolio/.env"
|
||||
assert _PROJECT["compose_files"] == ["docker-compose.yml"]
|
||||
assert _PROJECT["compose_project"] == "portfolio"
|
||||
assert _PROJECT["containers"] == ["Portfolio", "Portfolio-api"]
|
||||
assert _PROJECT["verify_oci_revision"] is False
|
||||
assert _PROJECT["environment"] == {
|
||||
"GIT_COMMIT": "{revision}",
|
||||
"BUILD_ID": "build-{short_revision}",
|
||||
}
|
||||
|
||||
|
||||
def test_portfolio_enrollment_registry_alias_matches_controller_cache_bind_source():
|
||||
assert 'registry_path = Path("/opt/gitea-deploy/projects.json")' in _ENROLL_SCRIPT
|
||||
assert (
|
||||
'host_registry_path = Path("/mnt/cache/appdata/gitea-deploy-runners/controller/projects.json")'
|
||||
in _ENROLL_SCRIPT
|
||||
)
|
||||
assert "os.path.samefile(registry_path, host_registry_path)" in _ENROLL_SCRIPT
|
||||
assert '/srv/example/appdata/gitea-deploy-runners/deploy.lock' not in _ENROLL_SCRIPT
|
||||
assert '/mnt/cache/appdata/gitea-deploy-runners/deploy.lock' in _ENROLL_SCRIPT
|
||||
|
||||
|
||||
def test_portfolio_enrollment_uses_project_then_global_lock_order_without_child_deadlock():
|
||||
project_lock = "fcntl.flock(project_lock, fcntl.LOCK_EX)"
|
||||
cache_lock = "fcntl.flock(lock, fcntl.LOCK_EX)"
|
||||
|
||||
assert _ENROLL_SCRIPT.index(project_lock) < _ENROLL_SCRIPT.index(cache_lock)
|
||||
assert "controller.bootstrap_legacy_state(repository, project, legacy_revision)" in _ENROLL_SCRIPT
|
||||
assert '["python3", "/opt/gitea-deploy/deploy.py", "bootstrap-legacy"' not in _ENROLL_SCRIPT
|
||||
|
||||
|
||||
def test_portfolio_enrollment_only_migrates_known_legacy_single_target():
|
||||
assert _LEGACY_SINGLE_PROJECT["containers"] == ["portfolio"]
|
||||
assert _LEGACY_SINGLE_PROJECT["compose_project"] == "portfolio"
|
||||
assert _LEGACY_SINGLE_PROJECT["compose_files"] == ["docker-compose.yml"]
|
||||
assert "env_source" not in _LEGACY_SINGLE_PROJECT
|
||||
|
||||
|
||||
def test_portfolio_target_registration_is_a_typed_high_risk_action():
|
||||
action = "deployment.target.register_portfolio"
|
||||
assert action in ACTIONS
|
||||
assert ACTION_RISK[action] == "high"
|
||||
assert action_default_target(action) == "jens/portfolio"
|
||||
assert approval_execution_supported(action) is True
|
||||
|
||||
|
||||
def test_portfolio_target_inspection_returns_only_sanitized_json_from_controller():
|
||||
portainer = _InspectPortainer()
|
||||
service = PortfolioDeploymentEnrollment(portainer=portainer)
|
||||
|
||||
result = service._inspect_current_target(endpoint="1", container_id="controller-id")
|
||||
|
||||
assert result == {
|
||||
"branch": "main",
|
||||
"compose_files": ["docker-compose.yml"],
|
||||
"containers": ["Portfolio", "Portfolio-api"],
|
||||
"present": True,
|
||||
}
|
||||
assert portainer.calls[0][2]["json"]["AttachStdout"] is True
|
||||
assert portainer.calls[0][2]["json"]["Tty"] is True
|
||||
assert portainer.calls[1][2]["json"] == {"Detach": False, "Tty": True}
|
||||
|
||||
|
||||
def test_portfolio_target_inspection_exposes_only_bounded_state_diagnostics():
|
||||
assert (
|
||||
'state_path = Path("/mnt/cache/appdata/gitea-deploy-runners/state/portfolio.json")'
|
||||
in _INSPECT_SCRIPT
|
||||
)
|
||||
for allowed in (
|
||||
'"schema_version"',
|
||||
'"live_revision"',
|
||||
'"live_status"',
|
||||
'"live_legacy_provenance"',
|
||||
'"last_attempt"',
|
||||
'"live_artifact_containers"',
|
||||
):
|
||||
assert allowed in _INSPECT_SCRIPT
|
||||
assert 'safe_attempt["message"]' in _INSPECT_SCRIPT
|
||||
assert "[:768]" in _INSPECT_SCRIPT
|
||||
assert 'state.get("live_receipt")' not in _INSPECT_SCRIPT
|
||||
assert 'state.get("rollback_snapshot")' not in _INSPECT_SCRIPT
|
||||
|
||||
|
||||
def test_portfolio_runtime_reconciliation_is_pinned_to_observed_failure():
|
||||
assert _RECOVERY_LIVE_REVISION == "52c6f2fc74a1e39ad288f1c5e987a9cd5b072d3e"
|
||||
assert _RECOVERY_FAILED_REVISION == "b7955d90b63860ffff8e0bd84be123aaba632043"
|
||||
assert (
|
||||
_RECOVERY_FAILURE_MESSAGE
|
||||
== "Existing production containers require a valid healthy live deployment state"
|
||||
)
|
||||
assert 'existing_state.get("live_status") == "unknown"' in _ENROLL_SCRIPT
|
||||
assert 'existing_state.get("live_legacy_provenance") is False' in _ENROLL_SCRIPT
|
||||
assert 'last_attempt.get("revision") == recovery_failed_revision' in _ENROLL_SCRIPT
|
||||
assert 'last_attempt.get("message") == recovery_failure_message' in _ENROLL_SCRIPT
|
||||
assert 'isinstance(live_receipt, dict)' in _ENROLL_SCRIPT
|
||||
assert 'bool(live_receipt)' in _ENROLL_SCRIPT
|
||||
assert 'set(artifact_containers) == set(project["containers"])' in _ENROLL_SCRIPT
|
||||
|
||||
|
||||
def test_portfolio_runtime_reconciliation_proves_exact_recorded_artifacts():
|
||||
assert 'revision_label != recovery_live_revision' in _ENROLL_SCRIPT
|
||||
assert 'build_label != f"build-{recovery_live_revision[:12]}"' in _ENROLL_SCRIPT
|
||||
assert 'artifact.get("image_id")' in _ENROLL_SCRIPT
|
||||
assert 'artifact.get("container_id")' in _ENROLL_SCRIPT
|
||||
assert 'str(container.get("Image") or "")' in _ENROLL_SCRIPT
|
||||
assert 'str(container.get("Id") or "")' in _ENROLL_SCRIPT
|
||||
assert 'reconciled_state = dict(existing_state)' in _ENROLL_SCRIPT
|
||||
assert 'reconciled_state["live_status"] = "healthy"' in _ENROLL_SCRIPT
|
||||
assert 'reconciled_state["status"] = "success"' in _ENROLL_SCRIPT
|
||||
assert 'bool(verify.get("live_receipt"))' in _ENROLL_SCRIPT
|
||||
assert "runtime-state-reconciled" in _ENROLL_SCRIPT
|
||||
Reference in new issue
Block a user