Files
Aegis/backend/app/routers/system.py
T
kitos 0ddd17047d 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.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:37:15 +02:00

188 lines
5.4 KiB
Python

"""System-level endpoints (admin only).
Provides manual triggers for background operations such as the MITRE
ATT&CK synchronisation, intel scanning, Atomic Red Team import, and
scheduler health introspection.
"""
# Import logging
import logging
# Import APIRouter, Depends, Request from fastapi
from fastapi import APIRouter, Depends, Request
# Import Session from sqlalchemy.orm
from sqlalchemy.orm import Session
# Import get_db from app.database
from app.database import get_db
# Import require_role from app.dependencies.auth
from app.dependencies.auth import require_role
# Import scheduler from app.jobs.mitre_sync_job
from app.jobs.mitre_sync_job import scheduler
# Import limiter from app.limiter
from app.limiter import limiter
# Import User from app.models.user
from app.models.user import User
# Import import_atomic_red_team from app.services.atomic_import_service
from app.services.atomic_import_service import import_atomic_red_team
# Import scan_intel from app.services.intel_service
from app.services.intel_service import scan_intel
# Import sync_mitre from app.services.mitre_sync_service
from app.services.mitre_sync_service import sync_mitre
# Assign logger = logging.getLogger(__name__)
logger = logging.getLogger(__name__)
# Assign router = APIRouter(prefix="/system", tags=["system"])
router = APIRouter(prefix="/system", tags=["system"])
# Apply the @router.post decorator
@router.post("/sync-mitre")
# Apply the @limiter.limit decorator
@limiter.limit("2/hour")
# Define function trigger_mitre_sync
def trigger_mitre_sync(
# Entry: request
request: Request,
# Entry: db
db: Session = Depends(get_db),
# Entry: current_user
current_user: User = Depends(require_role("admin")),
) -> dict:
"""Manually trigger a MITRE ATT&CK synchronisation.
**Requires** the ``admin`` role.
Returns a JSON object with the sync summary including the count of
new and updated techniques.
"""
# Assign summary = sync_mitre(db)
summary = sync_mitre(db)
# Return {
return {
# Literal argument value
"message": "MITRE sync completed",
# Literal argument value
"new": summary["created"],
# Literal argument value
"updated": summary["updated"],
}
# Apply the @router.post decorator
@router.post("/run-intel-scan")
# Define function trigger_intel_scan
def trigger_intel_scan(
# Entry: db
db: Session = Depends(get_db),
# Entry: current_user
current_user: User = Depends(require_role("admin")),
) -> dict:
"""Manually trigger a threat-intelligence scan.
**Requires** the ``admin`` role.
Returns a JSON object with the scan summary including the count of
new intel items found.
"""
# Assign summary = scan_intel(db)
summary = scan_intel(db)
# Return {
return {
# Literal argument value
"message": "Intel scan completed",
# Literal argument value
"new_items": summary["new_items"],
}
# Apply the @router.post decorator
@router.post("/import-atomic-tests")
# Apply the @limiter.limit decorator
@limiter.limit("2/hour")
# Define function trigger_atomic_import
def trigger_atomic_import(
# Entry: request
request: Request,
# Entry: db
db: Session = Depends(get_db),
# Entry: current_user
current_user: User = Depends(require_role("admin")),
) -> dict:
"""Trigger an import of Atomic Red Team tests as TestTemplates.
**Requires** the ``admin`` role.
Downloads the Atomic Red Team repository ZIP from GitHub, parses the
YAML files, and creates/updates TestTemplate records. Running this
endpoint multiple times is idempotent — duplicates are skipped.
Returns a JSON object with import statistics.
"""
# Attempt the following; catch errors below
try:
# Assign summary = import_atomic_red_team(db)
summary = import_atomic_red_team(db)
# Handle Exception
except Exception as exc:
# Log error: "Atomic Red Team import failed: %s", exc, exc_info
logger.error("Atomic Red Team import failed: %s", exc, exc_info=True)
# Return {
return {
# Literal argument value
"message": "Import failed. Check server logs for details.",
}
# Return {
return {
# Literal argument value
"message": "Import completed",
# Literal argument value
"imported": summary["created"],
# Literal argument value
"skipped": summary["skipped_existing"],
# Literal argument value
"total_parsed": summary["total_tests_parsed"],
}
# Apply the @router.get decorator
@router.get("/scheduler-status")
# Define function scheduler_status
def scheduler_status(
# Entry: current_user
current_user: User = Depends(require_role("admin")),
) -> dict:
"""Return the current state of the background scheduler.
**Requires** the ``admin`` role.
"""
# Assign jobs = scheduler.get_jobs()
jobs = scheduler.get_jobs()
# Return {
return {
# Literal argument value
"running": scheduler.running,
# Literal argument value
"jobs": [
{
# Literal argument value
"id": job.id,
# Literal argument value
"name": job.name,
# Literal argument value
"next_run_time": str(job.next_run_time) if job.next_run_time else None,
}
for job in jobs
],
}