When a user accepts an org invite, send a notification email to the
person who sent the invite with membership details (member name, email,
org name, role) and an optional View Organization button.
Added build_invite_accepted_html() template to email_templates.py,
wired it into the accept_invite() handler, and added a test case.
Remove UniqueConstraint('id') from all create_table calls in the initial
migration (40 occurrences) and the bulk constraint additions from the
superadmin migration (43 create + 43 drop). These were redundant with
PrimaryKeyConstraint('id') which already guarantees uniqueness.
Also removes duplicate unique enforcement on superadmins.email and
superadmin_sessions.token (kept the unique indexes, dropped the
table-level UniqueConstraints).
Fixes the root cause in BaseModel by removing unique=True from the id
column definition, which was causing Alembic autogenerate to produce
these redundant constraints.
Renames idx_cert_audit_org to ix_certificate_audit_logs_organization_id
to follow Alembic naming conventions.
- Refactor CORS middleware to echo request origin when wildcard + credentials
is configured (browsers reject Access-Control-Allow-Origin: * with
Access-Control-Allow-Credentials: true)
- Add _is_origin_allowed() and _cors_origin_header() helpers
- Use CORS_SUPPORTS_CREDENTIALS config consistently
- Ensure consistent Access-Control-Allow-Headers in all CORS paths
- Fix redirect validation in get_token() to allow wildcard CORS origins
- Add 46 unit tests covering encryption round-trips, idempotency, key
derivation, thread safety, CORS origin matching, and preflight responses
Previously, SSH key fingerprints were globally unique across all users,
preventing the same key from being registered by different users. This
change makes fingerprint uniqueness scoped to individual users.
- Remove global unique constraints on payload and fingerprint columns
- Add composite unique constraint on (user_id, fingerprint)
- Make add_ssh_key operation idempotent for same user
- Return tuple (SSHKey, is_new) from service to indicate creation status
- Update API to return 200 for existing keys, 201 for new keys
BREAKING CHANGE: API behavior changed - duplicate key addition now
returns 200 OK instead of 409 Conflict. Service method signature changed
from returning SSHKey to tuple[SSHKey, bool].
Add support for users who belong to multiple organizations to select
which organization's CA should sign their SSH certificates.
Changes:
- CLI: Add --org-id and --list-orgs options for organization selection
- API: Return MULTIPLE_ORGS_AMBIGUOUS error when org selection needed
- API: Add /users/me/organizations/simple endpoint for CLI org listing
- DB: Add organization_id to certificate_audit_logs for better tracking
- Include organization_name in certificate response for clarity
Handle edge case where removing a member would leave an organization
without any owners. Service layer raises ValueError for this scenario,
which the API endpoint catches and converts to a forbidden response
with actionable error message about transferring ownership.
Add 10 organization limit per user to prevent abuse. Includes
graceful fallback if count service is unavailable.
- Add get_user_org_count method to OrganizationService
- Check org count before allowing new organization creation
- Improve invite email mismatch error message for logged-in users
Add new /auth/me/resend-verification endpoint that allows logged-in users
to request a new email verification link. Includes rate limiting configuration
to prevent abuse of the verification email functionality.
Add POST /api/v1/contact endpoint to handle contact form submissions
from the marketing website. Includes:
- ContactSchema for validation with HTML sanitization
- Honeypot field for spam protection
- Rate limiting (5 per hour)
- Email notification to info@secuird.tech via NotificationService
Add get_active_memberships() method to User model that filters out
soft-deleted memberships and memberships of deleted organizations.
Update all usages of organization_memberships to use this method,
ensuring consistent handling of soft-deleted records across the
codebase. Also add deleted_at filters to CA queries in SSH helpers.
Add a configurable job runner script that executes Flask CLI commands
at specified intervals within Docker containers. Supports graceful
shutdown via SIGTERM/SIGINT signals and includes built-in job commands
for ZeroTier reconciliation and MFA compliance checks.
- Move OIDC endpoints from gatehouse_app/api/oidc.py to gatehouse_app/api/v1/oidc.py
- Register OIDC discovery endpoint directly on app instead of separate blueprint
- Update service name from authy2-backend to secuird-backend in health check
Separate OIDC discovery endpoint into its own blueprint registered at
root level (required by OIDC spec for .well-known path). Move all other
OIDC endpoints to /api/v1/oidc to conform to API versioning standard.
BREAKING CHANGE: OIDC endpoint URLs changed from /oidc/* to /api/v1/oidc/*
- Update org invite, password reset, email verification, and account activation emails to use HTML templates
- Update MFA deadline reminder and suspension notifications to use HTML templates
- Add html_body parameter to _send_email_async for rich email content
- Move POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB to .env
- Update docker-compose.yml to reference env vars instead of hardcoding
- Fix db healthcheck to use correct credentials from .env
- Update .env.example with matching placeholder values
- Update DATABASE_URL to use variable interpolation
Add pluggable email provider system supporting SMTP, Mailgun, and SendGrid
with factory pattern for runtime provider selection. Includes branded HTML
email templates for verification, password reset, MFA notifications, and
organization invites.
Also rebrands all email content from Gatehouse to Secuird, adds email
provider configuration options, and fixes duplicate log handlers in
development mode.
Add production-ready Docker setup with multi-stage Dockerfile, docker-compose
orchestration for API, PostgreSQL, Redis, and Nginx services. Includes
health checks, non-root user execution, and proper networking.
- Add multi-stage Dockerfile with gunicorn/gevent workers
- Add docker-compose.yml with api, db, redis, nginx services
- Add nginx reverse proxy configuration with security headers
- Update .env.example with Docker and production variables
- Add email provider configuration (Mailgun, SendGrid)
- Add requests dependency for HTTP client support
- Update documentation with Docker deployment guide
- Rebrand project name from Gatehouse to Secuird
Replace 35 incremental migration files with one comprehensive initial
migration that captures the complete database schema. This simplifies
the migration history and eliminates complex dependency chains between
migrations.
The new migration (6a4c4ed4a5c6) includes all tables for:
- Users, organizations, and authentication
- SSH CA and certificate management
- ZeroTier network integration
- OIDC/OAuth providers
- Security policies and audit logging