Secuird Integration Test Suite
This directory contains the integration test suite for the Secuird IAM platform.
Quick Start
Run all integration tests:
cd backend
pytest tests/integration/
Run a specific test file:
pytest tests/integration/test_ssh_workflows.py -v
Run without coverage (faster):
pytest tests/integration/ --no-cov
Fail fast (stop on first failure):
pytest tests/integration/ -x
Run previously failed tests first:
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.
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:
-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:
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:
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
# 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:
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:
- Run the integration suite:
pytest tests/integration/ -x - Verify coverage hasn't decreased:
pytest tests/integration/ --cov=gatehouse_app --cov-fail-under=85 - 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.