Безопасность довёл до ума — Cursor-генерацию переписал руками. IDOR закрыл, CSRF задушил, refresh rotation теперь как надо. HSTS на staging, ENABLE_DOCS=false, install.env recovery протестил. Backend: - jwt_denylist + auth_epoch: мгновенный revoke access JWT (logout/block/reset) - auth/admin/users: bump epoch, logout с Bearer, forgot_password skip для blocked - install_secrets: путь всегда apps/api/data/secrets/ (bootstrap из корня не ломает Docker) - seed: SEED_DEMO_USERS=false на prod/staging - тесты: jwt revoke, integration, coverage gate 90% Frontend: - logout шлёт Bearer, обработка TOKEN_REVOKED - guards TypeScript fix - E2E: blocked user → 401 сразу после block Infra: - staging/prod compose, TLS nginx, deploy-скрипты - k6 §17.2, backup/health/smoke scripts Docs: - docs/ на русском: project, security, deploy, release (старые md слили) - README короткий + план ТЗ + стандартные логины dev Код готов к плаванию. Капитан может идти писать фронт.
56 lines
2.0 KiB
Python
56 lines
2.0 KiB
Python
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
from app.core.install_secrets import load_install_secrets_to_env
|
|
|
|
load_install_secrets_to_env()
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
|
|
|
|
database_url: str = "postgresql+psycopg://user:pass@localhost:5432/compton"
|
|
redis_url: str = "redis://localhost:6379/0"
|
|
jwt_access_secret: str = "change-me-access-secret-with-at-least-32-bytes"
|
|
jwt_refresh_pepper: str = "change-me-refresh-pepper-with-at-least-32-bytes"
|
|
jwt_access_ttl_min: int = 15
|
|
jwt_refresh_ttl_days: int = 30
|
|
enable_docs: bool = True
|
|
cookie_secure: bool = False
|
|
cors_origins: list[str] = ["http://localhost:5173"]
|
|
enable_rate_limit: bool = True
|
|
auth_lockout_attempts: int = 5
|
|
auth_lockout_minutes: int = 15
|
|
admin_initial_password: str = "Admin1234"
|
|
demo_user_password: str = "User1234"
|
|
demo_ops_password: str = "OpsAdmin1234"
|
|
seed_demo_users: bool = True
|
|
smtp_host: str = "localhost"
|
|
smtp_port: int = 1025
|
|
smtp_user: str = ""
|
|
smtp_password: str = ""
|
|
smtp_from: str = "noreply@compton.example"
|
|
frontend_url: str = "http://localhost:5173"
|
|
public_base_url: str = "http://localhost:5173"
|
|
auth_token_ttl_hours: int = 1
|
|
email_delivery_mode: str = "smtp"
|
|
s3_endpoint: str = "http://localhost:9000"
|
|
s3_access_key: str = "minio"
|
|
s3_secret_key: str = "minio123"
|
|
s3_bucket: str = "compton"
|
|
s3_region: str = "us-east-1"
|
|
storage_mode: str = "s3"
|
|
avatar_max_bytes: int = 2 * 1024 * 1024
|
|
media_url_ttl_seconds: int = 600
|
|
log_level: str = "INFO"
|
|
audit_retention_days: int = 90
|
|
password_denylist_path: str = "data/security/password-denylist.txt"
|
|
compton_settings_path: str = "data/compton_settings.json"
|
|
admin_audit_log_path: str = "data/logs/admin-audit.jsonl"
|
|
server_log_path: str = "data/logs/server.log"
|
|
enable_test_routes: bool = False
|
|
app_env: str = "development"
|
|
trusted_proxy_ips: str = ""
|
|
|
|
|
|
settings = Settings()
|