refactor(scoring): persist weights in DB table, replace mutable Settings with scoring_config_service
This commit is contained in:
@@ -14,7 +14,6 @@ from app.dependencies.auth import get_current_user, require_role
|
||||
from app.models.user import User
|
||||
from app.models.technique import Technique
|
||||
from app.models.threat_actor import ThreatActor
|
||||
from app.config import settings
|
||||
from app.services.scoring_service import (
|
||||
calculate_technique_score,
|
||||
calculate_tactic_score,
|
||||
@@ -22,6 +21,10 @@ from app.services.scoring_service import (
|
||||
calculate_organization_score,
|
||||
get_score_history,
|
||||
)
|
||||
from app.services.scoring_config_service import (
|
||||
get_weights_dict,
|
||||
update_scoring_weights,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/scores", tags=["scores"])
|
||||
|
||||
@@ -117,79 +120,45 @@ def score_history(
|
||||
|
||||
@router.get("/config")
|
||||
def get_scoring_config(
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_role("admin")),
|
||||
):
|
||||
"""Get current scoring weights (admin only)."""
|
||||
return {
|
||||
"weights": {
|
||||
"tests": settings.SCORING_WEIGHT_TESTS,
|
||||
"detection_rules": settings.SCORING_WEIGHT_DETECTION_RULES,
|
||||
"d3fend": settings.SCORING_WEIGHT_D3FEND,
|
||||
"freshness": settings.SCORING_WEIGHT_FRESHNESS,
|
||||
"platform_diversity": settings.SCORING_WEIGHT_PLATFORM_DIVERSITY,
|
||||
},
|
||||
"total": (
|
||||
settings.SCORING_WEIGHT_TESTS
|
||||
+ settings.SCORING_WEIGHT_DETECTION_RULES
|
||||
+ settings.SCORING_WEIGHT_D3FEND
|
||||
+ settings.SCORING_WEIGHT_FRESHNESS
|
||||
+ settings.SCORING_WEIGHT_PLATFORM_DIVERSITY
|
||||
),
|
||||
}
|
||||
return get_weights_dict(db)
|
||||
|
||||
|
||||
# ── PATCH /scores/config ─────────────────────────────────────────────
|
||||
|
||||
|
||||
class ScoringConfigUpdate(BaseModel):
|
||||
tests: Optional[int] = None
|
||||
detection_rules: Optional[int] = None
|
||||
d3fend: Optional[int] = None
|
||||
freshness: Optional[int] = None
|
||||
platform_diversity: Optional[int] = None
|
||||
tests: Optional[float] = None
|
||||
detection_rules: Optional[float] = None
|
||||
d3fend: Optional[float] = None
|
||||
freshness: Optional[float] = None
|
||||
platform_diversity: Optional[float] = None
|
||||
|
||||
|
||||
@router.patch("/config")
|
||||
def update_scoring_config(
|
||||
payload: ScoringConfigUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_role("admin")),
|
||||
):
|
||||
"""Update scoring weights (admin only).
|
||||
|
||||
Note: Since we're using Opcion A (env vars / Settings), changes
|
||||
are applied at runtime but won't persist across restarts unless
|
||||
the .env file is also updated. For production, consider migrating
|
||||
to Option B (database table).
|
||||
Weights are persisted in the database and survive restarts.
|
||||
Validation enforces that all weights are non-negative and sum to 100.
|
||||
"""
|
||||
if payload.tests is not None:
|
||||
settings.SCORING_WEIGHT_TESTS = payload.tests
|
||||
if payload.detection_rules is not None:
|
||||
settings.SCORING_WEIGHT_DETECTION_RULES = payload.detection_rules
|
||||
if payload.d3fend is not None:
|
||||
settings.SCORING_WEIGHT_D3FEND = payload.d3fend
|
||||
if payload.freshness is not None:
|
||||
settings.SCORING_WEIGHT_FRESHNESS = payload.freshness
|
||||
if payload.platform_diversity is not None:
|
||||
settings.SCORING_WEIGHT_PLATFORM_DIVERSITY = payload.platform_diversity
|
||||
result = update_scoring_weights(
|
||||
db,
|
||||
tests=payload.tests,
|
||||
detection_rules=payload.detection_rules,
|
||||
d3fend=payload.d3fend,
|
||||
freshness=payload.freshness,
|
||||
platform_diversity=payload.platform_diversity,
|
||||
)
|
||||
|
||||
# Weights changed — bust the score cache
|
||||
from app.services.score_cache import invalidate
|
||||
invalidate()
|
||||
|
||||
return {
|
||||
"message": "Scoring config updated",
|
||||
"weights": {
|
||||
"tests": settings.SCORING_WEIGHT_TESTS,
|
||||
"detection_rules": settings.SCORING_WEIGHT_DETECTION_RULES,
|
||||
"d3fend": settings.SCORING_WEIGHT_D3FEND,
|
||||
"freshness": settings.SCORING_WEIGHT_FRESHNESS,
|
||||
"platform_diversity": settings.SCORING_WEIGHT_PLATFORM_DIVERSITY,
|
||||
},
|
||||
"total": (
|
||||
settings.SCORING_WEIGHT_TESTS
|
||||
+ settings.SCORING_WEIGHT_DETECTION_RULES
|
||||
+ settings.SCORING_WEIGHT_D3FEND
|
||||
+ settings.SCORING_WEIGHT_FRESHNESS
|
||||
+ settings.SCORING_WEIGHT_PLATFORM_DIVERSITY
|
||||
),
|
||||
}
|
||||
return {"message": "Scoring config updated", **result}
|
||||
|
||||
Reference in New Issue
Block a user