Files
ayurishchevandClaude Sonnet 5 a846d30872 IPAM Manager: API, UI-админка, журнал аудита
Backend (FastAPI, SQLAlchemy 2, Alembic, PostgreSQL 16):
- организации, VRF, префиксы (дерево, использование, автоназначение),
  адреса, операторы связи, устройства и типы устройств; JWT, роли admin/viewer;
- VRF принадлежит организации (составной FK), смена VRF у префикса
  переносит поддерево, имя VRF уникально в организации;
- журнал аудита: поиск и фильтры, ротация (срок/количество), очистка
  по паролю с блокировкой, IP клиента и метаданные запроса
  (X-Forwarded-For только от TRUSTED_PROXIES).

UI (web/, без сборки): экраны и диалоги по макетам «IPAM Manager»,
кликабельные строки реестров, локальные шрифты IBM Plex,
собственные выпадающие списки.

Окружение: docker-compose (postgres + app), миграции Alembic 0001-0004,
scripts/gen_env.py, scripts/seed_demo.py, 11 автотестов (pytest).
Документация: README.md и docs/changes/001-005 (планы и итоги).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 12:27:47 +03:00

3.2 KiB

Суммаризация: IP-адрес актора и метаданные запроса в журнале (изменение 004)

Сделано

  • БД (миграция 0004): audit_log + client_ip INET (индекс) и meta JSONB (user_agent, method, path, request_id). Проверено: upgrade → check (без дрейфа) → downgrade → upgrade.
  • Backend: app/request_context.py — ASGI-middleware кладёт метаданные запроса в ContextVar, audit() читает их (30 мест вызова не менялись); заголовок X-Request-ID в ответах. X-Forwarded-For принимается только от прокси из TRUSTED_PROXIES (по умолчанию пусто, справа налево — первый недоверенный адрес), IPv4-mapped нормализуется. Системные события (ротация, даже запущенная из запроса) пишутся без IP.
  • API: AuditOut.client_ip / meta; GET /audit?client_ip= (IP или CIDR, 422 на мусор); q ищет и по началу IP.
  • UI: колонка «IP-адрес» в таблице журнала (сетка … 110px 130px 96px), поиск «Сообщение, ID или IP», в окне записи — IP (с копированием), «Запрос», «User-Agent».
  • Кэш статики: Cache-Control: no-cache (ревалидация по ETag) — браузер больше не держит устаревший app.js/styles.css после обновления (ответ на «не вижу обновлений»; для уже закэшированной версии один раз нужен Ctrl+F5).

Проверка

  • 11 автотестов (2 новых: запись IP/метаданных, фильтр по IP и подсети, игнорирование поддельного X-Forwarded-For, пустой IP у системных событий; юнит-тест разбора цепочки прокси) — 11 passed.
  • Через LAN-адрес 192.168.5.9:8088: создание организации и неудачный вход записались с client_ip = 192.168.5.9, User-Agent и путём; фильтр 192.168.5.0/24 и поиск 192.168.5 находят записи; UI — колонка и окно записи проверены в браузере, ошибок JS нет.

Допущения и ограничения

  • IP пишется для всех действий из HTTP-запросов (admin и прочие роли, неудачные входы — как anonymous); старые записи — «—».
  • Через 127.0.0.1 Docker подставляет адрес шлюза сети (172.x.0.1) — особенность docker-proxy, не ошибка приложения.
  • За NAT или прокси виден адрес ближайшего недоверенного узла, а не «настоящего» клиента; с reverse-proxy нужно задать TRUSTED_PROXIES.
  • IP — персональные данные: срок хранения определяется ротацией журнала.