Files
hermes-agent/tools
Teknium 62a9c0f0e9 fix(file-safety): approval-gate ~/.ssh/config writes instead of hard-denying (#84663)
The write_file / patch file tools hard-denied ~/.ssh/config as a
"protected system/credential file", while the terminal tool only
*asked* for approval on ~/.ssh writes. That inconsistency meant a write
to ~/.ssh/config was refused via write_file but succeeded via terminal
after an approval prompt -- the same operation flip-flopping between
denied and OK depending on which tool ran it.

The SSH client config carries no private-key material, and editing it
(host aliases, ProxyJump, VS Code Remote-SSH targets) is a routine,
user-initiated task. It CAN carry ProxyCommand / Match exec directives
that run commands, so a free write is still inappropriate -- approval,
not a flat refusal, is the right policy, matching what the terminal tool
already does.

Changes:
- agent/file_safety.py: remove ~/.ssh/config from the flat credential
  deny; add build_write_approval_paths() + is_write_approval_required(),
  and short-circuit it out of the ~/.ssh/ prefix deny so the file is
  allowed at the classifier layer. Private keys, authorized_keys, and
  everything else under ~/.ssh/ stay hard-denied.
- tools/file_tools.py: _check_approval_required_write() routes ssh config
  writes through the shared _run_approval_gate (once/session/always,
  honors --yolo, fail-closed with no human), wired into write_file_tool
  and patch_tool right after the protected-instruction gate.
- Non-interactive consumers fail closed: the ACP file bridge
  (copilot_acp_client) rejects approval-required paths outright, and the
  TTS output-path picker refuses them as before.
- Docs + tests updated (security.md exception note;
  TestSshConfigApprovalGate covers config approval-gated, keys still
  hard-denied).
2026-08-12 11:04:45 -07:00
..