harden(mail): address PR #935 round-5 review
No blockers raised; residual cleanup: - processor.py: guard int(doc_task.doc_id) with is_valid_nextcloud_doc_id in the mail_message branch (consistent with search/context.py + the verifier). - mail metadata symmetry: store `bcc` in file_metadata and the Qdrant payload alongside cc (build_mail_content already emits a Bcc: line). - server/mail.py: extract _cap_attachment_content helper (byte-accurate cap) and unit-test it (small/None/oversized/multibyte). - client/mail.py: give the synthetic OCS-error Response an explicit empty body; add a test that a traversal-style attachment_id is percent-encoded. - models/mail.py: clarify ListMessagesResponse.total_count is the page count, not the mailbox total. Deferred (Deck #376): _potentially_deleted doc_type-in-key. It's pre-existing and spans ~30 sites across the notes/news/deck/file/mail scanners (whose deletion paths have no unit coverage), so it belongs in its own focused PR rather than expanding this mail PR's blast radius into other doc types. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0856d59956
commit
d006145444
@@ -42,6 +42,7 @@ from nextcloud_mcp_server.observability.metrics import (
|
||||
from nextcloud_mcp_server.observability.tracing import trace_operation
|
||||
from nextcloud_mcp_server.search.pdf_highlighter import PDFHighlighter
|
||||
from nextcloud_mcp_server.usage import UsageEventStore
|
||||
from nextcloud_mcp_server.utils.validation import is_valid_nextcloud_doc_id
|
||||
from nextcloud_mcp_server.vector import payload_keys
|
||||
from nextcloud_mcp_server.vector._errors import format_exception_group
|
||||
from nextcloud_mcp_server.vector.dead_letter import (
|
||||
@@ -848,6 +849,11 @@ async def _index_document(
|
||||
# Fetch the full message via the Mail OCS API. The Mail app handles
|
||||
# IMAP server-side; we only ever speak HTTP. build_mail_content is
|
||||
# shared with search/context.py so index- and query-time text match.
|
||||
# Guard the cast before the network call (consistent with the same
|
||||
# doc_type in search/context.py) so a malformed queue record produces
|
||||
# a specific error rather than a bare ValueError.
|
||||
if not is_valid_nextcloud_doc_id(doc_task.doc_id):
|
||||
raise ValueError(f"Invalid mail_message doc_id: {doc_task.doc_id!r}")
|
||||
message = await nc_client.mail.get_message(int(doc_task.doc_id))
|
||||
content = build_mail_content(message)
|
||||
|
||||
@@ -861,6 +867,7 @@ async def _index_document(
|
||||
"from": format_mail_addresses(message.get("from")),
|
||||
"to": format_mail_addresses(message.get("to")),
|
||||
"cc": format_mail_addresses(message.get("cc")),
|
||||
"bcc": format_mail_addresses(message.get("bcc")),
|
||||
"date_int": message.get("dateInt"),
|
||||
"has_attachments": bool(message.get("attachments")),
|
||||
"account_id": (doc_task.metadata or {}).get("account_id"),
|
||||
@@ -1640,6 +1647,7 @@ async def _index_document(
|
||||
"from": file_metadata.get("from"),
|
||||
"to": file_metadata.get("to"),
|
||||
"cc": file_metadata.get("cc"),
|
||||
"bcc": file_metadata.get("bcc"),
|
||||
"date_int": file_metadata.get("date_int"),
|
||||
"has_attachments": file_metadata.get("has_attachments"),
|
||||
"account_id": file_metadata.get("account_id"),
|
||||
|
||||
Reference in New Issue
Block a user