feat(rbac): pilot scope → только /trade-in/** #587

Merged
Light1YT merged 1 commit from feat/rbac-pilot-tradein-only into main 2026-05-26 07:40:44 +00:00
Owner

Summary

Decision 2026-05-26: pilot-аккаунты пилот-программы получают доступ только к разделу Trade-In (оценка вторички). Landing (/), Analytics, Site Finder, Concept — admin-only.

Изменения

auth/roles.yaml — pilot.paths сужен

# Было
pilot:
  paths:
    - "/"
    - "/analytics/**"
    - "/site-finder/**"
    - "/trade-in/**"
    - "/concept/**"
    - "/api/v1/**"
    - "/trade-in/api/v1/**"

# Стало
pilot:
  paths:
    - "/trade-in/**"
    - "/trade-in/api/v1/**"

Также синхронизированы с VPS local edits

  • caddy/users.caddy.snippet — regen'd user1..user10 hashes + admintest + pilottest entries
  • auth/roles.yaml users: блок — admintest: admin и pilottest: pilot (temp QA)

Без этого deploy.yml (git reset --hard origin/main) стёр бы локальные правки на VPS и QA accounts отвалились бы.

Effect на UX

User Open / Open /trade-in Open /admin/scrape TopNav
admin работает Все 5 пунктов
pilot fullscreen «Доступа нет» работает fullscreen Только «Trade-In»
unknown 403 от backend n/a (fullscreen)

Pilot login flow: Caddy basic_auth → main frontend → useMe → /me → scope (allowed=/trade-in/**). RouteGuard на /<NoAccessScreen variant="path" path="/">. Pilot должен открывать https://gendsgn.ru/trade-in/ напрямую.

Тесты

  • backend/tests/test_rbac.py: 20/20 pass (test_is_path_allowed_pilot_excludes_admin переписан в _pilot_only_tradein, test_get_user_scope_pilot обновлён)
  • tradein-mvp/backend/tests/test_rbac.py: 20/20 pass (mirror)
  • frontend/src/lib/__tests__/isPathAllowed.test.ts: parity tests обновлены
  • ruff clean

Test plan (post-deploy)

  • curl -u pilottest:7d8b3c267aa3 https://gendsgn.ru/api/v1/meallowed_paths: ["/trade-in/**", "/trade-in/api/v1/**"]
  • Safari incognito → login pilottest/ → fullscreen «Доступа нет», /trade-in → работает
  • Safari incognito → login admintest → все страницы открываются
  • TopNav на main frontend как pilot — только «Trade-In»

Follow-up (optional)

Mожно добавить auto-redirect в RouteGuard: если pilot landing-path в denied, redirect на первый allowed (/trade-in). Отдельный PR — не блокирует этот.

## Summary Decision 2026-05-26: pilot-аккаунты пилот-программы получают доступ **только** к разделу Trade-In (оценка вторички). Landing (`/`), Analytics, Site Finder, Concept — admin-only. ## Изменения ### `auth/roles.yaml` — pilot.paths сужен ```yaml # Было pilot: paths: - "/" - "/analytics/**" - "/site-finder/**" - "/trade-in/**" - "/concept/**" - "/api/v1/**" - "/trade-in/api/v1/**" # Стало pilot: paths: - "/trade-in/**" - "/trade-in/api/v1/**" ``` ### Также синхронизированы с VPS local edits - `caddy/users.caddy.snippet` — regen'd user1..user10 hashes + admintest + pilottest entries - `auth/roles.yaml` users: блок — `admintest: admin` и `pilottest: pilot` (temp QA) Без этого `deploy.yml` (git reset --hard origin/main) стёр бы локальные правки на VPS и QA accounts отвалились бы. ## Effect на UX | User | Open `/` | Open `/trade-in` | Open `/admin/scrape` | TopNav | |---|---|---|---|---| | admin | ✅ работает | ✅ | ✅ | Все 5 пунктов | | pilot | ❌ fullscreen «Доступа нет» | ✅ работает | ❌ fullscreen | Только «Trade-In» | | unknown | ❌ 403 от backend | ❌ | ❌ | n/a (fullscreen) | Pilot login flow: Caddy basic_auth → main frontend → useMe → /me → scope (allowed=/trade-in/**). RouteGuard на `/` → `<NoAccessScreen variant="path" path="/">`. Pilot должен открывать `https://gendsgn.ru/trade-in/` напрямую. ## Тесты - ✅ `backend/tests/test_rbac.py`: 20/20 pass (test_is_path_allowed_pilot_excludes_admin переписан в `_pilot_only_tradein`, test_get_user_scope_pilot обновлён) - ✅ `tradein-mvp/backend/tests/test_rbac.py`: 20/20 pass (mirror) - ✅ `frontend/src/lib/__tests__/isPathAllowed.test.ts`: parity tests обновлены - ✅ ruff clean ## Test plan (post-deploy) - [ ] `curl -u pilottest:7d8b3c267aa3 https://gendsgn.ru/api/v1/me` → `allowed_paths: ["/trade-in/**", "/trade-in/api/v1/**"]` - [ ] Safari incognito → login `pilottest` → `/` → fullscreen «Доступа нет», `/trade-in` → работает - [ ] Safari incognito → login `admintest` → все страницы открываются - [ ] TopNav на main frontend как pilot — только «Trade-In» ## Follow-up (optional) Mожно добавить auto-redirect в RouteGuard: если pilot landing-path в denied, redirect на первый allowed (`/trade-in`). Отдельный PR — не блокирует этот.
Light1YT added 1 commit 2026-05-26 07:40:34 +00:00
Decision 2026-05-26: pilot аккаунты пилот-программы получают доступ
ТОЛЬКО к разделу Trade-In (оценка вторички). Landing, Analytics,
Site Finder, Concept — admin-only.

Изменения:
- `auth/roles.yaml` — `pilot.paths` сужен с 7 путей до 2:
  `/trade-in/**` + `/trade-in/api/v1/**`. Deny список оставлен
  как есть для defense-in-depth.
- `backend/tests/test_rbac.py` + tradein mirror — переписан
  `test_is_path_allowed_pilot_excludes_admin` → `_pilot_only_tradein`:
  pilot allowed только /trade-in, denied на /, /analytics, /site-finder,
  /concept, /api/v1/parcels. Тест `test_get_user_scope_pilot` ассертит
  что /trade-in/** в allowed, / и /analytics/** нет.
- `frontend/src/lib/__tests__/isPathAllowed.test.ts` — те же parity
  обновления (pilot allowed list сужен, denied list расширен landing
  + non-tradein путями).
- `caddy/users.caddy.snippet` — синхронизирован с VPS-актуальной
  версией: regen'd user1..user10 hashes + admintest/pilottest entries
  (locally added на VPS 2026-05-26 для QA RBAC). Без этого `deploy.yml`
  делал бы `git reset --hard` и стирал бы локальные правки.
- `auth/roles.yaml` users: блок — также добавлены `admintest: admin`
  и `pilottest: pilot` (mirror VPS local edit).

Эффект для UX:
- pilot открывает `/` → frontend RouteGuard → fullscreen «Доступа нет»
  (т.к. `/` не в allowed_paths).
- pilot TopNav на main frontend — только пункт «Trade-In» виден
  (остальные `/analytics`, `/site-finder`, `/concept`, `/admin`
  отфильтрованы `isPathAllowed`).
- pilot открывает `/trade-in` → работает как раньше.
- admin (admintest, kopylov-если бы был admin) — без изменений.

Backend middleware path-enforcement не делает — security guarantee
по-прежнему на admin-only endpoints (`/api/v1/admin/*` блочится для
пилота). Path-filter на UI-уровне через `allowed_paths` /
`deny_paths` в /me response.

Pilot login flow: после basic_auth → main frontend → useMe → /me →
scope (allowed=/trade-in/**). RouteGuard на `/` → NoAccessScreen.
Pilot должен bookmark'ить `https://gendsgn.ru/trade-in/` напрямую.

Follow-up: можно добавить auto-redirect в RouteGuard — если pilot
landing-path → redirect на первый allowed (`/trade-in`). Отдельный PR.

Tests: 20/20 pass на обоих backend стэках, ruff clean.
Light1YT merged commit c08e4d7811 into main 2026-05-26 07:40:44 +00:00
Light1YT deleted branch feat/rbac-pilot-tradein-only 2026-05-26 07:40:45 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#587
No description provided.