-
fix(chat): post-merge audit follow-ups — API validation, DRY, logging, a11y, tests (#3891) (#4427)
发布于
2026-06-05 19:21:31 +00:00 - fix(chat): post-merge audit follow-ups — API validation, DRY, logging, a11y, tests (#3891)
Addresses the still-open, non-in-flight items from the chat-mode-v2
post-merge audit (#3891):- L_API1: send_message now rejects a non-boolean
trigger_researchwith
HTTP 400 instead of silently coercing a truthy value (e.g. "false") to
True and launching unwanted research. - L_SEC1: chat-session deletion logs the truncated username alongside the
session id, leaving a forensic trail for stolen-token bulk deletes. - M_DRY2: the duplicated atomic
UPDATE … RETURNINGcounter logic in
insert_message_in_db (message_count) and add_progress_step (step_count)
is extracted into a shared_atomic_incrementhelper. - M_LOG1: chat.js logs (instead of swallowing) a failed background
title-generation request. - L_FE1: the Markdown export documents that its output is a human-readable
archive that is not safe to feed back into a Markdown/HTML renderer
without escaping (assistant turns are themselves Markdown, so escaping
message content would corrupt legitimate formatting). - N_TEXTAREA / N_BTN_LABEL: chat input gains aria-required; welcome
suggestion buttons gain descriptive aria-labels.
Tests:
- H_TEST3: new tests/chat/test_chat_pagination_cap.py seeds 100+ messages
(disabling the send-route rate limiter) and asserts GET /messages clamps
an oversized limit to 100 and reports has_more — closing the gap the
existing test_pagination_limits_enforced flagged inline. - H_TEST2: TestRenderTimeEscaping asserts Jinja2 autoescape escapes a
script/HTML payload (the "silently disabled" regression guard) and that
the chat render path stays wired through the DOMPurify-backed
renderMarkdown / textContent fallback. - Updated test_trigger_research_non_boolean to the new 400 contract and
added a positive bool/default-accepted test.
Items confirmed already shipped in main (M_SEC1 PATCH/DELETE limits,
H_LOG1/H_LOG2/H_LOG3, M_DRY3, M_INTEG2) or covered by open PRs (#4350 dead
context code, #4357/#4358 follow-up context) are intentionally untouched.下载附件