Skip to content

Server & security middleware

Modules: server.py, security.py, config.py, cli.py (serve)

The server is a FastAPI application that exposes the engines over HTTP, serves the dashboard, and enforces the security policy for every request.

Request lifecycle

sequenceDiagram
    participant C as Client
    participant M as SecurityMiddleware
    participant R as Route handler
    participant E as Engines
    C->>M: HTTP request
    M->>M: Host header allowed?
    M->>M: State-changing → same Origin?
    M->>M: Token required → valid?
    alt rejected
        M-->>C: 400 / 403 / 401 (or redirect to /login)
    else accepted
        M->>R: forward
        R->>E: validated Pydantic input
        E-->>R: result
        R-->>M: response
        M-->>C: response + CSP, X-Frame-Options, nosniff, no-referrer, no-store
    end

Unhandled exceptions are logged server-side and returned as a generic 500 naming only the exception type, so command output and internals never reach the client.

Route groups

Group Examples Notes
Service /api/healthz, /api/version healthz is public for supervisors
Snapshot & diagnosis /api/v09/overview, /api/compare, /api/report, /api/live-rules Overview runs collector and capability probes in parallel; live-rules scores every published rule on the pair plus this host’s graph
Live graph /api/topics, /api/topic-inspect, /api/topic-sample, /api/graph Wrap live.py; /api/graph uses graph.py (one rclpy discovery pass, ros2 CLI fallback)
Endpoint check /api/endpoint-check Native C++ core when built, else the Python fallback in core.py; both emit the same codes (Endpoint check)
AI /api/assistant/stream, /api/rviz/plan, /api/ai/providers/* Streaming via StreamingResponse
Collector /api/agent/snapshot Always routed, but answers 403 unless AUTODIAG_AGENT_TOKEN is set; token in X-Autodiag-Token
UI /, /static/*, /login, /legacy, /api/docs Strict CSP (no inline script); /legacy and /api/docs allow inline

The full list is in the REST API reference.

Configuration

config.settings() reads AUTODIAG_* variables on every call instead of caching them at import time, so tests and long-running servers always see the current values. public_settings() is the only view of configuration exposed to clients and never contains secrets.

Safe startup

dds-autodiag serve refuses to bind to a non-loopback address unless AUTODIAG_UI_TOKEN is set (or --insecure-no-auth is passed explicitly), and warns when ROS 2 isn't sourced. See Security model.