Export: убран filename из Content-Disposition для диалога сохранения
Версия: 0.1.13 Документация: db-query-endpoint.md
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
# Endpoint SQL-запросов к БД (`/v2/db/query`)
|
||||
|
||||
> Создан: 2026-07-08
|
||||
|
||||
## Назначение
|
||||
|
||||
Дать DevOps-инженеру (одному человеку, заданному через `ADMIN_EMAIL`) возможность выполнять SQL-запросы к БД напрямую из браузера — без psql, без kubectl, без внешнего IP.
|
||||
|
||||
## Доступ
|
||||
|
||||
- Только один пользователь: `req.email === ADMIN_EMAIL`
|
||||
- Обычный юзер сервиса (проходит SSO как все)
|
||||
- Пример: `ADMIN_EMAIL=atazet@narod.ru`
|
||||
|
||||
## Адрес
|
||||
|
||||
```
|
||||
GET /v2/db/query?sql=<часть запроса после SELECT>
|
||||
```
|
||||
|
||||
## Как работает
|
||||
|
||||
1. Пользователь заходит в сервис через SSO (любой URL, например `/v2/app`)
|
||||
2. Меняет в адресной строке путь на `/v2/db/query?sql=...`
|
||||
3. Сервер:
|
||||
- Проверяет сессию (resolveContext)
|
||||
- Проверяет что `req.email === ADMIN_EMAIL`
|
||||
- Добавляет префикс `SELECT` перед вводом пользователя
|
||||
- Выполняет: `pool.query('SELECT ' + userInput)`
|
||||
- Возвращает JSON
|
||||
|
||||
## Примеры
|
||||
|
||||
| Ввод в браузере | Что выполняется |
|
||||
|---|---|
|
||||
| `/v2/db/query?sql=* FROM _migrations` | `SELECT * FROM _migrations` |
|
||||
| `/v2/db/query?sql=count(*) FROM companies` | `SELECT count(*) FROM companies` |
|
||||
| `/v2/db/query?sql=* FROM whitelist_entries LIMIT 10` | `SELECT * FROM whitelist_entries LIMIT 10` |
|
||||
| `/v2/db/query?sql=* FROM audit_log ORDER BY created_at DESC LIMIT 5` | `SELECT * FROM audit_log ORDER BY created_at DESC LIMIT 5` |
|
||||
|
||||
## Безопасность
|
||||
|
||||
1. **SELECT префикс** — жёстко добавляется `SELECT` перед вводом пользователя. DROP/INSERT/UPDATE/DELETE не работают:
|
||||
```
|
||||
/v2/db/query?sql=DROP TABLE companies
|
||||
→ SELECT DROP TABLE companies (ошибка SQL, не выполнится)
|
||||
```
|
||||
|
||||
2. **Одиночные запросы** — драйвер `pg` не поддерживает множественные запросы в одном `query()`. Попытка `1; DROP TABLE` не сработает.
|
||||
|
||||
3. **Доступ по email** — только один человек, заданный в `ADMIN_EMAIL`.
|
||||
|
||||
4. **Rate limiter** — endpoint защищён лимитером (как mutationLimiter).
|
||||
|
||||
## Ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"rows": [ ... ],
|
||||
"rowCount": 5,
|
||||
"fields": ["id", "filename", "applied_at"]
|
||||
}
|
||||
```
|
||||
|
||||
## Реализация
|
||||
|
||||
- Файл: `v2/src/db/query.js`
|
||||
- Middleware: `resolveContext` + проверка `req.canQueryDB`
|
||||
- Роутер монтируется в `v2/server.js` на `/db`
|
||||
- Флаг `req.canQueryDB` выставляется в `v2/src/router/index.js` (applyContext)
|
||||
|
||||
## Ограничения
|
||||
|
||||
- Только SELECT (через префикс)
|
||||
- Нет GUI — только JSON в браузере
|
||||
- SQL в URL (логируется в access_log nginx/ingress — это нормально для devops-инструмента)
|
||||
Reference in New Issue
Block a user