mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
fix(openai,oauth): 修复 resp_ ID 前缀转换和 token 失效误判为账号级 block
- OpenAI normalizer: resp_ 前缀 ID 规范化为 chatcmpl- 前缀,流式 tool_call index 增加 block_index 回落 - OAuth token: 提取 token 失效关键词为共享常量,token invalidated 不再被判定为账号级 block - Codex refresher: 403 + token invalidated 标记为 OAUTH_EXPIRED,允许 refresh_token 恢复
This commit is contained in:
@@ -107,3 +107,40 @@ def test_mark_refresh_token_invalid_persists_detached_key(
|
||||
assert row.oauth_invalid_at is not None
|
||||
assert str(key.oauth_invalid_reason).startswith("[REFRESH_FAILED] Token 续期失败 (401)")
|
||||
assert "refresh_token_reused" in str(row.oauth_invalid_reason)
|
||||
|
||||
|
||||
def test_account_block_token_invalidated_is_refresh_recoverable() -> None:
|
||||
from src.services.provider.oauth_token import is_account_level_block
|
||||
|
||||
assert (
|
||||
is_account_level_block(
|
||||
"[ACCOUNT_BLOCK] Authentication token has been invalidated. Please sign in again."
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
|
||||
def test_persist_refreshed_token_clears_legacy_token_invalidated_account_block(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
key = SimpleNamespace(
|
||||
id="key-1",
|
||||
api_key="old-api",
|
||||
auth_config="old-config",
|
||||
oauth_invalid_at=datetime.now(timezone.utc),
|
||||
oauth_invalid_reason=(
|
||||
"[ACCOUNT_BLOCK] Authentication token has been invalidated. Please sign in again."
|
||||
),
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
module, "object_session", lambda _key: (_ for _ in ()).throw(RuntimeError())
|
||||
)
|
||||
monkeypatch.setattr(module.crypto_service, "encrypt", lambda value: f"enc:{value}")
|
||||
|
||||
module._persist_refreshed_token(key, "new-token", {"refresh_token": "rt-2"})
|
||||
|
||||
assert key.api_key == "enc:new-token"
|
||||
assert key.auth_config == 'enc:{"refresh_token": "rt-2"}'
|
||||
assert key.oauth_invalid_at is None
|
||||
assert key.oauth_invalid_reason is None
|
||||
|
||||
@@ -264,6 +264,58 @@ async def test_codex_refresher_http_402_sets_quota_exhausted_metadata(
|
||||
assert state_updates["k1"]["oauth_invalid_reason"] is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_codex_refresher_http_403_token_invalidated_marks_oauth_expired(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.services.provider_keys.quota_refresh import codex_refresher as module
|
||||
|
||||
key = SimpleNamespace(
|
||||
id="k1", name="K1", api_key="enc", auth_type="api_key", auth_config=None, proxy=None
|
||||
)
|
||||
provider = SimpleNamespace(proxy=None)
|
||||
endpoint = SimpleNamespace()
|
||||
metadata_updates: dict[str, dict[str, Any]] = {}
|
||||
state_updates: dict[str, dict[str, Any]] = {}
|
||||
|
||||
async def _fake_auth_info(_endpoint: Any, _key: Any) -> Any:
|
||||
return None
|
||||
|
||||
_install_module(
|
||||
monkeypatch,
|
||||
"src.services.proxy_node.resolver",
|
||||
{
|
||||
"resolve_effective_proxy": lambda provider_proxy, key_proxy: None,
|
||||
"build_proxy_client_kwargs": lambda proxy, timeout: {"timeout": timeout},
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(module, "get_provider_auth", _fake_auth_info)
|
||||
monkeypatch.setattr(module.crypto_service, "decrypt", lambda _v: "sk-test")
|
||||
response = _FakeResponse(
|
||||
status_code=403,
|
||||
payload={"error": {"message": "Authentication token has been invalidated."}},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
module.httpx, "AsyncClient", lambda **kwargs: _FakeAsyncClient(response, **kwargs)
|
||||
)
|
||||
|
||||
result = await refresh_codex_key_quota(
|
||||
db=cast(Any, _FakeDB()),
|
||||
provider=cast(Any, provider),
|
||||
key=cast(Any, key),
|
||||
endpoint=cast(Any, endpoint),
|
||||
codex_wham_usage_url="https://example.test",
|
||||
metadata_updates=metadata_updates,
|
||||
state_updates=state_updates,
|
||||
)
|
||||
|
||||
assert result["status"] == "forbidden"
|
||||
assert result["status_code"] == 403
|
||||
assert result["auto_disabled"] is True
|
||||
assert state_updates["k1"]["is_active"] is False
|
||||
assert str(state_updates["k1"]["oauth_invalid_reason"]).startswith("[OAUTH_EXPIRED]")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_codex_refresher_success_updates_metadata(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
|
||||
Reference in New Issue
Block a user