Доки B23: README (010, password_history, таблица политики с колонкой «исполнение»), SETUP_GUIDE (cron бэкапа+purge, alembic 010, диагностика 400-пароль), чек-листы

This commit is contained in:
2026-09-25 09:58:23 +03:00
parent 2222b7ad5b
commit c6be70ce36
2 changed files with 42 additions and 19 deletions
+24 -16
View File
@@ -143,17 +143,19 @@
vector/ vector/
├── backend/ # FastAPI-приложение ├── backend/ # FastAPI-приложение
│ ├── main.py # Сборка приложения (12 роутеров) │ ├── main.py # Сборка приложения (12 роутеров)
│ ├── models.py # 21 таблица (SQLAlchemy) │ ├── models.py # 22 таблицы (SQLAlchemy, +password_history)
│ ├── schemas.py # Pydantic-схемы │ ├── schemas.py # Pydantic-схемы
│ ├── database.py # Репозиторий кейсов + статистика │ ├── database.py # Репозиторий кейсов + статистика
│ ├── audit.py # Журнал аудита + гео-скоуп │ ├── audit.py # Журнал аудита + гео-скоуп
│ ├── password_policy.py # B23: исполняемая политика паролей
│ ├── purge_logs.py # B23: ретенция журналов (DELETE, cron)
│ ├── rbac.py # Роли/права/политика безопасности │ ├── rbac.py # Роли/права/политика безопасности
│ ├── alembic/ # Миграции (006…009) │ ├── alembic/ # Миграции (006…010)
│ ├── seed_users.py # Сид первых пользователей │ ├── seed_users.py # Сид первых пользователей
│ ├── seed_units.py # Сид подразделений (РЦУ РЧС → ОУМЧС → Г(Р)ОЧС, 142 юнита) │ ├── seed_units.py # Сид подразделений (РЦУ РЧС → ОУМЧС → Г(Р)ОЧС, 142 юнита)
│ ├── routers/ # 12 модулей API (см. раздел 8) │ ├── routers/ # 12 модулей API (см. раздел 8)
│ ├── services/ # Адаптеры расчёта │ ├── services/ # Адаптеры расчёта
│ └── tests/ # 231 тест (pytest) │ └── tests/ # 263 теста (pytest)
├── services/ # Математика (чистые функции) ├── services/ # Математика (чистые функции)
│ ├── search_engine.py # SearchInput/SearchModel — ядро расчёта │ ├── search_engine.py # SearchInput/SearchModel — ядро расчёта
│ ├── distance_service.py # Максимальный радиус (КМЧ × коэффициенты) │ ├── distance_service.py # Максимальный радиус (КМЧ × коэффициенты)
@@ -187,7 +189,7 @@ vector/
## 6. База данных ## 6. База данных
**PostgreSQL 16 + PostGIS 3.6**, БД `vector_mchs`. Схема управления — Alembic (`backend/alembic/versions/`), актуальная ревизия **009_e3_operations**. **PostgreSQL 16 + PostGIS 3.6**, БД `vector_mchs`. Схема управления — Alembic (`backend/alembic/versions/`), актуальная ревизия **010_b23_policy**.
### Основные таблицы ### Основные таблицы
@@ -199,25 +201,30 @@ vector/
| `search_teams`, `field_observations`, `areas_checked`, `found_events` | Оперативные слои (состав групп, наблюдения, проверенные квадраты, находки) | | `search_teams`, `field_observations`, `areas_checked`, `found_events` | Оперативные слои (состав групп, наблюдения, проверенные квадраты, находки) |
| `reference_priors` | Слой 1: справочные приоритеты | | `reference_priors` | Слой 1: справочные приоритеты |
| `users`, `mchs_units` | Пользователи; иерархия РЦУ РЧС → 6 ОУМЧС → 135 Г(Р)ОЧС | | `users`, `mchs_units` | Пользователи; иерархия РЦУ РЧС → 6 ОУМЧС → 135 Г(Р)ОЧС |
| `password_history` | История паролей (bcrypt-хэши; проверка переиспользования, B23) |
| `roles`, `permissions`, `role_permissions`, `user_roles` | RBAC: 4 роли, 9 прав, матрица связей | | `roles`, `permissions`, `role_permissions`, `user_roles` | RBAC: 4 роли, 9 прав, матрица связей |
| `sessions`, `auth_events` | Server-side сессии (sha256-токены), журнал входов | | `sessions`, `auth_events` | Server-side сессии (sha256-токены), журнал входов |
| `security_settings` | Политика безопасности (10 параметров) | | `security_settings` | Политика безопасности (10 параметров, **исполняется кодом с B23**) |
| `search_operations` | Поисковые операции (статусная машина, привязка к кейсу и КОНТУРу) | | `search_operations` | Поисковые операции (статусная машина, привязка к кейсу и КОНТУРу) |
| `audit_events`, `audit_changes` | Неизменяемый журнал аудита, field-level изменения (ретенция 90 дней) | | `audit_events`, `audit_changes` | Неизменяемый журнал аудита, field-level изменения (ретенция 90 дней) |
| `planet_osm_*` | Импорт OSM Беларуси (osm2pgsql, SRID 4326/3857): дороги, леса, вода, НП | | `planet_osm_*` | Импорт OSM Беларуси (osm2pgsql, SRID 4326/3857): дороги, леса, вода, НП |
### Политика безопасности (`security_settings`, меняется в админке) ### Политика безопасности (`security_settings`, меняется в админке)
| Параметр | Значение | | Параметр | Значение | Исполнение (B23) |
|----------|----------| |----------|----------|------------------|
| Минимальная длина пароля | 8 | | Минимальная длина пароля | 8 | ✅ при смене/сбросе пароля |
| Сложность пароля | требуются буквы+цифры | | Сложность пароля | требуются буквы+цифры | ✅ при смене/сбросе пароля |
| Срок действия пароля | 90 дней | | Срок действия пароля | 90 дней | ✅ `enforce_expiry` на каждом запросе → `must_change_password` |
| История паролей | 5 (нельзя переиспользовать) | | История паролей | 5 (нельзя переиспользовать) | ✅ таблица `password_history` (5 последних старых хэшей + текущий) |
| Блокировка после неудачных входов | 5 (на 15 минут) | | Блокировка после неудачных входов | 5 (на 15 минут) | ✅ (с B21) |
| Тайм-аут сессии / неактивности | 24 ч / 60 мин | | Тайм-аут сессии | 24 ч | ✅ проверка `expires_at` при каждом запросе |
| Макс. параллельных сессий | 3 (старые отзываются) | | Тайм-аут неактивности | 60 мин | ⚠️ `last_seen_at` пишется, но не проверяется |
| Ретенция журнала аудита | 90 дней | | Макс. параллельных сессий | 3 (старые отзываются) | ✅ (с B21) |
| Ретенция журнала аудита | 90 дней | ✅ реальный DELETE: cron `python -m backend.purge_logs` (03:10) или POST `/admin/users/maintenance/purge-logs` |
Семантика истории: `password_history_count = N` хранит N последних *старых* хэшей;
вместе с текущим паролем защищено N+1 последних значений.
--- ---
@@ -401,7 +408,8 @@ SPA на react-scripts (CRA). Роутинг:
- Прикладное логирование `vector.*`: события анализа, входов, КОНТУРа, аудита (README §13а) - Прикладное логирование `vector.*`: события анализа, входов, КОНТУРа, аудита (README §13а)
- Интеграция с КОНТУР: отправка зон (контракт B20) - Интеграция с КОНТУР: отправка зон (контракт B20)
- Журнал аудита пользователей: входы, изменения, отправки - Журнал аудита пользователей: входы, изменения, отправки
- 239 автотестов (pytest), 5 skipped - 263 автотеста (pytest), 5 skipped
- B23: исполняемая политика паролей (срок/сложность/история), ретенция журналов реальным DELETE + cron
### В планах ### В планах
+18 -3
View File
@@ -153,7 +153,7 @@ docker compose ps # все 4 контейнера Up/healthy
```bash ```bash
docker exec vector-backend sh -c 'cd /app/backend && alembic upgrade head' docker exec vector-backend sh -c 'cd /app/backend && alembic upgrade head'
docker exec vector-backend sh -c 'cd /app/backend && alembic current' # 009_e3_operations docker exec vector-backend sh -c 'cd /app/backend && alembic current' # 010_b23_policy
``` ```
Миграции идемпотентны на чистой БД. **Если** БД уже была инициализирована через create_all и `alembic upgrade` падает `DuplicateTable` — применить стемп-скрипт: Миграции идемпотентны на чистой БД. **Если** БД уже была инициализирована через create_all и `alembic upgrade` падает `DuplicateTable` — применить стемп-скрипт:
@@ -330,6 +330,18 @@ docker exec vector-postgres pg_dump -U postgres -d vector_mchs \
Рекомендация: ежедневный cron прикладного дампа (он небольшой) + еженедельный полный. Хранить копии вне сервера. Рекомендация: ежедневный cron прикладного дампа (он небольшой) + еженедельный полный. Хранить копии вне сервера.
### Cron (рекомендуемый на сервере)
```cron
# 03:10 — ретенция журналов (удаление audit_events/auth_events старше audit_retention_days)
10 3 * * * docker exec vector-backend python -m backend.purge_logs >> /var/log/vector-purge.log 2>&1
# 03:00 — прикладной дамп (planet_osm_* исключены; OSM восстанавливается b16-import.sh)
0 3 * * * docker exec vector-postgres pg_dump -U postgres -d vector_mchs --exclude-table="planet_osm_*" -F c -f /tmp/vector_app_$(date +\%F).dump && docker cp vector-postgres:/tmp/vector_app_$(date +\%F).dump /root/backups/ && find /root/backups -name vector_app_*.dump -mtime +14 -delete >> /var/log/vector-backup.log 2>&1
```
Проверка разового прогона: `docker exec vector-backend python -m backend.purge_logs`
→ `purge: {'audit_events': N, 'auth_events': N}` (0 — норма).
**Docker volume — не backup.** Если сервер умер вместе с диском, volume умер вместе с ним. Что подлежит резервному копированию: **Docker volume — не backup.** Если сервер умер вместе с диском, volume умер вместе с ним. Что подлежит резервному копированию:
```text ```text
@@ -412,6 +424,8 @@ df -h && free -h # диск/память
### Диагностика по цепочке (начинать с места проблемы, не с перезапусков) ### Диагностика по цепочке (начинать с места проблемы, не с перезапусков)
**Смена пароля даёт 400 «Пароль должен содержать буквы и цифры» / «совпадает с ранее использованным»** — это B23-политика (`security_settings`), не ошибка: с 25.09.2026 требования сложности и истории исполняются. Пароль, возвращённый ранее, отвергается, пока он в последних `password_history_count` записях.
**Бэкенд не подключается к БД** — цепочка `backend → docker network → postgres:5432 → authentication → vector_mchs`: **Бэкенд не подключается к БД** — цепочка `backend → docker network → postgres:5432 → authentication → vector_mchs`:
```bash ```bash
@@ -490,7 +504,7 @@ docker exec vector-postgres psql -U postgres -d vector_mchs -c \
- [ ] прикладные логи `vector.*` доступны (`docker compose logs backend`, файл в контейнере) - [ ] прикладные логи `vector.*` доступны (`docker compose logs backend`, файл в контейнере)
- [ ] аудит 90 дней читается (вкладка «Аудит», право `view_audit`) - [ ] аудит 90 дней читается (вкладка «Аудит», право `view_audit`)
- [ ] ретенция настроена в `security_settings` - [ ] ретенция **исполняется**: cron purge-логов установлен, `python -m backend.purge_logs` даёт счётчики
### Backup ### Backup
@@ -506,7 +520,8 @@ docker exec vector-postgres psql -U postgres -d vector_mchs -c \
- [ ] Код получен (`/root/vector`), `.env` создан из `.env.example` - [ ] Код получен (`/root/vector`), `.env` создан из `.env.example`
- [ ] `JWT_SECRET` заменён на случайный; пароль БД сменён (compose + DATABASE_URL) - [ ] `JWT_SECRET` заменён на случайный; пароль БД сменён (compose + DATABASE_URL)
- [ ] `docker compose up -d` — 4 контейнера Up - [ ] `docker compose up -d` — 4 контейнера Up
- [ ] `alembic current` = `009_e3_operations` - [ ] `alembic current` = `010_b23_policy`
- [ ] cron бэкапа И cron purge-логов настроены (`crontab -l`), первый дамп лежит в /root/backups
- [ ] `seed_users.py` выполнен, пароль админа сменён при первом входе - [ ] `seed_users.py` выполнен, пароль админа сменён при первом входе
- [ ] `seed_units.py` выполнен (142 подразделения в селектах) - [ ] `seed_units.py` выполнен (142 подразделения в селектах)
- [ ] PostGIS установлен в контейнере БД, extension создан - [ ] PostGIS установлен в контейнере БД, extension создан