Panniantong/Agent-Reach · critical · ConfigSecurityError
{label}不能经过符号链接:{current}
Error message
{label}不能经过符号链接:{current} What it means
Config writes are hardened against symlink redirection: before atomically writing the YAML (in _atomic_write_yaml, agent_reach/config.py:43→53), the target config file path is checked with ensure_no_symlink_path. If the path to ~/.agent-reach/config.yaml traverses or ends at a symlink, a ConfigSecurityError (subclass of ConfigError/RuntimeError) is raised with the Chinese message '<label>不能经过符号链接:<path>' ('the config file path must not pass through a symlink'). This prevents an attacker from redirecting credential writes.
Source
Thrown at agent_reach/config.py:43
class ConfigError(RuntimeError):
"""Base class for configuration errors safe to show to the user."""
class ConfigReadOnlyError(ConfigError):
"""Raised when code tries to mutate an explicitly read-only config."""
class ConfigSecurityError(ConfigError):
"""Raised when a config path could redirect credential reads or writes."""
def _reject_symlink(path: Path, label: str) -> None:
try:
ensure_no_symlink_path(path, label)
except PrivatePathError as exc:
raise ConfigSecurityError(str(exc)) from exc
def _atomic_write_yaml(target: Path, data: dict) -> None:
"""Atomically replace ``target`` with owner-only YAML.
The temporary file lives beside the target so ``os.replace`` remains an
atomic same-filesystem operation. Existing symlinks are rejected rather
than followed or silently replaced.
"""
_reject_symlink(target, "配置文件")
fd, tmp_name = tempfile.mkstemp(
dir=str(target.parent),
prefix=f".{target.name}.",
suffix=".tmp",
)
tmp_path = Path(tmp_name)
try:
if os.name != "nt" and hasattr(os, "fchmod"):View on GitHub (pinned to 93ae1d18c3)
Solutions
- Replace the symlink with the real file/dir: move the actual config to ~/.agent-reach/config.yaml and remove the symlink
- If using a dotfile manager, exclude ~/.agent-reach from stow/mackup management, or have the manager copy instead of link
- Check every path component: ls -la ~/.agent-reach/ and readlink -f ~/.agent-reach/config.yaml to find the offending link
- If sharing across machines is the goal, copy the file explicitly (scp/rsync) rather than linking
Example fix
# before: symlink-managed config ~/.agent-reach/config.yaml -> ~/dotfiles/agent-reach/config.yaml # after: real file (sync by copying, not linking) rm ~/.agent-reach/config.yaml cp ~/dotfiles/agent-reach/config.yaml ~/.agent-reach/config.yaml chmod 600 ~/.agent-reach/config.yaml
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def config_path_is_safe(base: Path) -> bool:
"""True when no component of the config file path is a symlink."""
cur = base
while True:
if cur.is_symlink():
return False
if cur == cur.parent:
return True
cur = cur.parent
assert config_path_is_safe(Path.home() / ".agent-reach" / "config.yaml") Try / catch
from agent_reach.config import Config, ConfigSecurityError
try:
cfg = Config(); cfg.save()
except ConfigSecurityError as exc:
if "符号链接" in str(exc):
repair_symlinked_config() # convert link to real file, then retry
else:
raise Prevention
- Never let dotfile managers (stow/chezmoi/mackup) symlink ~/.agent-reach or its config.yaml
- After any home-directory tooling change, run `readlink -f ~/.agent-reach/config.yaml` and confirm the path is real
- Sync configs across machines by copying (rsync/scp), not by linking
When it happens
Trigger: Config.save() (or any `agent-reach configure` write) when ~/.agent-reach/config.yaml is a symlink to another location, or when ~/.agent-reach itself is a symlink (that case is labeled 配置目录 instead). Dotfile managers (stow, chezmoi, mackup) commonly create such symlinks.
Common situations: Users managing dotfiles with GNU stow or mackup symlinking ~/.agent-reach into a repo; multi-user setups sharing one config via symlink; sandboxed environments that symlink home subdirectories.
Related errors
- gh hosts.yml 无法安全读取
- gh hosts.yml 不是有效的 UTF-8 YAML
- gh hosts.yml 顶层必须是对象
- gh hosts.yml 的 github.com 配置无效
- gh hosts.yml 的 users 配置无效
AI-assisted analysis of Panniantong/Agent-Reach@93ae1d18c3 (2026-08-14).
Data as JSON: /api/errors/90db115f4894f72a.
Report an issue: GitHub.