|
Some checks failed
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 15s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Failing after 5m27s
Роль жила в двух местах сразу: люди заводятся в БД (`tradein_users.role`),
а `get_role` читал ТОЛЬКО `auth/roles.yaml` — и никто эти два источника не
сверял. Дефект двусторонний:
* вверх: менеджер заводил сотрудника с именем, которое уже числится в
roles.yaml админом (проверялись лишь regex и уникальность в БД) — на
входе тот получал admin из YAML, то есть чтение ЛЮБОЙ чужой оценки
(admin проходит мимо ownership-check в trade_in.py) и безлимитную квоту;
* вниз: сотрудник, которого в roles.yaml нет, ловил KeyError → 403 на
СОБСТВЕННУЮ оценку.
Источник теперь один и лечится один раз — в `app.core.auth.get_role`:
реестр (`tradein_users.role` / `auth.users.role`) спрашивается первым,
roles.yaml остаётся fallback для legacy-юзеров, у которых строки в реестре
нет. Реестр недоступен → тоже fallback: падение БД не выключает legacy-вход.
Вызывающие (rbac, trade_in, team, account_quota) не менялись.
Сопутствующее, чтобы поведение существующих аккаунтов не поехало:
* rbac_guard выбирает матчер путей по РОДУ роли (роль реестра → DB_ROLE_PATHS),
иначе employee/manager на legacy-пути получил бы 403 на всё;
* get_user_scope отдаёт scope роли реестра из того же DB_ROLE_PATHS;
* право на персональный `unlimited` осталось за roles.yaml (account_quota +
_batch_quota_status) — фикс убирает эскалацию, а не раздаёт новую;
* `_batch_quota_status` берёт роли из уже прочитанных строк — иначе список
«Команды» снова стал бы N+1.
Defense-in-depth: create_employee отдаёт 409 на username, за которым в
roles.yaml числится не-employee роль.
|
||
|---|---|---|
| .. | ||
| exporters | ||
| matching | ||
| payments | ||
| tgbot | ||
| __init__.py | ||
| account_quota.py | ||
| auth_session.py | ||
| backfill_block_breaker.py | ||
| brand.py | ||
| buildings_query.py | ||
| cache.py | ||
| cian_price_history.py | ||
| cian_session.py | ||
| dadata.py | ||
| data_erasure.py | ||
| domclick_session.py | ||
| domrf_kapremont_loader.py | ||
| estimator.py | ||
| gar_flats_loader.py | ||
| geocoder.py | ||
| house_dedup_merge.py | ||
| house_imv_backfill.py | ||
| house_metadata.py | ||
| identity_store.py | ||
| image_sanitizer.py | ||
| location_index.py | ||
| product_handlers.py | ||
| proxy_egress.py | ||
| proxy_pool.py | ||
| proxy_rotation.py | ||
| regions.py | ||
| rosreestr_poll.py | ||
| sber_index.py | ||
| scheduler.py | ||
| scrape_runs.py | ||
| scraper_adapters.py | ||
| scraper_settings.py | ||
| search_query.py | ||
| street_scheme.py | ||
| user_events.py | ||
| yandex_address_backfill.py | ||
| yandex_price_history.py | ||
| yandex_session.py | ||
| zhkh_flats_loader.py | ||