1818 from requests import Response
1919
2020
21- # D-013: cap how much of a response body we splice into an exception's human-facing
22- # message. The full body remains available to callers via :attr:`SafeguardError.response_body`
23- # for diagnostic use; this limit only bounds what lands in ``str(exc)`` (the form that
24- # typically reaches logs, crash reporters, and SIEMs). Truncation — not field-level
25- # redaction — is the chosen mitigation: it never wrongly masks legitimate Safeguard
26- # payload fields like ``PasswordRulesPolicyId``, ``ApiKeyName``, or
27- # ``RequirePasswordChange``.
28- _MAX_BODY_IN_MESSAGE = 200
29-
30-
31- def _truncate_for_message (body : str | None , limit : int = _MAX_BODY_IN_MESSAGE ) -> str :
32- """Bound a response body for inclusion in a human-readable exception message.
33-
34- Returns ``body`` unchanged if it is already at or under ``limit`` characters,
35- otherwise returns the first ``limit`` characters followed by a
36- ``... (truncated, N total chars)`` marker so the reader knows it was elided.
37- """
38- if body is None :
39- return ""
40- if len (body ) <= limit :
41- return body
42- return f"{ body [:limit ]} ... (truncated, { len (body )} total chars)"
43-
4421
4522class SafeguardError (Exception ):
4623 """Base exception for all PySafeguard errors.
@@ -105,9 +82,9 @@ class ApiError(SafeguardError):
10582 @classmethod
10683 def from_response (cls , resp : Response ) -> ApiError :
10784 """Create an ApiError from a sync ``requests.Response``."""
108- body = resp .text
109- message = f"{ resp .status_code } { resp .reason } : { resp .request .method } { resp .url } \n { _truncate_for_message (body )} "
85+ message = f"{ resp .status_code } { resp .reason } : { resp .request .method } { resp .url } \n { resp .text } "
11086 status_code = resp .status_code
87+ body = resp .text
11188
11289 subclass = _STATUS_MAP .get (status_code , cls )
11390 return subclass (message , status_code = status_code , response_body = body )
@@ -120,7 +97,7 @@ def from_async_response(cls, resp: ClientResponse, body: str) -> ApiError:
12097 :param body: The response body text (must be read by the caller
12198 with ``await resp.text()`` before calling this method).
12299 """
123- message = f"{ resp .status } { resp .reason } : { resp .method } { resp .url } \n { _truncate_for_message ( body ) } "
100+ message = f"{ resp .status } { resp .reason } : { resp .method } { resp .url } \n { body } "
124101 status_code = resp .status
125102
126103 subclass = _STATUS_MAP .get (status_code , cls )
0 commit comments