# Secuird Integration Test Suite This directory contains the integration test suite for the Secuird IAM platform. ## Quick Start Run all integration tests: ```bash cd backend pytest tests/integration/ ``` Run a specific test file: ```bash pytest tests/integration/test_ssh_workflows.py -v ``` Run without coverage (faster): ```bash pytest tests/integration/ --no-cov ``` Fail fast (stop on first failure): ```bash pytest tests/integration/ -x ``` Run previously failed tests first: ```bash pytest tests/integration/ --ff ``` ## Test Structure ``` tests/ ├── conftest.py # Base pytest fixtures (app, client, test_user) ├── integration/ # Integration tests │ ├── conftest.py # Integration-specific fixtures and factories │ ├── client/ # Reusable API client library │ │ ├── base.py # SecuirdClient with session management │ │ ├── auth.py # Authentication operations │ │ ├── users.py # User self-service operations │ │ ├── orgs.py # Organization operations │ │ ├── ssh.py # SSH key/cert operations │ │ ├── mfa.py # TOTP/WebAuthn operations │ │ ├── zerotier.py # ZeroTier network operations │ │ └── admin.py # Admin operations │ ├── fixtures/ # Test data and helpers │ │ ├── ssh_keys.py # Test SSH key pairs and helpers │ │ └── test_data.py # Common test data generators │ ├── test_auth_flows.py # Authentication flows (24 tests) │ ├── test_totp_workflows.py # TOTP MFA flows (15 tests) │ ├── test_ssh_workflows.py # SSH key/cert flows (34 tests) │ ├── test_org_workflows.py # Organization & invite flows (27 tests) │ ├── test_multi_org.py # Multi-organization access (4 tests) │ ├── test_self_service.py # User self-service features (9 tests) │ ├── test_admin_ops.py # Admin user management (9 tests) │ ├── test_authorization.py # RBAC & access control (8 tests) │ ├── test_security.py # Security & edge cases (5 tests) │ ├── test_dept_principal.py # Department & principal management (5 tests) │ ├── test_ca_management.py # Certificate authority management (4 tests) │ ├── test_policy_compliance.py # Security policy & compliance (4 tests) │ ├── test_webauthn_workflows.py# WebAuthn passkey flows (5 tests) │ └── test_zerotier.py # ZeroTier network access (8 tests) └── unit/ # Unit tests (existing) ``` ## Environment - **Python**: 3.10+ - **Database**: SQLite in-memory (`sqlite:///:memory:`) - **Rate Limiting**: Disabled in tests (`RATELIMIT_ENABLED = False`) - **CSRF**: Disabled (`WTF_CSRF_ENABLED = False`) - **Email**: Suppressed (`MAIL_SUPPRESS_SEND = True`) ## Configuration The `pytest.ini` file configures: - Verbose output (`-v`) - Coverage reporting (`--cov=gatehouse_app`) - Disabled maas plugins that cause import errors (see Known Issues below) - Custom markers for `unit`, `integration`, `slow`, etc. ## Coverage Coverage reports are generated automatically: - **Terminal**: printed after each run - **HTML**: `backend/htmlcov/index.html` Target coverage: **85% minimum**. ```bash pytest tests/integration/ --cov=gatehouse_app --cov-fail-under=85 ``` ## Known Issues ### maastesting Plugin Import Error The `maas` system package installs pytest entry points that fail to load in this environment. The `pytest.ini` file disables them automatically with: ```ini -p no:maas-django -p no:maas-perftest -p no:maas-seeds ``` If you see `ModuleNotFoundError: No module named 'maastesting'`, these flags are not being applied. Ensure you run pytest from the `backend/` directory. ### ssh-keygen Not Available One test (`test_verify_key_positive` in `test_ssh_workflows.py`) requires `ssh-keygen` to generate real Ed25519 key pairs for signature verification. It is automatically skipped when `ssh-keygen` is not available: ```bash sudo apt-get install openssh-client # Debian/Ubuntu ``` Other certificate signing tests use a DB helper (`_mark_key_verified`) to bypass the signature requirement in CI environments. ## Writing New Tests ### Pattern Every test must include a verbose docstring with `WHAT`, `WHY`, and `EXPECTED`: ```python def test_add_key_positive(self, integration_client, create_test_user): """TEST: SSH-KEY-01 — Add a new SSH public key. WHAT: Authenticated user POSTs a valid public key with a description. WHY: Users must be able to register their SSH keys for later certificate signing and server access. EXPECTED: 201 Created, response contains key id and metadata. """ ``` ### Fixtures | Fixture | Purpose | |---------|---------| | `integration_client` | Fresh `SecuirdClient` instance per test | | `create_test_user` | Factory returning `{"id", "email", "password", "full_name"}` | | `create_test_org` | Factory returning `{"id", "name", "slug"}` | | `create_test_membership` | Links user to org with a role | | `create_test_ca` | Creates a Certificate Authority for an org | ### Client Usage ```python # Authentication integration_client.auth.register(email, password, full_name) integration_client.auth.login(email, password) integration_client.auth.logout() # SSH integration_client.ssh.add_key(public_key, description) integration_client.ssh.sign_certificate(key_id=key_id, principals=["deploy"]) integration_client.ssh.revoke_certificate(cert_id) # Organizations integration_client.orgs.create(name, slug) integration_client.orgs.create_principal(org_id, name) integration_client.orgs.create_ca(org_id, name, ca_type="user") ``` ### Assertions Use the standard helpers: ```python def assert_success(response: dict, message_contains: str = "") -> dict: data = response.get("data", {}) assert response.get("success") is not False if message_contains: assert message_contains.lower() in response.get("message", "").lower() return data # Negative tests with pytest.raises(ApiError) as exc_info: integration_client.ssh.get_key(str(uuid.uuid4())) assert exc_info.value.status_code == 404 assert exc_info.value.error_type == "NOT_FOUND" ``` ## Test Counts | Module | Tests | Focus | |--------|-------|-------| | test_auth_flows.py | 24 | Registration, login, logout, sessions, password reset, email verification | | test_totp_workflows.py | 15 | TOTP enrollment, verification, backup codes, disable, regenerate | | test_ssh_workflows.py | 34 | Key CRUD, verification, certificate signing & management | | test_org_workflows.py | 27 | Org CRUD, members, roles, invites, ownership transfer | | test_multi_org.py | 4 | Cross-org isolation, role-based access | | test_self_service.py | 9 | Profile, password change, account deletion | | test_admin_ops.py | 9 | Suspend, unsuspend, verify email, set password, remove MFA, hard delete | | test_authorization.py | 8 | RBAC, cross-user isolation, soft-delete behavior | | test_security.py | 5 | SQL injection, XSS, oversized payload, malformed JSON, empty body | | test_dept_principal.py | 5 | Department/principal CRUD, membership, linking | | test_ca_management.py | 4 | CA creation, listing, rotation | | test_policy_compliance.py | 4 | Security policy, MFA compliance | | test_webauthn_workflows.py | 5 | WebAuthn registration/login (mocked) | | test_zerotier.py | 8 | Network CRUD, devices, approvals, memberships (mocked) | | **Total** | **162** | | ## Pre-Commit Checklist Before committing backend changes: 1. Run the integration suite: `pytest tests/integration/ -x` 2. Verify coverage hasn't decreased: `pytest tests/integration/ --cov=gatehouse_app --cov-fail-under=85` 3. If tests fail, fix before committing ## CI/CD Integration tests run automatically on: - Every pull request - Every push to main - Nightly builds **Failure policy**: Integration test failures block merging.