Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Foundational changes required before any new feature work can begin. - 0.1 Redis infrastructure: add redis:7-alpine to docker-compose dev and prod, REDIS_URL config, singleton client in app/infrastructure/redis_client.py - 0.2 Token blacklist on Redis SEC-001: replace in-memory dict with Redis SETEX keyed by jti, auto-expiring TTL derived from token exp - 0.3 Database indexes SR-006: Alembic migration b019 with 5 composite indexes for scoring, MTTD/MTTR, remediation, and notification queries - 0.4 Domain exceptions TD-003: app/domain/exceptions.py with typed errors, error_handler middleware mapping them to HTTP, services decoupled from FastAPI - 0.5 Fix silenced exceptions TD-007: replace 4 bare except-pass blocks in test_workflow_service with logger.warning with exc_info - 0.6 CI pipeline TD-009: GitHub Actions workflow with Postgres and Redis service containers, ruff lint, pytest; ruff.toml for baseline config
84 lines
3.9 KiB
Python
84 lines
3.9 KiB
Python
import os
|
|
import secrets
|
|
import warnings
|
|
|
|
from pydantic_settings import BaseSettings
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Detect environment: "production" when AEGIS_ENV or common indicators are set
|
|
# ---------------------------------------------------------------------------
|
|
_is_production = os.environ.get("AEGIS_ENV", "").lower() == "production" or bool(
|
|
os.environ.get("SECRET_KEY") # having an explicit SECRET_KEY hints prod
|
|
)
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
DATABASE_URL: str = "postgresql://postgres:postgres@postgres:5432/attackdb"
|
|
|
|
# ── Security ──────────────────────────────────────────────────────
|
|
# SECRET_KEY has NO safe default. In development a random key is
|
|
# generated at startup (tokens invalidate on restart — acceptable
|
|
# for local dev). In production it MUST be supplied via env/.env
|
|
# so tokens survive restarts.
|
|
SECRET_KEY: str = ""
|
|
ALGORITHM: str = "HS256"
|
|
ACCESS_TOKEN_EXPIRE_MINUTES: int = 15 # short-lived for security; configurable via env
|
|
|
|
# ── Redis ─────────────────────────────────────────────────────────
|
|
REDIS_URL: str = "redis://redis:6379/0"
|
|
|
|
# ── CORS ─────────────────────────────────────────────────────────
|
|
# Comma-separated list of allowed origins, or a JSON array.
|
|
# In dev this defaults to common local ports; in production set it
|
|
# to the actual frontend domain(s).
|
|
CORS_ORIGINS: str = "http://localhost:3000,http://localhost:5173"
|
|
|
|
# ── MinIO / S3 ───────────────────────────────────────────────────
|
|
MINIO_ENDPOINT: str = "minio:9000"
|
|
MINIO_ACCESS_KEY: str = "minioadmin"
|
|
MINIO_SECRET_KEY: str = "minioadmin"
|
|
MINIO_BUCKET: str = "evidence"
|
|
MINIO_SECURE: bool = False # True → use HTTPS to connect to MinIO
|
|
|
|
# ── Re-testing ───────────────────────────────────────────────────
|
|
MAX_RETEST_COUNT: int = 3 # maximum automatic retests per original test
|
|
|
|
# ── Scoring weights (must sum to 100) ────────────────────────────
|
|
SCORING_WEIGHT_TESTS: int = 40
|
|
SCORING_WEIGHT_DETECTION_RULES: int = 20
|
|
SCORING_WEIGHT_D3FEND: int = 15
|
|
SCORING_WEIGHT_FRESHNESS: int = 15
|
|
SCORING_WEIGHT_PLATFORM_DIVERSITY: int = 10
|
|
|
|
class Config:
|
|
env_file = ".env"
|
|
|
|
|
|
settings = Settings()
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Post-init validation for SECRET_KEY
|
|
# ---------------------------------------------------------------------------
|
|
_UNSAFE_SECRETS = {
|
|
"",
|
|
"change-me-in-production",
|
|
"change-me-in-production-use-a-long-random-string",
|
|
}
|
|
|
|
if settings.SECRET_KEY in _UNSAFE_SECRETS:
|
|
if _is_production:
|
|
raise RuntimeError(
|
|
"CRITICAL: SECRET_KEY is not configured. "
|
|
"Set a strong random value (>= 32 chars) via the SECRET_KEY "
|
|
"environment variable or in your .env file before running in "
|
|
"production. Example: openssl rand -hex 32"
|
|
)
|
|
# Development: auto-generate an ephemeral key and warn
|
|
settings.SECRET_KEY = secrets.token_hex(32)
|
|
warnings.warn(
|
|
"SECRET_KEY was not set — using an auto-generated ephemeral key. "
|
|
"JWT tokens will be invalidated on every restart. "
|
|
"Set SECRET_KEY in your environment for persistent sessions.",
|
|
stacklevel=2,
|
|
)
|