Add OAuth2/OIDC per-user Gitea authentication
Introduce a GiteaOAuthValidator for JWT and userinfo validation and fallbacks, add /oauth/token proxy, and thread per-user tokens through the request context and automation paths. Update config and .env.example for OAuth-first mode, add OpenAPI, extensive unit/integration tests, GitHub/Gitea CI workflows, docs, and lint/test enforcement (>=80% cov).
This commit is contained in:
140
tests/test_automation_manager.py
Normal file
140
tests/test_automation_manager.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""Unit tests for automation manager job paths."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from aegis_gitea_mcp.automation import AutomationError, AutomationManager
|
||||
from aegis_gitea_mcp.config import reset_settings
|
||||
from aegis_gitea_mcp.policy import reset_policy_engine
|
||||
|
||||
|
||||
class StubAutomationGiteaClient:
|
||||
"""Async context manager stub for automation jobs."""
|
||||
|
||||
def __init__(self, token: str, issues: list[dict] | None = None) -> None:
|
||||
self.token = token
|
||||
self._issues = issues or []
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *_args):
|
||||
return None
|
||||
|
||||
async def list_issues(self, owner, repo, *, state, page, limit, labels=None):
|
||||
return self._issues
|
||||
|
||||
async def create_issue(self, owner, repo, *, title, body, labels=None, assignees=None):
|
||||
return {"number": 77, "title": title, "body": body}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_globals() -> None:
|
||||
"""Reset singleton state between tests."""
|
||||
reset_settings()
|
||||
reset_policy_engine()
|
||||
yield
|
||||
reset_settings()
|
||||
reset_policy_engine()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def automation_env(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> Path:
|
||||
"""Set environment for automation manager tests."""
|
||||
policy_path = tmp_path / "policy.yaml"
|
||||
policy_path.write_text(
|
||||
(
|
||||
"defaults:\n"
|
||||
" read: allow\n"
|
||||
" write: allow\n"
|
||||
"tools:\n"
|
||||
" allow:\n"
|
||||
" - automation_stale_issue_detection\n"
|
||||
" - automation_auto_issue_creation\n"
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.setenv("GITEA_URL", "https://gitea.example.com")
|
||||
monkeypatch.setenv("GITEA_TOKEN", "legacy-token")
|
||||
monkeypatch.setenv("MCP_API_KEYS", "a" * 64)
|
||||
monkeypatch.setenv("ENVIRONMENT", "test")
|
||||
monkeypatch.setenv("AUTOMATION_ENABLED", "true")
|
||||
monkeypatch.setenv("POLICY_FILE_PATH", str(policy_path))
|
||||
monkeypatch.setenv("WRITE_MODE", "true")
|
||||
monkeypatch.setenv("WRITE_REPOSITORY_WHITELIST", "acme/demo")
|
||||
monkeypatch.setenv("AUTOMATION_STALE_DAYS", "30")
|
||||
return policy_path
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stale_issue_detection_job_finds_old_issues(
|
||||
automation_env: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Stale issue detection returns issue numbers older than cutoff."""
|
||||
|
||||
issues = [
|
||||
{"number": 1, "updated_at": "2020-01-01T00:00:00Z"},
|
||||
{"number": 2, "updated_at": "2999-01-01T00:00:00Z"},
|
||||
]
|
||||
|
||||
monkeypatch.setattr(
|
||||
"aegis_gitea_mcp.automation.GiteaClient",
|
||||
lambda token: StubAutomationGiteaClient(token=token, issues=issues),
|
||||
)
|
||||
|
||||
manager = AutomationManager()
|
||||
result = await manager.run_job(
|
||||
job_name="stale_issue_detection",
|
||||
owner="acme",
|
||||
repo="demo",
|
||||
user_token="user-token",
|
||||
)
|
||||
|
||||
assert result["stale_issue_numbers"] == [1]
|
||||
assert result["stale_count"] == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auto_issue_creation_requires_token(
|
||||
automation_env: Path,
|
||||
) -> None:
|
||||
"""Auto-issue creation is denied when no user token is provided."""
|
||||
manager = AutomationManager()
|
||||
|
||||
with pytest.raises(AutomationError, match="missing authenticated user token"):
|
||||
await manager.run_job(
|
||||
job_name="auto_issue_creation",
|
||||
owner="acme",
|
||||
repo="demo",
|
||||
user_token=None,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auto_issue_creation_job_success(
|
||||
automation_env: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Auto-issue creation succeeds with write mode + scope + token."""
|
||||
monkeypatch.setattr(
|
||||
"aegis_gitea_mcp.automation.GiteaClient",
|
||||
lambda token: StubAutomationGiteaClient(token=token),
|
||||
)
|
||||
|
||||
manager = AutomationManager()
|
||||
result = await manager.run_job(
|
||||
job_name="auto_issue_creation",
|
||||
owner="acme",
|
||||
repo="demo",
|
||||
user_token="user-token",
|
||||
finding_title="Security finding",
|
||||
finding_body="Details",
|
||||
)
|
||||
|
||||
assert result["job"] == "auto_issue_creation"
|
||||
assert result["issue_number"] == 77
|
||||
Reference in New Issue
Block a user