3392d8f69b
Add aegis_gitea_mcp.authz: classify every dispatched call (typed tools and gitea_request) by resource type (repository/org/user_self/user_owned/ misc_global/admin/unknown) and enforce a type-specific rule in service-PAT mode, on top of policy + WRITE_MODE. Every decision fails closed: - org: signed-in user must be a verified org member (Gitea-checked). - user_owned: owner must be the caller or a member org of the caller. - user_self: token-owner-scoped endpoints denied (token is the bot's). - admin: default-deny; allowed only with RAW_API_ALLOW_SENSITIVE opt-in AND a verified site admin. - misc_global: reads allowed, writes denied. - unknown / unverifiable: denied and audited. Wire it into the server's service-PAT dispatch: repository calls keep the existing per-user collaborator check; non-repo calls (previously blanket-denied) now go through the resource-type gate, opening the org/user/admin surface safely. Verification results are cached briefly (fail-closed: positives only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
"""Pytest configuration and fixtures."""
|
|
|
|
from collections.abc import Generator
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from aegis_gitea_mcp.audit import reset_audit_logger
|
|
from aegis_gitea_mcp.auth import reset_validator
|
|
from aegis_gitea_mcp.authz import reset_authz_caches
|
|
from aegis_gitea_mcp.config import reset_settings
|
|
from aegis_gitea_mcp.oauth import reset_oauth_validator
|
|
from aegis_gitea_mcp.oauth_flow import reset_oauth_client_registry
|
|
from aegis_gitea_mcp.observability import reset_metrics_registry
|
|
from aegis_gitea_mcp.policy import reset_policy_engine
|
|
from aegis_gitea_mcp.rate_limit import reset_rate_limiter
|
|
from aegis_gitea_mcp.request_context import clear_gitea_auth_context
|
|
from aegis_gitea_mcp.server import reset_repo_authz_cache
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def reset_globals(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Generator[None, None, None]:
|
|
"""Reset global singletons between tests and set up temp audit log."""
|
|
# Reset singletons before each test to ensure clean state
|
|
reset_settings()
|
|
reset_audit_logger()
|
|
reset_validator()
|
|
reset_oauth_validator()
|
|
reset_oauth_client_registry()
|
|
reset_repo_authz_cache()
|
|
reset_authz_caches()
|
|
reset_policy_engine()
|
|
reset_rate_limiter()
|
|
reset_metrics_registry()
|
|
clear_gitea_auth_context()
|
|
|
|
# Use temporary directory for audit logs in tests
|
|
audit_log_path = tmp_path / "audit.log"
|
|
monkeypatch.setenv("AUDIT_LOG_PATH", str(audit_log_path))
|
|
|
|
yield
|
|
|
|
# Also reset after test for cleanup
|
|
reset_settings()
|
|
reset_audit_logger()
|
|
reset_validator()
|
|
reset_oauth_validator()
|
|
reset_oauth_client_registry()
|
|
reset_repo_authz_cache()
|
|
reset_authz_caches()
|
|
reset_policy_engine()
|
|
reset_rate_limiter()
|
|
reset_metrics_registry()
|
|
clear_gitea_auth_context()
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""Set up mock environment variables for testing (standard API key mode)."""
|
|
monkeypatch.setenv("GITEA_URL", "https://gitea.example.com")
|
|
monkeypatch.setenv("GITEA_TOKEN", "test-token-12345")
|
|
monkeypatch.setenv("ENVIRONMENT", "test")
|
|
monkeypatch.setenv("MCP_HOST", "127.0.0.1")
|
|
monkeypatch.setenv("MCP_PORT", "8080")
|
|
monkeypatch.setenv("LOG_LEVEL", "DEBUG")
|
|
monkeypatch.setenv("MCP_API_KEYS", "a" * 64)
|
|
monkeypatch.setenv("STARTUP_VALIDATE_GITEA", "false")
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_env_oauth(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""Set up mock environment variables for OAuth mode testing."""
|
|
monkeypatch.setenv("GITEA_URL", "https://gitea.example.com")
|
|
monkeypatch.setenv("ENVIRONMENT", "test")
|
|
monkeypatch.setenv("MCP_HOST", "127.0.0.1")
|
|
monkeypatch.setenv("MCP_PORT", "8080")
|
|
monkeypatch.setenv("LOG_LEVEL", "DEBUG")
|
|
monkeypatch.setenv("OAUTH_MODE", "true")
|
|
monkeypatch.setenv("GITEA_OAUTH_CLIENT_ID", "test-client-id")
|
|
monkeypatch.setenv("GITEA_OAUTH_CLIENT_SECRET", "test-client-secret")
|
|
monkeypatch.setenv("OAUTH_STATE_SECRET", "test-state-secret-0123456789abcdef")
|
|
monkeypatch.setenv("STARTUP_VALIDATE_GITEA", "false")
|