mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-09 13:21:42 +00:00
* fix(docker): heal pairing-dir ownership after `docker exec` writes (#10270) The official Docker image runs the gateway as the unprivileged `hermes` user (uid 10000) via `gosu`, but `docker exec` defaults to root. Approval files written by `docker exec <container> hermes pairing approve <code>` end up as `-rw------- root:root`, and the post-gosu gateway process cannot read them. The approval is silently ignored — the user keeps hitting 'Unauthorized user' on every message. The entrypoint's existing top-level chown is gated on the top-level $HERMES_HOME being mis-owned, so on warm boots (where /opt/data is already hermes:hermes) the recursive chown is skipped — meaning a container restart does NOT self-heal the bug either. Three-part fix: 1. docker/entrypoint.sh: chown the platforms/pairing/ (and legacy pairing/) subtree on every container start, regardless of the top-level decision. The directory is tiny (a few JSON files), so the unconditional chown is effectively free. Container restart now self-heals. 2. gateway/pairing.py: PairingStore._load_json was swallowing PermissionError under its bare 'except OSError' branch, which is what made this a silent failure. Split it out: log a WARNING that names the file, the gateway's uid, the file's owner/mode, and the exact docker exec -u hermes workaround. Still falls back to {} so the gateway stays up. 3. website/docs/user-guide/security.md: add a Docker tip to the pairing-CLI section pointing users at `docker exec -u hermes …` up front. Reproduced end-to-end in a containerized harness — before the fix the gateway sees 0 approved users after `docker exec` + restart; after the fix it sees the expected 1, and the file on disk goes from `root:root 600` back to `hermes:hermes 600` on next start. Fixes #10270 * fix(pairing): gate os.geteuid for Windows in PermissionError warning |
||
|---|---|---|
| .. | ||
| assets | ||
| builtin_hooks | ||
| platforms | ||
| relay | ||
| __init__.py | ||
| authz_mixin.py | ||
| cgroup_cleanup.py | ||
| channel_directory.py | ||
| code_skew.py | ||
| config.py | ||
| cwd_placeholder.py | ||
| dead_targets.py | ||
| delivery.py | ||
| display_config.py | ||
| drain_control.py | ||
| hooks.py | ||
| kanban_watchers.py | ||
| memory_monitor.py | ||
| message_timestamps.py | ||
| mirror.py | ||
| pairing.py | ||
| platform_registry.py | ||
| response_filters.py | ||
| restart.py | ||
| restart_loop_guard.py | ||
| rich_sent_store.py | ||
| run.py | ||
| runtime_footer.py | ||
| scale_to_zero.py | ||
| session.py | ||
| session_context.py | ||
| shutdown_forensics.py | ||
| slash_access.py | ||
| slash_commands.py | ||
| status.py | ||
| status_phrases.py | ||
| sticker_cache.py | ||
| stream_consumer.py | ||
| stream_dispatch.py | ||
| stream_events.py | ||
| whatsapp_identity.py | ||