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
+1
View File
@@ -8,6 +8,7 @@ from pydantic import BaseModel, EmailStr, Field
class LoginRequest(BaseModel):
email: EmailStr = Field(..., examples=["admin@leocrm.local"])
password: str = Field(..., min_length=1, examples=["secure-password"])
tenant_slug: str | None = Field(None, description="Tenant slug to select tenant at login", examples=["tenant-a"])
class PasswordResetRequest(BaseModel):
+26 -21
View File
@@ -2,6 +2,8 @@
from __future__ import annotations
from decimal import Decimal
from pydantic import BaseModel, Field
@@ -70,10 +72,11 @@ class ContactPersonResponse(BaseModel):
class ContactCreate(BaseModel):
type: str = Field("company", pattern="^(company|person)$")
status: str | None = Field(None, pattern="^(lead|qualified|customer|inactive)$")
name: str | None = Field(None, max_length=255)
firstname: str | None = Field(None, max_length=100)
surname: str | None = Field(None, max_length=100)
surfix: str | None = Field(None, max_length=50)
suffix: str | None = Field(None, max_length=50)
ext_name_line: str | None = Field(None, max_length=255)
gender: str | None = Field(None, max_length=20)
code: str | None = Field(None, max_length=100)
@@ -124,12 +127,12 @@ class ContactCreate(BaseModel):
bic: str | None = Field(None, max_length=50)
bank_account: str | None = Field(None, max_length=50)
# Discounts
discount_crew: float = 0
discount_transport: float = 0
discount_rental: float = 0
discount_sale: float = 0
discount_subrent: float = 0
discount_total: float = 0
discount_crew: Decimal = Decimal("0")
discount_transport: Decimal = Decimal("0")
discount_rental: Decimal = Decimal("0")
discount_sale: Decimal = Decimal("0")
discount_subrent: Decimal = Decimal("0")
discount_total: Decimal = Decimal("0")
# Geo
latitude: float | None = None
longitude: float | None = None
@@ -149,10 +152,11 @@ class ContactCreate(BaseModel):
class ContactUpdate(BaseModel):
type: str | None = Field(None, pattern="^(company|person)$")
status: str | None = Field(None, pattern="^(lead|qualified|customer|inactive)$")
name: str | None = Field(None, max_length=255)
firstname: str | None = Field(None, max_length=100)
surname: str | None = Field(None, max_length=100)
surfix: str | None = Field(None, max_length=50)
suffix: str | None = Field(None, max_length=50)
ext_name_line: str | None = Field(None, max_length=255)
gender: str | None = Field(None, max_length=20)
code: str | None = Field(None, max_length=100)
@@ -196,12 +200,12 @@ class ContactUpdate(BaseModel):
purchase_number: str | None = Field(None, max_length=100)
bic: str | None = Field(None, max_length=50)
bank_account: str | None = Field(None, max_length=50)
discount_crew: float | None = None
discount_transport: float | None = None
discount_rental: float | None = None
discount_sale: float | None = None
discount_subrent: float | None = None
discount_total: float | None = None
discount_crew: Decimal | None = None
discount_transport: Decimal | None = None
discount_rental: Decimal | None = None
discount_sale: Decimal | None = None
discount_subrent: Decimal | None = None
discount_total: Decimal | None = None
latitude: float | None = None
longitude: float | None = None
projectnote: str | None = None
@@ -219,10 +223,11 @@ class ContactResponse(BaseModel):
id: str
type: str
displayname: str
status: str = "lead"
name: str | None = None
firstname: str | None = None
surname: str | None = None
surfix: str | None = None
suffix: str | None = None
ext_name_line: str | None = None
gender: str | None = None
code: str | None = None
@@ -267,12 +272,12 @@ class ContactResponse(BaseModel):
purchase_number: str | None = None
bic: str | None = None
bank_account: str | None = None
discount_crew: float = 0
discount_transport: float = 0
discount_rental: float = 0
discount_sale: float = 0
discount_subrent: float = 0
discount_total: float = 0
discount_crew: Decimal = Decimal("0")
discount_transport: Decimal = Decimal("0")
discount_rental: Decimal = Decimal("0")
discount_sale: Decimal = Decimal("0")
discount_subrent: Decimal = Decimal("0")
discount_total: Decimal = Decimal("0")
latitude: float | None = None
longitude: float | None = None
projectnote: str | None = None