release: v3.3.0 — platform hardening & admin unification (Track F.1–F.8)

Plugin visibility control, UI/UX fixes, unified admin panel,
database-backed settings, and security hardening.

Highlights:
- ENABLED_PLUGINS env var for plugin visibility (F.1)
- Admin designation via ADMIN_EMAILS (F.4a)
- Master key scope control (F.4b)
- Panel unification + settings from UI (F.4c)
- exec() removal, shell injection fix, bcrypt migration (F.8)
- 5 new test suites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 09:55:49 +02:00
parent f6dbbeaab0
commit 9b70b259bb
47 changed files with 2122 additions and 366 deletions

View File

@@ -92,6 +92,7 @@
{# ── Derive RBAC info from session ── #}
{% set _is_admin = is_admin_session(session) %}
{% set _is_oauth_admin = _is_admin and session is mapping %}
{% set _display = get_session_display_info(session) %}
<body class="bg-gray-50 text-gray-900 dark:bg-gray-900 dark:text-gray-100 min-h-screen transition-colors duration-200"
@@ -134,6 +135,7 @@
('my_sites', t.get('my_sites', 'My Sites'), 'M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0
01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9',
'/dashboard/sites'),
('services', t.get('services', 'Services'), 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10', '/dashboard/services'),
('connect', t.get('connect', 'Connect'), 'M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656
5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1', '/dashboard/connect'),
] %}
@@ -172,8 +174,8 @@
</a>
{% endfor %}
{# Render user nav (non-admin only) #}
{% if not _is_admin %}
{# Render user nav (non-admin users + OAuth admins) #}
{% if not _is_admin or _is_oauth_admin %}
{% for item_id, label, icon_path, url in user_nav %}
<a href="{{ url }}{% if lang and lang != 'en' %}?lang={{ lang }}{% endif %}"
class="flex items-center px-3 py-2 rounded-lg transition-colors {% if current_page == item_id %}bg-primary-600 text-white{% else %}text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white{% endif %}">
@@ -206,15 +208,28 @@
{% endif %}
</nav>
<!-- Version footer -->
<div x-show="sidebarOpen" class="px-4 py-2 text-xs text-gray-400 dark:text-gray-600">
v{{ project_version | default('') }}
<!-- Support link -->
<div x-show="sidebarOpen" class="px-4 py-2">
<a href="https://nowpayments.io/donation/airano" target="_blank" rel="noopener noreferrer"
class="flex items-center text-xs text-gray-400 dark:text-gray-500 hover:text-pink-400 dark:hover:text-pink-400 transition-colors">
<svg class="w-4 h-4 mr-1.5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
</svg>
{% if lang == 'fa' %}حمایت از MCP Hub{% else %}Support MCP Hub{% endif %}
</a>
</div>
<!-- Version footer -->
{% if project_version %}
<div x-show="sidebarOpen" class="px-4 py-2 text-xs text-gray-400 dark:text-gray-600">
v{{ project_version }}
</div>
{% endif %}
<!-- User Section -->
<div class="p-4 border-t border-gray-200 dark:border-gray-700">
{# Profile link for OAuth users #}
{% if not _is_admin %}
{# Profile link for OAuth users (including OAuth admins) #}
{% if not _is_admin or _is_oauth_admin %}
<a href="/dashboard/profile{% if lang and lang != 'en' %}?lang={{ lang }}{% endif %}"
class="flex items-center px-3 py-2 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-white rounded-lg transition-colors mb-1 {% if current_page == 'profile' %}bg-primary-600 text-white{% endif %}">
<svg class="w-5 h-5 sidebar-icon flex-shrink-0" fill="none" stroke="currentColor"