Add was_pii_redacted and pii_types_redacted to the ai_chat audit log
entry. Both are tracked through the full_message build block (typed
message + attachments) so any redaction that occurs is always
reflected in the compliance record.
Fix response.user_message + suffix potentially yielding 'undefined...'
when user_message is absent. Now unconditionally calls
updateMessageContent with (response.user_message ?? message) + suffix,
so the bubble always shows a valid string regardless of backend build.
Update TICKET-pii-bypass-chat-attachments.md to reflect the final
auto-redact design (not block/warn) so automated review comparisons
against the ticket stop flagging design decisions as defects.
File attachments were embedded into AI messages without any PII
scanning, allowing credentials, tokens, and other sensitive data
to be forwarded to AI providers in plaintext.
Typed chat messages had the same gap: a user could type a password
or API key directly and it would be sent unscanned.
Changes:
- chat_message (Rust): defence-in-depth scan of all attachment body
content (between --- Attached: markers); hard rejects if PII found
- detect_pii (Rust): fix return type from pii::PiiDetectionResult
(spans/original_text) to db::models::PiiDetectionResult
(detections/total_pii_found) to match the TypeScript contract; the
LogUpload PII review workflow was receiving undefined for detections
- scan_text_for_pii (Rust): new command — scans arbitrary text for PII
without creating DB records; used for typed message warnings
- Triage/index.tsx: PendingFile now carries logFileId; handleSend gates
each text attachment through detectPiiCmd (hard block on PII found);
typed message text scanned via scanTextForPiiCmd with a one-time
warning — second send of same message proceeds as acknowledgment