refactor(security): убрать UI ввода admin token (backend не требует с PR #437) #442

Merged
lekss361 merged 1 commit from refactor/remove-admin-token-ui into main 2026-05-23 12:06:38 +00:00
Owner

⚠️ Critical bug fix + dead UI cleanup

После PR #437 backend больше не требует X-Admin-Token header. Frontend всё ещё имел input fields и логику для ввода token — это блокировало доступ для новых users.

Critical bug

useQuery({ enabled: !!token, ... }) блокирует queries когда token пустой → новые users (kopylov, user1..10 с чистым browser) видят «Загрузка…» навсегда на admin pages.

Только у меня (admin) работало потому что в localStorage остался старый token из дней X-Admin-Token. Кейс воспроизводится в incognito или у любого нового стейкхолдера.

Что сделано

9 файлов изменены, +69 / -483 LOC:

Файл Что
src/app/admin/scrape/page.tsx DOM.РФ scraper
src/app/admin/scrape/all/page.tsx Все скраперы (сводно)
src/app/admin/scrape/cadastre/page.tsx Cadastre
src/app/admin/scrape/geo/page.tsx NSPD geo
src/app/admin/scrape/objective/page.tsx ETL Objective
src/app/admin/leads/page.tsx Лиды PRINZIP
src/components/admin/BulkGeoPanel.tsx компонент
src/components/admin/JobSettingsPanel.tsx компонент
src/components/admin/ScrapeLogsPanel.tsx компонент (доп. найден worker'ом)

В каждом файле:

  • Удалён token state + localStorage.getItem/setItem("admin_token")
  • Удалены headers: { "X-Admin-Token": token } из всех apiFetch calls
  • Удалён enabled: !!token из всех useQuery (всегда enabled)
  • Удалён token из queryKey массивов
  • Удалены <input type="password"> для token
  • Удалены !token conditional guards («Введите Admin Token...»)
  • token: string prop удалён из 3 компонентов (backward-compatible — caller уже не передаёт)

НЕ менялось

  • backend/app/core/deps.pyverify_admin_token остаётся (rollback safety, как и в PR #437)
  • frontend/src/lib/api.tsapiFetch impl остаётся
  • Caddy basic_auth — единственный auth layer (защищает endpoints)

Verify after merge

  1. Зайти под kopylov:wGLG9RS1uEIBjYCL в private browser (без localStorage)
  2. /admin/scrape → data должна загружаться без ввода token
  3. Кнопка «Запустить сейчас» НЕ disabled
  4. /admin/leads → таблица загружается сразу
  • PR #437 (backend X-Admin-Token removal)
  • PR #426 (basic_auth gate)
## ⚠️ Critical bug fix + dead UI cleanup После [PR #437](https://git.gendsgn.ru/lekss361/gendesign/pulls/437) backend больше не требует `X-Admin-Token` header. Frontend всё ещё имел input fields и логику для ввода token — **это блокировало доступ для новых users**. ## Critical bug `useQuery({ enabled: !!token, ... })` блокирует queries когда `token` пустой → новые users (`kopylov`, `user1..10` с чистым browser) видят «**Загрузка…**» **навсегда** на admin pages. Только у меня (admin) работало потому что в localStorage остался старый token из дней X-Admin-Token. Кейс воспроизводится в incognito или у любого нового стейкхолдера. ## Что сделано 9 файлов изменены, **+69 / -483 LOC**: | Файл | Что | |---|---| | `src/app/admin/scrape/page.tsx` | DOM.РФ scraper | | `src/app/admin/scrape/all/page.tsx` | Все скраперы (сводно) | | `src/app/admin/scrape/cadastre/page.tsx` | Cadastre | | `src/app/admin/scrape/geo/page.tsx` | NSPD geo | | `src/app/admin/scrape/objective/page.tsx` | ETL Objective | | `src/app/admin/leads/page.tsx` | Лиды PRINZIP | | `src/components/admin/BulkGeoPanel.tsx` | компонент | | `src/components/admin/JobSettingsPanel.tsx` | компонент | | `src/components/admin/ScrapeLogsPanel.tsx` | компонент (доп. найден worker'ом) | В каждом файле: - Удалён `token` state + `localStorage.getItem/setItem("admin_token")` - Удалены `headers: { "X-Admin-Token": token }` из всех `apiFetch` calls - Удалён `enabled: !!token` из всех `useQuery` (всегда enabled) - Удалён `token` из `queryKey` массивов - Удалены `<input type="password">` для token - Удалены `!token` conditional guards («Введите Admin Token...») - `token: string` prop удалён из 3 компонентов (backward-compatible — caller уже не передаёт) ## НЕ менялось - `backend/app/core/deps.py` — `verify_admin_token` остаётся (rollback safety, как и в PR #437) - `frontend/src/lib/api.ts` — `apiFetch` impl остаётся - Caddy basic_auth — единственный auth layer (защищает endpoints) ## Verify after merge 1. Зайти под `kopylov:wGLG9RS1uEIBjYCL` в **private browser** (без localStorage) 2. `/admin/scrape` → data должна загружаться без ввода token 3. Кнопка «Запустить сейчас» НЕ disabled 4. `/admin/leads` → таблица загружается сразу ## Related - PR #437 (backend X-Admin-Token removal) - PR #426 (basic_auth gate)
lekss361 added 1 commit 2026-05-23 11:59:00 +00:00
- Удалить token state + localStorage.setItem("admin_token") из всех admin pages
- Удалить X-Admin-Token header из всех apiFetch вызовов
- Убрать enabled: !!token из useQuery — fix «Загрузка…» forever для новых users
- Убрать token prop из BulkGeoPanel, JobSettingsPanel, ScrapeLogsPanel
- Удалить !token guards и UI input fields для ввода токена
- queryKey: убрать token из ключей (scrape-runs, scrape-queue, etc.)
lekss361 merged commit a2953e97c4 into main 2026-05-23 12:06:38 +00:00
Author
Owner

Merged via deep-code-reviewer — verdict APPROVE.

Deep review summary

Files reviewed: 9 (P1: 6 admin pages, P2: 3 reusable panels)
Lines: +69 / -483 (massive net delete = good signal)
Time: ~8 min

Complete removal verification (CRITICAL focus #1)

Grep на PR-branch tree (worktree из df34ad7):

Pattern Match? Notes
X-Admin-Token в admin pages/panels none весь scope clean
admin_token localStorage app/legacy/site-finder/page.tsx:135legacy path, out of scope
enabled: !!token none все 19 ранее-найденных removed
SCRAPE_ADMIN_TOKEN placeholder none input fields gone
<input type="password"> для token none UI fields removed

Out-of-scope stale refs (acceptable, follow-up):

  • frontend/src/lib/api/weightProfiles.ts:94-95 — отдельный admin scope (site-finder weight profiles), не покрыт PR #437. Backend admin_weight_profiles.py упомянут в decision как тоже cleaned → frontend hook сюда не задели. Follow-up PR нужен.
  • frontend/src/lib/api-types.ts — 27× "X-Admin-Token"?: string | null (codegen из OpenAPI). Поскольку backend verify_admin_token оставлен для rollback safety, OpenAPI schema продолжает эмитить header param. Чистится регенерацией после полного backend removal.

Findings detail

  1. enabled: !!token root-cause fix — verified. Все non-token enabled сохранены корректно:
    • cadastre/page.tsx:160enabled: expandedId !== null (row expand gate)
    • scrape/page.tsx:208enabled: showFailures (lazy load failures)
    • JobSettingsPanel s.enabled / draft.enabled — это domain field (cron enabled), не auth gate
  2. Component callers<JobSettingsPanel />, <BulkGeoPanel />, <ScrapeLogsPanel ...> все updated, не передают token. TS strict — signature breaking, build fail если caller остался.
  3. ImportsinputStyle удалён из scrape/all/page.tsx (orphan), остальные файлы продолжают использовать. Link в leads/page.tsx — used (line 517 в jobs table). Все imports чистые.
  4. Cross-PR rebase — merge_base a2147872, отстал на 1 commit (PR #441 tradein-mvp/backend/app/services/scrapers/{avito,base}.py). Zero file overlap с frontend → conflict-free squash.
  5. Deploy paths.forgejo/workflows/deploy.yml frontend/** filter сработает, frontend image rebuild → push к Beget VPS.
  6. <form> orphan check — нет orphaned form wrappers (cadastre create job form и BulkGeoPanel form остались с real bodies).
  7. localStorage cleanup — stale admin_token остаётся в localStorage admin users. Backend ignores, не security risk. Активный removeItem — nice-to-have (можно в onMount addEventListener), не блок.

Follow-up tasks (post-merge, non-blocking)

  • Update vault: decisions/Decision_Remove_AppLevel_AdminAuth_May23.md — добавить раздел "Frontend cleanup completed PR #442", убрать "frontend: продолжает слать X-Admin-Token" из "Что НЕ менялось"
  • Follow-up PR: weightProfiles.ts hooks убрать adminToken parameter (site-finder weight profiles backend тоже без auth per decision)
  • Post-deploy: regen api-types (npm run codegen) после full backend removal verify_admin_token
  • Optional: на mount admin pages localStorage.removeItem("admin_token") для cleaner state

Self-acknowledged missed pattern (4-й подряд)

В review PR #437 я указал "Frontend cleanup next sprint" как acceptable trade-off — НЕ identified что enabled: !!token блокирует UI для new users без token. Этот паттерн идёт в vault как universal review rule:

При removal of auth header в frontend — также check useQuery({ enabled: !!token }) dependencies. Если enabled зависит от auth var → query гарантированно disabled при пустом state → UI заблокирована для users без stale localStorage.

Risk / reversibility

  • Risk: Low (delete-only diff, +69/-483, deploy revert one commit)
  • Reversibility: Easy revert (single squash commit a2953e97)
  • Merge window: anytime (pilot demo unblocker)
Merged via deep-code-reviewer — verdict APPROVE. ## Deep review summary **Files reviewed**: 9 (P1: 6 admin pages, P2: 3 reusable panels) **Lines**: +69 / -483 (massive net delete = good signal) **Time**: ~8 min ### Complete removal verification (CRITICAL focus #1) Grep на PR-branch tree (worktree из `df34ad7`): | Pattern | Match? | Notes | |---|---|---| | `X-Admin-Token` в admin pages/panels | none | весь scope clean | | `admin_token` localStorage | 1× | `app/legacy/site-finder/page.tsx:135` — **legacy path**, out of scope | | `enabled: !!token` | none | все 19 ранее-найденных removed | | `SCRAPE_ADMIN_TOKEN` placeholder | none | input fields gone | | `<input type="password">` для token | none | UI fields removed | **Out-of-scope stale refs (acceptable, follow-up)**: - `frontend/src/lib/api/weightProfiles.ts:94-95` — отдельный admin scope (site-finder weight profiles), не покрыт PR #437. Backend `admin_weight_profiles.py` упомянут в decision как тоже cleaned → frontend hook сюда не задели. Follow-up PR нужен. - `frontend/src/lib/api-types.ts` — 27× `"X-Admin-Token"?: string | null` (codegen из OpenAPI). Поскольку backend `verify_admin_token` оставлен для rollback safety, OpenAPI schema продолжает эмитить header param. Чистится регенерацией после полного backend removal. ### Findings detail 1. **enabled: !!token root-cause fix** — verified. Все non-token `enabled` сохранены корректно: - `cadastre/page.tsx:160` — `enabled: expandedId !== null` (row expand gate) ✅ - `scrape/page.tsx:208` — `enabled: showFailures` (lazy load failures) ✅ - `JobSettingsPanel` `s.enabled` / `draft.enabled` — это domain field (cron enabled), не auth gate ✅ 2. **Component callers** — `<JobSettingsPanel />`, `<BulkGeoPanel />`, `<ScrapeLogsPanel ...>` все updated, не передают `token`. TS strict — signature breaking, build fail если caller остался. 3. **Imports** — `inputStyle` удалён из `scrape/all/page.tsx` (orphan), остальные файлы продолжают использовать. `Link` в `leads/page.tsx` — used (line 517 в jobs table). Все imports чистые. 4. **Cross-PR rebase** — merge_base `a2147872`, отстал на 1 commit (PR #441 `tradein-mvp/backend/app/services/scrapers/{avito,base}.py`). **Zero file overlap** с frontend → conflict-free squash. 5. **Deploy paths** — `.forgejo/workflows/deploy.yml` `frontend/**` filter сработает, frontend image rebuild → push к Beget VPS. 6. **`<form>` orphan check** — нет orphaned form wrappers (cadastre create job form и BulkGeoPanel form остались с real bodies). 7. **localStorage cleanup** — stale `admin_token` остаётся в localStorage admin users. Backend ignores, не security risk. Активный `removeItem` — nice-to-have (можно в onMount addEventListener), не блок. ### Follow-up tasks (post-merge, non-blocking) - [ ] Update vault: `decisions/Decision_Remove_AppLevel_AdminAuth_May23.md` — добавить раздел "Frontend cleanup completed PR #442", убрать "frontend: продолжает слать X-Admin-Token" из "Что НЕ менялось" - [ ] Follow-up PR: `weightProfiles.ts` hooks убрать `adminToken` parameter (site-finder weight profiles backend тоже без auth per decision) - [ ] Post-deploy: regen api-types (`npm run codegen`) после full backend removal `verify_admin_token` - [ ] Optional: на mount admin pages `localStorage.removeItem("admin_token")` для cleaner state ### Self-acknowledged missed pattern (4-й подряд) В review PR #437 я указал "Frontend cleanup next sprint" как acceptable trade-off — НЕ identified что `enabled: !!token` блокирует UI для new users без token. Этот паттерн идёт в vault как universal review rule: > При removal of auth header в frontend — также check `useQuery({ enabled: !!token })` dependencies. Если `enabled` зависит от auth var → query гарантированно disabled при пустом state → UI заблокирована для users без stale localStorage. ### Risk / reversibility - **Risk**: Low (delete-only diff, +69/-483, deploy revert one commit) - **Reversibility**: Easy revert (single squash commit `a2953e97`) - **Merge window**: anytime (pilot demo unblocker)
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#442
No description provided.