Files
mcphub/tests/test_dashboard_keys_unified.py
airano-ir 788439e377
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
feat(F.7+F.17): v3.11.0 — Coolify plugin (67 tools) + tool access overhaul
Catch-up sync spanning v3.7.0 → v3.11.0 of the internal repo.

Platform
- Total tools: 565 → 633 (+68) across 10 plugins (Coolify added)
- Tests: 481 → 828 passing

New plugin: Coolify (67 tools, Track F.17)
- Applications (17): CRUD, lifecycle, logs, env vars
- Deployments (5): list/get/cancel/deploy, app history
- Servers (8): CRUD, resources, domains, validation
- Projects (8), Databases (16, 6 DB types + backups), Services (13)

Tool access system (Track F.7 → F.7d)
- Scope → category mapping with per-tool `category` + `sensitivity`
- Schema v7: `site_tool_toggles(site_id)` + `sites.tool_scope` column
- Schema v8: per-site API keys (`api_keys.site_id`)
- Plugin-specific access-level presets (WP / WC / Gitea / OpenPanel /
  Coolify 5-tier)
- Credential-requirement notice tailored per plugin and tier
- Admin Tools count card on service page
- Dropped redundant `write` tier on WP / WP Advanced / WooCommerce
  (admin-scope tool count = 0 → identical to admin tier)

Dashboard
- Unified site manage page (Connection / Tool Access / Connect)
- /dashboard/keys unified (was /api-keys and /connect)
- CSRF interceptor via meta-tag; removed conflicting cookie reader
- Tailwind: pre-built CSS (scripts/build-css.sh) replaces CDN

Docs
- README / DOCKER_README / CLAUDE updated to 633 tools / 10 plugins
- CHANGELOG entries for v3.7.0 → v3.11.0
- FastMCP compatibility note updated to 3.x (post-v3.5 upgrade)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 21:05:07 +02:00

82 lines
2.7 KiB
Python

"""Tests for the unified /dashboard/keys page (F.7b session 2)."""
from __future__ import annotations
import pytest
from starlette.testclient import TestClient
import core.dashboard.routes as routes_module
import core.database as db_module
from core.database import Database
@pytest.fixture
async def patched_db(tmp_path, monkeypatch):
database = Database(str(tmp_path / "keys.db"))
await database.initialize()
monkeypatch.setattr(db_module, "_database", database)
yield database
await database.close()
monkeypatch.setattr(db_module, "_database", None)
@pytest.fixture
async def user_row(patched_db):
return await patched_db.create_user(
email="keys@example.com",
name="keysuser",
provider="github",
provider_id="gh-keys-user",
)
@pytest.fixture
def user_client(monkeypatch, user_row, patched_db):
from server import create_multi_endpoint_app
def fake_user_session(_request):
return {"user_id": user_row["id"], "type": "user"}, None
monkeypatch.setattr(routes_module, "_require_user_session", fake_user_session)
# Also patch auth so dashboard_keys_unified finds the user session
class FakeAuth:
def get_session_from_request(self, _r):
return None # not admin
def get_user_session_from_request(self, _r):
return {"user_id": user_row["id"], "type": "user"}
monkeypatch.setattr(routes_module, "get_dashboard_auth", lambda: FakeAuth())
app = create_multi_endpoint_app()
return TestClient(app, follow_redirects=False)
class TestUnifiedKeysUserView:
def test_get_keys_page_returns_200(self, user_client):
r = user_client.get("/dashboard/keys")
assert r.status_code == 200
assert "API Key" in r.text or "کلید" in r.text
def test_old_connect_redirects_301(self, user_client):
r = user_client.get("/dashboard/connect")
assert r.status_code == 301
assert "/dashboard/keys" in r.headers["location"]
def test_old_api_keys_redirects_301(self, user_client):
r = user_client.get("/dashboard/api-keys")
assert r.status_code == 301
assert "/dashboard/keys" in r.headers["location"]
def test_user_view_has_full_access_badge(self, user_client):
r = user_client.get("/dashboard/keys")
assert r.status_code == 200
# F.7c: No scope selector — shows "Full Access" badge instead
assert "Full Access" in r.text or "دسترسی کامل" in r.text
def test_user_view_shows_create_button(self, user_client):
r = user_client.get("/dashboard/keys")
assert r.status_code == 200
assert "Create" in r.text or "ایجاد" in r.text