Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
144 lines
5.0 KiB
Python
144 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test API Key Access Control Fix
|
|
|
|
Validates that:
|
|
1. Site-level keys get proper error message for system tools (not validation failure)
|
|
2. Global keys work for all tools
|
|
3. Per-project keys work for their own unified tools
|
|
"""
|
|
|
|
|
|
def test_system_tool_detection():
|
|
"""Test that system tools are detected correctly."""
|
|
SYSTEM_TOOLS = [
|
|
"list_projects",
|
|
"get_project_info",
|
|
"check_all_projects_health",
|
|
"get_project_health",
|
|
"get_system_metrics",
|
|
"get_system_uptime",
|
|
"get_rate_limit_stats",
|
|
"export_health_metrics",
|
|
"manage_api_keys_list",
|
|
"manage_api_keys_get_info",
|
|
]
|
|
|
|
# Test with and without MCP prefix
|
|
test_cases = [
|
|
("list_projects", True),
|
|
("mcp__coolify-projects__list_projects", True),
|
|
("get_project_info", True),
|
|
("wordpress_list_posts", False),
|
|
("woocommerce_list_orders", False),
|
|
("unknown", False),
|
|
]
|
|
|
|
for tool_name, expected in test_cases:
|
|
is_system_tool = any(tool_name.endswith(st) for st in SYSTEM_TOOLS)
|
|
assert (
|
|
is_system_tool == expected
|
|
), f"Failed for {tool_name}: expected {expected}, got {is_system_tool}"
|
|
print(f"✓ {tool_name}: is_system_tool={is_system_tool}")
|
|
|
|
|
|
def test_unified_tool_detection():
|
|
"""Test that unified tools are detected correctly."""
|
|
test_cases = [
|
|
("wordpress_list_posts", True),
|
|
("woocommerce_list_orders", True),
|
|
("mcp__coolify-projects__wordpress_list_posts", True),
|
|
("mcp__coolify-projects__woocommerce_list_orders", True),
|
|
("list_projects", False),
|
|
("get_project_info", False),
|
|
("unknown", True), # Falls to fallback
|
|
]
|
|
|
|
for tool_name, expected in test_cases:
|
|
if tool_name == "unknown":
|
|
is_unified_tool = True # Fallback
|
|
else:
|
|
is_unified_tool = (
|
|
tool_name.startswith("wordpress_")
|
|
or tool_name.startswith("woocommerce_")
|
|
or tool_name.startswith("mcp__coolify-projects__wordpress_")
|
|
or tool_name.startswith("mcp__coolify-projects__woocommerce_")
|
|
)
|
|
assert (
|
|
is_unified_tool == expected
|
|
), f"Failed for {tool_name}: expected {expected}, got {is_unified_tool}"
|
|
print(f"✓ {tool_name}: is_unified_tool={is_unified_tool}")
|
|
|
|
|
|
def test_skip_project_check_logic():
|
|
"""Test that skip_project_check is set correctly."""
|
|
SYSTEM_TOOLS = [
|
|
"list_projects",
|
|
"get_project_info",
|
|
"check_all_projects_health",
|
|
"get_project_health",
|
|
"get_system_metrics",
|
|
"get_system_uptime",
|
|
"get_rate_limit_stats",
|
|
"export_health_metrics",
|
|
"manage_api_keys_list",
|
|
"manage_api_keys_get_info",
|
|
]
|
|
|
|
test_cases = [
|
|
# (tool_name, expected_skip)
|
|
("list_projects", True), # System tool
|
|
("wordpress_list_posts", True), # Unified tool
|
|
("woocommerce_list_orders", True), # Unified tool
|
|
("mcp__coolify-projects__list_projects", True), # System tool with prefix
|
|
("mcp__coolify-projects__wordpress_list_posts", True), # Unified tool with prefix
|
|
("unknown", True), # Fallback to unified
|
|
]
|
|
|
|
for tool_name, expected_skip in test_cases:
|
|
# Determine is_system_tool
|
|
is_system_tool = any(tool_name.endswith(st) for st in SYSTEM_TOOLS)
|
|
|
|
# Determine is_unified_tool
|
|
if tool_name == "unknown":
|
|
is_unified_tool = True
|
|
else:
|
|
is_unified_tool = (
|
|
tool_name.startswith("wordpress_")
|
|
or tool_name.startswith("woocommerce_")
|
|
or tool_name.startswith("mcp__coolify-projects__wordpress_")
|
|
or tool_name.startswith("mcp__coolify-projects__woocommerce_")
|
|
)
|
|
|
|
# Calculate skip_project_check
|
|
skip_project_check = is_unified_tool or is_system_tool
|
|
|
|
assert skip_project_check == expected_skip, (
|
|
f"Failed for {tool_name}: expected skip={expected_skip}, got {skip_project_check} "
|
|
f"(unified={is_unified_tool}, system={is_system_tool})"
|
|
)
|
|
print(
|
|
f"✓ {tool_name}: skip_project_check={skip_project_check} (unified={is_unified_tool}, system={is_system_tool})"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("\n=== Testing System Tool Detection ===")
|
|
test_system_tool_detection()
|
|
|
|
print("\n=== Testing Unified Tool Detection ===")
|
|
test_unified_tool_detection()
|
|
|
|
print("\n=== Testing skip_project_check Logic ===")
|
|
test_skip_project_check_logic()
|
|
|
|
print("\n✅ All tests passed!")
|
|
print("\nExpected behavior after fix:")
|
|
print("1. Site-level key + list_projects → Validation passes, then gets proper error:")
|
|
print(" 'System tools require global API key (project_id=\"*\")'")
|
|
print(
|
|
"2. Site-level key + wordpress_list_posts(site=other) → Validation passes, handler blocks with:"
|
|
)
|
|
print(" 'Access denied. This API key is restricted to project X'")
|
|
print("3. Global key + any tool → Works")
|