Skip to content

Latest commit

 

History

History
134 lines (107 loc) · 3.43 KB

File metadata and controls

134 lines (107 loc) · 3.43 KB

Scenario — Run an AI agent inside a linpodx sandbox

This walks through running an AI-agent CLI inside a sandboxed linpodx container so it can execute shell commands without touching the host.

What you get

  • Container has its own rootfs and $HOME.
  • Egress is filtered to a DNS allowlist (no exfiltration to arbitrary hosts).
  • Every shell command the agent runs flows through an approval gate; auto-allow, prompt, or deny per rule.
  • Audit log entry per command, hash-chained.

Prerequisites

  • linpodx daemon running (linpodx-daemon & or systemd user unit).
  • Podman ≥ 4.6.0 rootless.
  • A YAML sandbox profile (we'll create one).

1. Author the profile

~/.config/linpodx/profiles/agent-readonly.yml:

name: agent-readonly
description: AI agent sandbox — read-only host project mount, prompt on writes
mounts:
  - source: ${HOME}/projects/demo
    target: /work
    read_only: true
network:
  egress_dns_allowlist:
    - registry.npmjs.org
    - crates.io
mcp_policy:
  - method: tools/call
    tool_name: read_file
    decision: auto_allow
  - method: tools/call
    tool_name: write_file
    decision: prompt
  - method: tools/call
    decision: prompt
audit:
  hash_chain: true

Validate it:

$ linpodx sandbox validate ~/.config/linpodx/profiles/agent-readonly.yml
profile: agent-readonly
status:  ok
mounts:  1
egress:  2 hosts allowed
mcp:     3 rules

2. Apply the profile

$ linpodx sandbox apply --profile ~/.config/linpodx/profiles/agent-readonly.yml
profile_id: prof_01HZ...
audit_hash: 9f2c8a1c...

3. Launch the container with the profile

$ linpodx run \
    --profile agent-readonly \
    --image docker.io/library/node:20-alpine \
    --interactive --tty \
    --name agent-1
container_id: abc123...
state:        running

4. Start the MCP bridge

In a second terminal:

$ linpodx mcp attach --container agent-1 -- automation-agent mcp serve
mcp_session_id: sess_01HZ...
bridge:         host stdio <-> container stdio
policy:         3 rules loaded

5. Watch approvals as they arrive

$ linpodx events --filter approval
[2026-05-10T09:14:02Z] sess_01HZ... tools/call write_file → PROMPT
   payload: {"path":"/work/src/index.ts","content":"..."}
   approve? [y/N]: n
[2026-05-10T09:14:09Z] sess_01HZ... tools/call read_file → AUTO_ALLOW
[2026-05-10T09:14:11Z] sess_01HZ... tools/call write_file → PROMPT
   payload: {"path":"/work/notes.md","content":"..."}
   approve? [y/N]: y

6. Inspect the audit chain

$ linpodx audit verify --session sess_01HZ...
session: sess_01HZ...
events:  47
chain:   OK (head 9f2c8a1c..., tail 4d11abef...)

7. Snapshot before the agent starts a risky refactor

$ linpodx snapshot create agent-1 --label "before-refactor"
job_id: snap-7a3f4c2

$ linpodx snapshot job-status snap-7a3f4c2
status: succeeded
image:  linpodx/snapshot/agent-1:before-refactor

$ linpodx snapshot rollback agent-1 --to before-refactor
rolled_back: true

Troubleshooting

  • error: profile not found — run linpodx sandbox apply first; the daemon doesn't read ~/.config on its own.
  • error: dns lookup denied for github.com — add the host to network.egress_dns_allowlist in the profile and reapply.
  • Approval prompt never appears — make sure linpodx events is running and not filtered out; CLI listener resolves prompts within a 30-second window before the call is denied by default.