agentcage 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentcage-0.1.0/.github/workflows/publish.yml +18 -0
- agentcage-0.1.0/.github/workflows/test.yml +21 -0
- agentcage-0.1.0/.gitignore +11 -0
- agentcage-0.1.0/CHANGELOG.md +32 -0
- agentcage-0.1.0/CONTRIBUTING.md +31 -0
- agentcage-0.1.0/LICENSE +21 -0
- agentcage-0.1.0/PKG-INFO +399 -0
- agentcage-0.1.0/README.md +370 -0
- agentcage-0.1.0/SECURITY.md +18 -0
- agentcage-0.1.0/docs/agentcage.png +0 -0
- agentcage-0.1.0/docs/architecture.md +129 -0
- agentcage-0.1.0/docs/configuration.md +376 -0
- agentcage-0.1.0/docs/openclaw.md +186 -0
- agentcage-0.1.0/docs/security.md +122 -0
- agentcage-0.1.0/examples/basic/README.md +27 -0
- agentcage-0.1.0/examples/basic/agent/agent.js +73 -0
- agentcage-0.1.0/examples/basic/config.yaml +23 -0
- agentcage-0.1.0/examples/openclaw/README.md +11 -0
- agentcage-0.1.0/examples/openclaw/config.yaml +172 -0
- agentcage-0.1.0/pyproject.toml +53 -0
- agentcage-0.1.0/src/agentcage/__init__.py +0 -0
- agentcage-0.1.0/src/agentcage/cli.py +722 -0
- agentcage-0.1.0/src/agentcage/config.py +195 -0
- agentcage-0.1.0/src/agentcage/data/containers/Containerfile.dns +8 -0
- agentcage-0.1.0/src/agentcage/data/containers/Containerfile.helper +2 -0
- agentcage-0.1.0/src/agentcage/data/containers/Containerfile.proxy +11 -0
- agentcage-0.1.0/src/agentcage/data/patches/package-lock.json +25 -0
- agentcage-0.1.0/src/agentcage/data/patches/package.json +16 -0
- agentcage-0.1.0/src/agentcage/data/patches/proxy-fetch.mjs +19 -0
- agentcage-0.1.0/src/agentcage/data/proxy/addon.py +410 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/__init__.py +5 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/base.py +93 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/body_size.py +34 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/content_type.py +99 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/domain.py +46 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/entropy.py +147 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/secrets.py +117 -0
- agentcage-0.1.0/src/agentcage/data/proxy/inspectors/util.py +71 -0
- agentcage-0.1.0/src/agentcage/data/proxy/secret_injector.py +232 -0
- agentcage-0.1.0/src/agentcage/podman.py +122 -0
- agentcage-0.1.0/src/agentcage/py.typed +0 -0
- agentcage-0.1.0/src/agentcage/quadlets.py +124 -0
- agentcage-0.1.0/src/agentcage/state.py +99 -0
- agentcage-0.1.0/src/agentcage/systemd.py +21 -0
- agentcage-0.1.0/src/agentcage/templates/cage.container.j2 +88 -0
- agentcage-0.1.0/src/agentcage/templates/dns.container.j2 +17 -0
- agentcage-0.1.0/src/agentcage/templates/network.j2 +4 -0
- agentcage-0.1.0/src/agentcage/templates/proxy.container.j2 +30 -0
- agentcage-0.1.0/src/agentcage/templates/volume.j2 +2 -0
- agentcage-0.1.0/tests/__init__.py +0 -0
- agentcage-0.1.0/tests/agent/test-curl.sh +66 -0
- agentcage-0.1.0/tests/agent/test.js +88 -0
- agentcage-0.1.0/tests/cage/Containerfile +2 -0
- agentcage-0.1.0/tests/cage/config.yaml +20 -0
- agentcage-0.1.0/tests/cage/scripts/test-all.js +113 -0
- agentcage-0.1.0/tests/configs/test-curl.yaml +22 -0
- agentcage-0.1.0/tests/configs/test.yaml +22 -0
- agentcage-0.1.0/tests/conftest.py +107 -0
- agentcage-0.1.0/tests/test_addon.py +119 -0
- agentcage-0.1.0/tests/test_cage_cli.py +183 -0
- agentcage-0.1.0/tests/test_config.py +292 -0
- agentcage-0.1.0/tests/test_defaults.py +198 -0
- agentcage-0.1.0/tests/test_domain_cli.py +140 -0
- agentcage-0.1.0/tests/test_inspectors.py +730 -0
- agentcage-0.1.0/tests/test_quadlets.py +408 -0
- agentcage-0.1.0/tests/test_secret_cli.py +123 -0
- agentcage-0.1.0/tests/test_secret_injector.py +404 -0
- agentcage-0.1.0/uv.lock +222 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment: pypi
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: astral-sh/setup-uv@v5
|
|
17
|
+
- run: uv build
|
|
18
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: astral-sh/setup-uv@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- run: uv sync --dev
|
|
21
|
+
- run: uv run pytest
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-02-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- CLI with `cage create`, `cage update`, `cage destroy`, `cage list`, `cage verify`, `cage reload`, and `cage logs` commands
|
|
13
|
+
- Secret management with `secret set`, `secret list`, and `secret rm` commands
|
|
14
|
+
- Domain management with `domain add`, `domain list`, and `domain rm` commands
|
|
15
|
+
- Network isolation via rootless Podman with `--internal` network (no internet gateway for the agent)
|
|
16
|
+
- Domain allowlist/blocklist filtering at both proxy and DNS layers
|
|
17
|
+
- Secret injection — the cage never sees real API keys; the proxy swaps placeholders transparently
|
|
18
|
+
- 19 built-in secret detection patterns (OpenAI, Anthropic, AWS, GitHub, Google, Slack, Stripe, and more)
|
|
19
|
+
- Built-in `allow_to_domains` mappings so standard API keys reach their provider domains without configuration
|
|
20
|
+
- Shannon entropy analysis for detecting encrypted/compressed exfiltration payloads
|
|
21
|
+
- Content-type mismatch and base64 blob detection
|
|
22
|
+
- Per-host token-bucket rate limiting
|
|
23
|
+
- WebSocket frame inspection (secrets, entropy)
|
|
24
|
+
- Custom inspector support via Python files
|
|
25
|
+
- Structured JSON audit logging
|
|
26
|
+
- Container hardening defaults (read-only root, dropped capabilities, no-new-privileges)
|
|
27
|
+
- Node.js `fetch()` proxy patch via `--import` loader
|
|
28
|
+
- Supply chain hardening (pinned image digests, lockfile integrity, patch file SHA-256 verification)
|
|
29
|
+
- systemd quadlet generation with proper dependency ordering
|
|
30
|
+
- OpenClaw example configuration and setup guide
|
|
31
|
+
|
|
32
|
+
[0.1.0]: https://github.com/agentcage/agentcage/releases/tag/v0.1.0
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Contributing to agentcage
|
|
2
|
+
|
|
3
|
+
## Development Setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
git clone https://github.com/agentcage/agentcage.git
|
|
7
|
+
cd agentcage
|
|
8
|
+
uv sync --dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Running Tests
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv run pytest
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Making Changes
|
|
18
|
+
|
|
19
|
+
1. Fork the repository and create a feature branch.
|
|
20
|
+
2. Make your changes and add tests where appropriate.
|
|
21
|
+
3. Run `uv run pytest` and ensure all tests pass.
|
|
22
|
+
4. Submit a pull request with a clear description of what changed and why.
|
|
23
|
+
|
|
24
|
+
## Code Style
|
|
25
|
+
|
|
26
|
+
- Follow existing patterns in the codebase.
|
|
27
|
+
- Keep changes focused — one concern per PR.
|
|
28
|
+
|
|
29
|
+
## Security Issues
|
|
30
|
+
|
|
31
|
+
Please **do not** open public issues for security vulnerabilities. See [SECURITY.md](SECURITY.md) for responsible disclosure instructions.
|
agentcage-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Luca Martinetti
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
agentcage-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentcage
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Defense-in-depth proxy sandbox for AI agents
|
|
5
|
+
Project-URL: Homepage, https://github.com/agentcage/agentcage
|
|
6
|
+
Project-URL: Repository, https://github.com/agentcage/agentcage
|
|
7
|
+
Project-URL: Documentation, https://github.com/agentcage/agentcage/tree/master/docs
|
|
8
|
+
Project-URL: Issues, https://github.com/agentcage/agentcage/issues
|
|
9
|
+
Author: Luca Martinetti
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent,ai,container,mitmproxy,proxy,sandbox,security
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: System Administrators
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Security
|
|
23
|
+
Classifier: Topic :: System :: Networking :: Monitoring
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: click>=8.1
|
|
26
|
+
Requires-Dist: jinja2>=3.1
|
|
27
|
+
Requires-Dist: pyyaml>=6.0
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="docs/agentcage.png" alt="agentcage logo" width="250">
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
# agentcage
|
|
35
|
+
|
|
36
|
+
*Defense-in-depth proxy sandbox for AI agents.*
|
|
37
|
+
|
|
38
|
+
Sandboxed container environments for AI agents, powered by rootless [Podman](https://podman.io/) and [mitmproxy](https://mitmproxy.org/).
|
|
39
|
+
|
|
40
|
+
> ⚠️ **Warning:** This is an experimental project. It has not been audited by security professionals. Use it at your own risk. See [Security & Threat Model](docs/security.md) for details and known limitations.
|
|
41
|
+
|
|
42
|
+
> **Setting up OpenClaw?** See the [OpenClaw guide](docs/openclaw.md) and [`openclaw/config.yaml`](examples/openclaw/).
|
|
43
|
+
|
|
44
|
+
## What is it?
|
|
45
|
+
|
|
46
|
+
agentcage is a CLI that generates hardened, sandboxed container environments for AI agents. It produces [systemd quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html) files that deploy three containers on a rootless [Podman](https://podman.io/) network -- no root privileges required. Your agent runs on an internal-only network with no internet gateway; the only way out is through an inspecting [mitmproxy](https://mitmproxy.org/) that scans every HTTP request before forwarding it.
|
|
47
|
+
|
|
48
|
+
## Why is it needed?
|
|
49
|
+
|
|
50
|
+
Most AI agent deployments hand the agent a [**lethal trifecta**](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/):
|
|
51
|
+
|
|
52
|
+
1. **Internet access** -- the agent can reach any server on the internet.
|
|
53
|
+
2. **Credentials** -- API keys, tokens, and secrets are passed as environment variables or mounted files.
|
|
54
|
+
3. **Arbitrary code execution** -- the agent runs code it writes itself, or code suggested by a model.
|
|
55
|
+
|
|
56
|
+
Any one of these alone is manageable. Combined, they create an exfiltration risk: if the agent is compromised, misaligned, or simply makes a mistake, it can send your credentials, source code, or private data to any endpoint on the internet. Most current setups have zero defense against this -- the agent has the same network access as any other process on the machine.
|
|
57
|
+
|
|
58
|
+
agentcage breaks the trifecta by placing the agent behind a defense-in-depth proxy sandbox: network isolation, domain filtering, secret injection, credential scanning, payload analysis, and container hardening -- all fail-closed. See [Security & Threat Model](docs/security.md) for the full breakdown of each layer and known limitations.
|
|
59
|
+
|
|
60
|
+
## How does it work?
|
|
61
|
+
|
|
62
|
+
The agent container has no internet gateway. All HTTP traffic is routed via `HTTP_PROXY` / `HTTPS_PROXY` to a dual-homed mitmproxy container, which is the agent's only path to the outside world. A pluggable inspector chain evaluates every request -- enforcing domain allowlists, scanning for secret leaks, and optionally analyzing payloads -- before forwarding or blocking with a 403.
|
|
63
|
+
|
|
64
|
+
See [Architecture](docs/architecture.md) for the full container topology, inspector chain, startup order, and certificate sharing.
|
|
65
|
+
|
|
66
|
+
## Prerequisites
|
|
67
|
+
|
|
68
|
+
- [Podman](https://podman.io/) (rootless)
|
|
69
|
+
- Python 3.12+
|
|
70
|
+
- [uv](https://docs.astral.sh/uv/) (Python package manager)
|
|
71
|
+
|
|
72
|
+
### Linux
|
|
73
|
+
|
|
74
|
+
**Arch Linux:**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
sudo pacman -S podman python uv
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Debian / Ubuntu (24.04+):**
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
sudo apt install podman python3
|
|
84
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Fedora:**
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
sudo dnf install podman python3 uv
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### macOS
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
brew install podman python uv
|
|
97
|
+
podman machine init
|
|
98
|
+
podman machine start
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> **Note:** On macOS, Podman runs containers inside a Linux VM. `podman machine init` creates and `podman machine start` starts it.
|
|
102
|
+
|
|
103
|
+
## Install
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv tool install agentcage # from PyPI (when published)
|
|
107
|
+
uv tool install git+https://github.com/agentcage/agentcage.git # from GitHub
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Or for development:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git clone https://github.com/agentcage/agentcage.git
|
|
114
|
+
cd agentcage
|
|
115
|
+
uv run agentcage --help
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Quick Start
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
# Edit config (set your allowed domains, image, etc.)
|
|
122
|
+
cp examples/basic/config.yaml config.yaml
|
|
123
|
+
|
|
124
|
+
# Store secrets first (they're required before cage creation)
|
|
125
|
+
agentcage secret set myapp ANTHROPIC_API_KEY
|
|
126
|
+
|
|
127
|
+
# Create the cage (builds images, generates quadlets, starts containers)
|
|
128
|
+
agentcage cage create -c config.yaml
|
|
129
|
+
|
|
130
|
+
# Verify everything is healthy
|
|
131
|
+
agentcage cage verify myapp
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## CLI Reference
|
|
135
|
+
|
|
136
|
+
The CLI is organized into two command groups: **`cage`** (manage cages) and **`secret`** (manage cage-scoped secrets).
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
agentcage <group> <command> [options]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### `cage` -- Manage cages
|
|
143
|
+
|
|
144
|
+
| Command | Description |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `cage create -c CONFIG` | Build images, generate quadlets, install, and start a new cage |
|
|
147
|
+
| `cage update NAME [-c CONFIG]` | Rebuild images and restart an existing cage |
|
|
148
|
+
| `cage list` | List all cages with status |
|
|
149
|
+
| `cage destroy NAME [-y]` | Stop containers, remove quadlets, state, and scoped secrets |
|
|
150
|
+
| `cage verify NAME` | Health checks (containers, certs, proxy, egress, rootless) |
|
|
151
|
+
| `cage reload NAME` | Restart containers without rebuilding images |
|
|
152
|
+
|
|
153
|
+
### `secret` -- Manage cage-scoped secrets
|
|
154
|
+
|
|
155
|
+
| Command | Description |
|
|
156
|
+
|---|---|
|
|
157
|
+
| `secret list NAME` | List secrets for a cage (with status if cage exists) |
|
|
158
|
+
| `secret set NAME KEY` | Set a secret (prompts for value or reads stdin) |
|
|
159
|
+
| `secret rm NAME KEY` | Remove a secret |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### `cage create`
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
agentcage cage create -c <config>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Creates a new cage from a config file. This single command:
|
|
170
|
+
|
|
171
|
+
1. Validates the config
|
|
172
|
+
2. Checks that all required secrets exist in Podman
|
|
173
|
+
3. Saves deployment state to `~/.config/agentcage/deployments/<name>/config.yaml`
|
|
174
|
+
4. Builds the proxy and DNS container images
|
|
175
|
+
5. Generates and installs 5 quadlet files into `~/.config/containers/systemd/`
|
|
176
|
+
6. Reloads systemd and starts the cage
|
|
177
|
+
|
|
178
|
+
The generated quadlet files are:
|
|
179
|
+
|
|
180
|
+
- `<name>-net.network` -- internal network with fixed subnet
|
|
181
|
+
- `<name>-certs.volume` -- shared certificate volume
|
|
182
|
+
- `<name>-dns.container` -- DNS sidecar (dnsmasq)
|
|
183
|
+
- `<name>-proxy.container` -- mitmproxy with inspector chain
|
|
184
|
+
- `<name>-cage.container` -- your agent container
|
|
185
|
+
|
|
186
|
+
Fails if any required secrets are missing. The error message tells you exactly which secrets to create:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
error: missing secrets for cage 'myapp':
|
|
190
|
+
ANTHROPIC_API_KEY
|
|
191
|
+
Create them with:
|
|
192
|
+
agentcage secret set myapp ANTHROPIC_API_KEY
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### `cage update`
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
agentcage cage update <name> [-c <config>]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Rebuild and restart an existing cage. Use this after changing code or config:
|
|
202
|
+
|
|
203
|
+
- **With `-c`**: Updates the stored config, then rebuilds and restarts.
|
|
204
|
+
- **Without `-c`**: Rebuilds from the previously stored config (useful when only the container image or proxy code has changed).
|
|
205
|
+
|
|
206
|
+
Stops the running services before rebuilding, then starts them again.
|
|
207
|
+
|
|
208
|
+
### `cage list`
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
agentcage cage list
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Lists all known cages with their current status:
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
NAME STATUS
|
|
218
|
+
myapp running (3/3)
|
|
219
|
+
testcage stopped (0/3)
|
|
220
|
+
broken degraded (2/3)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `cage destroy`
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
agentcage cage destroy <name> [-y|--yes]
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Tears down a cage completely:
|
|
230
|
+
|
|
231
|
+
1. Stops all containers (cage, proxy, DNS)
|
|
232
|
+
2. Removes quadlet files from `~/.config/containers/systemd/`
|
|
233
|
+
3. Removes the Podman network and certificate volume
|
|
234
|
+
4. Removes all scoped secrets (e.g., `myapp.ANTHROPIC_API_KEY`)
|
|
235
|
+
5. Removes deployment state from `~/.config/agentcage/deployments/<name>/`
|
|
236
|
+
|
|
237
|
+
User-defined named volumes and bind-mounted data are never removed. Pass `-y` to skip the confirmation prompt.
|
|
238
|
+
|
|
239
|
+
### `cage verify`
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
agentcage cage verify <name>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Runs health checks against a running cage:
|
|
246
|
+
|
|
247
|
+
- All 3 containers running (cage, proxy, DNS)
|
|
248
|
+
- CA certificate present in the shared volume
|
|
249
|
+
- `HTTP_PROXY` / `HTTPS_PROXY` set in the cage container
|
|
250
|
+
- Egress filtering working (blocked domain returns 403)
|
|
251
|
+
- Podman running rootless
|
|
252
|
+
|
|
253
|
+
Example output:
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
=== agentcage verify: myapp ===
|
|
257
|
+
|
|
258
|
+
-- Containers --
|
|
259
|
+
[PASS] myapp-proxy is running
|
|
260
|
+
[PASS] myapp-dns is running
|
|
261
|
+
[PASS] myapp-cage is running
|
|
262
|
+
|
|
263
|
+
-- CA Certificate --
|
|
264
|
+
[PASS] mitmproxy CA cert exists in shared volume
|
|
265
|
+
|
|
266
|
+
-- Proxy Configuration --
|
|
267
|
+
[PASS] HTTP_PROXY is set
|
|
268
|
+
[PASS] HTTPS_PROXY is set
|
|
269
|
+
|
|
270
|
+
-- Egress Filtering --
|
|
271
|
+
[PASS] Blocked domain (evil-exfil-server.io) is denied (HTTP 403)
|
|
272
|
+
|
|
273
|
+
-- Podman --
|
|
274
|
+
[PASS] Podman is running rootless
|
|
275
|
+
|
|
276
|
+
=== Results: 8 passed, 0 failed, 0 warnings ===
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### `cage reload`
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
agentcage cage reload <name>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Restarts containers without rebuilding images. Useful after config-only changes (the config YAML is bind-mounted into the proxy container, so a restart picks it up).
|
|
286
|
+
|
|
287
|
+
### `secret set`
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
agentcage secret set <name> <key>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Sets a deployment-scoped secret. When run interactively, prompts for the value with hidden input. Also accepts piped input:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# Interactive (prompts for value)
|
|
297
|
+
agentcage secret set myapp ANTHROPIC_API_KEY
|
|
298
|
+
|
|
299
|
+
# Piped from a command
|
|
300
|
+
echo "sk-ant-abc123" | agentcage secret set myapp ANTHROPIC_API_KEY
|
|
301
|
+
|
|
302
|
+
# From a file
|
|
303
|
+
agentcage secret set myapp ANTHROPIC_API_KEY < /path/to/key.txt
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Secrets are stored in Podman as `<name>.<key>` (e.g., `myapp.ANTHROPIC_API_KEY`) and mapped back to the original env var name via `target=` in the quadlet templates, so the container sees `ANTHROPIC_API_KEY` as expected.
|
|
307
|
+
|
|
308
|
+
If the cage is currently running, it is automatically reloaded after the secret is set.
|
|
309
|
+
|
|
310
|
+
### `secret list`
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
agentcage secret list <name>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Lists secrets for a cage. If the cage has deployment state, cross-references with the config to show expected secrets and their status:
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
NAME TYPE STATUS
|
|
320
|
+
ANTHROPIC_API_KEY injection ok
|
|
321
|
+
GITHUB_TOKEN direct MISSING
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Secret types:
|
|
325
|
+
- **injection** -- managed by the proxy's secret injection system (the cage sees a placeholder; the proxy swaps in the real value)
|
|
326
|
+
- **direct** -- passed directly to the cage container via `podman_secrets`
|
|
327
|
+
|
|
328
|
+
If no deployment state exists, lists all Podman secrets matching the `<name>.` prefix.
|
|
329
|
+
|
|
330
|
+
### `secret rm`
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
agentcage secret rm <name> <key>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Removes a secret from Podman. If the cage is currently running, it is automatically reloaded.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Typical Workflow
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# 1. Write your config
|
|
344
|
+
cp examples/basic/config.yaml config.yaml
|
|
345
|
+
vim config.yaml
|
|
346
|
+
|
|
347
|
+
# 2. Store secrets (before creating the cage)
|
|
348
|
+
agentcage secret set myapp ANTHROPIC_API_KEY
|
|
349
|
+
agentcage secret set myapp GITHUB_TOKEN
|
|
350
|
+
|
|
351
|
+
# 3. Create the cage
|
|
352
|
+
agentcage cage create -c config.yaml
|
|
353
|
+
|
|
354
|
+
# 4. Verify it's healthy
|
|
355
|
+
agentcage cage verify myapp
|
|
356
|
+
|
|
357
|
+
# 5. View logs
|
|
358
|
+
journalctl --user -u myapp-cage -f
|
|
359
|
+
|
|
360
|
+
# 6. Update after code/config changes
|
|
361
|
+
agentcage cage update myapp -c config.yaml
|
|
362
|
+
|
|
363
|
+
# 7. Rotate a secret (auto-reloads the cage)
|
|
364
|
+
agentcage secret set myapp ANTHROPIC_API_KEY
|
|
365
|
+
|
|
366
|
+
# 8. Restart without rebuild (config-only change)
|
|
367
|
+
agentcage cage reload myapp
|
|
368
|
+
|
|
369
|
+
# 9. Tear it all down
|
|
370
|
+
agentcage cage destroy myapp
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### View logs
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
journalctl --user -u myapp-cage -f
|
|
377
|
+
journalctl --user -u myapp-proxy -f
|
|
378
|
+
journalctl --user -u myapp-dns -f
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Deployment State
|
|
382
|
+
|
|
383
|
+
agentcage tracks each cage in `~/.config/agentcage/deployments/<name>/config.yaml`. This stored config copy allows commands like `cage update` (without `-c`) and `cage reload` to operate without requiring the original config file. The state is removed when a cage is destroyed.
|
|
384
|
+
|
|
385
|
+
## Architecture
|
|
386
|
+
|
|
387
|
+
Three containers on an internal Podman network: the agent (no internet gateway), a dual-homed DNS sidecar, and a dual-homed mitmproxy that inspects and forwards all traffic. See [Architecture](docs/architecture.md) for the full topology, inspector chain, startup order, and certificate sharing.
|
|
388
|
+
|
|
389
|
+
## Configuration
|
|
390
|
+
|
|
391
|
+
See the [Configuration Reference](docs/configuration.md) for all settings, defaults, and examples. Example configs: [`basic/config.yaml`](examples/basic/) | [`openclaw/config.yaml`](examples/openclaw/)
|
|
392
|
+
|
|
393
|
+
## Security
|
|
394
|
+
|
|
395
|
+
The agent has no internet gateway -- all traffic must pass through the proxy, which applies domain filtering, secret detection, payload inspection, and custom inspectors. See [Security & Threat Model](docs/security.md) for the full threat model, defense layers, and known limitations.
|
|
396
|
+
|
|
397
|
+
## License
|
|
398
|
+
|
|
399
|
+
MIT
|