Harden live release workflow #25
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import pytest
|
||||
|
||||
|
||||
def test_health_contains_build_info(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
@@ -21,6 +24,16 @@ def test_build_date_is_rendered_in_local_time(monkeypatch):
|
||||
assert build_info.build_info()["build_date"] == "2026-07-29T14:00:00+02:00"
|
||||
|
||||
|
||||
def test_build_info_prefers_installed_release_provenance(monkeypatch):
|
||||
import importarr.build_info as build_info
|
||||
|
||||
monkeypatch.setenv("IMPORTARR_VERSION", "v1.2.3")
|
||||
monkeypatch.setenv("IMPORTARR_GIT_SHA", "abc123")
|
||||
|
||||
assert build_info.build_info()["version"] == "v1.2.3"
|
||||
assert build_info.build_info()["git_sha"] == "abc123"
|
||||
|
||||
|
||||
def test_status_contains_service_configuration(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
@@ -132,3 +145,83 @@ def test_connection_test_rejects_unknown_service(tmp_path, monkeypatch):
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_control_endpoints_require_configured_bearer_token(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
monkeypatch.setattr(main.settings, "auth_token", "test-token")
|
||||
client = TestClient(main.app)
|
||||
|
||||
for method, endpoint in (("get", "/api/control/update-check"), ("post", "/api/control/update"), ("post", "/api/control/restart")):
|
||||
assert getattr(client, method)(endpoint).status_code == 401
|
||||
assert getattr(client, method)(endpoint, headers={"Authorization": "Bearer wrong"}).status_code == 401
|
||||
|
||||
|
||||
def test_write_endpoint_fails_closed_without_token_on_non_loopback_bind(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
monkeypatch.setattr(main.settings, "auth_token", None)
|
||||
monkeypatch.setattr(main.settings, "bind_host", "0.0.0.0")
|
||||
assert TestClient(main.app).post("/api/control/restart").status_code == 503
|
||||
|
||||
|
||||
def test_tokenless_local_development_remains_available(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
|
||||
monkeypatch.setattr(main.settings, "auth_token", None)
|
||||
monkeypatch.setattr(main.settings, "bind_host", "127.0.0.1")
|
||||
main.require_write_auth()
|
||||
|
||||
|
||||
def test_update_schedules_exact_latest_release_tag(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: {"status": "update_available", "current_version": "v1.0.0", "latest_version": "v1.2.3", "update_available": True})
|
||||
monkeypatch.setattr(main.settings, "update_command", ["/opt/importarr/repo-upgrade.sh"])
|
||||
scheduled = []
|
||||
monkeypatch.setattr(main, "_schedule_update", scheduled.append)
|
||||
|
||||
response = main.update_service(expected_tag="v1.2.3")
|
||||
assert scheduled == [["/opt/importarr/repo-upgrade.sh", "v1.2.3"]]
|
||||
assert response["status"] == "update_scheduled"
|
||||
|
||||
|
||||
def test_update_endpoint_requires_expected_tag(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
monkeypatch.setattr(main.settings, "auth_token", "test-token")
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: pytest.fail("release lookup must not run"))
|
||||
|
||||
response = TestClient(main.app).post(
|
||||
"/api/control/update",
|
||||
headers={"Authorization": "Bearer test-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
assert response.json()["detail"][0]["loc"] == ["query", "expected_tag"]
|
||||
|
||||
|
||||
def test_update_rejects_unexpected_latest_release(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("IMPORTARR_STATE_PATH", str(tmp_path / "state.db"))
|
||||
import importarr.main as main
|
||||
from fastapi import HTTPException
|
||||
|
||||
monkeypatch.setattr(main, "check_update_available", lambda: {"latest_version": "v1.2.4", "update_available": True})
|
||||
scheduled = []
|
||||
monkeypatch.setattr(main, "_schedule_update", scheduled.append)
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
main.update_service(expected_tag="v1.2.3")
|
||||
|
||||
assert exc_info.value.status_code == 409
|
||||
assert scheduled == []
|
||||
|
||||
Reference in New Issue
Block a user