refactor(docs+comments): add Google-style docstrings and inline comments across backend
Task D — Google-style docstrings (Args/Returns) on every public function, method, and class across all 158 Python files in the backend. Zero ruff D violations (pydocstyle Google convention). Task E — Explanatory one-line comment before every code line (~11600 new comments). ruff check passes clean after isort re-sort.
This commit is contained in:
@@ -3,20 +3,37 @@
|
||||
Provides granular scoring with breakdowns and configurable weights.
|
||||
"""
|
||||
|
||||
# Import Optional from typing
|
||||
from typing import Optional
|
||||
|
||||
# Import APIRouter, Depends, Query from fastapi
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
|
||||
# Import BaseModel from pydantic
|
||||
from pydantic import BaseModel
|
||||
|
||||
# Import Session from sqlalchemy.orm
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# Import get_db from app.database
|
||||
from app.database import get_db
|
||||
|
||||
# Import get_current_user, require_role from app.dependencies.auth
|
||||
from app.dependencies.auth import get_current_user, require_role
|
||||
|
||||
# Import UnitOfWork from app.domain.unit_of_work
|
||||
from app.domain.unit_of_work import UnitOfWork
|
||||
|
||||
# Import User from app.models.user
|
||||
from app.models.user import User
|
||||
|
||||
# Import from app.services.scoring_config_service
|
||||
from app.services.scoring_config_service import (
|
||||
get_weights_dict,
|
||||
update_scoring_weights,
|
||||
)
|
||||
|
||||
# Import from app.services.scoring_service
|
||||
from app.services.scoring_service import (
|
||||
calculate_tactic_score,
|
||||
get_score_history,
|
||||
@@ -24,6 +41,7 @@ from app.services.scoring_service import (
|
||||
score_technique_by_mitre_id,
|
||||
)
|
||||
|
||||
# Assign router = APIRouter(prefix="/scores", tags=["scores"])
|
||||
router = APIRouter(prefix="/scores", tags=["scores"])
|
||||
|
||||
|
||||
@@ -31,12 +49,26 @@ router = APIRouter(prefix="/scores", tags=["scores"])
|
||||
|
||||
|
||||
@router.get("/technique/{mitre_id}")
|
||||
# Define function score_technique
|
||||
def score_technique(
|
||||
# Entry: mitre_id
|
||||
mitre_id: str,
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""Get detailed score with breakdown for a specific technique."""
|
||||
"""Get detailed score with breakdown for a specific technique.
|
||||
|
||||
Args:
|
||||
mitre_id (str): MITRE ATT&CK technique ID (e.g. ``T1059``).
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated user making the request.
|
||||
|
||||
Returns:
|
||||
dict: Score value and component breakdown (tests, detection rules, recency, etc.).
|
||||
"""
|
||||
# Return score_technique_by_mitre_id(db, mitre_id)
|
||||
return score_technique_by_mitre_id(db, mitre_id)
|
||||
|
||||
|
||||
@@ -44,12 +76,26 @@ def score_technique(
|
||||
|
||||
|
||||
@router.get("/tactic/{tactic}")
|
||||
# Define function score_tactic
|
||||
def score_tactic(
|
||||
# Entry: tactic
|
||||
tactic: str,
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""Get average score for a tactic."""
|
||||
"""Get average score for a tactic.
|
||||
|
||||
Args:
|
||||
tactic (str): MITRE ATT&CK tactic slug (e.g. ``initial-access``).
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated user making the request.
|
||||
|
||||
Returns:
|
||||
dict: Average score and per-technique breakdown for the tactic.
|
||||
"""
|
||||
# Return calculate_tactic_score(tactic, db)
|
||||
return calculate_tactic_score(tactic, db)
|
||||
|
||||
|
||||
@@ -57,12 +103,26 @@ def score_tactic(
|
||||
|
||||
|
||||
@router.get("/threat-actor/{actor_id}")
|
||||
# Define function score_threat_actor
|
||||
def score_threat_actor(
|
||||
# Entry: actor_id
|
||||
actor_id: str,
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""Get coverage score against a specific threat actor."""
|
||||
"""Get coverage score against a specific threat actor.
|
||||
|
||||
Args:
|
||||
actor_id (str): UUID string of the threat actor to score against.
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated user making the request.
|
||||
|
||||
Returns:
|
||||
dict: Coverage score and per-technique breakdown for the threat actor.
|
||||
"""
|
||||
# Return score_actor_by_id(db, actor_id)
|
||||
return score_actor_by_id(db, actor_id)
|
||||
|
||||
|
||||
@@ -70,13 +130,26 @@ def score_threat_actor(
|
||||
|
||||
|
||||
@router.get("/organization")
|
||||
# Define function score_organization
|
||||
def score_organization(
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""Get the overall organization security score (cached for 5 min)."""
|
||||
"""Get the overall organization security score (cached for 5 min).
|
||||
|
||||
Args:
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated user making the request.
|
||||
|
||||
Returns:
|
||||
dict: Aggregate organization score with tactic-level breakdowns.
|
||||
"""
|
||||
# Import get_organization_score_cached from app.services.score_cache
|
||||
from app.services.score_cache import get_organization_score_cached
|
||||
|
||||
# Return get_organization_score_cached(db)
|
||||
return get_organization_score_cached(db)
|
||||
|
||||
|
||||
@@ -84,12 +157,26 @@ def score_organization(
|
||||
|
||||
|
||||
@router.get("/history")
|
||||
# Define function score_history
|
||||
def score_history(
|
||||
# Entry: period
|
||||
period: str = Query("90d", pattern="^(30d|90d|1y)$"),
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(get_current_user),
|
||||
) -> dict:
|
||||
"""Get historical score data points (weekly)."""
|
||||
"""Get historical score data points (weekly).
|
||||
|
||||
Args:
|
||||
period (str): Time window for history — one of ``30d``, ``90d``, or ``1y``.
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated user making the request.
|
||||
|
||||
Returns:
|
||||
dict: Weekly score data points for the requested period.
|
||||
"""
|
||||
# Return get_score_history(db, period)
|
||||
return get_score_history(db, period)
|
||||
|
||||
|
||||
@@ -97,11 +184,23 @@ def score_history(
|
||||
|
||||
|
||||
@router.get("/config")
|
||||
# Define function get_scoring_config
|
||||
def get_scoring_config(
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(require_role("admin")),
|
||||
) -> dict:
|
||||
"""Get current scoring weights (admin only)."""
|
||||
"""Get current scoring weights (admin only).
|
||||
|
||||
Args:
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated admin user.
|
||||
|
||||
Returns:
|
||||
dict: Current weight values for each scoring component.
|
||||
"""
|
||||
# Return get_weights_dict(db)
|
||||
return get_weights_dict(db)
|
||||
|
||||
|
||||
@@ -109,41 +208,77 @@ def get_scoring_config(
|
||||
|
||||
|
||||
class ScoringConfigUpdate(BaseModel):
|
||||
"""Partial update payload for the scoring weight configuration."""
|
||||
|
||||
# Assign tests = None
|
||||
tests: Optional[float] = None
|
||||
# Assign detection_rules = None
|
||||
detection_rules: Optional[float] = None
|
||||
# Assign d3fend = None
|
||||
d3fend: Optional[float] = None
|
||||
# Assign recency = None
|
||||
recency: Optional[float] = None
|
||||
# Assign severity = None
|
||||
severity: Optional[float] = None
|
||||
# Assign freshness = None
|
||||
freshness: Optional[float] = None
|
||||
# Assign platform_diversity = None
|
||||
platform_diversity: Optional[float] = None
|
||||
|
||||
|
||||
# Apply the @router.patch decorator
|
||||
@router.patch("/config")
|
||||
# Define function update_scoring_config
|
||||
def update_scoring_config(
|
||||
# Entry: payload
|
||||
payload: ScoringConfigUpdate,
|
||||
# Entry: db
|
||||
db: Session = Depends(get_db),
|
||||
# Entry: current_user
|
||||
current_user: User = Depends(require_role("admin")),
|
||||
) -> dict:
|
||||
"""Update scoring weights (admin only).
|
||||
|
||||
Weights are persisted in the database and survive restarts.
|
||||
Validation enforces that all weights are non-negative and sum to 100.
|
||||
|
||||
Args:
|
||||
payload (ScoringConfigUpdate): Partial weight update; only set fields are changed.
|
||||
db (Session): SQLAlchemy database session.
|
||||
current_user (User): Authenticated admin user.
|
||||
|
||||
Returns:
|
||||
dict: Confirmation message plus the full updated weight configuration.
|
||||
"""
|
||||
# Open context manager
|
||||
with UnitOfWork(db) as uow:
|
||||
# Assign result = update_scoring_weights(
|
||||
result = update_scoring_weights(
|
||||
db,
|
||||
# Keyword argument: tests
|
||||
tests=payload.tests,
|
||||
# Keyword argument: detection_rules
|
||||
detection_rules=payload.detection_rules,
|
||||
# Keyword argument: d3fend
|
||||
d3fend=payload.d3fend,
|
||||
# Keyword argument: recency
|
||||
recency=payload.recency,
|
||||
# Keyword argument: severity
|
||||
severity=payload.severity,
|
||||
# Keyword argument: freshness
|
||||
freshness=payload.freshness,
|
||||
# Keyword argument: platform_diversity
|
||||
platform_diversity=payload.platform_diversity,
|
||||
# Keyword argument: updated_by
|
||||
updated_by=current_user.id,
|
||||
)
|
||||
# Call uow.commit()
|
||||
uow.commit()
|
||||
|
||||
# Import invalidate from app.services.score_cache
|
||||
from app.services.score_cache import invalidate
|
||||
# Call invalidate()
|
||||
invalidate()
|
||||
|
||||
# Return {"message": "Scoring config updated", **result}
|
||||
return {"message": "Scoring config updated", **result}
|
||||
|
||||
Reference in New Issue
Block a user