fix(python-client): redact operator password from AcknowledgeAlarmReply errors

Claude-Session: https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
This commit is contained in:
Joseph Doherty
2026-10-19 19:44:49 -04:00
parent 7b81cb7f72
commit 027cc7393d
2 changed files with 45 additions and 6 deletions
@@ -3,6 +3,7 @@
from __future__ import annotations
from collections.abc import AsyncIterator, Sequence
from typing import Any
from .auth import redact_secret
from .errors import MalformedReplyError, MxGatewayError, ensure_mxaccess_success
@@ -943,22 +944,26 @@ def _redact_error(error: MxGatewayError, secrets: Sequence[str | None]) -> None:
error.raw_reply = _redact_reply(error.raw_reply, scrubbed)
def _redact_reply(reply: pb.MxCommandReply, secrets: Sequence[str]) -> pb.MxCommandReply:
def _redact_reply(reply: Any, secrets: Sequence[str]) -> Any:
"""Return a deep copy of *reply* with credential text scrubbed from diagnostics.
Operates on a clone so the caller's original reply object is never mutated.
Only the free-text diagnostic fields that can echo a client-supplied secret
are scrubbed; the structured/enum fields the gateway itself sets are left as-is.
Works for any reply message (``MxCommandReply``, ``AcknowledgeAlarmReply``, ...):
each field is scrubbed only when the message type declares it.
"""
clone = type(reply)()
clone.CopyFrom(reply)
if clone.protocol_status.message:
fields = clone.DESCRIPTOR.fields_by_name
if "protocol_status" in fields and clone.protocol_status.message:
clone.protocol_status.message = redact_secret(clone.protocol_status.message, secrets)
if clone.diagnostic_message:
if "diagnostic_message" in fields and clone.diagnostic_message:
clone.diagnostic_message = redact_secret(clone.diagnostic_message, secrets)
for status in clone.statuses:
if status.diagnostic_text:
status.diagnostic_text = redact_secret(status.diagnostic_text, secrets)
if "statuses" in fields:
for status in clone.statuses:
if status.diagnostic_text:
status.diagnostic_text = redact_secret(status.diagnostic_text, secrets)
return clone