fix(web): в мастере подключения были выдуманные коды устройства

Владелец: «грок не даёт добавить https://x.ai/device» — страница отдаёт
404. Причина хуже опечатки в адресе.

Веб-мастер для Grok и Codex не был подключён к серверу ВООБЩЕ. Он
показывал жёстко вписанный адрес x.ai/device (настоящий —
auth.x.ai/device, и тот приходит от провайдера полем verification_uri) и
ВЫДУМАННЫЕ коды устройства GRK-7842 и CDX-9104. Пользователь вводил бы
несуществующий код бесконечно.

Это тот самый класс дефекта, который вычищали из десктопа в первом
аудите, вернувшийся в новом коде.

Выдуманные значения убраны. Пока поток не проведён через веб-API, шаг
честно сообщает, что подключение через веб не реализовано, и указывает
рабочий путь — десктопное приложение, где поток проведён полностью.

Отдельно: тест test_headless_server_auth_matrix ТРЕБОВАЛ наличия
"https://x.ai/device" в коде, то есть закреплял дефект как требование.
Переписан на противоположное — запрещает выдуманные коды и зашитые
адреса провайдеров.

Тесты: 375 passed, ruff чисто.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hermes Team 2026-08-24 10:25:58 +07:00
parent 03d73f8d0b
commit 6b8a4aad78
2 changed files with 39 additions and 25 deletions

View file

@ -1458,27 +1458,25 @@ function showWizardStep2(providerId) {
let bodyHtml = '';
if (providerId === 'grok' || providerId === 'openai-codex') {
// Здесь стояли ВЫДУМАННЫЕ код устройства (GRK-7842 / CDX-9104) и жёстко
// вписанный адрес x.ai/device, который отдаёт 404. Мастер не был подключён
// к серверу вовсе: пользователь вводил бы несуществующий код бесконечно.
// Пока поток не проведён через API, честнее сказать правду и указать
// рабочий путь, чем показывать правдоподобную пустышку.
const providerName = providerId === 'grok' ? 'Grok (xAI)' : 'OpenAI Codex';
bodyHtml = `
<div style="margin-bottom:12px; font-size:13px; color:var(--text-secondary);">
Шаг 2 из 3: Авторизация ${providerId === 'grok' ? 'Grok (xAI)' : 'OpenAI Codex'} (Device Code OAuth)
Шаг 2 из 3: Авторизация ${providerName}
</div>
<div style="background:var(--surface-muted); padding:14px; border-radius:var(--radius-sm); border:1px solid var(--border-subtle); margin-bottom:14px;">
<div style="font-weight:700; margin-bottom:6px;">1. Откройте ссылку на любом устройстве:</div>
<div style="display:flex; gap:8px; margin-bottom:12px;">
<input type="text" class="input-text" style="flex:1;" id="wiz-auth-url" value="${providerId === 'grok' ? 'https://x.ai/device' : 'https://auth.openai.com/device'}" readonly>
<button class="btn btn-secondary btn-sm" onclick="navigator.clipboard.writeText(document.getElementById('wiz-auth-url').value); showToast('Ссылка скопирована', 'success');">📋 Копировать</button>
</div>
<div style="font-weight:700; margin-bottom:6px;">2. Введите код подтверждения:</div>
<div style="display:flex; align-items:center; gap:12px; margin-bottom:12px;">
<div style="font-family:var(--font-mono); font-size:22px; font-weight:700; color:var(--text-accent); letter-spacing:2px;" id="wiz-auth-code">
${providerId === 'grok' ? 'GRK-7842' : 'CDX-9104'}
</div>
<button class="btn btn-secondary btn-sm" onclick="navigator.clipboard.writeText(document.getElementById('wiz-auth-code').innerText); showToast('Код скопирован', 'success');">📋 Копировать код</button>
</div>
<div style="font-size:11px; color:var(--text-muted);">
3. Подтвердите доступ в браузере. Hub автоматически зафиксирует авторизацию.
<div class="modal-feedback warning" style="margin-bottom:14px;">
<strong>Подключение через веб-интерфейс пока не реализовано.</strong><br>
Вход по коду устройства выполняется на стороне сервера, и этот поток
ещё не выведен в веб-API. Показывать здесь код было бы обманом:
настоящий код выдаёт провайдер, а не интерфейс.
<div style="margin-top:8px;">
<strong>Рабочий путь:</strong> подключите аккаунт в десктопном
приложении Hermes Hub там поток проведён полностью и получает
настоящий адрес и код от провайдера.
</div>
</div>
`;

View file

@ -87,17 +87,33 @@ def test_account_card_compact_height_and_quota_rendering():
def test_headless_server_auth_matrix():
"""Verify headless server honesty in Add Account Wizard (Grok/Codex device-code vs Antigravity/Claude redirect warning)."""
"""Клиент не должен показывать выдуманные коды и зашитые адреса провайдеров.
Раньше этот тест ТРЕБОВАЛ наличия "https://x.ai/device" в коде то есть
закреплял дефект как требование. Адрес отдаёт 404, а рядом стояли
выдуманные коды устройства GRK-7842 и CDX-9104: мастер не был подключён к
серверу, и пользователь вводил бы несуществующий код бесконечно.
Настоящие адрес и код выдаёт провайдер в ответе device-flow.
"""
app_js = (STATIC_DIR / "app.js").read_text(encoding="utf-8")
assert "Device Code OAuth" in app_js
assert "https://x.ai/device" in app_js
assert "https://auth.openai.com/device" in app_js
# Проверяем суть, а не дословную формулировку: текст правился уже дважды,
# и тест на точную фразу падал, хотя поведение оставалось верным.
for fake in ("GRK-7842", "CDX-9104"):
assert app_js.count(fake) <= 1, (
f"выдуманный код устройства {fake} снова показывается пользователю"
)
for line in app_js.splitlines():
if line.lstrip().startswith("//"):
continue
assert "x.ai/device" not in line, (
"зашитый адрес x.ai/device вернулся в интерфейс; он отдаёт 404, "
"настоящий приходит от провайдера в verification_uri"
)
# Честность про сервер без экрана должна остаться.
assert "Headless" in app_js, "нет предупреждения про сервер без экрана"
assert "agy" in app_js, "не сказано, что вход идёт через консоль agy"
assert "launcher/main.py" not in app_js, "инструкция ведёт на несуществующий файл"
assert "ssh -L 8085:localhost:8085" in app_js
def test_actions_contract_handling():