re-uploading work

This commit is contained in:
2026-02-04 17:46:30 -06:00
commit 3b14c65998
1388 changed files with 381262 additions and 0 deletions

View File

@@ -0,0 +1,524 @@
"""
T3.10: RBAC Permission Checks Test
Tests that role-based access control (RBAC) is enforced across all API endpoints.
Users with different roles should have different levels of access.
Priority: MEDIUM
Duration: ~20 seconds
"""
import pytest
from helpers.client import AttuneClient
from helpers.fixtures import unique_ref
@pytest.mark.tier3
@pytest.mark.security
@pytest.mark.rbac
def test_viewer_role_permissions(client: AttuneClient):
"""
Test that viewer role can only read resources, not create/update/delete.
Note: This test assumes RBAC is implemented. If not yet implemented,
this test will document the expected behavior.
"""
print("\n" + "=" * 80)
print("T3.10a: Viewer Role Permission Test")
print("=" * 80)
# Step 1: Create a viewer user
print("\n[STEP 1] Creating viewer user...")
viewer_username = f"viewer_{unique_ref()}"
viewer_email = f"{viewer_username}@example.com"
viewer_password = "viewer_password_123"
# Register viewer (using admin client)
try:
viewer_reg = client.register(
username=viewer_username,
email=viewer_email,
password=viewer_password,
role="viewer", # Request viewer role
)
print(f"✓ Viewer user created: {viewer_username}")
except Exception as e:
print(f"⚠ Viewer registration failed: {e}")
print(" Note: RBAC may not be fully implemented yet")
pytest.skip("RBAC registration not available")
# Login as viewer
viewer_client = AttuneClient(base_url=client.base_url)
try:
viewer_client.login(username=viewer_username, password=viewer_password)
print(f"✓ Viewer logged in")
except Exception as e:
print(f"⚠ Viewer login failed: {e}")
pytest.skip("Could not login as viewer")
# Step 2: Test READ operations (should succeed)
print("\n[STEP 2] Testing READ operations (should succeed)...")
read_tests = []
# Test listing packs
try:
packs = viewer_client.list_packs()
print(f"✓ Viewer can list packs: {len(packs)} packs visible")
read_tests.append(("list_packs", True))
except Exception as e:
print(f"✗ Viewer cannot list packs: {e}")
read_tests.append(("list_packs", False))
# Test listing actions
try:
actions = viewer_client.list_actions()
print(f"✓ Viewer can list actions: {len(actions)} actions visible")
read_tests.append(("list_actions", True))
except Exception as e:
print(f"✗ Viewer cannot list actions: {e}")
read_tests.append(("list_actions", False))
# Test listing rules
try:
rules = viewer_client.list_rules()
print(f"✓ Viewer can list rules: {len(rules)} rules visible")
read_tests.append(("list_rules", True))
except Exception as e:
print(f"✗ Viewer cannot list rules: {e}")
read_tests.append(("list_rules", False))
# Step 3: Test CREATE operations (should fail)
print("\n[STEP 3] Testing CREATE operations (should fail with 403)...")
create_tests = []
# Test creating pack
try:
pack_data = {
"ref": f"test_pack_{unique_ref()}",
"name": "Test Pack",
"version": "1.0.0",
}
pack_response = viewer_client.create_pack(pack_data)
print(f"✗ SECURITY VIOLATION: Viewer created pack: {pack_response.get('ref')}")
create_tests.append(("create_pack", False)) # Should have failed
except Exception as e:
if (
"403" in str(e)
or "forbidden" in str(e).lower()
or "permission" in str(e).lower()
):
print(f"✓ Viewer blocked from creating pack (403 Forbidden)")
create_tests.append(("create_pack", True))
else:
print(f"⚠ Viewer create pack failed with unexpected error: {e}")
create_tests.append(("create_pack", False))
# Test creating action
try:
action_data = {
"ref": f"test_action_{unique_ref()}",
"name": "Test Action",
"runner_type": "python",
"entry_point": "main.py",
"pack": "core",
}
action_response = viewer_client.create_action(action_data)
print(
f"✗ SECURITY VIOLATION: Viewer created action: {action_response.get('ref')}"
)
create_tests.append(("create_action", False))
except Exception as e:
if (
"403" in str(e)
or "forbidden" in str(e).lower()
or "permission" in str(e).lower()
):
print(f"✓ Viewer blocked from creating action (403 Forbidden)")
create_tests.append(("create_action", True))
else:
print(f"⚠ Viewer create action failed: {e}")
create_tests.append(("create_action", False))
# Test creating rule
try:
rule_data = {
"name": f"Test Rule {unique_ref()}",
"trigger": "core.timer.interval",
"action": "core.echo",
"enabled": True,
}
rule_response = viewer_client.create_rule(rule_data)
print(f"✗ SECURITY VIOLATION: Viewer created rule: {rule_response.get('id')}")
create_tests.append(("create_rule", False))
except Exception as e:
if (
"403" in str(e)
or "forbidden" in str(e).lower()
or "permission" in str(e).lower()
):
print(f"✓ Viewer blocked from creating rule (403 Forbidden)")
create_tests.append(("create_rule", True))
else:
print(f"⚠ Viewer create rule failed: {e}")
create_tests.append(("create_rule", False))
# Step 4: Test EXECUTE operations (should fail)
print("\n[STEP 4] Testing EXECUTE operations (should fail with 403)...")
execute_tests = []
# Test executing action
try:
exec_data = {"action": "core.echo", "parameters": {"message": "test"}}
exec_response = viewer_client.execute_action(exec_data)
print(
f"✗ SECURITY VIOLATION: Viewer executed action: {exec_response.get('id')}"
)
execute_tests.append(("execute_action", False))
except Exception as e:
if (
"403" in str(e)
or "forbidden" in str(e).lower()
or "permission" in str(e).lower()
):
print(f"✓ Viewer blocked from executing action (403 Forbidden)")
execute_tests.append(("execute_action", True))
else:
print(f"⚠ Viewer execute failed: {e}")
execute_tests.append(("execute_action", False))
# Summary
print("\n" + "=" * 80)
print("VIEWER ROLE TEST SUMMARY")
print("=" * 80)
print(f"User: {viewer_username} (role: viewer)")
print("\nREAD Permissions (should succeed):")
for operation, passed in read_tests:
status = "" if passed else ""
print(f" {status} {operation}: {'PASS' if passed else 'FAIL'}")
print("\nCREATE Permissions (should fail):")
for operation, blocked in create_tests:
status = "" if blocked else ""
print(
f" {status} {operation}: {'BLOCKED' if blocked else 'ALLOWED (VIOLATION)'}"
)
print("\nEXECUTE Permissions (should fail):")
for operation, blocked in execute_tests:
status = "" if blocked else ""
print(
f" {status} {operation}: {'BLOCKED' if blocked else 'ALLOWED (VIOLATION)'}"
)
# Check results
all_read_passed = all(passed for _, passed in read_tests)
all_create_blocked = all(blocked for _, blocked in create_tests)
all_execute_blocked = all(blocked for _, blocked in execute_tests)
if all_read_passed and all_create_blocked and all_execute_blocked:
print("\n✅ VIEWER ROLE PERMISSIONS CORRECT!")
else:
print("\n⚠️ RBAC ISSUES DETECTED:")
if not all_read_passed:
print(" - Viewer cannot read some resources")
if not all_create_blocked:
print(" - Viewer can create resources (SECURITY ISSUE)")
if not all_execute_blocked:
print(" - Viewer can execute actions (SECURITY ISSUE)")
print("=" * 80)
# Note: We may skip assertions if RBAC not fully implemented
if not create_tests and not execute_tests:
pytest.skip("RBAC not fully implemented yet")
@pytest.mark.tier3
@pytest.mark.security
@pytest.mark.rbac
def test_admin_role_permissions(client: AttuneClient):
"""
Test that admin role has full access to all resources.
"""
print("\n" + "=" * 80)
print("T3.10b: Admin Role Permission Test")
print("=" * 80)
# The default client is typically admin
print("\n[STEP 1] Testing admin permissions (using default client)...")
operations = []
# Test create pack
try:
pack_data = {
"ref": f"admin_test_pack_{unique_ref()}",
"name": "Admin Test Pack",
"version": "1.0.0",
"description": "Testing admin permissions",
}
pack_response = client.create_pack(pack_data)
print(f"✓ Admin can create pack: {pack_response['ref']}")
operations.append(("create_pack", True))
# Clean up
client.delete_pack(pack_response["ref"])
print(f"✓ Admin can delete pack")
operations.append(("delete_pack", True))
except Exception as e:
print(f"✗ Admin cannot create/delete pack: {e}")
operations.append(("create_pack", False))
operations.append(("delete_pack", False))
# Test create action
try:
action_data = {
"ref": f"admin_test_action_{unique_ref()}",
"name": "Admin Test Action",
"runner_type": "python",
"entry_point": "main.py",
"pack": "core",
"enabled": True,
}
action_response = client.create_action(action_data)
print(f"✓ Admin can create action: {action_response['ref']}")
operations.append(("create_action", True))
# Clean up
client.delete_action(action_response["ref"])
print(f"✓ Admin can delete action")
operations.append(("delete_action", True))
except Exception as e:
print(f"✗ Admin cannot create/delete action: {e}")
operations.append(("create_action", False))
# Test execute action
try:
exec_data = {"action": "core.echo", "parameters": {"message": "admin test"}}
exec_response = client.execute_action(exec_data)
print(f"✓ Admin can execute action: execution {exec_response['id']}")
operations.append(("execute_action", True))
except Exception as e:
print(f"✗ Admin cannot execute action: {e}")
operations.append(("execute_action", False))
# Summary
print("\n" + "=" * 80)
print("ADMIN ROLE TEST SUMMARY")
print("=" * 80)
print("Admin Operations:")
for operation, passed in operations:
status = "" if passed else ""
print(f" {status} {operation}: {'PASS' if passed else 'FAIL'}")
all_passed = all(passed for _, passed in operations)
if all_passed:
print("\n✅ ADMIN HAS FULL ACCESS!")
else:
print("\n⚠️ ADMIN MISSING SOME PERMISSIONS")
print("=" * 80)
assert all_passed, "Admin should have full permissions"
@pytest.mark.tier3
@pytest.mark.security
@pytest.mark.rbac
def test_executor_role_permissions(client: AttuneClient):
"""
Test that executor role can execute actions but not create resources.
Executor role is for service accounts or CI/CD systems that only need
to trigger executions, not manage infrastructure.
"""
print("\n" + "=" * 80)
print("T3.10c: Executor Role Permission Test")
print("=" * 80)
# Step 1: Create executor user
print("\n[STEP 1] Creating executor user...")
executor_username = f"executor_{unique_ref()}"
executor_email = f"{executor_username}@example.com"
executor_password = "executor_password_123"
try:
executor_reg = client.register(
username=executor_username,
email=executor_email,
password=executor_password,
role="executor",
)
print(f"✓ Executor user created: {executor_username}")
except Exception as e:
print(f"⚠ Executor registration not available: {e}")
pytest.skip("Executor role not implemented yet")
# Login as executor
executor_client = AttuneClient(base_url=client.base_url)
try:
executor_client.login(username=executor_username, password=executor_password)
print(f"✓ Executor logged in")
except Exception as e:
print(f"⚠ Executor login failed: {e}")
pytest.skip("Could not login as executor")
# Step 2: Test EXECUTE permissions (should succeed)
print("\n[STEP 2] Testing EXECUTE permissions (should succeed)...")
execute_tests = []
try:
exec_data = {"action": "core.echo", "parameters": {"message": "executor test"}}
exec_response = executor_client.execute_action(exec_data)
print(f"✓ Executor can execute action: execution {exec_response['id']}")
execute_tests.append(("execute_action", True))
except Exception as e:
print(f"✗ Executor cannot execute action: {e}")
execute_tests.append(("execute_action", False))
# Step 3: Test CREATE permissions (should fail)
print("\n[STEP 3] Testing CREATE permissions (should fail)...")
create_tests = []
# Try to create pack (should fail)
try:
pack_data = {
"ref": f"exec_test_pack_{unique_ref()}",
"name": "Executor Test Pack",
"version": "1.0.0",
}
pack_response = executor_client.create_pack(pack_data)
print(f"✗ VIOLATION: Executor created pack: {pack_response['ref']}")
create_tests.append(("create_pack", False))
except Exception as e:
if "403" in str(e) or "forbidden" in str(e).lower():
print(f"✓ Executor blocked from creating pack")
create_tests.append(("create_pack", True))
else:
print(f"⚠ Unexpected error: {e}")
create_tests.append(("create_pack", False))
# Step 4: Test READ permissions (should succeed)
print("\n[STEP 4] Testing READ permissions (should succeed)...")
read_tests = []
try:
actions = executor_client.list_actions()
print(f"✓ Executor can list actions: {len(actions)} visible")
read_tests.append(("list_actions", True))
except Exception as e:
print(f"✗ Executor cannot list actions: {e}")
read_tests.append(("list_actions", False))
# Summary
print("\n" + "=" * 80)
print("EXECUTOR ROLE TEST SUMMARY")
print("=" * 80)
print(f"User: {executor_username} (role: executor)")
print("\nEXECUTE Permissions (should succeed):")
for operation, passed in execute_tests:
status = "" if passed else ""
print(f" {status} {operation}: {'PASS' if passed else 'FAIL'}")
print("\nCREATE Permissions (should fail):")
for operation, blocked in create_tests:
status = "" if blocked else ""
print(
f" {status} {operation}: {'BLOCKED' if blocked else 'ALLOWED (VIOLATION)'}"
)
print("\nREAD Permissions (should succeed):")
for operation, passed in read_tests:
status = "" if passed else ""
print(f" {status} {operation}: {'PASS' if passed else 'FAIL'}")
all_execute_ok = all(passed for _, passed in execute_tests)
all_create_blocked = all(blocked for _, blocked in create_tests)
all_read_ok = all(passed for _, passed in read_tests)
if all_execute_ok and all_create_blocked and all_read_ok:
print("\n✅ EXECUTOR ROLE PERMISSIONS CORRECT!")
else:
print("\n⚠️ EXECUTOR ROLE ISSUES DETECTED")
print("=" * 80)
@pytest.mark.tier3
@pytest.mark.security
@pytest.mark.rbac
def test_role_permissions_summary():
"""
Summary test documenting the expected RBAC permission matrix.
This is a documentation test that doesn't execute API calls,
but serves as a reference for the expected permission model.
"""
print("\n" + "=" * 80)
print("T3.10d: RBAC Permission Matrix Reference")
print("=" * 80)
permission_matrix = {
"admin": {
"packs": ["create", "read", "update", "delete"],
"actions": ["create", "read", "update", "delete", "execute"],
"rules": ["create", "read", "update", "delete"],
"triggers": ["create", "read", "update", "delete"],
"executions": ["read", "cancel"],
"datastore": ["read", "write", "delete"],
"secrets": ["create", "read", "update", "delete"],
"users": ["create", "read", "update", "delete"],
},
"editor": {
"packs": ["create", "read", "update"],
"actions": ["create", "read", "update", "execute"],
"rules": ["create", "read", "update"],
"triggers": ["create", "read", "update"],
"executions": ["read", "execute", "cancel"],
"datastore": ["read", "write"],
"secrets": ["read", "update"],
"users": ["read"],
},
"executor": {
"packs": ["read"],
"actions": ["read", "execute"],
"rules": ["read"],
"triggers": ["read"],
"executions": ["read", "execute"],
"datastore": ["read"],
"secrets": ["read"],
"users": [],
},
"viewer": {
"packs": ["read"],
"actions": ["read"],
"rules": ["read"],
"triggers": ["read"],
"executions": ["read"],
"datastore": ["read"],
"secrets": [],
"users": [],
},
}
print("\nExpected Permission Matrix:\n")
for role, permissions in permission_matrix.items():
print(f"{role.upper()} Role:")
for resource, ops in permissions.items():
ops_str = ", ".join(ops) if ops else "none"
print(f" - {resource}: {ops_str}")
print()
print("=" * 80)
print("📋 This matrix defines the expected RBAC behavior")
print("=" * 80)
# This test always passes - it's documentation
assert True