hermes-hub/tests/test_provider_proxy.py
Hermes Team fa7bbef8af feat(antigravity): выход через прокси вместо патча бинарника
Вход через терминал прошёл: agy запустился в изолированном каталоге ag-5 и
опознал аккаунт владельца. Отказал Google: «Eligibility check failed: not
currently available in your location». Проверка смотрит на адрес выхода.

У владельца есть узлы 3x-ui в разных странах. Поэтому обход делается выходом
через разрешённую страну, а не патчем чужого бинарника: ничего не ломается при
обновлении Antigravity и не выполняется сторонний код.

Адрес задаётся общий в настройках и отдельный на профиль — разным аккаунтам
может требоваться разная страна. Применяется к запросу каталога моделей, к
вызовам моделей и к сценарию входа в терминале.

Пишутся и заглавные, и строчные имена переменных: Go читает HTTPS_PROXY,
многие библиотеки — https_proxy; ALL_PROXY нужен для socks5.

Адрес проверяется по существу, а не по схеме: приписать socks5:// можно чему
угодно, и тогда мусор выглядел бы принятым, а обращения провайдера молча
ломались бы без внятной причины.

695 passed, 2 skipped; ruff чисто; релизный гейт пройден.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 16:49:04 +07:00

113 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Обход проверки доступности по стране — через прокси, а не патч бинарника.
Вход владельца через терминал прошёл: agy запустился в изолированном каталоге и
опознал аккаунт. Отказал Google: «Eligibility check failed: Your current account
is not eligible for Antigravity, because it is not currently available in your
location». Проверка смотрит на адрес выхода.
Правильный ответ — выйти через разрешённую страну. У владельца несколько узлов
в разных странах, поэтому адрес задаётся и общий, и на каждый профиль отдельно.
"""
from __future__ import annotations
from unittest.mock import patch
import pytest
from antigravity_provider.agy_subprocess import (
proxy_env_overrides,
resolve_provider_proxy,
write_login_helper,
)
from antigravity_provider.router.settings_service import _normalize_proxy_url
@pytest.mark.parametrize(
"given, expected",
[
("socks5://127.0.0.1:1080", "socks5://127.0.0.1:1080"),
("127.0.0.1:1080", "socks5://127.0.0.1:1080"),
("http://proxy.example.com:8080", "http://proxy.example.com:8080"),
("socks5h://10.0.0.5:1080", "socks5h://10.0.0.5:1080"),
("", ""),
(" ", ""),
],
)
def test_valid_addresses_are_kept(given, expected):
assert _normalize_proxy_url(given) == expected
@pytest.mark.parametrize(
"junk",
["мусор!!", "не адрес вовсе", "ftp://1.2.3.4:21", "socks5://1.2.3.4:99999", "://"],
)
def test_junk_is_rejected_not_dressed_up_with_a_scheme(junk):
"""Приписать socks5:// можно чему угодно.
Если бы мусор проходил, он выглядел бы принятым, а все обращения провайдера
молча ломались бы без внятной причины.
"""
assert _normalize_proxy_url(junk) == ""
def test_env_covers_upper_lower_and_socks():
env = proxy_env_overrides("socks5://127.0.0.1:1080")
# Go читает HTTPS_PROXY, curl и многие библиотеки — https_proxy,
# ALL_PROXY нужен для socks5.
assert set(env) == {
"HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY",
"http_proxy", "https_proxy", "all_proxy",
}
assert set(env.values()) == {"socks5://127.0.0.1:1080"}
def test_no_proxy_means_no_variables():
assert proxy_env_overrides("") == {}
assert proxy_env_overrides(" ") == {}
def test_profile_address_wins_over_the_common_one():
"""Узлы в разных странах: разным аккаунтам может требоваться разный выход."""
with patch(
"antigravity_provider.router.profile_manager.ProfileAuthManager.load_profile_auth",
return_value={"proxy_url": "socks5://nl.example:1080"},
), patch(
"antigravity_provider.router.settings_service.get_hub_settings",
return_value={"provider_proxy_url": "socks5://de.example:1080"},
):
assert resolve_provider_proxy("ag-1") == "socks5://nl.example:1080"
def test_common_address_is_used_when_profile_has_none():
with patch(
"antigravity_provider.router.profile_manager.ProfileAuthManager.load_profile_auth",
return_value={},
), patch(
"antigravity_provider.router.settings_service.get_hub_settings",
return_value={"provider_proxy_url": "socks5://de.example:1080"},
):
assert resolve_provider_proxy("ag-1") == "socks5://de.example:1080"
def test_login_script_exports_the_proxy(tmp_path):
with patch(
"antigravity_provider.agy_subprocess.resolve_provider_proxy",
return_value="socks5://127.0.0.1:1080",
):
body = write_login_helper(tmp_path, "/usr/local/bin/agy", "ag-1").read_text(
encoding="utf-8"
)
assert "HTTPS_PROXY=" in body
assert "export " in body and "ALL_PROXY" in body
assert "socks5://127.0.0.1:1080" in body
def test_login_script_without_proxy_mentions_none(tmp_path):
with patch("antigravity_provider.agy_subprocess.resolve_provider_proxy", return_value=""):
body = write_login_helper(tmp_path, "/usr/local/bin/agy", "ag-1").read_text(
encoding="utf-8"
)
assert "PROXY" not in body