feat(F.7b): tool access UI + unified keys page (v3.9.0)
Some checks failed
Release / Test before release (push) Has been cancelled
Release / Publish to PyPI (push) Has been cancelled
Release / Publish to Docker Hub (push) Has been cancelled
Release / Create GitHub Release (push) Has been cancelled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 21:00:42 +02:00
parent 3fc02b5734
commit d8a0805412
30 changed files with 2965 additions and 72 deletions

View File

@@ -0,0 +1,136 @@
از مهارت project-ops برای آشنایی با محیط استفاده کن. حافظه و فایل‌های مرجع را بررسی کن.
## فایل‌های مرجع
- docs/plans/2026-03-25-v4-development-cycle.md (mcphub-internal) ← Phase F.7 طراحی کامل
- core/tool_generator.py (mcphub-internal) ← تولید ابزار فعلی
- core/tool_registry.py (mcphub-internal) ← رجیستری ابزار
- core/user_endpoints.py (mcphub-internal) ← فیلتر ابزار در endpoint کاربر
- core/user_keys.py (mcphub-internal) ← سیستم API key کاربر
- core/database.py (mcphub-internal) ← دیتابیس و مایگریشن
- core/plugin_visibility.py (mcphub-internal) ← فیلتر پلاگین فعلی
- core/dashboard/routes.py (mcphub-internal) ← روت‌های داشبورد
- server.py (mcphub-internal) ← middleware و scope enforcement
- CLAUDE.md (mcphub-internal)
## وضعیت فعلی
- MCPHub: v3.8.0 — 633 ابزار، 10 پلاگین، 67 ابزار Coolify
- تست‌ها: 766 (internal), 734 (public)
- CI سبز
- Scope فعلی: read/write/admin (سه سطح ساده)
- فیلتر فعلی: فقط plugin-level (ENABLED_PLUGINS) — بدون per-tool toggle
## ریپازیتوری
- MCPHub (internal): `/config/workspace/mcphub-internal` (branch Phase-1)
## هدف session: F.7 — Smart Tool Visibility & Scope-Based Access Control
### مشکلاتی که حل می‌شوند
1. همه ابزارهای یک پلاگین فعال به همه کاربران نشان داده می‌شوند — کنترل per-tool نداریم
2. وقتی کاربر API key با scope خاص (مثلا read) می‌سازد، باز هم همه ابزارها در tools/list نمایش داده می‌شوند
3. ابزارهای وردپرس که نیاز به افزونه‌های کمکی دارند (SEO Bridge, WP-CLI) بدون بررسی prerequisite نشان داده می‌شوند
4. کاربران نمی‌توانند ابزارهایی که نیاز ندارند را غیرفعال کنند
### مدل scope پیشنهادی (گسترش‌یافته)
فعلی: `read`, `write`, `admin`
جدید:
- `deploy` — عملیات lifecycle (start/stop/restart/deploy) + read
- `read:sensitive` — read + لاگ، env var، بکاپ، connection string
**نگاشت scope → دسته‌بندی ابزار:**
| Scope | ابزارها |
|-------|---------|
| `read` | list_*, get_* (بدون sensitive) |
| `read:sensitive` | read + *_logs, *_envs, *_backups |
| `deploy` | read + start_*, stop_*, restart_*, deploy |
| `write` | deploy + create_*, update_*, delete_*_env |
| `admin` | write + delete_* (منابع)، create_server |
### بخش اول: Core — ساختار داده و مدیریت دسترسی (بدون UI)
#### مرحله ۱: دیتابیس
- [ ] جدول `user_tool_toggles` در `core/database.py`
```sql
CREATE TABLE user_tool_toggles (
id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
tool_name TEXT NOT NULL, enabled INTEGER NOT NULL DEFAULT 1,
reason TEXT, updated_at TEXT NOT NULL, UNIQUE(user_id, tool_name)
);
```
- [ ] جدول `scope_presets` — پریست‌های scope سیستمی + سفارشی
- [ ] Migration اجرا شود
#### مرحله ۲: ماژول tool_access.py
- [ ] `core/tool_access.py` — کلاس `ToolAccessManager`
- [ ] `get_visible_tools(user_id, scopes, plugin_type)` → لیست فیلتر شده
- [ ] `apply_scope_filter(tools, scopes)` → فقط ابزارهای مجاز بر اساس scope
- [ ] `apply_user_toggles(tools, user_id)` → اعمال toggleهای کاربر
- [ ] `toggle_tool(user_id, tool_name, enabled)` → ذخیره تنظیم
- [ ] `bulk_toggle_by_scope(user_id, scope_name)` → فعال/غیرفعال دسته‌جمعی
#### مرحله ۳: Tool metadata enhancement
- [ ] اضافه کردن `sensitivity` و `category` به tool specs در handlerها:
- `sensitivity`: "normal" | "sensitive" (لاگ، env، بکاپ)
- `category`: "read" | "lifecycle" | "crud" | "env" | "backup" | "system"
- [ ] شروع از Coolify (آخرین و تمیزترین) سپس سایر پلاگین‌ها
- [ ] ToolDefinition در tool_registry.py آپدیت شود
#### مرحله ۴: فیلتر در user_endpoints.py
- [ ] `_get_tools_for_plugin()` از ToolAccessManager استفاده کند
- [ ] Pipeline فیلتر:
1. plugin_visibility (موجود)
2. scope-to-tool mapping (جدید)
3. user toggles (جدید)
- [ ] Scope enforcement در middleware آپدیت شود (server.py)
#### مرحله ۵: تست
- [ ] `tests/test_tool_access.py` — unit tests
- [ ] تست‌های scope mapping: key با scope "read" → فقط ابزارهای read
- [ ] تست‌های toggle: کاربر disable کرده → ابزار در tools/list نیست
- [ ] تست‌های integration: API key scope → فیلتر واقعی
### بخش دوم: API — روت‌های مدیریت toggle
- [ ] `GET /api/user/tools` — لیست ابزارها با وضعیت toggle
- [ ] `PATCH /api/user/tools/{tool_name}` — تغییر toggle
- [ ] `POST /api/user/tools/bulk-toggle` — toggle دسته‌جمعی بر اساس scope
- [ ] `GET /api/user/scope-presets` — لیست presetها
- [ ] تست: روت‌ها کار کنند
### بخش سوم: Prerequisites (وردپرس/ووکامرس)
- [ ] `check_prerequisites(tools, site_config)` در tool_access.py
- [ ] تشخیص SEO Bridge: `wp-json/airano-mcp-seo-bridge/v1/status`
- [ ] تشخیص WP-CLI: بررسی `container` field در credentials
- [ ] تشخیص WooCommerce: `wp-json/wc/v3/system_status`
- [ ] ابزارهای وابسته علامت‌گذاری شوند (نه حذف — فقط annotation)
### بخش چهارم: UI — صفحه مدیریت ابزار
- [ ] `core/templates/dashboard/tool-preferences.html`
- [ ] لیست ابزارها گروه‌بندی شده بر اساس category
- [ ] Toggle switch برای هر ابزار
- [ ] Badge برای prerequisite (نصب نشده / نیاز به Docker)
- [ ] Dropdown برای اعمال scope preset
- [ ] در صفحه Connect: پیش‌نمایش ابزارها هنگام ساخت API key
### بخش پنجم: ثبت و تست نهایی
- [ ] `uvx --python 3.12 black .`
- [ ] `uvx ruff check --fix .`
- [ ] `pytest` — همه تست‌ها سبز
- [ ] Commit: `feat(F.7): add smart tool visibility and scope-based access control`
- [ ] Push و درخواست redeploy
- [ ] تست live: ساخت API key با scope "read" → بررسی tools/list
- [ ] Sync به نسخه عمومی
- [ ] آپدیت ورژن به v3.9.0 (اگر تأیید شد)
- [ ] حافظه آپدیت شود
- [ ] پلن آپدیت شود (F.7 complete)
## نکات مهم
- فیلتر scope باید backward-compatible باشد — keyهای موجود بدون تغییر کار کنند
- Default: همه ابزارها فعال — فقط explicit disable ذخیره شود
- `user_tool_toggles` فقط overrideها رو ذخیره می‌کنه، نه همه ابزارها
- Prerequisite check باید non-blocking باشه — ابزار حذف نشه، فقط annotate بشه
- server.py نیازی به تغییر زیاد ندارد — فقط middleware scope check آپدیت شود
- ایمیل git داخلی: mcphub.dev@gmail.com
- بخش اول و دوم اولویت اصلی هستند — بخش سوم و چهارم اگر وقت شد

