015c622016
Add 162 integration tests covering authentication flows, TOTP MFA, SSH key/certificate management, organization workflows, multi-org access, self-service features, admin operations, authorization, security edge cases, department/principal management, CA management, policy compliance, WebAuthn passkeys, and ZeroTier network access. Includes: - Reusable API client library with session management - Test fixtures for users, organizations, memberships, and CAs - Helper functions for SSH key generation and verification - Documentation for running and writing tests Also update test configuration to disable conflicting maas plugins and configure WebAuthn/session settings for localhost testing.
179 lines
8.0 KiB
Python
179 lines
8.0 KiB
Python
"""Department and principal integration tests.
|
|
|
|
Covers department CRUD, principal CRUD, membership management, and
|
|
principal-department linking.
|
|
"""
|
|
import pytest
|
|
import uuid
|
|
|
|
from tests.integration.client.base import ApiError
|
|
from gatehouse_app.utils.constants import OrganizationRole
|
|
|
|
|
|
def assert_success(response: dict, message_contains: str = "") -> dict:
|
|
data = response.get("data", {})
|
|
assert response.get("success") is not False, (
|
|
f"Expected success but got error: {response.get('message')}"
|
|
)
|
|
if message_contains:
|
|
assert message_contains.lower() in response.get("message", "").lower()
|
|
return data
|
|
|
|
|
|
def assert_error(exc: ApiError, expected_status: int, expected_error_type: str | None = None):
|
|
assert exc.status_code == expected_status, (
|
|
f"Expected status {expected_status} but got {exc.status_code}"
|
|
)
|
|
if expected_error_type:
|
|
assert exc.error_type == expected_error_type, (
|
|
f"Expected error_type '{expected_error_type}' but got '{exc.error_type}'"
|
|
)
|
|
|
|
|
|
class TestDepartmentCRUD:
|
|
"""Test department lifecycle."""
|
|
|
|
def test_create_department_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: DEPT-01 — Create department as admin.
|
|
|
|
WHAT: Admin POST /organizations/<id>/departments.
|
|
WHY: Departments group users for access control.
|
|
EXPECTED: 201 Created with department data.
|
|
"""
|
|
admin = create_test_user(password="AdminPass123!")
|
|
org = create_test_org()
|
|
create_test_membership(admin["id"], org["id"], OrganizationRole.ADMIN)
|
|
|
|
integration_client.auth.login(email=admin["email"], password="AdminPass123!")
|
|
result = integration_client.orgs.create_department(org["id"], "Engineering", "Software dev team")
|
|
data = assert_success(result)
|
|
assert "id" in data.get("department", data)
|
|
|
|
def test_create_department_non_admin_negative(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: DEPT-02 — Reject department creation as member.
|
|
|
|
WHAT: Member attempts POST /organizations/<id>/departments.
|
|
WHY: Department management is admin-only.
|
|
EXPECTED: 403 Forbidden.
|
|
"""
|
|
member = create_test_user(password="MemberPass123!")
|
|
org = create_test_org()
|
|
create_test_membership(member["id"], org["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=member["email"], password="MemberPass123!")
|
|
with pytest.raises(ApiError) as exc_info:
|
|
integration_client.orgs.create_department(org["id"], "Engineering")
|
|
assert exc_info.value.status_code == 403
|
|
|
|
def test_list_departments_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: DEPT-03 — List departments.
|
|
|
|
WHAT: GET /organizations/<id>/departments.
|
|
WHY: Users need to see available departments.
|
|
EXPECTED: 200 OK with departments array.
|
|
"""
|
|
user = create_test_user(password="MyPassword123!")
|
|
org = create_test_org()
|
|
create_test_membership(user["id"], org["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=user["email"], password="MyPassword123!")
|
|
result = integration_client.orgs.list_departments(org["id"])
|
|
data = assert_success(result)
|
|
assert "departments" in data
|
|
|
|
def test_add_department_member_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: DEPT-04 — Add member to department.
|
|
|
|
WHAT: Admin adds a member to a department by email.
|
|
WHY: Department membership controls access.
|
|
EXPECTED: 200 OK.
|
|
"""
|
|
admin = create_test_user(password="AdminPass123!")
|
|
member = create_test_user(password="MemberPass123!")
|
|
org = create_test_org()
|
|
create_test_membership(admin["id"], org["id"], OrganizationRole.ADMIN)
|
|
create_test_membership(member["id"], org["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=admin["email"], password="AdminPass123!")
|
|
dept_result = integration_client.orgs.create_department(org["id"], "Engineering")
|
|
dept_id = dept_result["data"]["department"]["id"]
|
|
|
|
result = integration_client.orgs.add_department_member(org["id"], dept_id, member["email"])
|
|
assert_success(result)
|
|
|
|
|
|
class TestPrincipalCRUD:
|
|
"""Test principal lifecycle."""
|
|
|
|
def test_create_principal_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: PRINC-01 — Create principal as admin.
|
|
|
|
WHAT: Admin POST /organizations/<id>/principals.
|
|
WHY: Principals represent SSH access roles.
|
|
EXPECTED: 201 Created.
|
|
"""
|
|
admin = create_test_user(password="AdminPass123!")
|
|
org = create_test_org()
|
|
create_test_membership(admin["id"], org["id"], OrganizationRole.ADMIN)
|
|
|
|
integration_client.auth.login(email=admin["email"], password="AdminPass123!")
|
|
result = integration_client.orgs.create_principal(org["id"], "deploy", "Deployment access")
|
|
data = assert_success(result)
|
|
assert "id" in data.get("principal", data)
|
|
|
|
def test_list_principals_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: PRINC-02 — List principals.
|
|
|
|
WHAT: GET /organizations/<id>/principals.
|
|
WHY: Users need visibility into available principals.
|
|
EXPECTED: 200 OK with principals array.
|
|
"""
|
|
user = create_test_user(password="MyPassword123!")
|
|
org = create_test_org()
|
|
create_test_membership(user["id"], org["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=user["email"], password="MyPassword123!")
|
|
result = integration_client.orgs.list_principals(org["id"])
|
|
data = assert_success(result)
|
|
assert "principals" in data
|
|
|
|
def test_add_principal_member_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: PRINC-03 — Add member to principal.
|
|
|
|
WHAT: Admin adds a user to a principal.
|
|
WHY: Principal membership grants SSH principals.
|
|
EXPECTED: 200 OK.
|
|
"""
|
|
admin = create_test_user(password="AdminPass123!")
|
|
member = create_test_user(password="MemberPass123!")
|
|
org = create_test_org()
|
|
create_test_membership(admin["id"], org["id"], OrganizationRole.ADMIN)
|
|
create_test_membership(member["id"], org["id"], OrganizationRole.MEMBER)
|
|
|
|
integration_client.auth.login(email=admin["email"], password="AdminPass123!")
|
|
princ_result = integration_client.orgs.create_principal(org["id"], "deploy")
|
|
princ_id = princ_result["data"]["principal"]["id"]
|
|
|
|
result = integration_client.orgs.add_principal_member(org["id"], princ_id, member["email"])
|
|
assert_success(result)
|
|
|
|
def test_link_principal_department_positive(self, integration_client, create_test_user, create_test_org, create_test_membership):
|
|
"""TEST: PRINC-04 — Link principal to department.
|
|
|
|
WHAT: Admin links a principal to a department.
|
|
WHY: Department-principal links automate access assignment.
|
|
EXPECTED: 200 OK.
|
|
"""
|
|
admin = create_test_user(password="AdminPass123!")
|
|
org = create_test_org()
|
|
create_test_membership(admin["id"], org["id"], OrganizationRole.ADMIN)
|
|
|
|
integration_client.auth.login(email=admin["email"], password="AdminPass123!")
|
|
dept_result = integration_client.orgs.create_department(org["id"], "Engineering")
|
|
dept_id = dept_result["data"]["department"]["id"]
|
|
princ_result = integration_client.orgs.create_principal(org["id"], "deploy")
|
|
princ_id = princ_result["data"]["principal"]["id"]
|
|
|
|
result = integration_client.orgs.link_principal_department(org["id"], princ_id, dept_id)
|
|
assert_success(result)
|