267abfd552
* fix: /model command now auto-switches provider when model exists elsewhere Made-with: Cursor * fix: address Sourcery review - log get_models() failures in cross-provider lookup Made-with: Cursor * fix: integer branch exception handling and API key masking in model command Made-with: Cursor * fix: harden cross-provider model resolution * fix: improve model lookup resilience and cache hygiene * refactor: simplify model switch lookup flow * refactor: streamline provider model cache updates * fix: align provider annotations and key error flow * fix: narrow provider command exception handling * refactor: harden provider command error redaction and flow * fix: improve provider model lookup and secret redaction * refactor: cache normalized model names in provider lookup * refactor: simplify provider model lookup helpers * refactor: extract provider model lookup helpers * fix: harden provider lookup cancellation and redaction * refactor: streamline provider cache and lookup settings * refactor: simplify provider command setting and update helpers * refactor: streamline provider model lookup config usage * refactor: flatten provider lookup settings and filter model lookup providers * refactor: simplify provider cache and callback flow * refactor: simplify provider command model cache flow * refactor: scope provider model cache by session * fix: preserve redaction context and restore provider hooks * refactor: unify provider model lookup config flow * refactor: inline provider model cache access flow * fix: align provider lookup cache and callback semantics * refactor: centralize provider model fetch error handling * refactor: simplify provider model cache and lookup flow --------- Co-authored-by: 邹永赫 <1259085392@qq.com>
83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
import re
|
|
|
|
_SECRET_KEYS = (
|
|
r"(?:api_?key|access_?token|auth_?token|refresh_?token|session_?id|secret|password)"
|
|
)
|
|
|
|
_JSON_FIELD_PATTERN = re.compile(
|
|
rf"(?i)(?P<prefix>(?P<kq>['\"]){_SECRET_KEYS}(?P=kq)\s*:\s*)(?P<vq>['\"])(?P<value>[^'\"]+)(?P=vq)"
|
|
)
|
|
_AUTH_JSON_FIELD_PATTERN = re.compile(
|
|
r"(?i)(?P<prefix>(?P<kq>['\"])authorization(?P=kq)\s*:\s*)(?P<vq>['\"])bearer\s+[^'\"]+(?P=vq)"
|
|
)
|
|
_QUERY_FIELD_PATTERN = re.compile(
|
|
rf"(?i)(?P<prefix>{_SECRET_KEYS}\s*=\s*)(?P<value>[^&'\" ]+)"
|
|
)
|
|
_QUERY_PARAM_PATTERN = re.compile(
|
|
r"(?i)(?P<prefix>[?&](?:api_?key|key|access_?token|auth_?token)=)(?P<value>[^&'\" ]+)"
|
|
)
|
|
_AUTH_HEADER_PATTERN = re.compile(
|
|
r"(?i)(?P<prefix>\bauthorization\s*:\s*bearer\s+)(?P<token>[A-Za-z0-9._\-]+)"
|
|
)
|
|
_BEARER_PATTERN = re.compile(r"(?i)(?P<prefix>\bbearer\s+)(?P<token>[A-Za-z0-9._\-]+)")
|
|
_SK_PATTERN = re.compile(r"\bsk-[A-Za-z0-9]{16,}\b")
|
|
|
|
|
|
def _redact_json_field(match: re.Match[str]) -> str:
|
|
quote = match.group("vq")
|
|
return f"{match.group('prefix')}{quote}[REDACTED]{quote}"
|
|
|
|
|
|
def _redact_auth_json_field(match: re.Match[str]) -> str:
|
|
quote = match.group("vq")
|
|
return f"{match.group('prefix')}{quote}Bearer [REDACTED]{quote}"
|
|
|
|
|
|
def _redact_prefixed_value(match: re.Match[str]) -> str:
|
|
return f"{match.group('prefix')}[REDACTED]"
|
|
|
|
|
|
def _redact_bearer_token(match: re.Match[str]) -> str:
|
|
return f"{match.group('prefix')}[REDACTED]"
|
|
|
|
|
|
def _redact_json_like(text: str) -> str:
|
|
text = _JSON_FIELD_PATTERN.sub(_redact_json_field, text)
|
|
return _AUTH_JSON_FIELD_PATTERN.sub(_redact_auth_json_field, text)
|
|
|
|
|
|
def _redact_query_like(text: str) -> str:
|
|
text = _QUERY_FIELD_PATTERN.sub(_redact_prefixed_value, text)
|
|
return _QUERY_PARAM_PATTERN.sub(_redact_prefixed_value, text)
|
|
|
|
|
|
def _redact_tokens(text: str) -> str:
|
|
text = _AUTH_HEADER_PATTERN.sub(_redact_bearer_token, text)
|
|
text = _BEARER_PATTERN.sub(_redact_bearer_token, text)
|
|
return _SK_PATTERN.sub("[REDACTED]", text)
|
|
|
|
|
|
def redact_sensitive_text(text: str) -> str:
|
|
text = _redact_json_like(text)
|
|
text = _redact_query_like(text)
|
|
text = _redact_tokens(text)
|
|
return text
|
|
|
|
|
|
def safe_error(
|
|
prefix: str,
|
|
error: Exception | BaseException | str,
|
|
*,
|
|
redact: bool = True,
|
|
) -> str:
|
|
try:
|
|
text = str(error)
|
|
except Exception:
|
|
try:
|
|
text = repr(error)
|
|
except Exception:
|
|
text = "<unprintable error>"
|
|
if redact:
|
|
text = redact_sensitive_text(text)
|
|
return prefix + text
|