mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-06-18 21:55:59 +00:00
fix(channels): harden runtime credential management APIs (#3581)
* fix(channels): harden runtime credential management APIs * fix(channels): address review feedback on credential hardening Follow-up to the runtime credential-hardening pass, resolving five review findings: - WeChat auth persistence now writes through a 0o600 NamedTemporaryFile + Path.replace instead of write_text-then-chmod, so the iLink bot_token is never briefly readable at umask defaults (mirrors ChannelRuntimeConfigStore). - The post-write chmod is split into its own try/except: a chmod failure on a filesystem without POSIX perms now logs at debug instead of masquerading as a "failed to persist" warning. - Extracted the three near-identical _require_admin_user helpers (mcp, channel_connections, channels) into a single require_admin_user(request, *, detail) in app/gateway/deps.py; each router supplies its own detail string. - Strengthened the runtime-config-store chmod coverage: a new test injects a temp-file chmod failure and asserts it is logged at debug while the destination is still owner-only (mutation-verified to fail if the chmod is dropped), plus a loose-pre-existing-file case. - Removed the unused _FakeRepo from the blocking-io test: its isinstance gate routes through the repo-less 503 path, so neither stub was ever invoked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import json
|
||||
import logging
|
||||
import mimetypes
|
||||
import secrets
|
||||
import tempfile
|
||||
import time
|
||||
from collections.abc import Mapping
|
||||
from enum import IntEnum
|
||||
@@ -1376,9 +1377,29 @@ class WechatChannel(Channel):
|
||||
if self._auth_path:
|
||||
try:
|
||||
self._auth_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self._auth_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
# Write through a 0o600 temp file and atomically rename so the
|
||||
# iLink bot_token is never briefly readable at umask defaults
|
||||
# (mirrors ChannelRuntimeConfigStore._save). NamedTemporaryFile
|
||||
# uses mkstemp, which creates the file at 0o600 from the start.
|
||||
fd = tempfile.NamedTemporaryFile(mode="w", dir=self._auth_path.parent, suffix=".tmp", delete=False, encoding="utf-8")
|
||||
try:
|
||||
json.dump(data, fd, ensure_ascii=False, indent=2)
|
||||
fd.close()
|
||||
Path(fd.name).replace(self._auth_path)
|
||||
except BaseException:
|
||||
fd.close()
|
||||
Path(fd.name).unlink(missing_ok=True)
|
||||
raise
|
||||
except OSError:
|
||||
logger.warning("[WeChat] failed to persist auth state to %s", self._auth_path)
|
||||
else:
|
||||
# Hardening only; the destination already inherits 0o600 from the
|
||||
# temp file. A chmod failure on filesystems without POSIX perms
|
||||
# must not masquerade as a persist failure.
|
||||
try:
|
||||
self._auth_path.chmod(0o600)
|
||||
except OSError:
|
||||
logger.debug("[WeChat] unable to chmod auth state at %s", self._auth_path, exc_info=True)
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
|
||||
Reference in New Issue
Block a user