montana/Node/External-Audit/SINGLE-SOURCE-OF-TRUTH.md
2026-05-21 03:44:38 +03:00

138 lines
7.4 KiB
Markdown
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.

# Single Source of Truth — VPN-сеть Montana
Версия: **2026-05-19**
## Принцип
Вся канонически верифицируемая правда о состоянии VPN-сети живёт в **одном append-only signed event log**:
```
https://montana.quest/vpn/events.jsonl
```
Каждая строка — событие, индивидуально подписанное **ed25519**:
```jsonl
{"data":{...},"seq":N,"sig":"ed25519:...","ts":"2026-05-19T19:00:00Z","type":"node_register"}
```
**Свойства:**
- **Append-only:** запись только в конец, прошлые события не переписываются.
- **Подписанные:** каждое событие проверяется публичным ключом `d9a8bf07871d35c8e85f7de4a9b62896c330ba0987732468515c7bda8bb4adde`.
- **Монотонный seq:** счётчик никогда не убывает, гэпы запрещены.
- **Pure-function state:** state = replay(events).
## Типы событий
| type | data | когда |
|---|---|---|
| `node_register` | `{alias, ip, country, label}` | admin регистрирует узел через /vpn/node/register |
| `node_deregister` | `{alias, ip}` | узел остановлен (xray ExecStopPost) |
| `node_online` | `{alias, ip}` | orchestrator watchdog: probe OK после offline |
| `node_offline` | `{alias, ip}` | orchestrator watchdog: 2 probe fails подряд |
| `unique_user` | `{ip_hash}` | новый sha256(client_IP) в логе xray |
| `metric` | произвольное | периодические метрики (нагрузка, throughput) |
| `checkpoint` | `{seq_range, merkle}` | каждые 1000 событий (план) |
## Derived state
`https://montana.quest/vpn/state.json` — кешированный результат `build_state(events)`. Любой может перепостроить и сравнить.
```json
{
"head_seq": 1502,
"head_ts": "2026-05-19T19:25:30Z",
"built_at": "...",
"nodes": {
"helsinki": {"online": true, "ip": "91.132.142.42", "country": "FI", ...},
"frankfurt": {"online": true, ...},
"newyork": {"online": true, ...}
},
"unique_users": 957,
"unique_users_merkle": "...",
"pubkey_hex": "d9a8bf07...",
"event_log_url": "https://montana.quest/vpn/events.jsonl"
}
```
`state.json` rebuilds каждые 30 секунд через `montana-state-builder.timer` на Moscow.
## Что НЕ публикуется
- IP-адреса пользователей (это PII). В события `unique_user` идёт **только sha256 IP** — не обратимо без brute-force на 32-битное IPv4 пространство (~4 сек на rainbow tabe).
- Чтобы усложнить brute-force, в roadmap — добавить **secret salt** с публикацией с задержкой 7 дней.
## Архитектура emitters
```
┌─────────────────────────┐
│ /opt/montana-vpn-stats │
│ /event_log.py │
│ (sign + append) │
└────────────┬────────────┘
┌────────────────────────────┼────────────────────────────┐
│ │ │
orchestrator watchdog xray-stats collector admin /register
(online/offline transitions) (new unique IPs) (manual events)
│ │ │
└────────────────────────────▼────────────────────────────┘
/var/www/montana_quest/vpn/events.jsonl
montana-state-builder.timer (30s)
/var/www/montana_quest/vpn/state.json
сайт + /vpn/sub + /vpn/node/uptime (читают state.json)
```
## Гарантии
| Гарантия | Как доказывается |
|---|---|
| Число уникальных пользователей не подделано | каждое событие `unique_user` подписано; state.json содержит merkle root; replay воспроизводит число |
| Узел не «фейково онлайн» | переходы online↔offline — отдельные подписанные события с timestamp |
| История не переписана | append-only; seq монотонный без гэпов; любой имеет полный лог |
| Нельзя backdate | timestamp на каждом событии; запланировано daily anchoring через OpenTimestamps |
## Что НЕ гарантируется (пока)
- **Forced inclusion:** мы можем замедлить добавление события в лог. Защита: автоматический rebuild каждые 30 секунд.
- **Privatekey compromise:** если ключ утечёт, можно подделать события. Защита: privateKey 600 root на Moscow.
- **Tampering архивных событий:** теоретически root доступом на Moscow можно переписать `events.jsonl`. **Защита roadmap:** ежедневный snapshot хеша всего лога в Bitcoin через OpenTimestamps — нельзя backdate.
## Аудит
Любой может проверить single-source-of-truth:
```bash
bash Montana/Node/External-Audit/scripts/verify-state.sh
```
Этот скрипт:
1. Скачивает `events.jsonl` и `state.json`.
2. Проверяет ed25519-подпись каждого события.
3. Проверяет монотонность seq без гэпов.
4. Replay events до `head_seq` из state.json.
5. Сравнивает результат replay со state.json: `head_seq`, `unique_users`, `merkle root`, `nodes online/offline`.
Если хотя бы один тест провалится — мы лжём.
## Сейчас зелёные тесты
```
✓ все 1531 events подписаны валидно, seq непрерывен
✓ replay matches claimed state: head_seq=1502, nodes=3, unique_users=957
=== ВСЕ ПРОВЕРКИ ЗЕЛЁНЫЕ ===
```
## Roadmap
- **P1:** daily checkpoint в Bitcoin через OpenTimestamps. Дописать `transparency.md`.
- **P2:** мульти-эмиттер — каждый узел независимо подписывает свои события + threshold-signature (2 of 3). Устраняет single trust на Moscow privateKey.
- **P3:** GraphQL-like derivation API — клиенты запрашивают subset state через `?fields=...`.
- **P4:** Public mirror лога на IPFS/GitHub raw — анти-цензура.