Security fixes: P0-P2 complete (22 fixes)

P0 (7): Auth-bypass removed, migrations fixed, plugin-upload disabled, RLS FORCE+WITH CHECK, plugin double-registration fixed, persistent volume, domain removed
P1 (11): User/tenant model, Redis centralized, worker separated, transactional outbox, XSS fixed, DMS chunked streaming, permissions unified, password reset, metrics secured, config/docs fixed, cross-tenant FK
P2 (4): Contact model normalized, cross-imports reduced 94%, commands+state machines for contacts/dms/mail/calendar, SPA path-traversal

8 new migrations, 99 unit tests, 13 commands, 8 contracts, 72 files changed
This commit is contained in:
Agent Zero
2026-07-25 21:03:46 +02:00
parent aaa7406929
commit 727d86614e
103 changed files with 6831 additions and 1053 deletions
+56
View File
@@ -0,0 +1,56 @@
"""SQLAlchemy model for the transactional event outbox table."""
from __future__ import annotations
import uuid
from datetime import datetime
from sqlalchemy import DateTime, Integer, String, func
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.dialects.postgresql import UUID as PGUUID
from sqlalchemy.orm import Mapped, mapped_column
from app.core.db import Base
class EventOutbox(Base):
"""Row in the ``event_outbox`` table.
Each row represents a domain event that was written within a business
transaction and is waiting to be published to the in-process event bus
by the outbox worker.
"""
__tablename__ = "event_outbox"
id: Mapped[uuid.UUID] = mapped_column(
PGUUID(as_uuid=True),
primary_key=True,
server_default=func.gen_random_uuid(),
)
tenant_id: Mapped[uuid.UUID] = mapped_column(
PGUUID(as_uuid=True), nullable=False, index=True,
)
event_name: Mapped[str] = mapped_column(String(255), nullable=False)
payload: Mapped[dict] = mapped_column(JSONB, nullable=False)
status: Mapped[str] = mapped_column(
String(20), nullable=False, server_default="pending",
)
attempts: Mapped[int] = mapped_column(
Integer, nullable=False, server_default="0",
)
max_attempts: Mapped[int] = mapped_column(
Integer, nullable=False, server_default="5",
)
next_retry_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True,
)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now(),
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now(),
)
published_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True,
)