# Криптографический аудит харнеса (t-260930083716) Запрос Alex (m-516173240): у харнеса свой приватный ключ; каждое событие стора и каждая команда подписаны. Цели: полная аудируемость, доказуемое авторство («сделал харнес»), защита стора и командной шины от инъекций. ## Схема - **Алгоритм:** ed25519 (библиотека `cryptography`). - **Ключи:** прив. `/root/simbiot-harness/.audit/ed25519.key` (0600, создан атомарно tmp+rename), публ. рядом `ed25519.pub` (0644, отдавай внешним аудиторам). `key_id` = первые 16 hex sha256 от публ. ключа. - **Активные ключи (созданы 2026-10-02):** - pubkey (raw b64): `P8puVpwg9UtKtEnYUKCCGz/NA4zXU1ubgkdurp2V+CY=` - key_id: `faf8d19d9aed71fe` ## Что подписывается 1. **События стора** — `es.append_event` подписывает каждое событие при записи. Плайлоад: `aggregate|aggregate_id|event_type|canonical_json(data)| timestamp|version|prev_sig|key_id` (`\x1f`-сшит). В колонки события пишутся `sig, key_id, prev_sig`. 2. **Тампер-цепочка:** `prev_sig` каждого события = подпись предыдущего — переписать середину стора, не сломав голову цепочки, нельзя. 3. **Команды CLI** — `cli.py audit-command '{"op":…}'` → конверт `{envelope, payload_b64, signature, key_id}`; вход в командную шину верифицируется `cli.py verify-command` (выход 0/2). ## Верификация - `cli.py verify` — полный аудит цепочки (выход 0/2): криптопроверка каждой подписанной строки + link-check `prev_sig`. Может выполнять любая внешняя сторона с публичным ключом. - Проекции (`es.run_projections`) проверяют хвост-дельту: событие с битой подписью или разрывом цепочки ⇒ RuntimeError — подделка не попадает в read model (проверено тестом). - `cli.py audit-key` — публичный ключ/отпечаток/пути. ## Граница доверия: genesis и legacy - Все события **до** внедрения подписи (2026-10-02, 465 255 шт.) помечены ретро-маркером `sig='genesis:'` (водяной знак `projection_meta. sig_genesis_upto` — раз и навсегда). Это честная граница: до неё авторство не доказывалось криптоключом. - Подписанная строка после границы, чей `prev_sig` указывает на дого- генезисное состояние, не бракуется по link-check (граница сбрасывает проверку сцепки), но её payload-подпись строго проверяется — контент послегенезисной строки тамперить нельзя. - Неподписанные послегенезисные строки (старый код демонов до их рестарта) = `legacy`: аудит их считает, ошибкой является только тампер **подписанной** строки. После рестарта сервисов (просьба к Alex в дайджесте дня) всё новое гарантированно подписано. ## Инвариант защиты | Атака | Чем ловится | |---|---| | Правка data/timestamp события | подпись payload (verify) | | Правка middle-строки всего стора | подпись + цепочка (full audit) | | Вставка фейкового события | нет валидной подписи → legacy-статус, но не «валидный харнес»; в хвосте проекций — RuntimeError | | Подмена команды | конверт-подпись (verify-command) | | Кража подписи | плайлоад привязан к содержимому; ключ 0600 | ## Файлы - `harness/audit.py` — ключи, каноника, sign/verify, командные конверты - `harness/es.py` — миграция (sig-колонки/genesis), подпись в `append_event`, хвост-верификация в `run_projections` - `cli.py` — `verify`, `audit-command`, `verify-command`, `audit-key` - Тест: `tests/test_audit.py` (17 проверок, hermetic: тампер/genesis/ legacy/конверты/CLI)