"""Pytest fixtures for integration tests.""" import pytest import uuid from datetime import datetime, timezone from gatehouse_app import create_app, db from gatehouse_app.extensions import limiter from gatehouse_app.models.user.user import User from gatehouse_app.models.organization.organization import Organization from gatehouse_app.models.organization.organization_member import OrganizationMember from gatehouse_app.models.ssh_ca.ca import CA, CaType, KeyType from gatehouse_app.utils.constants import OrganizationRole from tests.integration.client.base import SecuirdClient # Disable the global rate limiter for integration tests. # The default app created at module level in gatehouse_app/__init__.py # initializes the limiter with production settings; we turn it off here # so tests don't hit rate limits. limiter.enabled = False @pytest.fixture(scope="module") def integration_app(): """Create a test Flask app with in-memory SQLite. Yields the configured application; tears down the DB after the module finishes. """ app = create_app(config_name="testing") app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:" app.config["TESTING"] = True app.config["WTF_CSRF_ENABLED"] = False app.config["RATELIMIT_ENABLED"] = False with app.app_context(): db.create_all() yield app db.session.remove() db.drop_all() @pytest.fixture def integration_client(integration_app): """Yield a fresh SecuirdClient for every test function.""" with integration_app.test_client() as flask_client: client = SecuirdClient(flask_client) yield client client.clear_token() @pytest.fixture def create_test_user(integration_app): """Return a factory that creates a user inside the app context.""" from gatehouse_app.models.auth.authentication_method import AuthenticationMethod from gatehouse_app.utils.constants import AuthMethodType def _factory( *, email: str | None = None, password: str = "password123", full_name: str = "Test User", email_verified: bool = True, ) -> dict: email = email or f"test_{uuid.uuid4().hex[:8]}@example.com" with integration_app.app_context(): user = User( email=email, full_name=full_name, email_verified=email_verified, ) db.session.add(user) db.session.commit() from gatehouse_app.extensions import bcrypt password_hash = bcrypt.generate_password_hash(password).decode("utf-8") auth_method = AuthenticationMethod( user_id=user.id, method_type=AuthMethodType.PASSWORD, password_hash=password_hash, is_primary=True, verified=True, ) db.session.add(auth_method) db.session.commit() return { "id": str(user.id), "email": user.email, "password": password, "full_name": user.full_name, } return _factory @pytest.fixture def create_test_org(integration_app): """Return a factory that creates an organization inside the app context.""" def _factory(*, name: str | None = None, slug: str | None = None) -> dict: name = name or f"Test Org {uuid.uuid4().hex[:8]}" slug = slug or name.lower().replace(" ", "-") with integration_app.app_context(): org = Organization(name=name, slug=slug) db.session.add(org) db.session.commit() return {"id": str(org.id), "name": org.name, "slug": org.slug} return _factory @pytest.fixture def create_test_membership(integration_app): """Return a factory that creates an org membership.""" def _factory(user_id: str, org_id: str, role: OrganizationRole = OrganizationRole.MEMBER) -> dict: with integration_app.app_context(): membership = OrganizationMember( user_id=user_id, organization_id=org_id, role=role, ) db.session.add(membership) db.session.commit() return {"id": str(membership.id), "role": role.value} return _factory @pytest.fixture def create_test_ca(integration_app): """Return a factory that creates a Certificate Authority.""" def _factory( *, org_id: str, name: str = "Test CA", ca_type: CaType = CaType.USER, key_type: KeyType = KeyType.ED25519, ) -> dict: with integration_app.app_context(): ca = CA( organization_id=org_id, name=name, ca_type=ca_type, key_type=key_type, private_key="encrypted_private_key_placeholder", public_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...", fingerprint="sha256:ABC123...", is_active=True, ) db.session.add(ca) db.session.commit() return {"id": str(ca.id), "name": ca.name, "ca_type": ca.ca_type.value} return _factory