Skip to content

feat(agent): dependency hooks in the Docker sandbox - #69

Merged
radim10 merged 6 commits into
masterfrom
feat/agent-dependency-hook-docker
Oct 9, 2026
Merged

radim10 merged 6 commits into
masterfrom
feat/agent-dependency-hook-docker

Conversation

@radim10

@radim10 radim10 commented Oct 9, 2026

Copy link
Copy Markdown
Member

Problem

The dependency hook (stashbase agent hooks, installed by stashbase agent hooks deps install) did not run in Docker sandbox sessions: the image has no Stashbase CLI, and Claude Code treats a missing hook command as non-blocking, so installs went unchecked without any error. Global hooks installed on the host were also invisible inside the container, whose home is the stashbase-agent-home volume.

Changes

  • Host-side agent hook route. New Agent Proxy route /__stashbase/agent-hook (requires allow_hooks = ["dependency_check"], Docker runs only). It runs the host's own stashbase agent hooks with the agent's hook payload as stdin and returns its output (the allow/deny/warn JSON). Same confinement, scratch HOME/TMPDIR, API URL, serialization and output caps as the secret-scan route; payload capped at 1 MiB, 60 s timeout.
  • stashbase stand-in in the container. When the route is served, a small script is mounted read-only at /usr/local/bin/stashbase. Existing hook configs keep working unchanged. It forwards only stashbase agent hooks and exits 2 (blocking the command) if the broker is unreachable, so installs no longer pass unchecked. Any other stashbase command is refused.
  • --docker for agent hooks deps install|check|uninstall. Writes the hook config into the Docker sandbox's home volume, shared by every Docker run, so it acts as a global install for Docker. The volume's files are staged on the host via docker run --network none with the default image, edited by the existing install logic, and copied back. Install functions now take a HookScope (Project/Global/Docker) instead of global: bool.
  • Startup and validate checks. dependency_check under Docker now requires the same confinement as secret_scan (Seatbelt on macOS, bubblewrap on Linux). The run refuses at startup before any Docker setup, and agent validate flags it.
  • Shared host-command runner extracted from the secret-scan route; both routes use it.
  • Docs: README hook sections, docs/agent-profiles.md (API Hooks), docs/sandboxing.md.

Testing

  • Unit tests: agent-hook route (stdin passthrough, key and broker mode, failure exit reporting, 413 on oversize payload, 403 without dependency_check), stand-in mount and script behavior, Docker-only enablement and confinement, Docker hook scope install/check/uninstall.
  • Manual on macOS with the Docker sandbox: npm install in a sandboxed Claude Code session is checked through the host, with both a project-level hook and a --docker-installed hook.

Notes

  • The native backend is unchanged: there the hook already runs the real CLI in broker mode.
  • Without dependency_check in the profile, the hook stays off as before (fail-open), unlike the secret scan.

@radim10 radim10 self-assigned this Oct 9, 2026
@radim10
radim10 merged commit 50c2f56 into master Oct 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant