Some checks failed
CI / changes (push) Successful in 6s
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
Deploy Trade-In / changes (push) Successful in 7s
Deploy / changes (push) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 36s
Deploy / build-backend (push) Successful in 1m39s
Deploy / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 48s
Deploy / build-worker (push) Successful in 2m41s
Deploy / deploy (push) Failing after 4s
Deploy Trade-In / deploy (push) Successful in 47s
CI / backend-tests (push) Successful in 6m38s
CI / backend-tests (pull_request) Successful in 6m30s
EPIC18/§19. analyst sees everything (deals, insights, exports, site-finder, analytics, concept) EXCEPT admin/data-management. Enforcement is backend-hard (the existing rbac_guard already 403s any non-admin role on /api/v1/admin/*, so adding the role auto-blocks it) + frontend (deny_paths via /me) + audit. §19 audit: new best-effort HTTP middleware logs the sensitive actions (analyze / forecast / forecast-export) to a new audit_log table after the response. Audit failures never break or delay-fail the request (2-layer try/except + finally close). Registered INNER to rbac_guard so only authorized requests are audited (a 403 short-circuits before audit). classify_path matches export before forecast (anchored). - auth/roles.yaml: analyst role (paths /**, deny admin-mgmt) + analysttest QA user - core/auth.py (+ tradein mirror): Role Literal += analyst - core/audit_middleware.py (new) + main.py registration - data/sql/144_audit_log.sql (idempotent; auto-applies) - tests: analyst rbac (403 admin / 200 parcels) + 11 audit cases No data-level ACL (analyst sees data per policy) -> no #948 dependency. No new deps. parcels.py untouched. Real analyst logins still need adding to caddy/users.caddy.snippet (devops). Refs #962.
78 lines
3.4 KiB
YAML
78 lines
3.4 KiB
YAML
# RBAC roles + user → role mapping.
|
||
#
|
||
# Single source of truth for both main backend (backend/app/core/auth.py) and
|
||
# tradein backend (tradein-mvp/backend/app/core/auth.py). Mounted into both
|
||
# containers at /app/auth/roles.yaml via docker-compose bind-mount.
|
||
#
|
||
# Glob semantics (fnmatch-based, see app.core.auth.is_path_allowed):
|
||
# - "/**" → matches any path (admin scope).
|
||
# - "/foo/**" → matches /foo, /foo/, /foo/bar, /foo/bar/baz/...
|
||
# - "/foo" → matches exactly /foo.
|
||
#
|
||
# A path is allowed iff (1) it matches one of `paths` AND (2) it does NOT match
|
||
# any pattern in `deny`. `deny` overrides `paths` (deny-by-default within
|
||
# match scope).
|
||
#
|
||
# Username list MUST match exactly the entries in caddy/users.caddy.snippet
|
||
# — Caddy basic_auth sets X-Authenticated-User from {http.auth.user.id}, and
|
||
# unknown users hit /me with 403 ("user not in roles config").
|
||
#
|
||
# Last updated: 2026-05-26 (pilot scope narrowed to /trade-in/** only — decision
|
||
# 2026-05-26: pilot аккаунты пилот-программы видят ТОЛЬКО раздел Trade-In;
|
||
# Analytics / Site Finder / Concept / landing — admin-only).
|
||
|
||
roles:
|
||
admin:
|
||
paths:
|
||
- "/**"
|
||
deny: []
|
||
pilot:
|
||
# Pilot имеет доступ ТОЛЬКО к разделу Trade-In (оценка вторички).
|
||
# Landing (/), analytics, site-finder, concept, остальной /api/v1/* — закрыты.
|
||
# Backend middleware всё равно пропускает known users на все non-admin paths
|
||
# (path-level enforcement делает frontend RouteGuard через `allowed_paths`),
|
||
# но для UX/security принципов keep deny список explicit.
|
||
paths:
|
||
- "/trade-in/**"
|
||
- "/trade-in/api/v1/**"
|
||
deny:
|
||
- "/admin/**"
|
||
- "/api/v1/admin/**"
|
||
- "/trade-in/api/v1/admin/**"
|
||
analyst:
|
||
# #962 (EPIC18, ТЗ §19): analyst видит ВСЁ (deals, insights, exports,
|
||
# site-finder, analytics, concept) КРОМЕ admin/data-management.
|
||
# paths "/**" = доступ ко всему; deny = админ-управление (scraper-триггеры,
|
||
# sync-таски, data-management, user/role management).
|
||
# Backend hard-gate: app/main.py rbac_guard уже блокирует /api/v1/admin/*
|
||
# для любого role != "admin" → analyst авто-403 на admin-API без доп. кода.
|
||
# deny ниже драйвит фронтовый RouteGuard (deny_paths из /me) для UI-gating
|
||
# /admin/** страниц.
|
||
paths:
|
||
- "/**"
|
||
deny:
|
||
- "/admin/**"
|
||
- "/api/v1/admin/**"
|
||
- "/trade-in/api/v1/admin/**"
|
||
|
||
# NB: реальные analyst-логины ДОЛЖНЫ быть добавлены и в
|
||
# caddy/users.caddy.snippet (Caddy basic_auth) силами devops — иначе Caddy не
|
||
# пропустит юзера и не выставит X-Authenticated-User. Здесь только role-mapping;
|
||
# Caddy НЕ редактируем из этого таска.
|
||
users:
|
||
admin: admin
|
||
kopylov: pilot
|
||
user1: pilot
|
||
user2: pilot
|
||
user3: pilot
|
||
user4: pilot
|
||
user5: pilot
|
||
user6: pilot
|
||
user7: pilot
|
||
user8: pilot
|
||
user9: pilot
|
||
user10: pilot
|
||
praktika: pilot # пилот-аккаунт агентства «Практика» 2026-05-29
|
||
admintest: admin # temp QA 2026-05-26
|
||
pilottest: pilot # temp QA 2026-05-26
|
||
analysttest: analyst # temp QA 2026-06-07 (#962)
|