feat(rbac): role-based access control via X-Authenticated-User middleware (PR A — backend + Caddy) #585
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#585
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/rbac-pra-backend-caddy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Backend-side enforcement RBAC поверх Caddy basic_auth — defense-in-depth для 12-юзеров на gendsgn.ru. Решает запрос Лёхи на ограничение видимости админ-страниц по ролям + критичное требование «человек без ролей вообще ничего не видит».
Что включено:
auth/roles.yaml— SSOT для 2 ролей (admin, pilot) + 12 user→role mappingsapp/core/auth.py(main + tradein-mvp mirror) — YAML loader +get_role/get_user_scope/is_path_allowed(fnmatch globs)GET /api/v1/me(×2) — фронт читает scope для nav-фильтра в PR Brbac_guardmiddleware (×2):X-Authenticated-User→ 401/api/v1/admin/*— только role=admin, иначе 403Caddyfile—header_up X-Authenticated-User {http.auth.user.id}в 6reverse_proxyблоках (gendsgn.ru main + trade-in + git.gendsgn.ru)docker-compose.prod.yml(×2) — bind-mountauth/roles.yaml:/app/auth/roles.yaml:roFrontend nav-filter + 403 fullscreen — отдельный PR B (после merge этого).
Test plan
E F I B UP N RUF ASYNC)caddy validate)curl https://gendsgn.ru/api/v1/meбез auth → 401; с unknown user → 403; сkopylov→ 200+role=pilot; сadmin→ 200+role=admin/admin/*→ 403, admin → 200; ничего не сломано на gendsgn.ru main app + tradeinИзменения в репо
auth/roles.yaml(new) — SSOTbackend/app/{core/auth.py,api/v1/me.py,main.py,tests/test_rbac.py}— RBAC ядро + 20 тестовtradein-mvp/backend/app/{core/auth.py,api/v1/me.py,main.py,tests/test_rbac.py}— MIRRORCaddyfile,docker-compose.prod.yml(×2),backend/pyproject.toml(+pyyaml)Follow-ups (code-reviewer nits)
_load_roles_config()в lifespan (fail-fast если YAML сломан)_ADMIN_API_RE/_PUBLIC_PATHSвapp.core.auth(сейчас 4 копии)caddy/auth-header.snippetдляheader_up(6 копий)Backend-side enforcement поверх Caddy basic_auth — defense-in-depth для 12-юзеров на gendsgn.ru (admin + kopylov + 10 пилотных слотов). - `auth/roles.yaml` — single source of truth: 2 роли (admin, pilot) + 12 user→role mappings. Bind-mounted в обоих backend контейнерах. - `app/core/auth.py` (main + tradein-mvp mirror) — YAML loader через `pyyaml`, `get_role`/`get_user_scope`/`is_path_allowed` с fnmatch globs. Custom `_glob_to_regex` чтобы `/**` ≠ `/*` (matches multi-segment paths). - `GET /api/v1/me` (main + tradein) — фронт читает scope при login, фильтрует nav по `allowed_paths`/`deny_paths`. - `rbac_guard` middleware (main + tradein): * любой non-public path требует `X-Authenticated-User` → иначе 401 * юзер должен быть в roles.yaml → иначе 403 («человек без ролей вообще ничего не видит» — decided 2026-05-25) * /api/v1/admin/* — только role=admin, иначе 403 - `Caddyfile` — `header_up X-Authenticated-User {http.auth.user.id}` в 6 reverse_proxy блоках (gendsgn.ru main + trade-in + git.gendsgn.ru). - Tests: 20 unit + integration в обоих стэках. Покрытие: no-header / unknown user / pilot / admin × admin-path / non-admin path. `_build_test_app()` копирует middleware inline, чтобы обойти heavy imports (weasyprint dlopen падает на macOS dev). Public paths (/health, /docs, /redoc, /openapi.json) пропускаются — X-Authenticated-User там просто не приходит из Caddy. Frontend nav-filter + 403 fullscreen — отдельный PR B.