docs: apply Codex review round 1
Accepted: dep major ranges, ssh client leak fix, tmp-name hardening, dispose-ordering note, invalidate-during-build test, testable parseArgs, coverage justification, README security sections. Rejected with evidence: MySQL session read-only blocks DML/DDL (verified on mysql:8.4, ERROR 1792); in-process store races impossible (synchronous read-modify-write).
This commit is contained in:
@@ -8,7 +8,8 @@ MCP-сервер (stdio) для работы с PostgreSQL и MySQL через
|
||||
## Стек
|
||||
|
||||
- TypeScript, ESM, Node >= 20
|
||||
- `@modelcontextprotocol/sdk` — McpServer + StdioServerTransport
|
||||
- `@modelcontextprotocol/server` (MCP SDK v2) — McpServer + StdioServerTransport;
|
||||
`@modelcontextprotocol/client` в devDeps для тестов через InMemoryTransport
|
||||
- `zod` — схемы входов тулзов и валидация конфигов
|
||||
- `pg` — драйвер PostgreSQL, `mysql2` — драйвер MySQL
|
||||
- `ssh2` — SSH-туннели (pure JS, не требует ssh-бинаря в Docker)
|
||||
@@ -33,8 +34,11 @@ MCP-сервер (stdio) для работы с PostgreSQL и MySQL через
|
||||
- Стор перечитывается при каждом обращении (resolve, list, mutate) — без
|
||||
кеширования файла. Несколько одновременных инстансов dbmole видят изменения
|
||||
друг друга сразу.
|
||||
- Запись стора атомарная: tmp-файл + rename. Перед каждой мутацией — re-read
|
||||
(read-modify-write), последняя запись побеждает.
|
||||
- Атомарность — на уровне подмены файла: tmp-файл + rename (атомарен на POSIX).
|
||||
Внутри процесса мутации сериализованы синхронным выполнением (в read-modify-write
|
||||
нет await-точек, event loop не прерывает его). Между процессами остаётся окно
|
||||
check-then-write — принято осознанно: последняя запись побеждает, конфликт
|
||||
означает потерю одной мутации и чинится повторным add/update.
|
||||
- У каждого подключения в выдаче `list_connections` есть `source: env | config | store`.
|
||||
- `update/remove_connection` по записи из env/config → ошибка с указанием источника.
|
||||
- `add_connection` с именем, занятым любым слоем, → ошибка (никаких теневых записей).
|
||||
@@ -108,13 +112,19 @@ src/
|
||||
|
||||
## Readonly
|
||||
|
||||
Серверное принуждение, не SQL-парсинг. На каждом новом коннекте пула:
|
||||
Серверное принуждение, не SQL-парсинг:
|
||||
|
||||
- pg: `SET default_transaction_read_only = on`
|
||||
- mysql: `SET SESSION TRANSACTION READ ONLY`
|
||||
- pg: startup-параметр libpq `options='-c default_transaction_read_only=on'` —
|
||||
сессия рождается read-only, гонки с выдачей коннекта из пула исключены
|
||||
- mysql: `SET SESSION TRANSACTION READ ONLY` при первом checkout каждого
|
||||
физического соединения пула (у mysql2 нет init-SQL опции в конфиге пула)
|
||||
|
||||
Блокирует DML и DDL на стороне движка. Обходится только явным `SET` в SQL —
|
||||
для агентского сценария приемлемо (защита от случайной записи, не от злого умысла).
|
||||
Блокирует DML и DDL на стороне движка. Проверено эмпирически на mysql:8.4:
|
||||
INSERT/UPDATE/CREATE TABLE под session read-only падают с ERROR 1792
|
||||
«Cannot execute statement in a READ ONLY transaction», SELECT работает.
|
||||
Обходится только явным `SET` в SQL — это защита от случайной записи, не от
|
||||
злого умысла. Жёсткая гарантия — read-only пользователь БД; рекомендация
|
||||
фиксируется в README.
|
||||
|
||||
## Тулзы
|
||||
|
||||
|
||||
Reference in New Issue
Block a user