2bc8ad87e1
security: rate limiter, is_admin flag, password policy, log masking
...
M-3: Role.name == 'Admin' string comparison → Role.is_admin boolean flag.
Admin role created with is_admin=True. has_permission checks getattr(role,
'is_admin', False) instead of comparing role names.
M-2: In-memory rate limiter on /api/auth/login. Tracks failed attempts
per IP (10 in 5 min window, 15 min ban). Thread-safe via threading.Lock.
M-5: Password policy — UserCreate.password: min_length=8, must include
uppercase, lowercase, and digit.
L-1: log_security_event details dict now masks sensitive fields:
password, secret, token, api_key, authorization. Recursive masking
for nested dicts. Sensitive field names matched via regex.
OTHER:
- 4 rate limiter tests (under limit, ban, success clears, IP isolation)
- 4 password policy tests (too short, no upper, no digit, valid)
- 2 log masking tests (flat keys, nested)
2026-05-26 15:17:19 +03:00
23719ecfbc
security: JWT aud/iss validation, token blacklist, encryption key crash-early
...
C-2 (CRITICAL): JWT decode_token now validates aud, iss, iat, jti claims.
Tokens without these claims are rejected. Audience 'ss-tools-api' and
issuer 'ss-tools' prevent cross-service token reuse.
H-2 (HIGH): Server-side JWT revocation via token_blacklist table.
- New TokenBlacklist model (SHA-256 hash only, never raw token)
- blacklist_token() on logout — revokes current session
- is_token_blacklisted() check in get_current_user
- Expired entries auto-pruned via _prune_blacklist()
H-3 (HIGH): Encryption key auto-generation removed — crash-early instead.
Previously, ensure_encryption_key() would auto-generate a Fernet key
on first run and write it to .env. This made encrypted data unrecoverable
when the key changed between deployments. Now raises RuntimeError with
a clear command to generate the key explicitly.
Also: update orthogonal security test for crash-early behavior.
2026-05-26 15:08:55 +03:00
a9a453109c
security: critical auth fixes, test migration to SQLite+FK, 44 test fixes
...
CRITICAL (CVE-class):
- C-4: Remove DEV_MODE fallback with hardcoded postgres:postgres credentials
- C-3: WebSocket endpoints now require JWT or API key token (?token=) auth
- C-1: Superset environment passwords encrypted via Fernet at rest in DB
- H-4: SESSION_SECRET_KEY separated from JWT AUTH_SECRET_KEY
- H-1: Log injection via %s-formatting instead of f-strings
- H-5: X-Trace-ID header validated as UUID4 to prevent trace poisoning
INFRASTRUCTURE:
- New src/core/encryption.py — EncryptionManager extracted from llm_provider
- Test DB: per-module sqlite:///:memory: with PRAGMA foreign_keys=ON
- testcontainers PostgreSQL via TEST_DB=postgres env var
- conftest temp-file global engine (no 10GB shared-cache leak)
TEST FIXES (44 pre-existing → 0):
- test_smoke_plugins: module-level sys.modules mock isolated to per-test fixture
- test_migration_engine: EXT:Python:uuid → uuid syntax fix
- test_dashboards_api: mock env attributes + correct patch target
- test_constants_audit_fixes: sync expected constant names with actual
- test_defensive_guards: patch.object instead of module-level Repo mock
- test_clean_release_cli: removed empty config.json directory
- FK violations: TaskRecord parents in log_persistence, Environment in
mapping_service, ReleaseCandidate in candidate_manifest_services
ORTHOGONAL TESTS (18 new):
- test_security_orthogonal.py: bcrypt 72-byte limit, unicode, API key
format invariants, Fernet robustness, encryption key lifecycle,
log injection protection, JWT edge cases
MODEL FIXES:
- MetricSnapshot.job_id: nullable with SET NULL (was broken FK for
aggregate prune snapshots, hidden by SQLite)
CLEANUP:
- Removed stale :memory:test_main/test_auth/test_tasks file databases
- Removed duplicate #endregion in encryption_key.py
2026-05-26 14:58:49 +03:00