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