Register runtime.break_glass_restart in the multi-service operation normalizer and enforce it through the real profile gate. Authorize only the exact trusted prgs-controller profile plus that capability; remove substring controller authority so declared reconciler roles and cleanup_merged_pr_branch semantics are preserved. Route non-dry-run apply through a canonical injectable executor delegate with truthful execution flags. Correct under/over-redaction for credentials while preserving benign sec- text. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
+64
-4
@@ -34,10 +34,34 @@ PENDING = "pending"
|
||||
REDACTED = "[REDACTED]"
|
||||
|
||||
# A dict key containing any of these (case-insensitive) has its value redacted.
|
||||
_SECRET_KEY_HINTS = ("token", "password", "secret", "authorization", "auth")
|
||||
_SECRET_KEY_HINTS = (
|
||||
"token",
|
||||
"password",
|
||||
"passwd",
|
||||
"pwd",
|
||||
"secret",
|
||||
"authorization",
|
||||
"auth",
|
||||
"api_key",
|
||||
"apikey",
|
||||
"access_key",
|
||||
"private_key",
|
||||
"client_secret",
|
||||
"credential",
|
||||
)
|
||||
# A string value starting with one of these has the following run redacted.
|
||||
_SECRET_VALUE_PREFIXES = ("token ", "Basic ", "Bearer ", "token:", "bearer:", "basic:")
|
||||
# Space-terminated scheme prefixes only. Colon forms (``token:`` / ``api_key:``)
|
||||
# and ``Authorization: Bearer …`` are handled by ``_ASSIGNMENT_SECRET_PATTERN``
|
||||
# so policy/docs text that merely *names* a scheme is not itself flagged as a
|
||||
# live secret by console detectors.
|
||||
_SECRET_VALUE_PREFIXES = (
|
||||
"token ",
|
||||
"Basic ",
|
||||
"Bearer ",
|
||||
)
|
||||
|
||||
# Bare token-shaped values only — never a broad ``sec-`` prefix that erases
|
||||
# ordinary words (#664 B8 over-redaction).
|
||||
_BARE_SECRET_PATTERN = re.compile(
|
||||
r'(?i)\b(?:'
|
||||
r'ghp_[A-Za-z0-9_]{16,}'
|
||||
@@ -49,10 +73,28 @@ _BARE_SECRET_PATTERN = re.compile(
|
||||
r'|sk-proj-[A-Za-z0-9_-]{16,}'
|
||||
r'|sk-[A-Za-z0-9_-]{20,}'
|
||||
r'|glpat-[A-Za-z0-9_-]{16,}'
|
||||
r'|sec-[A-Za-z0-9_-]{16,}'
|
||||
r')\b'
|
||||
)
|
||||
|
||||
# Key/value credentials embedded in free text (password=..., api_key: ..., etc.).
|
||||
# Value group accepts quoted strings, Authorization scheme + credential
|
||||
# (Bearer/Basic/Token + token), or a single non-space run.
|
||||
_ASSIGNMENT_SECRET_PATTERN = re.compile(
|
||||
r'(?i)\b('
|
||||
r'token|password|passwd|pwd|secret|api[_-]?key|access[_-]?key|'
|
||||
r'client[_-]?secret|private[_-]?key|authorization|credential'
|
||||
r')\b(\s*[:=]\s*)('
|
||||
r'"[^"]*"|\'[^\']*\'|'
|
||||
r'(?:Bearer|Basic|Token)\s+\S+|'
|
||||
r'\S+'
|
||||
r')'
|
||||
)
|
||||
|
||||
# Connection-string style credentials: Password=...; User ID=...; etc.
|
||||
_CONN_STRING_SECRET_PATTERN = re.compile(
|
||||
r'(?i)\b((?:password|pwd|user\s*id|uid|username|account)\s*=\s*)([^\s;\'"]+)'
|
||||
)
|
||||
|
||||
|
||||
# Known synthetic test-only domains/hostnames to preserve
|
||||
_SYNTHETIC_HOSTS = {
|
||||
@@ -133,11 +175,29 @@ def redact_urls(text: str) -> str:
|
||||
return out
|
||||
|
||||
|
||||
def _mask_assignment(match: re.Match) -> str:
|
||||
"""Keep the key and separator; replace only the secret value."""
|
||||
return f"{match.group(1)}{match.group(2)}{REDACTED}"
|
||||
|
||||
|
||||
def _mask_conn_secret(match: re.Match) -> str:
|
||||
"""Keep the connection-string key; replace only the credential value."""
|
||||
return f"{match.group(1)}{REDACTED}"
|
||||
|
||||
|
||||
def _redact_str(text):
|
||||
"""Redact anything that looks like an Authorization credential, bare secret token, or raw URL in *text*."""
|
||||
"""Redact credentials, bare token shapes, and raw URLs in *text* (#664 B8).
|
||||
|
||||
Covers key/value credentials, authorization/bearer material, bare
|
||||
token-shaped values, connection-string credentials, and secrets embedded
|
||||
in larger sentences. Deliberately does **not** erase ordinary words that
|
||||
merely begin with a broad ``sec-`` prefix.
|
||||
"""
|
||||
if not isinstance(text, str) or not text:
|
||||
return text
|
||||
out = _BARE_SECRET_PATTERN.sub(REDACTED, text)
|
||||
out = _ASSIGNMENT_SECRET_PATTERN.sub(_mask_assignment, out)
|
||||
out = _CONN_STRING_SECRET_PATTERN.sub(_mask_conn_secret, out)
|
||||
out_lower = out.lower()
|
||||
for prefix in _SECRET_VALUE_PREFIXES:
|
||||
prefix_lower = prefix.lower()
|
||||
|
||||
Reference in New Issue
Block a user