View File

@@ -0,0 +1,98 @@
از مهارت project-ops برای آشنایی با محیط استفاده کن. حافظه و فایل‌های مرجع را بررسی کن.
## فایل‌های مرجع
- docs/plans/2026-04-04-f7b-site-scoped-tool-access.md ← پلن کامل F.7b
- core/tool_access.py ← ToolAccessManager (سایت‌محور — session 1)
- core/dashboard/routes.py ← روت‌های API site tools (بخش F.7b)
- core/templates/dashboard/sites/edit.html ← صفحه edit سایت (بدون بخش tools)
- core/templates/dashboard/connect.html ← صفحه connect فعلی (config snippets + keys)
- core/templates/dashboard/api-keys/list.html ← صفحه admin کلیدها (UI بهتر)
- core/dashboard/routes.py::dashboard_connect_page / dashboard_api_keys_list
- CLAUDE.md (mcphub-internal)
## وضعیت فعلی
- MCPHub: v3.8.0 + F.7b session 1 (commit روی Phase-1)
- Tests: 813 passed، CI سبز
- Backend F.7b کامل است: per-site tool_scope + site_tool_toggles + 4 روت جدید تحت `/api/sites/{site_id}/...` + `/api/scope-presets`
- فقط UI باقی مانده — هدف این session
## ریپازیتوری
- MCPHub (internal): `/config/workspace/mcphub-internal` (branch Phase-1)
## هدف session: F.7b — UI + page merge
### ۱. بخش "Tool Access" در صفحه edit سایت
فایل: `core/templates/dashboard/sites/edit.html`
- [ ] اضافه کردن یک کارت جدید "Tool Access" بعد از فرم credentials
- [ ] Dropdown برای `tool_scope` (values: read / read:sensitive / deploy / write / admin / custom)
- PATCH روی `/api/sites/{site_id}/tool-scope` با body `{scope: "..."}`
- توضیح کوتاه کنار هر گزینه: "Read (X tools)" — شمارش زنده از `/api/sites/{site_id}/tools`
- [ ] Collapsible "Advanced — per-tool overrides":
- گرید/لیست گروه‌بندی شده بر اساس `category` (read / read_sensitive / lifecycle / crud / env / backup / system)
- Toggle switch برای هر ابزار → PATCH `/api/sites/{site_id}/tools/{tool_name}` با `{enabled: bool}`
- Badge قرمز برای `sensitivity=sensitive`
- نام کوتاه از `name`، tooltip با `description`
- [ ] استفاده از HTMX (در پروژه موجود است) برای updates بدون full reload
- [ ] CSRF token از cookie `dashboard_csrf` به header `X-CSRF-Token`
### ۲. انتقال config snippets از connect به صفحه سایت
فایل: `core/templates/dashboard/sites/view.html` (یا ایجاد اگر وجود ندارد)
- [ ] هر سایت در `/dashboard/sites/{id}` نمایش دهد:
- URL MCP مخصوص آن سایت: `{PUBLIC_URL}/u/{user_id}/{alias}/mcp`
- Tabs یا accordion با snippets برای Claude Desktop / Cursor / Zed / کلاینت‌های دیگر
- استفاده از `core/config_snippets.py::get_supported_clients` (موجود)
- [ ] از صفحه `/dashboard/sites` (list) دکمه "Connect" به این صفحه لینک بزند
### ۳. ادغام `/dashboard/connect` و `/dashboard/api-keys` → `/dashboard/keys` (گزینه A)
UI مبنا: `core/templates/dashboard/api-keys/list.html` (قشنگ‌تر و کامل‌تر است طبق تأیید کاربر)
- [ ] ساخت handler `dashboard_keys_unified(request)` که بر اساس session type branch می‌زند:
- OAuth user → نمایش `user_api_keys` برای آن کاربر
- Admin/master → نمایش کامل `api_keys` (همان view فعلی)
- [ ] template جدید `core/templates/dashboard/keys/list.html` با ادغام design از `api-keys/list.html`
- User view: ساده‌تر، scope selector در create dialog، لیست کلیدهای خود کاربر
- Admin view: فیلترهای کامل (project, status, search, pagination) — بدون تغییر
- [ ] **Scope selector در create-key dialog** — این بخش حیاتی است:
- Radio/select: read / read:sensitive / deploy / write / admin
- Helper text: "Per-site tool filters are set in Site Settings"
- POST به `/api/keys` (همان endpoint فعلی) با `scopes: "<selected>"`
- [ ] Redirect های قدیمی:
- `/dashboard/connect``/dashboard/keys` (301)
- `/dashboard/api-keys``/dashboard/keys` (301)
- [ ] حذف handler های قدیمی `dashboard_connect_page` و `dashboard_api_keys_list` و یا تبدیل به thin wrapper redirect
- [ ] منوی navigation sidebar را update کن — فقط یک entry "API Keys"
### ۴. گزینه B (ادغام عمیق DB) — deferred
در پلن session 1 ذکر شده اما اجرا نمی‌کنیم مگر کاربر صراحتاً درخواست کند. کامنت در code اضافه کنید به `api_create_key` که "dual-table model is intentional — see F.7b plan".
### ۵. تست
- [ ] `tests/test_dashboard_keys_unified.py` — تست منوی unified، scope selector، 301 redirect از URL های قدیمی
- [ ] `tests/test_sites_tool_access_ui.py` — smoke test که edit page با tool_scope=read درست render شود (می‌توان با TestClient چک کرد که template بدون 500 می‌آید)
- [ ] به‌روزرسانی `tests/test_dashboard.py::test_dashboard_connect_page` → به `/dashboard/keys` منتقل شود یا به پذیرش redirect
- [ ] pytest کامل سبز
### ۶. ورژن، sync، commit
- [ ] `uvx --python 3.12 black . && uvx --python 3.12 ruff check --fix .`
- [ ] bump version به `v3.9.0` در pyproject.toml + `__version__` در server.py (اگر وجود دارد)
- [ ] Commit: `feat(F.7b): tool access UI + unified keys page (v3.9.0)`
- [ ] Push به Phase-1
- [ ] `python3.11 scripts/community-build/sync.py --output ../mcphub/` سپس در repo عمومی `black` + `ruff`
- [ ] Commit عمومی با ایمیل `hi.airano@gmail.com` و push
- [ ] درخواست deploy از کاربر
### ۷. تست live پس از deploy
- [ ] ورود به `/dashboard/sites/{id}/edit` → بخش Tool Access → تغییر scope به `read` → save
- [ ] بدون ساخت کلید جدید، MCP client (همان کلید admin موجود) روی آن alias → `tools/list` باید فقط ابزارهای read را نشان دهد
- [ ] تغییر به `custom` → Advanced → disable یک ابزار خاص (مثلاً `coolify_delete_server`) → تست
- [ ] ساخت کلید جدید از صفحه unified با scope=`read` → بررسی در لیست
## نکات مهم
- **Backward compatibility:** سایت‌های موجود `tool_scope='admin'` دارند (default migration v7) → هیچ تغییر رفتاری روی سایت‌های قدیمی
- **فیلترها:** key scope و site scope **intersect** می‌شوند. admin key + site=read → فقط read. write key + site=deploy → فقط read + lifecycle.
- **CSRF:** middleware روی `/api/sites/*` فعال است. UI باید header `X-CSRF-Token` از cookie `dashboard_csrf` بفرستد. HTMX این را با `hx-headers` هندل می‌کند.
- **CSS:** پروژه Tailwind دارد. از همان کلاس‌های موجود در `api-keys/list.html` استفاده کن برای consistency.
- **i18n:** پروژه EN/FA است. متن‌های جدید را به `core/i18n.py` اضافه کن.
- **ایمیل git داخلی:** mcphub.dev@gmail.com | ایمیل عمومی: hi.airano@gmail.com
- **نباید:** توابع F.7 v1 (با `user_` prefix) را بازگردانی کنی. همه سایت‌محور است.