docs(agents): HUB-1 — зелёный main и P0 из аудита для серверной сессии

Задание для серверной сессии Claude (не для agy): довести main до зелёного и
закрыть P0 аудита Hermes Hub. Шаг 1 плана слияния — стабильный Hermes как эталон
переноса.

Причина красного main найдена ревьюером в логе CI, а не по аудиту:
- test_a37_isolation_guards.py:394 — WorkspaceBoundaryGuard пропускает
  rm -rf $HOME/.hermes на Windows (провал security-инварианта);
- verify_multi_provider_router.py:63 — UnicodeEncodeError на cp1252 при печати
  русского текста.
Остальные P0 (Release Gate hash, publication gate fail-open, /api/action CSRF) —
подтвердить исполнением перед правкой. pricing safe_dump — реальный, в P1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hermes Team 2026-09-02 23:44:08 +07:00
parent 144f6a5d59
commit 93da1b22fd

View file

@ -0,0 +1,150 @@
# Задание HUB-1: зелёный main и P0 из аудита Hermes Hub
## Для кого
**Серверная сессия Claude (пользователь `ochenstarik`), не для agy.** Это работа
исполнителя-Claude: правка кода, прогон, пуш. Ревьюер (сессия на ПК) принимает.
## Дата
2026-09-02.
## База
`origin/main` (`144f6a5`).
```
git fetch origin --prune
git checkout -b hub/audit-p0-green-main origin/main
```
В `main` напрямую не пушить. **Координация:** над `main` работают две сессии.
Перед пушем — `git fetch` и `git log --oneline origin/main`; при расхождении
перенести правки поверх, как это уже делалось.
## Зачем
По решению о слиянии (`docs/research/kagent-merge-decision.md`) шаг 1 —
**Hermes довести до зелёного и стабильного**, потому что он служит эталоном
переноса, а сломанный эталон портировать нельзя. Сейчас `main` красный. Полный
аудит — на рабочем столе владельца (`HERMES_HUB_FULL_AUDIT_2026-09-02.md`);
здесь только то, что подтверждено исполнением.
---
## Что ревьюер уже проверил — заново не выяснять
### CI на main красный. Причина — два дефекта, оба видны в логе последнего прогона
**1. Security-инвариант A37 не держится на Windows.**
`tests/test_a37_isolation_guards.py:394` падает:
```
AssertionError: команда со стильдой прошла мимо защиты: rm -rf $HOME/.hermes (OK)
assert not True
```
WorkspaceBoundaryGuard пропускает разрушительную команду с `$HOME`, потому что
раскрытие переменных и нормализация путей на Windows и Linux различаются. Это
не косметика — это граница вокруг агентских shell-действий. Пока она работает
по-разному на поддерживаемых системах, sandbox нельзя считать доказанным.
**2. Windows UTF-8 роняет verification-скрипт.**
`scripts/verify_multi_provider_router.py:63`:
```
UnicodeEncodeError: 'charmap' codec can't encode characters ...
```
Скрипт печатает русский текст (`[PASS] Чистая конфигурация...`), а консоль
Windows в CI — cp1252. Падает `print`, не логика.
Красные джобы: `Headless Run (no GUI dependencies)` и
`Clean Windows Runner Test`.
### Баг pricing fallback (P2, но реальный)
`src/antigravity_provider/router/telemetry_service.py:164`:
```python
data = yaml.safe_dump(p.read_text(encoding="utf-8"))
if isinstance(data, dict) and "pricing" in data: # всегда False
```
`safe_dump` вместо `safe_load` — таблица цен из `pricing.yaml` не грузится
никогда, и `except: pass` это глушит. Должно быть `safe_load`.
---
## P0-1. Зелёный main (это первично)
1. **Исправить UTF-8 в verification-скрипте**: принудительный UTF-8 вывода
(`PYTHONUTF8`, `PYTHONIOENCODING=utf-8`, реконфигурация `sys.stdout`, либо
безопасное кодирование). Кросс-платформенно, проверяемо на обеих системах.
2. **Исправить WorkspaceBoundaryGuard** единым конвейером: классификация
диалекта shell → раскрытие только распознанных переменных → нормализация
разделителей → разрешение `$HOME`/`%USERPROFILE%` → канонизация пути →
сравнение с защищёнными корнями → **fail closed**. Одинаковый тест-набор для
Windows и Linux; `test_a37_isolation_guards` должен ловить `rm -rf $HOME/...`
на обеих системах.
3. **Проверка — по зелёному CI**, а не локально: локальный прогон на Linux эти
две джобы не воспроизводит. Довести оба Windows-джоба до зелёного.
## P0-2. Остальные P0 аудита — подтвердить исполнением ПЕРЕД правкой
Ревьюер их не проверял. По каждому: сначала воспроизвести, потом чинить. Не
чинить со слов аудита.
1. **Release Gate заявляет проверку хеша, которой не было** — частичный HTTP
Range, но `PACKAGE_HASH_VERIFIED=True` без полного SHA-256. Прочитать
`scripts/release_gate.py`, подтвердить, затем считать полный хеш или брать
достоверный digest из release API.
2. **Publication gate fail-open** — 404/сеть/отсутствие пакета возвращаются как
PASS. Разделить Offline Gate (тесты, updater, статика, сборка) и Publication
Gate (релиз есть, ассеты есть, digest сверен, скачивание прошло).
3. **localhost `/api/action` без CSRF/Origin** — на loopback токен не требуется,
а действие меняет состояние. Проверить, затем: bootstrap-токен, проверка
`Origin`/`Sec-Fetch-Site`, авторизация небезопасных методов.
## P1. После зелёного main
1. **Zip-slip в updater**: распаковка обязана проверять каждый путь
(`resolved.is_relative_to(staging)`), запрет абсолютных путей, `..`, symlink,
device.
2. **pricing fallback**: `safe_load` вместо `safe_dump` (см. выше).
3. **CI-матрица Windows + Linux**: сейчас Linux-джоба нет, а проект на Linux и
активно получает Linux-фиксы.
4. Прочее из аудита (failover error policy, `uv sync --frozen`, лишний `web`
extra, secret-scan шире) — отдельными заданиями, не в этом.
---
## Ограничения
- Правки ревьюера из `main` не откатывать.
- Фронтенд без npm/сборки/фреймворков — `docs/web-api/CONTRACT.md` §1.
- Проверку SHA-256 и список разрешённых адресов обновления не ослаблять.
- Учётные данные и `~/.hermes/agy_profiles/` не трогать.
- Версию `0.1.3` не понижать.
- Правило честности: неизмеренное — `Н/Д` с причиной.
## Критерии приёмки
1. Ветка в `origin`, `git status` чист.
2. **Оба Windows-джоба CI зелёные** — ссылка на зелёный прогон в отчёте.
3. `test_a37_isolation_guards` ловит `rm -rf $HOME/...` на Windows и Linux;
guard fail-closed.
4. verification-скрипт не падает на cp1252.
5. Остальные P0 либо исправлены с доказательством, либо явно помечены как
отложенные с причиной.
6. `ruff check .` чисто; локальный прогон Linux зелёный; число тестов не меньше
текущего.
7. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`,
`X passed / Y skipped / Z failed`, ссылка на зелёный CI.
## Главное
Первично — зелёный main, и обе причины уже найдены: security-guard на Windows и
UTF-8 в verification. Остальные P0 аудита — только после подтверждения
исполнением. Это фундамент под слияние: пока Hermes красный и его sandbox-guard
дырявый на одной из систем, переносить его поведение в KAgent нельзя.
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA` и ссылку на зелёный прогон CI.