From 61d373f076a2fcb1621a285f3ed6452910d61a66 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 12 May 2026 15:30:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D0=A0=D0=A5=20-=20=D0=9C=D0=95=D0=96?= =?UTF-8?q?=D0=9F=D0=A0=D0=9E=D0=95=D0=9A=D0=A2=D0=9D=D0=90=D0=AF=20=D0=9A?= =?UTF-8?q?=D0=9E=D0=9C=D0=9C=D0=A3=D0=9D=D0=98=D0=9A=D0=90=D0=A6=D0=98?= =?UTF-8?q?=D0=AF:=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D0=B0=20=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=80=D0=B8=D0=BD=D1=8B=20=D1=81=D0=B5=D1=80=D0=B2?= =?UTF-8?q?=D0=B8=D1=81=D0=BE=D0=B2=20=D0=B8=20security=20handoff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/DEVOPS_SECURITY_HANDOFF.md | 6 ++-- docs/SECURITY_CHECKLIST.md | 3 +- docs/SERVICE_CATALOG_UX_RULES.md | 56 ++++++++++++++++++++++++++++++++ docs/STAGING_SECURITY_PLAN.md | 4 +-- 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 docs/SERVICE_CATALOG_UX_RULES.md diff --git a/docs/DEVOPS_SECURITY_HANDOFF.md b/docs/DEVOPS_SECURITY_HANDOFF.md index f001ac4..65eceef 100644 --- a/docs/DEVOPS_SECURITY_HANDOFF.md +++ b/docs/DEVOPS_SECURITY_HANDOFF.md @@ -49,7 +49,7 @@ docker run --rm --env-file .env.staging.example -v "$PWD/reverse-proxy/Caddyfile - control-plane snapshot перенесён из public static в server-only storage; - `/storage/launcher-data.json` закрыт; - `/api/storage/data` и `/api/storage/upload` требуют session; -- `/api/apps` отдаёт только приложения с app access; +- `/api/apps` отдаёт каталог сервисов с флагами доступа; карточки сервисов видны всем authenticated users, но launch разрешён только при app access; - hard delete вызывает Tasker cleanup: sessions, identity links, workspace/project memberships, issue assignees; - internal API token отделён от OIDC client secret; - повторный accept уже принятого invite отклоняется. @@ -252,8 +252,8 @@ docker compose --env-file plane-app/plane.env.staging -f plane-app/docker-compos 3. Ответы содержат HSTS. 4. Cookies выставляются как `Secure` и `HttpOnly`. 5. Без login Launcher ведёт в Authentik. -6. Active user видит только разрешённые сервисы. -7. User без Task Manager app access не видит Task Manager в Launcher и получает deny по прямому `https://task...`. +6. Active user видит все карточки сервисов, но открыть может только разрешённые сервисы. +7. User без Task Manager app access видит карточку Task Manager в Launcher, не может открыть сервис и получает deny по прямому `https://task...`. 8. Blocked/annulled user теряет Launcher и Tasker session после hard refresh. 9. Self-host workspace invite создаёт pending request в Launcher. 10. Launcher-managed workspace не принимает self-service invite request из Tasker. diff --git a/docs/SECURITY_CHECKLIST.md b/docs/SECURITY_CHECKLIST.md index 6e02621..5e9b38c 100644 --- a/docs/SECURITY_CHECKLIST.md +++ b/docs/SECURITY_CHECKLIST.md @@ -2,6 +2,7 @@ Staging path and runbook: `docs/STAGING_SECURITY_PLAN.md`. DevOps handoff: `docs/DEVOPS_SECURITY_HANDOFF.md`. +Service catalog UX rules: `docs/SERVICE_CATALOG_UX_RULES.md`. ## Network @@ -55,7 +56,7 @@ DevOps handoff: `docs/DEVOPS_SECURITY_HANDOFF.md`. ## Acceptance scenarios - [x] Без логина Launcher отправляет в Authentik. -- [x] Пользователь без Task Manager app access не видит Task Manager в Launcher. +- [ ] Пользователь без Task Manager app access видит карточку Task Manager в Launcher, но не может открыть сервис. - [x] Пользователь без Task Manager app access получает deny в Tasker access middleware при прямом доступе. - [ ] Пользователь с доступом открывает Task Manager. - [ ] Старый Plane admin после OIDC видит старые workspace/tasks/comments. diff --git a/docs/SERVICE_CATALOG_UX_RULES.md b/docs/SERVICE_CATALOG_UX_RULES.md new file mode 100644 index 0000000..4377a7d --- /dev/null +++ b/docs/SERVICE_CATALOG_UX_RULES.md @@ -0,0 +1,56 @@ +# Service Catalog UX Rules + +Актуализировано: 2026-05-12. + +Этот документ фиксирует обязательное правило Launcher-витрины NODE.DC. + +## Главное правило + +Все authenticated users видят карточки всех сервисов, добавленных в каталог Launcher, независимо от текущего app access. + +Видимость карточки сервиса не означает право запуска сервиса. + +## Зачем это нужно + +Launcher — это не только access gate, но и витрина платформы. Пользователь должен видеть, какие приложения существуют в NODE.DC, даже если доступ к конкретному приложению ещё не выдан. + +Это нужно для: + +- демонстрации состава платформы; +- ручного запроса доступа; +- будущих тарифов и paid access; +- понимания, какие модули доступны в экосистеме. + +## Как должен работать UI + +Для сервиса без доступа: + +- карточка сервиса остаётся видимой в нижней/сервисной панели; +- описание, медиа и карточка доступны для чтения; +- статус/chip показывает отсутствие доступа; +- кнопка открытия сервиса disabled или ведёт в controlled request/access flow; +- прямой запуск через `/api/services/:serviceSlug/launch` обязан возвращать deny. + +Для сервиса с доступом: + +- карточка сервиса видима; +- кнопка открытия активна; +- launch идёт только через Launcher BFF, а не прямым trust из UI. + +## Realtime правило + +Изменение доступа должно обновлять состояние карточки без hard refresh: + +- выдали доступ — кнопка открытия становится активной; +- сняли доступ — карточка остаётся видимой, но кнопка открытия выключается; +- direct launch после снятия доступа остаётся запрещённым server-side. + +Нельзя чинить безопасность через скрытие карточек. Безопасность обеспечивается server-side launch deny, Tasker middleware и internal access enforcement. + +## Что запрещено + +- Фильтровать `/api/apps` только до доступных пользователю приложений, если это ломает витрину. +- Убирать карточку сервиса из UI только потому, что у пользователя нет app access. +- Считать скрытие карточки security control. +- Ломать realtime-переключение кнопки `Открыть` при approve/revoke доступа. + diff --git a/docs/STAGING_SECURITY_PLAN.md b/docs/STAGING_SECURITY_PLAN.md index 465ee4d..88b0766 100644 --- a/docs/STAGING_SECURITY_PLAN.md +++ b/docs/STAGING_SECURITY_PLAN.md @@ -146,8 +146,8 @@ Rotation policy до допуска внешних пользователей: Минимальный staging smoke: 1. Super sudo входит в Launcher через `https://launcher...`. -2. Обычный active user видит только разрешённые сервисы. -3. User без Task Manager app access не видит Task Manager в витрине и получает deny по прямому `https://task...`. +2. Обычный active user видит все карточки сервисов, но открыть может только разрешённые сервисы. +3. User без Task Manager app access видит карточку Task Manager в витрине, не может открыть сервис и получает deny по прямому `https://task...`. 4. Blocked/annulled user теряет Launcher и Tasker session после hard refresh. 5. Self-host workspace invite создаёт pending request в Launcher. 6. Launcher-managed workspace не принимает self-service invite request из Tasker.