From 60be78f97ce4370d546e6b2b79e0b4b4d5241389 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Mon, 13 Jul 2026 18:09:52 +0300 Subject: [PATCH 1/2] fix(tradein/auth): restore brusnika (user2) pilot access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Откат expire-trial от 2026-07-09 (#2472/#2473): user2 expired→pilot в auth/roles.yaml. Оба зеркала test_rbac.py возвращены к «все user1..user10 == pilot». Правки под backend/** и tradein-mvp/** сами триггерят deploy + deploy-tradein (обход paths-filter trap: auth/** не входит в paths-фильтры). 50 попыток (оценок) выданы отдельно прямым UPSERT в прод account_estimate_usage (user2, период 2026-07, used=-35 → remaining=50) по runbook tradein_grant_estimate_attempts — грант живёт до конца календарного месяца UTC. --- auth/roles.yaml | 2 +- backend/tests/test_rbac.py | 4 +--- tradein-mvp/backend/tests/test_rbac.py | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/auth/roles.yaml b/auth/roles.yaml index b4c35079..3227f325 100644 --- a/auth/roles.yaml +++ b/auth/roles.yaml @@ -70,7 +70,7 @@ users: admin: admin kopylov: pilot user1: pilot - user2: expired # «Брусника» — пробный доступ закрыт 2026-07-09 (аналогично praktika) — NoAccessScreen variant="trial" + user2: pilot # «Брусника» — доступ восстановлен 2026-07-13 (снят trial-expire от 2026-07-09) user3: pilot user4: pilot user5: pilot diff --git a/backend/tests/test_rbac.py b/backend/tests/test_rbac.py index 169e57ab..3c2435dc 100644 --- a/backend/tests/test_rbac.py +++ b/backend/tests/test_rbac.py @@ -114,9 +114,7 @@ def test_get_role_known_users() -> None: assert auth_mod.get_role("admin") == "admin" assert auth_mod.get_role("kopylov") == "pilot" for n in range(1, 11): - # user2 = «Брусника»: пробный доступ закрыт 2026-07-09 (roles.yaml) - expected = "expired" if n == 2 else "pilot" - assert auth_mod.get_role(f"user{n}") == expected + assert auth_mod.get_role(f"user{n}") == "pilot" def test_get_role_unknown_user_raises() -> None: diff --git a/tradein-mvp/backend/tests/test_rbac.py b/tradein-mvp/backend/tests/test_rbac.py index 6ff637b9..2513a210 100644 --- a/tradein-mvp/backend/tests/test_rbac.py +++ b/tradein-mvp/backend/tests/test_rbac.py @@ -132,9 +132,7 @@ def test_get_role_known_users() -> None: assert auth_mod.get_role("admin") == "admin" assert auth_mod.get_role("kopylov") == "pilot" for n in range(1, 11): - # user2 = «Брусника»: пробный доступ закрыт 2026-07-09 (roles.yaml) - expected = "expired" if n == 2 else "pilot" - assert auth_mod.get_role(f"user{n}") == expected + assert auth_mod.get_role(f"user{n}") == "pilot" def test_get_role_unknown_user_raises() -> None: -- 2.45.3 From 409c53b41ba0dd0a8a92953e7281c5ddee32dd06 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Mon, 13 Jul 2026 18:16:12 +0300 Subject: [PATCH 2/2] test(rbac): scope tradein expired-role tests to praktika (user2 restored) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_rbac_expired_denied_on_non_admin_api и test_rbac_expired_allowed_on_bootstrap хардкодили user2 как expired-субъект (только в tradein-зеркале — в main backend этих тестов нет, потому упал лишь CI Trade-In). user2 восстановлен в pilot → переводим оба на praktika (остаётся expired). Покрытие поведения expired-роли сохранено. --- tradein-mvp/backend/tests/test_rbac.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tradein-mvp/backend/tests/test_rbac.py b/tradein-mvp/backend/tests/test_rbac.py index 2513a210..74c393e3 100644 --- a/tradein-mvp/backend/tests/test_rbac.py +++ b/tradein-mvp/backend/tests/test_rbac.py @@ -320,7 +320,7 @@ def test_rbac_expired_denied_on_non_admin_api(client: TestClient) -> None: """#R2-H3: revoked (role=expired, paths:[] deny:/**) НЕ достаёт non-admin API. Раньше rbac_guard гейтил только /admin/* → expired имел полный non-admin доступ (POST /search экспорт листингов и т.д.). Теперь scope-blocked → 403.""" - for user in ("user2", "praktika"): # оба role=expired (trial отозван) + for user in ("praktika",): # role=expired (trial отозван; user2 восстановлен 2026-07-13) for path in ("/api/v1/search", "/api/v1/trade-in/dummy"): resp = client.get(path, headers={"X-Authenticated-User": user}) assert resp.status_code == 403, f"{user} {path}: {resp.status_code}" @@ -330,10 +330,10 @@ def test_rbac_expired_denied_on_non_admin_api(client: TestClient) -> None: def test_rbac_expired_allowed_on_bootstrap(client: TestClient) -> None: """expired ДОЛЖЕН достучаться до /me (получить role=expired → trial-экран) и /brand/* (брендинг trial-экрана) — иначе UX сломан. Bootstrap-исключение.""" - resp_me = client.get("/api/v1/me", headers={"X-Authenticated-User": "user2"}) + resp_me = client.get("/api/v1/me", headers={"X-Authenticated-User": "praktika"}) assert resp_me.status_code == 200, resp_me.text assert resp_me.json()["role"] == "expired" - resp_brand = client.get("/api/v1/brand/dummy", headers={"X-Authenticated-User": "user2"}) + resp_brand = client.get("/api/v1/brand/dummy", headers={"X-Authenticated-User": "praktika"}) assert resp_brand.status_code == 200, resp_brand.text -- 2.45.3