Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020
This commit is contained in:
commit
cb5be898ea
663 files changed
+82674
No files matched your search
@@ -0,0 +1,220 @@
|
||||
"""Regression contract for persistent ChatGPT OAuth connectivity."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
from urllib.request import Request
|
||||
|
||||
from scripts.promotion_preflight import _oidc_discovery_checks, run
|
||||
from tests.test_promotion_preflight import _failed, _fixture
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class _DiscoveryResponse:
|
||||
def __init__(
|
||||
self, payload: dict[str, object], url: str, *, final_url: str | None = None
|
||||
) -> None:
|
||||
self.status = 200
|
||||
self._body = json.dumps(payload).encode()
|
||||
self._url = final_url or url
|
||||
|
||||
def __enter__(self) -> _DiscoveryResponse:
|
||||
return self
|
||||
|
||||
def __exit__(self, *_: object) -> None:
|
||||
return None
|
||||
|
||||
def read(self, _: int) -> bytes:
|
||||
return self._body
|
||||
|
||||
def geturl(self) -> str:
|
||||
return self._url
|
||||
|
||||
|
||||
def _discovery_response(request: Any, *, refresh_capable: bool) -> _DiscoveryResponse:
|
||||
url = str(request.full_url)
|
||||
issuer = url.removesuffix("/.well-known/openid-configuration") + "/"
|
||||
scopes = ["openid", "profile", "email"]
|
||||
grants = ["authorization_code"]
|
||||
if refresh_capable:
|
||||
scopes.append("offline_access")
|
||||
grants.append("refresh_token")
|
||||
return _DiscoveryResponse(
|
||||
{
|
||||
"issuer": issuer,
|
||||
"authorization_endpoint": "https://auth.test/application/o/authorize/",
|
||||
"token_endpoint": "https://auth.test/application/o/token/",
|
||||
"scopes_supported": scopes,
|
||||
"grant_types_supported": grants,
|
||||
"code_challenge_methods_supported": ["S256"],
|
||||
},
|
||||
url,
|
||||
)
|
||||
|
||||
|
||||
def test_authentik_scope_template_requests_offline_access() -> None:
|
||||
env_example = (ROOT / "infrastructure/compose/.env.example").read_text(encoding="utf-8")
|
||||
assert "AUTHENTIK_SCOPES=openid,profile,email,groups,offline_access" in env_example
|
||||
|
||||
|
||||
def test_resource_metadata_and_challenge_share_refresh_capable_scopes() -> None:
|
||||
from services.runtime.oauth_metadata import (
|
||||
CHATGPT_OAUTH_SCOPES,
|
||||
OAuthMetadataSettings,
|
||||
bearer_challenge,
|
||||
protected_resource_metadata,
|
||||
)
|
||||
|
||||
expected = ("openid", "profile", "email", "offline_access")
|
||||
settings = OAuthMetadataSettings(
|
||||
public_origin="https://mcp.example.test",
|
||||
issuer="https://auth.example.test/application/o/chatgpt/",
|
||||
)
|
||||
metadata = protected_resource_metadata("gitea-all/prod", settings)
|
||||
challenge = bearer_challenge("gitea-all/prod", settings)
|
||||
|
||||
assert CHATGPT_OAUTH_SCOPES == expected
|
||||
assert metadata["scopes_supported"] == list(expected)
|
||||
assert metadata["authorization_servers"] == [settings.issuer]
|
||||
assert metadata["resource"] == "https://mcp.example.test/mcp/gitea-all/prod"
|
||||
assert f'scope="{" ".join(expected)}"' in challenge
|
||||
assert "/.well-known/oauth-protected-resource/mcp/gitea-all/prod" in challenge
|
||||
|
||||
|
||||
def test_oauth_metadata_settings_fail_closed_on_unsafe_values(
|
||||
monkeypatch: Any,
|
||||
) -> None:
|
||||
from services.runtime.oauth_metadata import OAuthMetadataSettings
|
||||
|
||||
monkeypatch.setenv("HUB_PUBLIC_MCP_URL", "http://mcp.example.test")
|
||||
monkeypatch.setenv(
|
||||
"HUB_MCP_ADDITIONAL_OIDC_ISSUER", "https://auth.example.test/application/o/chatgpt/"
|
||||
)
|
||||
|
||||
try:
|
||||
OAuthMetadataSettings.from_environment()
|
||||
except ValueError as exc:
|
||||
assert "HUB_PUBLIC_MCP_URL" in str(exc)
|
||||
else:
|
||||
raise AssertionError("unsafe public OAuth origin was accepted")
|
||||
|
||||
|
||||
def test_preflight_rejects_missing_offline_access(tmp_path: Path) -> None:
|
||||
environment, _ = _fixture(tmp_path)
|
||||
environment["AUTHENTIK_SCOPES"] = "openid,profile,email"
|
||||
|
||||
result = run(environment, "predeploy")
|
||||
|
||||
assert result["passed"] is False
|
||||
assert _failed(result, "auth.coherence")
|
||||
|
||||
|
||||
def test_preflight_accepts_refresh_capable_scope_contract(tmp_path: Path) -> None:
|
||||
environment, _ = _fixture(tmp_path)
|
||||
|
||||
result = run(environment, "predeploy")
|
||||
|
||||
assert result["passed"] is True
|
||||
assert not _failed(result, "auth.coherence")
|
||||
|
||||
|
||||
def test_preflight_rejects_cross_host_chatgpt_issuer(tmp_path: Path) -> None:
|
||||
environment, _ = _fixture(tmp_path)
|
||||
environment["HUB_MCP_ADDITIONAL_OIDC_ISSUER"] = (
|
||||
"https://other-auth.test/application/o/chatgpt-itworx-gitea/"
|
||||
)
|
||||
|
||||
result = run(environment, "predeploy")
|
||||
|
||||
assert result["passed"] is False
|
||||
assert _failed(result, "auth.coherence")
|
||||
|
||||
|
||||
def test_preflight_rejects_non_strict_chatgpt_callback(tmp_path: Path) -> None:
|
||||
environment, _ = _fixture(tmp_path)
|
||||
environment["HUB_MCP_ADDITIONAL_OIDC_REDIRECT_URI"] = (
|
||||
"https://chatgpt.com/connector/oauth/connector/extra"
|
||||
)
|
||||
|
||||
result = run(environment, "predeploy")
|
||||
|
||||
assert result["passed"] is False
|
||||
assert _failed(result, "auth.coherence")
|
||||
|
||||
|
||||
def test_live_discovery_check_accepts_refresh_capable_providers() -> None:
|
||||
environment = {
|
||||
"HUB_OIDC_ISSUER": "https://auth.test/application/o/itworx/",
|
||||
"HUB_MCP_ADDITIONAL_OIDC_ISSUER": ("https://auth.test/application/o/chatgpt-itworx-gitea/"),
|
||||
}
|
||||
results: list[dict[str, str]] = []
|
||||
with patch(
|
||||
"scripts.promotion_preflight._OIDC_DISCOVERY_OPENER.open",
|
||||
side_effect=lambda request, timeout: _discovery_response(request, refresh_capable=True),
|
||||
):
|
||||
passed = _oidc_discovery_checks(environment, results, True)
|
||||
|
||||
assert passed is True
|
||||
assert all(item["status"] == "pass" for item in results)
|
||||
|
||||
|
||||
def test_live_discovery_check_rejects_missing_refresh_capability() -> None:
|
||||
environment = {
|
||||
"HUB_OIDC_ISSUER": "https://auth.test/application/o/itworx/",
|
||||
"HUB_MCP_ADDITIONAL_OIDC_ISSUER": ("https://auth.test/application/o/chatgpt-itworx-gitea/"),
|
||||
}
|
||||
results: list[dict[str, str]] = []
|
||||
with patch(
|
||||
"scripts.promotion_preflight._OIDC_DISCOVERY_OPENER.open",
|
||||
side_effect=lambda request, timeout: _discovery_response(request, refresh_capable=False),
|
||||
):
|
||||
passed = _oidc_discovery_checks(environment, results, True)
|
||||
|
||||
assert passed is False
|
||||
assert all(item["status"] == "fail" for item in results)
|
||||
|
||||
|
||||
def test_live_discovery_check_rejects_redirected_document() -> None:
|
||||
environment = {
|
||||
"HUB_OIDC_ISSUER": "https://auth.test/application/o/itworx/",
|
||||
"HUB_MCP_ADDITIONAL_OIDC_ISSUER": ("https://auth.test/application/o/chatgpt-itworx-gitea/"),
|
||||
}
|
||||
results: list[dict[str, str]] = []
|
||||
|
||||
def redirected(request: Any, timeout: int) -> _DiscoveryResponse:
|
||||
url = str(request.full_url)
|
||||
issuer = url.removesuffix("/.well-known/openid-configuration") + "/"
|
||||
return _DiscoveryResponse(
|
||||
{
|
||||
"issuer": issuer,
|
||||
"authorization_endpoint": "https://auth.test/application/o/authorize/",
|
||||
"token_endpoint": "https://auth.test/application/o/token/",
|
||||
"scopes_supported": ["openid", "offline_access"],
|
||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||
"code_challenge_methods_supported": ["S256"],
|
||||
},
|
||||
url,
|
||||
final_url="https://auth.test/unexpected-discovery",
|
||||
)
|
||||
|
||||
with patch("scripts.promotion_preflight._OIDC_DISCOVERY_OPENER.open", side_effect=redirected):
|
||||
passed = _oidc_discovery_checks(environment, results, True)
|
||||
|
||||
assert passed is False
|
||||
assert all(item["status"] == "fail" for item in results)
|
||||
|
||||
|
||||
def test_oidc_discovery_redirect_handler_never_follows_target() -> None:
|
||||
from scripts.promotion_preflight import _RejectOidcDiscoveryRedirects
|
||||
|
||||
handler = _RejectOidcDiscoveryRedirects()
|
||||
request = Request("https://auth.test/.well-known/openid-configuration")
|
||||
|
||||
assert (
|
||||
handler.redirect_request(request, None, 302, "Found", {}, "http://127.0.0.1/internal")
|
||||
is None
|
||||
)
|
||||
Reference in new issue
Block a user