From f8943991659db7a57ed5d4f3f7d339c342f1efdc Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 25 Apr 2026 21:50:57 +0200 Subject: [PATCH] =?UTF-8?q?feat(agent):=20isolate=20from=20erik=20?= =?UTF-8?q?=E2=80=94=20dedicated=20overlord-agent=20user?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The agent service was running as User=erik, which meant: - Sessions polluted erik's ~/.claude/projects/ - erik's .claude/settings.local.json (months of accumulated dev permissions for docker/git/dotnet/etc.) was loaded by the production agent, defeating the --allowed-tools whitelist - Subscription rate quota mingled between human-erik's interactive Claude Code use and the production assistant - Theoretical access to /home/erik/.ssh, .bash_history, .gitconfig Now: - User=overlord-agent (system account, no shell, /var/lib/overlord-agent home) - HOME=/var/lib/overlord-agent — claude state fully isolated from erik - /home/erik/.claude permissions tightened to 0700 (was 0755) - group=overlord-agent on the repo + /etc/overlord/agent.env (read-only) Project settings: - New strict committed .claude/settings.json: deny Bash/Read/Write/Edit/ Glob/Grep/NotebookEdit/WebSearch; allow only WebFetch(domain:acpedia.org) - .claude/settings.local.json now gitignored (was leaking dev permissions to the server through the deploy) --- .claude/settings.json | 19 +++++++++++++++++++ .gitignore | 5 +++++ agent/overlord-agent.service | 32 ++++++++++++++++++-------------- 3 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 .claude/settings.json diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..9f471bab --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,19 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:acpedia.org)" + ], + "deny": [ + "Bash", + "Write", + "Edit", + "Read", + "Glob", + "Grep", + "NotebookEdit", + "WebSearch" + ], + "ask": [] + }, + "enableAllProjectMcpServers": true +} diff --git a/.gitignore b/.gitignore index e7b24d9a..5eb460cd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,8 @@ __pycache__ static/v2/ frontend/node_modules/ + +# Claude Code per-machine permissions (do NOT deploy to server — production +# agent must run with the strict permissions in committed .claude/settings.json) +.claude/settings.local.json +.claude/settings.local.json.* diff --git a/agent/overlord-agent.service b/agent/overlord-agent.service index d9f75220..6f40f5dd 100644 --- a/agent/overlord-agent.service +++ b/agent/overlord-agent.service @@ -5,18 +5,23 @@ Wants=network-online.target [Service] Type=simple -User=erik -Group=erik -# Working directory MUST be the repo root so: -# - claude -p sessions land at ~/.claude/projects/-home-erik-MosswartOverlord/ -# - .mcp.json is auto-loaded +# Dedicated unprivileged user — kernel-level isolation from `erik`. +# overlord-agent has NO access to /home/erik/.claude (mode 0700), +# /home/erik/.ssh, /home/erik/.bash_history, /home/erik/.gitconfig, etc. +# Its own claude state lives at /var/lib/overlord-agent/.claude/ and its +# claude session JSONLs land there — completely separate from any +# interactive Claude Code use by the human user. +User=overlord-agent +Group=overlord-agent +# Working directory: the repo root (group-readable to overlord-agent). +# claude session JSONLs path-encode this cwd so it's important to keep +# stable across restarts. WorkingDirectory=/home/erik/MosswartOverlord -# Secrets moved OUT of /home/erik/ to /etc/overlord/agent.env so -# ProtectHome=read-only blocks their read entirely. The file is -# root-owned, mode 0640, group=erik. +# HOME explicitly set so claude reads /var/lib/overlord-agent/.claude/* +# instead of trying /home/erik/.claude/* (which is now 0700, locked out). +Environment="HOME=/var/lib/overlord-agent" +# Secrets file (root:overlord-agent 0640). EnvironmentFile=-/etc/overlord/agent.env -# Backwards-compat: also try the old location during transition. -EnvironmentFile=-/home/erik/MosswartOverlord/.env # Run inside the venv populated by install.sh. ExecStart=/home/erik/MosswartOverlord/agent/.venv/bin/python -m agent.service Restart=on-failure @@ -37,12 +42,11 @@ ProtectHome=read-only # Allow writing only to the explicit paths claude / our service need. # - ~/.claude — session JSONL files # - .venv pycache — minor pip cache writes -ReadWritePaths=/home/erik/.claude +ReadWritePaths=/var/lib/overlord-agent/.claude ReadWritePaths=/home/erik/MosswartOverlord/agent/.venv ReadWritePaths=/var/log/overlord-agent -# Keep $HOME visible to the venv python so it can find pip cache etc. -# (read-only via ProtectHome=read-only — this writable carve-out is -# narrowly the .claude session dir above.) +# StateDirectory creates/owns /var/lib/overlord-agent automatically. +StateDirectory=overlord-agent LogsDirectory=overlord-agent LogsDirectoryMode=0755 PrivateTmp=true