feat: 扩展 Rust gateway 全功能模块,新增 billing/crypto/wallet crate 及完整数据层

- 新增 aether-billing、aether-crypto、aether-wallet 独立 crate
- aether-data 扩展 repository 层:announcements、auth_modules、billing、
  candidate_selection、gemini_file_mappings、global_models、management_tokens、
  oauth_providers、proxy_nodes、quota、users、wallet 等模块
- aether-gateway 新增 api/auth/billing/control/middleware/scheduler/usage/
  video_tasks/hooks/maintenance/model_fetch/provider_transport 等功能模块
- 重构 executor decision 和 gateway state 为模块目录结构
- 新增 gateway router、frontdoor 路由层及对应测试
- Python 侧 API 路由重构,新增 compat/support 模块
- 前端 Logo 组件更新及 Provider 管理页面调整
This commit is contained in:
fawney19
2026-03-31 19:19:04 +08:00
parent b5a0070023
commit ddf18fed9a
690 changed files with 235087 additions and 16301 deletions

View File

@@ -11,6 +11,7 @@ from sqlalchemy.orm import sessionmaker
from src.core.enums import AuthSource, UserRole
from src.models.database import Base, OAuthProvider, User, UserOAuthLink
from src.services.auth.oauth.models import OAuthFlowError
from src.services.auth.oauth.service import OAuthService
from src.services.auth.oauth.state import OAuthStateData
@@ -133,6 +134,127 @@ async def test_handle_callback_allows_bind_state_without_device_id(
assert parse_qs(parsed.query)["oauth_bound"] == ["GitHub"]
@pytest.mark.asyncio
async def test_handle_callback_redirects_when_provider_http_is_rust_only(
monkeypatch: pytest.MonkeyPatch,
) -> None:
db = MagicMock()
provider = SimpleNamespace(
exchange_code=AsyncMock(
side_effect=OAuthFlowError("provider_unavailable", "OAuth 仅支持 Rust executor")
),
get_user_info=AsyncMock(),
)
config = SimpleNamespace(
frontend_callback_url="https://app.example.com/auth/callback",
display_name="GitHub",
is_enabled=True,
)
monkeypatch.setattr(
"src.services.auth.oauth.service.OAuthService._require_module_active",
lambda _db: None,
)
monkeypatch.setattr(
"src.services.auth.oauth.service.OAuthService._get_provider_impl",
lambda _provider_type: provider,
)
monkeypatch.setattr(
"src.services.auth.oauth.service.OAuthService._get_provider_config",
lambda _db, _provider_type: config,
)
monkeypatch.setattr(
"src.services.auth.oauth.service.get_redis_client",
AsyncMock(return_value=object()),
)
monkeypatch.setattr(
"src.services.auth.oauth.service.consume_oauth_state",
AsyncMock(
return_value=OAuthStateData(
nonce="state-1",
provider_type="github",
action="login",
user_id=None,
client_device_id="device-1",
created_at=123,
)
),
)
result = await OAuthService.handle_callback(
db=db,
provider_type="github",
state="state-1",
code="code-1",
error=None,
error_description=None,
client_ip=None,
user_agent="pytest-agent",
headers={},
)
parsed = urlparse(result.redirect_url)
params = parse_qs(parsed.query)
assert params["error_code"] == ["provider_unavailable"]
assert params["error_detail"] == ["OAuth 仅支持 Rust executor"]
provider.get_user_info.assert_not_called()
@pytest.mark.asyncio
async def test_test_provider_config_returns_rust_only_failure_without_network(
monkeypatch: pytest.MonkeyPatch,
) -> None:
db = MagicMock()
monkeypatch.setattr(
"src.services.auth.oauth.service.OAuthService._get_provider_impl",
lambda _provider_type: SimpleNamespace(),
)
monkeypatch.setattr(
"src.services.auth.oauth.service.OAuthService._get_provider_config",
lambda *_args, **_kwargs: (_ for _ in ()).throw(
AssertionError("Python OAuth config probe should not read DB config")
),
)
result = await OAuthService.test_provider_config(db, "github")
assert result == {
"authorization_url_reachable": False,
"token_url_reachable": False,
"secret_status": "unsupported",
"details": "OAuth 配置测试仅支持 Rust executor",
}
@pytest.mark.asyncio
async def test_test_provider_config_with_data_returns_rust_only_failure(
monkeypatch: pytest.MonkeyPatch,
) -> None:
provider = SimpleNamespace(
authorization_url="https://provider.example/authorize",
token_url="https://provider.example/token",
)
monkeypatch.setattr(
"src.services.auth.oauth.service.OAuthService._get_provider_impl",
lambda _provider_type: provider,
)
result = await OAuthService.test_provider_config_with_data(
provider_type="github",
client_id="client-id",
client_secret="secret",
authorization_url_override=None,
token_url_override=None,
redirect_uri="https://api.example.com/api/oauth/github/callback",
)
assert result == {
"authorization_url_reachable": False,
"token_url_reachable": False,
"secret_status": "unsupported",
"details": "OAuth 配置测试仅支持 Rust executor",
}
def test_handle_login_sync_returns_user_snapshot_outside_db_session(
monkeypatch: pytest.MonkeyPatch,
) -> None: