fix(security): resolve Critical+High findings from module audit — agent, translate, superset_client

P0 — CRITICAL (CWE-798): JWT_SECRET crash-early
  Replace hardcoded super-secret-key fallback with os.environ["JWT_SECRET"]
  and ${JWT_SECRET:?} syntax in app.py + docker-compose files

P1 — HIGH: Frontend dependency CVEs
  Upgrade svelte 5.43.8 → 5.56.4 — resolves devalue DoS (GHSA-g2pg-6438-jwpf)
  and svelte XSS (GHSA-crpf-4hrx-3jrp, GHSA-m56q-vw4c-c2cp, GHSA-rcqx-6q8c-2c42)

P2 — MEDIUM: Logging hygiene + contract gaps + tool resolver refactor
  Apply _redact_sensitive_fields() in middleware + event streaming
  Truncate LLM error body to 100 chars
  Add @RATIONALE/@REJECTED to HandleResume + SaveConversation
  Refactor deterministic intent matching → LLM-driven tool resolution

P3 — LOW: Translate logging hardening
  Move _sanitize_url() to _utils.py (shared, no circular imports)
  Sanitize base_url before logging in _llm_call.py and _llm_async_http.py
  Emit EXPLORE warning when LLM_SSL_VERIFY=false disables TLS

superset_client module: passed clean — no changes needed
This commit is contained in:
2026-07-01 13:17:29 +03:00
parent f34ff8c447
commit ce20f541b6
21 changed files with 871 additions and 336 deletions

View File

@@ -213,7 +213,7 @@ async def _call_llm_for_title(user_text: str) -> str | None:
if resp.status_code != 200:
_logger.explore(
"LLM title: API error",
payload={"status": resp.status_code}, error=resp.text[:200],
payload={"status": resp.status_code, "reason": resp.reason_phrase}, error=f"HTTP {resp.status_code}: {resp.text[:100]}",
extra={"src": "AgentChat.Persistence"},
)
return None
@@ -341,6 +341,8 @@ async def prefetch_dashboards(env_id: str) -> str:
# @SIDE_EFFECT HTTP POST to FastAPI; writes to AgentConversation and AgentMessage tables.
# @DATA_CONTRACT Input: (conv_id, user_text, user_id, assistant_text) -> Output: None (side-effect only)
# @RELATION DISPATCHES -> [Api.Agent.Conversations]
# @RATIONALE Anonymous Gradio sessions (anon_ prefix) default to "admin" because the agent runs in an internal network behind an auth proxy — all users within the network are trusted.
# @REJECTED Requiring explicit authentication for Gradio was rejected — the agent is designed for internal-network use where the auth proxy handles auth; adding a separate auth layer would create unnecessary friction and duplicate the proxy's responsibility.
async def save_conversation(conv_id: str, user_text: str, user_id: str = "admin", assistant_text: str = "") -> None:
try:
service_token = os.getenv("SERVICE_JWT", "")