Files
security-alert-center/backend/app/config.py
T
PapaTramp 415d863b3b feat: SAC daily reports from DB aggregation (notif-32)
- Aggregate report.daily.ssh/rdp from 24h ingest; job and systemd timer

- notify_daily_report bypasses NOTIFY_MIN_SEVERITY; ingest routes agent reports

- HTML templates, env SAC_DAILY_REPORT_*, docs and tests (56 cases)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-29 16:30:07 +10:00

107 lines
3.4 KiB
Python

import os
from functools import lru_cache
from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
ROOT = Path(__file__).resolve().parents[2]
SCHEMA_PATH = ROOT / "schemas" / "event-schema-v1.json"
DEFAULT_CONFIG_FILE = Path("/opt/security-alert-center/config/sac-api.env")
def _resolve_config_files() -> tuple[str, ...]:
"""Файлы конфигурации для pydantic (корректный разбор кавычек и URL)."""
candidates: list[Path] = []
explicit = os.environ.get("SAC_CONFIG_FILE", "").strip()
if explicit:
candidates.append(Path(explicit))
else:
candidates.append(DEFAULT_CONFIG_FILE)
candidates.append(Path(".env"))
return tuple(str(p) for p in candidates if p.is_file())
def _settings_config() -> SettingsConfigDict:
files = _resolve_config_files()
return SettingsConfigDict(
env_file=files if files else None,
env_file_encoding="utf-8",
extra="ignore",
)
class Settings(BaseSettings):
model_config = _settings_config()
database_url: str = "postgresql+psycopg2://sac:sac@localhost:5432/sac"
sac_public_url: str = "http://localhost:8000"
jwt_secret: str = "change-me-in-production"
jwt_algorithm: str = "HS256"
jwt_expire_minutes: int = 60 * 24
sac_bootstrap_api_key: str = ""
sac_admin_username: str = "admin"
sac_admin_password: str = ""
event_schema_path: str = str(SCHEMA_PATH)
cors_origins: str = "*"
telegram_enabled: bool = False
telegram_bot_token: str = ""
telegram_chat_id: str = ""
telegram_min_severity: str = "high"
webhook_enabled: bool = False
webhook_url: str = ""
webhook_secret_header: str = ""
webhook_secret: str = ""
webhook_min_severity: str = "high"
smtp_enabled: bool = False
smtp_host: str = ""
smtp_port: int = 587
smtp_user: str = ""
smtp_password: str = ""
smtp_from: str = ""
smtp_to: str = ""
smtp_starttls: bool = True
smtp_ssl: bool = False
smtp_min_severity: str = "high"
notify_min_severity: str = "warning"
notify_channels: str = "telegram,webhook,email"
# F-NOT-03: cooldown исходящих оповещений (dedup_key / fingerprint)
sac_notify_cooldown_enabled: bool = True
sac_notify_event_cooldown_sec: int = 90
sac_notify_problem_cooldown_sec: int = 300
# F-NOT-05: суточные отчёты из агрегации событий SAC (для exclusive / без отчёта агента)
sac_daily_report_enabled: bool = True
sac_daily_report_hour: int = 9
sac_daily_report_timezone: str = "Europe/Moscow"
sac_daily_report_skip_if_agent_sent: bool = True
sac_daily_report_require_activity: bool = True
# Порог «живости» агента
sac_heartbeat_stale_minutes: int = 780
# Окно корреляции Problems: host + type + rule в одном open Problem
sac_problem_correlation_window_minutes: int = 60
# rule:brute_force_burst — ssh.login.failed / rdp.login.failed
sac_brute_force_window_minutes: int = 15
sac_brute_force_threshold: int = 30
# rule:privilege_spike — privilege.sudo.command
sac_privilege_spike_window_minutes: int = 10
sac_privilege_spike_threshold: int = 10
# Retention (app.jobs.retention / systemd timer)
sac_events_retention_days: int = 90
sac_problems_retention_days: int = 180
@lru_cache
def get_settings() -> Settings:
return Settings()