"""Import der Gitea-Actions-Variablen in die Einstellungen (mit gefakter Gitea-API).""" import pytest from fastapi.testclient import TestClient from app.db import session from app.main import app from app.services import gitea_import class FakeGitea: def __init__(self, repo_vars, org_vars=None, status=200): self.repo_vars, self.org_vars, self.status, self.urls, self.tokens = repo_vars, org_vars or [], status, [], [] def __call__(self, url, token): self.urls.append(url) self.tokens.append(token) if self.status != 200: return self.status, None if "/orgs/" in url: return (404, None) if self.org_vars is None else (200, self.org_vars) return 200, self.repo_vars def test_fetch_merges_org_and_repo_and_maps_settings(): g = FakeGitea([{"name": "DOMAIN", "data": "kunde.de"}, {"name": "LLM_MODEL", "data": "claude-x"}, {"name": "REGISTRY", "data": "reg/o"}], [{"name": "LLM_MODEL", "data": "org-model"}, {"name": "SMTP_HOST", "data": "mail.x"}]) v = gitea_import.fetch_variables("https://gitea.test", "Org/Repo", "tok", g) assert v == {"LLM_MODEL": "claude-x", "SMTP_HOST": "mail.x", "DOMAIN": "kunde.de", "REGISTRY": "reg/o"} # Repo schlägt Organisation assert all(t == "tok" for t in g.tokens) and g.urls[0].startswith("https://gitea.test/api/v1/orgs/Org/actions/variables") def test_errors_are_explained(): with pytest.raises(gitea_import.GiteaError, match="Zugriff"): gitea_import.fetch_variables("https://g", "O/R", "t", FakeGitea([], status=403)) with pytest.raises(gitea_import.GiteaError, match="nicht verfügbar"): gitea_import.fetch_variables("https://g", "O/R", "t", FakeGitea(None, None, status=404) if False else (lambda u, t: (404, None))) with pytest.raises(gitea_import.GiteaError, match="Besitzer/Name"): gitea_import.fetch_variables("https://g", "nurname", "t", FakeGitea([])) def test_preview_statuses_and_masking(): with TestClient(app): with session() as db: rows = {r["name"]: r for r in gitea_import.preview(db, {"DOMAIN": "kunde.de", "AUTH_ENABLED": "true", "SMTP_HOST": "mail.x", "REGISTRY_HOST": "h", "GLADIA_NER": "1", "SOME_API_KEY": "geheim", "LLM_MODEL": "claude-4-6-sonnet"})} assert rows["DOMAIN"]["setting"] == "base_domain" and rows["DOMAIN"]["status"] == "geändert" assert rows["AUTH_ENABLED"]["status"] == "gleich" and rows["SMTP_HOST"]["status"] == "neu" and rows["LLM_MODEL"]["status"] == "gleich" assert rows["REGISTRY_HOST"]["status"] == "ignoriert" and rows["GLADIA_NER"]["status"] == "unbekannt" assert rows["SOME_API_KEY"]["status"] == "unbekannt" def test_endpoint_never_stores_or_echoes_the_token(monkeypatch): monkeypatch.setattr(gitea_import, "_real_get", lambda url, token: (200, [{"name": "DOMAIN", "data": "kunde.de"}]) if "/repos/" in url else (404, None)) monkeypatch.setattr(gitea_import, "fetch_variables", lambda base, repo, token, get=None: {"DOMAIN": "kunde.de"}) with TestClient(app) as c: r = c.post("/api/gitea/variables", json={"repo": "O/R", "token": "supergeheim"}) assert r.status_code == 200 and "supergeheim" not in r.text and r.json()["rows"][0]["setting"] == "base_domain" assert c.post("/api/gitea/variables", json={"repo": "O/R"}).status_code == 400 assert "supergeheim" not in c.get("/api/settings").text