fix(secrets): Slack-pattern scoped credential reads — Feishu, WeCom, Photon, Buzz

FEISHU_APP_SECRET/FEISHU_ENCRYPT_KEY/FEISHU_VERIFICATION_TOKEN, WECOM_SECRET,
PHOTON_PROJECT_SECRET/PHOTON_SIDECAR_TOKEN (adapter + auth.load_project_credentials)
and BUZZ_PRIVATE_KEY now read through _get_scoped_secret.
This commit is contained in:
Teknium
2026-08-02 00:53:55 -07:00
parent 6333180c9a
commit f4b268b785
5 changed files with 130 additions and 10 deletions
+25 -1
View File
@@ -49,6 +49,30 @@ from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from urllib.parse import urlsplit, urlunsplit
from agent.secret_scope import UnscopedSecretError as _UnscopedSecretError
from agent.secret_scope import get_secret as _scoped_get_secret
def _get_scoped_secret(name, default=None):
"""Scope-aware credential read with the default-profile startup fallback.
Secondary profiles construct their adapters under a profile secret
scope -- the scope is authoritative and a scoped miss returns ``default``
(no cross-profile borrow from ``os.environ``, which may hold another
profile's value). The DEFAULT profile's adapter constructs and sends
*unscoped* under multiplexing, where a bare ``get_secret`` would raise
``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
profile's own value, so fall back to it. Same pattern as the Slack
``SLACK_APP_TOKEN`` read (#59739) and
``gateway/platforms/whatsapp_common.py::_get_wsecret``.
"""
try:
val = _scoped_get_secret(name, default)
except _UnscopedSecretError:
val = os.getenv(name)
return val if val is not None else default
logger = logging.getLogger(__name__)
from gateway.platforms.base import (
@@ -226,7 +250,7 @@ def _resolve_private_key(extra: Optional[dict] = None) -> str:
NEVER log the return value.
"""
key = os.getenv("BUZZ_PRIVATE_KEY", "").strip()
key = _get_scoped_secret("BUZZ_PRIVATE_KEY", "").strip()
if key:
return key
configured = os.getenv("BUZZ_CREDENTIALS_FILE", "").strip() or (extra or {}).get("credentials_file", "")
+27 -3
View File
@@ -145,6 +145,30 @@ from gateway.status import acquire_scoped_lock, release_scoped_lock
from hermes_constants import get_hermes_home
from utils import atomic_json_write, env_float, env_int
from agent.secret_scope import UnscopedSecretError as _UnscopedSecretError
from agent.secret_scope import get_secret as _scoped_get_secret
def _get_scoped_secret(name, default=None):
"""Scope-aware credential read with the default-profile startup fallback.
Secondary profiles construct their adapters under a profile secret
scope -- the scope is authoritative and a scoped miss returns ``default``
(no cross-profile borrow from ``os.environ``, which may hold another
profile's value). The DEFAULT profile's adapter constructs and sends
*unscoped* under multiplexing, where a bare ``get_secret`` would raise
``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
profile's own value, so fall back to it. Same pattern as the Slack
``SLACK_APP_TOKEN`` read (#59739) and
``gateway/platforms/whatsapp_common.py::_get_wsecret``.
"""
try:
val = _scoped_get_secret(name, default)
except _UnscopedSecretError:
val = os.getenv(name)
return val if val is not None else default
logger = logging.getLogger(__name__)
# ---------------------------------------------------------------------------
@@ -1553,14 +1577,14 @@ class FeishuAdapter(BasePlatformAdapter):
return FeishuAdapterSettings(
app_id=str(extra.get("app_id") or os.getenv("FEISHU_APP_ID", "")).strip(),
app_secret=str(extra.get("app_secret") or os.getenv("FEISHU_APP_SECRET", "")).strip(),
app_secret=str(extra.get("app_secret") or _get_scoped_secret("FEISHU_APP_SECRET", "")).strip(),
domain_name=str(extra.get("domain") or os.getenv("FEISHU_DOMAIN", "feishu")).strip().lower(),
connection_mode=str(
extra.get("connection_mode") or os.getenv("FEISHU_CONNECTION_MODE", "websocket")
).strip().lower(),
encrypt_key=str(extra.get("encrypt_key") or os.getenv("FEISHU_ENCRYPT_KEY", "")).strip(),
encrypt_key=str(extra.get("encrypt_key") or _get_scoped_secret("FEISHU_ENCRYPT_KEY", "")).strip(),
verification_token=str(
extra.get("verification_token") or os.getenv("FEISHU_VERIFICATION_TOKEN", "")
extra.get("verification_token") or _get_scoped_secret("FEISHU_VERIFICATION_TOKEN", "")
).strip(),
group_policy=os.getenv("FEISHU_GROUP_POLICY", "allowlist").strip().lower(),
allowed_group_users=frozenset(
+28 -4
View File
@@ -67,6 +67,30 @@ from gateway.platforms.helpers import compile_mention_patterns, strip_markdown
from .auth import load_project_credentials
from agent.secret_scope import UnscopedSecretError as _UnscopedSecretError
from agent.secret_scope import get_secret as _scoped_get_secret
def _get_scoped_secret(name, default=None):
"""Scope-aware credential read with the default-profile startup fallback.
Secondary profiles construct their adapters under a profile secret
scope -- the scope is authoritative and a scoped miss returns ``default``
(no cross-profile borrow from ``os.environ``, which may hold another
profile's value). The DEFAULT profile's adapter constructs and sends
*unscoped* under multiplexing, where a bare ``get_secret`` would raise
``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
profile's own value, so fall back to it. Same pattern as the Slack
``SLACK_APP_TOKEN`` read (#59739) and
``gateway/platforms/whatsapp_common.py::_get_wsecret``.
"""
try:
val = _scoped_get_secret(name, default)
except _UnscopedSecretError:
val = os.getenv(name)
return val if val is not None else default
logger = logging.getLogger(__name__)
# ---------------------------------------------------------------------------
@@ -511,7 +535,7 @@ def _reinstall_sidecar_deps() -> None:
def validate_config(cfg: PlatformConfig) -> bool:
extra = cfg.extra or {}
project_id = extra.get("project_id") or os.getenv("PHOTON_PROJECT_ID")
project_secret = extra.get("project_secret") or os.getenv("PHOTON_PROJECT_SECRET")
project_secret = extra.get("project_secret") or _get_scoped_secret("PHOTON_PROJECT_SECRET")
if not project_id or not project_secret:
# Fall back to auth.json
stored_id, stored_sec = load_project_credentials()
@@ -694,7 +718,7 @@ class PhotonAdapter(BasePlatformAdapter):
or ""
)
self._project_secret: str = (
os.getenv("PHOTON_PROJECT_SECRET")
_get_scoped_secret("PHOTON_PROJECT_SECRET")
or extra.get("project_secret")
or stored_sec
or ""
@@ -707,7 +731,7 @@ class PhotonAdapter(BasePlatformAdapter):
)
self._sidecar_bind = _DEFAULT_SIDECAR_BIND
self._sidecar_token = (
os.getenv("PHOTON_SIDECAR_TOKEN") or secrets.token_hex(16)
_get_scoped_secret("PHOTON_SIDECAR_TOKEN") or secrets.token_hex(16)
)
self._autostart_sidecar = str(
os.getenv("PHOTON_SIDECAR_AUTOSTART", "true")
@@ -2730,7 +2754,7 @@ async def _standalone_send(
(pconfig.extra or {}).get("sidecar_port") or os.getenv("PHOTON_SIDECAR_PORT"),
_DEFAULT_SIDECAR_PORT,
)
token = os.getenv("PHOTON_SIDECAR_TOKEN")
token = _get_scoped_secret("PHOTON_SIDECAR_TOKEN")
if not token:
# Fall back to the runtime record the gateway persists once its
# sidecar passes /healthz (issue #69960) — the token only exists in
+25 -1
View File
@@ -53,6 +53,30 @@ try:
except ImportError: # pragma: no cover - httpx is a hermes dependency
httpx = None # type: ignore[assignment]
from agent.secret_scope import UnscopedSecretError as _UnscopedSecretError
from agent.secret_scope import get_secret as _scoped_get_secret
def _get_scoped_secret(name, default=None):
"""Scope-aware credential read with the default-profile startup fallback.
Secondary profiles construct their adapters under a profile secret
scope -- the scope is authoritative and a scoped miss returns ``default``
(no cross-profile borrow from ``os.environ``, which may hold another
profile's value). The DEFAULT profile's adapter constructs and sends
*unscoped* under multiplexing, where a bare ``get_secret`` would raise
``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
profile's own value, so fall back to it. Same pattern as the Slack
``SLACK_APP_TOKEN`` read (#59739) and
``gateway/platforms/whatsapp_common.py::_get_wsecret``.
"""
try:
val = _scoped_get_secret(name, default)
except _UnscopedSecretError:
val = os.getenv(name)
return val if val is not None else default
logger = logging.getLogger(__name__)
@@ -231,7 +255,7 @@ def load_project_credentials() -> Tuple[Optional[str], Optional[str]]:
is the unified project id (dashboard id == spectrumProjectId).
"""
env_id = os.getenv("PHOTON_PROJECT_ID")
env_sec = os.getenv("PHOTON_PROJECT_SECRET")
env_sec = _get_scoped_secret("PHOTON_PROJECT_SECRET")
if env_id and env_sec:
return env_id, env_sec
auth = _load_auth()
+25 -1
View File
@@ -70,6 +70,30 @@ from gateway.platforms.base import (
)
from utils import env_float
from agent.secret_scope import UnscopedSecretError as _UnscopedSecretError
from agent.secret_scope import get_secret as _scoped_get_secret
def _get_scoped_secret(name, default=None):
"""Scope-aware credential read with the default-profile startup fallback.
Secondary profiles construct their adapters under a profile secret
scope -- the scope is authoritative and a scoped miss returns ``default``
(no cross-profile borrow from ``os.environ``, which may hold another
profile's value). The DEFAULT profile's adapter constructs and sends
*unscoped* under multiplexing, where a bare ``get_secret`` would raise
``UnscopedSecretError`` and crash this path; there ``os.environ`` is that
profile's own value, so fall back to it. Same pattern as the Slack
``SLACK_APP_TOKEN`` read (#59739) and
``gateway/platforms/whatsapp_common.py::_get_wsecret``.
"""
try:
val = _scoped_get_secret(name, default)
except _UnscopedSecretError:
val = os.getenv(name)
return val if val is not None else default
logger = logging.getLogger(__name__)
DEFAULT_WS_URL = "wss://openws.work.weixin.qq.com"
@@ -154,7 +178,7 @@ class WeComAdapter(BasePlatformAdapter):
extra = config.extra or {}
self._bot_id = str(extra.get("bot_id") or os.getenv("WECOM_BOT_ID", "")).strip()
self._secret = str(extra.get("secret") or os.getenv("WECOM_SECRET", "")).strip()
self._secret = str(extra.get("secret") or _get_scoped_secret("WECOM_SECRET", "")).strip()
self._ws_url = str(
extra.get("websocket_url")
or extra.get("websocketUrl")