🛟 Updated.Unverified
dea4bcd added
.gitignore +9 -0 | new file mode 100644 | ||
| @@ -0,0 +1,9 @@ | ||
| 1 | +sandboxes | |
| 2 | +docker-agent | |
| 3 | +.notes | |
| 4 | +.mm | |
| 5 | +.tmp | |
| 6 | +.claude | |
| 7 | +slides | |
| 8 | +*.fr.md | |
| 9 | +.backup | |
| \ No newline at end of file | ||
| new file mode 100644 | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | +sandboxes | ||
| 2 | +docker-agent | ||
| 3 | +.notes | ||
| 4 | +.mm | ||
| 5 | +.tmp | ||
| 6 | +.claude | ||
| 7 | +slides | ||
| 8 | +*.fr.md | ||
| 9 | +.backup | ||
| \ No newline at end of file | \ No newline at end of file | ||
added
.vscode/extensions.json +12 -0 | new file mode 100644 | ||
| @@ -0,0 +1,12 @@ | ||
| 1 | +{ | |
| 2 | + "recommendations": [ | |
| 3 | + "ms-azuretools.vscode-docker", | |
| 4 | + "pkief.material-icon-theme", | |
| 5 | + "pkief.material-product-icons", | |
| 6 | + "aaron-bond.better-comments", | |
| 7 | + "hediet.vscode-drawio", | |
| 8 | + "anseki.vscode-color", | |
| 9 | + "jeronimoekerdt.color-picker-universal", | |
| 10 | + "wayou.vscode-todo-highlight", | |
| 11 | + ] | |
| 12 | +} | |
| \ No newline at end of file | ||
| new file mode 100644 | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | +{ | ||
| 2 | + "recommendations": [ | ||
| 3 | + "ms-azuretools.vscode-docker", | ||
| 4 | + "pkief.material-icon-theme", | ||
| 5 | + "pkief.material-product-icons", | ||
| 6 | + "aaron-bond.better-comments", | ||
| 7 | + "hediet.vscode-drawio", | ||
| 8 | + "anseki.vscode-color", | ||
| 9 | + "jeronimoekerdt.color-picker-universal", | ||
| 10 | + "wayou.vscode-todo-highlight", | ||
| 11 | + ] | ||
| 12 | +} | ||
| \ No newline at end of file | \ No newline at end of file | ||
added
.vscode/settings.json +48 -0 | new file mode 100644 | ||
| @@ -0,0 +1,48 @@ | ||
| 1 | +{ | |
| 2 | + "workbench.iconTheme": "material-icon-theme", | |
| 3 | + "workbench.colorTheme": "Light Modern", | |
| 4 | + "editor.fontSize": 14, | |
| 5 | + "terminal.integrated.fontSize": 14, | |
| 6 | + "editor.insertSpaces": true, | |
| 7 | + "editor.tabSize": 4, | |
| 8 | + "editor.detectIndentation": true, | |
| 9 | + "files.autoSave": "afterDelay", | |
| 10 | + "files.autoSaveDelay": 1000, | |
| 11 | + "workbench.tree.indent": 20, | |
| 12 | + "window.zoomLevel": 0.0, | |
| 13 | + "[markdown]": { | |
| 14 | + "editor.unicodeHighlight.ambiguousCharacters": false, | |
| 15 | + "editor.unicodeHighlight.invisibleCharacters": false, | |
| 16 | + "diffEditor.ignoreTrimWhitespace": false, | |
| 17 | + "editor.fontWeight": "normal", | |
| 18 | + "editor.fontFamily": "'Droid Sans Mono', 'monospace', monospace", | |
| 19 | + "editor.fontSize": 14, | |
| 20 | + "editor.wordWrap": "on", | |
| 21 | + "editor.quickSuggestions": { | |
| 22 | + "comments": "off", | |
| 23 | + "strings": "off", | |
| 24 | + "other": "off" | |
| 25 | + } | |
| 26 | + }, | |
| 27 | + "markdown.preview.fontSize": 14, | |
| 28 | + // "workbench.editorAssociations": { | |
| 29 | + // "*.md": "vscode.markdown.preview.editor" | |
| 30 | + // }, | |
| 31 | + "[dockerfile]": { | |
| 32 | + "editor.fontSize": 14, | |
| 33 | + }, | |
| 34 | + "[dockercompose]": { | |
| 35 | + "editor.fontSize": 14, | |
| 36 | + }, | |
| 37 | + "[json]": { | |
| 38 | + "editor.fontSize": 14, | |
| 39 | + }, | |
| 40 | + "[yaml]": { | |
| 41 | + "editor.fontSize": 14, | |
| 42 | + | |
| 43 | + }, | |
| 44 | + "[go]": { | |
| 45 | + "editor.fontSize": 14, | |
| 46 | + }, | |
| 47 | + | |
| 48 | +} | |
| new file mode 100644 | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | +{ | ||
| 2 | + "workbench.iconTheme": "material-icon-theme", | ||
| 3 | + "workbench.colorTheme": "Light Modern", | ||
| 4 | + "editor.fontSize": 14, | ||
| 5 | + "terminal.integrated.fontSize": 14, | ||
| 6 | + "editor.insertSpaces": true, | ||
| 7 | + "editor.tabSize": 4, | ||
| 8 | + "editor.detectIndentation": true, | ||
| 9 | + "files.autoSave": "afterDelay", | ||
| 10 | + "files.autoSaveDelay": 1000, | ||
| 11 | + "workbench.tree.indent": 20, | ||
| 12 | + "window.zoomLevel": 0.0, | ||
| 13 | + "[markdown]": { | ||
| 14 | + "editor.unicodeHighlight.ambiguousCharacters": false, | ||
| 15 | + "editor.unicodeHighlight.invisibleCharacters": false, | ||
| 16 | + "diffEditor.ignoreTrimWhitespace": false, | ||
| 17 | + "editor.fontWeight": "normal", | ||
| 18 | + "editor.fontFamily": "'Droid Sans Mono', 'monospace', monospace", | ||
| 19 | + "editor.fontSize": 14, | ||
| 20 | + "editor.wordWrap": "on", | ||
| 21 | + "editor.quickSuggestions": { | ||
| 22 | + "comments": "off", | ||
| 23 | + "strings": "off", | ||
| 24 | + "other": "off" | ||
| 25 | + } | ||
| 26 | + }, | ||
| 27 | + "markdown.preview.fontSize": 14, | ||
| 28 | + // "workbench.editorAssociations": { | ||
| 29 | + // "*.md": "vscode.markdown.preview.editor" | ||
| 30 | + // }, | ||
| 31 | + "[dockerfile]": { | ||
| 32 | + "editor.fontSize": 14, | ||
| 33 | + }, | ||
| 34 | + "[dockercompose]": { | ||
| 35 | + "editor.fontSize": 14, | ||
| 36 | + }, | ||
| 37 | + "[json]": { | ||
| 38 | + "editor.fontSize": 14, | ||
| 39 | + }, | ||
| 40 | + "[yaml]": { | ||
| 41 | + "editor.fontSize": 14, | ||
| 42 | + | ||
| 43 | + }, | ||
| 44 | + "[go]": { | ||
| 45 | + "editor.fontSize": 14, | ||
| 46 | + }, | ||
| 47 | + | ||
| 48 | +} | ||
added
00-introduction/README.md +54 -0 | new file mode 100644 | ||
| @@ -0,0 +1,54 @@ | ||
| 1 | +# Introduction | |
| 2 | + | |
| 3 | +## What we are going to do | |
| 4 | + | |
| 5 | +An AI agent that reads files, runs commands and calls APIs is powerful, but if it runs directly on your machine, it has access to your files, your environment variables, and therefore your secrets. | |
| 6 | + | |
| 7 | +In this workshop, we will: | |
| 8 | + | |
| 9 | +1. **Create a Mistral AI account** and an API key (`01-mistral-ai`). | |
| 10 | +2. **Install Docker Agent** (`02-docker-agent`). | |
| 11 | +3. **Write our first agent** with Docker Agent and the Mistral model, run it on our machine, and see that it is not without risk (`03-first-agent`). | |
| 12 | +4. **Discover `sbx`** and start our first sandbox (`04-sbx`). | |
| 13 | +5. **Sandbox our agent**: run Docker Agent in a sandbox, connected to Mistral AI, without the API key ever entering the sandbox (`05-sbx-docker-agent`). | |
| 14 | +6. **Describe the sandbox declaratively** with an `sbxenv.yaml` file and `sbx env` (`06-sbx-docker-agent-sbx-env`). | |
| 15 | +7. **Compose the sandbox with kits**, like Lego bricks: one kit for the agent, another for the Rust toolchain (`07-play-lego-with-kits`). | |
| 16 | +8. **Add policies** to control what the sandbox can reach on the network, for example to forbid `gitlab.com` (`08-policies`). | |
| 17 | + | |
| 18 | +## What is Docker Agent? | |
| 19 | + | |
| 20 | +**Docker Agent** (`docker-agent`) lets you create and run AI agents, and teams of agents that work together, without writing code: an agent is described in a YAML file (model, instructions, tools). | |
| 21 | + | |
| 22 | +- Agents can use built-in tools (`filesystem`, `shell`, ...) and any [MCP](https://modelcontextprotocol.io/) server. | |
| 23 | +- It does not depend on a model provider: OpenAI, Anthropic, Gemini, Mistral, [Docker Model Runner](https://docs.docker.com/ai/model-runner/) (local models), etc. | |
| 24 | +- You start it with `docker agent run agent.yaml` (Docker CLI plugin) or `docker-agent run agent.yaml` (standalone binary). | |
| 25 | + | |
| 26 | +References: | |
| 27 | +- Documentation: [https://docker.github.io/docker-agent/](https://docker.github.io/docker-agent/) | |
| 28 | +- Installation: [https://docker.github.io/docker-agent/getting-started/installation/](https://docker.github.io/docker-agent/getting-started/installation/) | |
| 29 | +- Source code: [https://github.com/docker/docker-agent](https://github.com/docker/docker-agent) | |
| 30 | + | |
| 31 | +## What is `sbx`? | |
| 32 | + | |
| 33 | +**Docker Sandboxes** (`sbx` CLI) runs AI coding agents in **isolated microVMs**. Each sandbox has its own filesystem, its own network and its own Docker daemon; only the workspace you choose is shared with the host. | |
| 34 | + | |
| 35 | +What it gives you: | |
| 36 | + | |
| 37 | +- **Isolation**: the agent no longer sees your machine, only the shared workspace. | |
| 38 | +- **Protected secrets**: API keys stay on the host and a proxy injects them into outbound requests. The sandbox only sees a placeholder value. | |
| 39 | +- **Network policies**: you decide which hosts the sandbox can reach (`sbx policy allow/deny`). | |
| 40 | +- **Declarative environments**: an `sbxenv.yaml` file describes the agent, the kits, the variables, the secrets and the ports, and `sbx env` creates, starts and removes the matching sandbox. | |
| 41 | +- **Kits**: reusable bricks to compose a sandbox (agent, tools, network rules). | |
| 42 | + | |
| 43 | +References: | |
| 44 | +- Documentation: [https://docs.docker.com/ai/sandboxes/](https://docs.docker.com/ai/sandboxes/) | |
| 45 | +- Installation: [https://docs.docker.com/ai/sandboxes/install/](https://docs.docker.com/ai/sandboxes/install/) | |
| 46 | +- Environment files (`sbxenv.yaml`): [https://docs.docker.com/ai/sandboxes/configuration/environment-files/](https://docs.docker.com/ai/sandboxes/configuration/environment-files/) | |
| 47 | + | |
| 48 | +## Prerequisites | |
| 49 | + | |
| 50 | +- A machine running macOS, Linux or Windows (this workshop was tested on macOS Apple Silicon). | |
| 51 | +- A [Mistral AI](https://console.mistral.ai/) account and an API key. | |
| 52 | +- `docker-agent` and `sbx` installed (see steps 02 and 04). | |
| 53 | + | |
| 54 | +**Let's start with the Mistral AI API key: go to `01-mistral-ai`.** | |
| new file mode 100644 | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | +# Introduction | ||
| 2 | + | ||
| 3 | +## What we are going to do | ||
| 4 | + | ||
| 5 | +An AI agent that reads files, runs commands and calls APIs is powerful, but if it runs directly on your machine, it has access to your files, your environment variables, and therefore your secrets. | ||
| 6 | + | ||
| 7 | +In this workshop, we will: | ||
| 8 | + | ||
| 9 | +1. **Create a Mistral AI account** and an API key (`01-mistral-ai`). | ||
| 10 | +2. **Install Docker Agent** (`02-docker-agent`). | ||
| 11 | +3. **Write our first agent** with Docker Agent and the Mistral model, run it on our machine, and see that it is not without risk (`03-first-agent`). | ||
| 12 | +4. **Discover `sbx`** and start our first sandbox (`04-sbx`). | ||
| 13 | +5. **Sandbox our agent**: run Docker Agent in a sandbox, connected to Mistral AI, without the API key ever entering the sandbox (`05-sbx-docker-agent`). | ||
| 14 | +6. **Describe the sandbox declaratively** with an `sbxenv.yaml` file and `sbx env` (`06-sbx-docker-agent-sbx-env`). | ||
| 15 | +7. **Compose the sandbox with kits**, like Lego bricks: one kit for the agent, another for the Rust toolchain (`07-play-lego-with-kits`). | ||
| 16 | +8. **Add policies** to control what the sandbox can reach on the network, for example to forbid `gitlab.com` (`08-policies`). | ||
| 17 | + | ||
| 18 | +## What is Docker Agent? | ||
| 19 | + | ||
| 20 | +**Docker Agent** (`docker-agent`) lets you create and run AI agents, and teams of agents that work together, without writing code: an agent is described in a YAML file (model, instructions, tools). | ||
| 21 | + | ||
| 22 | +- Agents can use built-in tools (`filesystem`, `shell`, ...) and any [MCP](https://modelcontextprotocol.io/) server. | ||
| 23 | +- It does not depend on a model provider: OpenAI, Anthropic, Gemini, Mistral, [Docker Model Runner](https://docs.docker.com/ai/model-runner/) (local models), etc. | ||
| 24 | +- You start it with `docker agent run agent.yaml` (Docker CLI plugin) or `docker-agent run agent.yaml` (standalone binary). | ||
| 25 | + | ||
| 26 | +References: | ||
| 27 | +- Documentation: [https://docker.github.io/docker-agent/](https://docker.github.io/docker-agent/) | ||
| 28 | +- Installation: [https://docker.github.io/docker-agent/getting-started/installation/](https://docker.github.io/docker-agent/getting-started/installation/) | ||
| 29 | +- Source code: [https://github.com/docker/docker-agent](https://github.com/docker/docker-agent) | ||
| 30 | + | ||
| 31 | +## What is `sbx`? | ||
| 32 | + | ||
| 33 | +**Docker Sandboxes** (`sbx` CLI) runs AI coding agents in **isolated microVMs**. Each sandbox has its own filesystem, its own network and its own Docker daemon; only the workspace you choose is shared with the host. | ||
| 34 | + | ||
| 35 | +What it gives you: | ||
| 36 | + | ||
| 37 | +- **Isolation**: the agent no longer sees your machine, only the shared workspace. | ||
| 38 | +- **Protected secrets**: API keys stay on the host and a proxy injects them into outbound requests. The sandbox only sees a placeholder value. | ||
| 39 | +- **Network policies**: you decide which hosts the sandbox can reach (`sbx policy allow/deny`). | ||
| 40 | +- **Declarative environments**: an `sbxenv.yaml` file describes the agent, the kits, the variables, the secrets and the ports, and `sbx env` creates, starts and removes the matching sandbox. | ||
| 41 | +- **Kits**: reusable bricks to compose a sandbox (agent, tools, network rules). | ||
| 42 | + | ||
| 43 | +References: | ||
| 44 | +- Documentation: [https://docs.docker.com/ai/sandboxes/](https://docs.docker.com/ai/sandboxes/) | ||
| 45 | +- Installation: [https://docs.docker.com/ai/sandboxes/install/](https://docs.docker.com/ai/sandboxes/install/) | ||
| 46 | +- Environment files (`sbxenv.yaml`): [https://docs.docker.com/ai/sandboxes/configuration/environment-files/](https://docs.docker.com/ai/sandboxes/configuration/environment-files/) | ||
| 47 | + | ||
| 48 | +## Prerequisites | ||
| 49 | + | ||
| 50 | +- A machine running macOS, Linux or Windows (this workshop was tested on macOS Apple Silicon). | ||
| 51 | +- A [Mistral AI](https://console.mistral.ai/) account and an API key. | ||
| 52 | +- `docker-agent` and `sbx` installed (see steps 02 and 04). | ||
| 53 | + | ||
| 54 | +**Let's start with the Mistral AI API key: go to `01-mistral-ai`.** | ||
added
01-mistral-ai/README.md +27 -0 | new file mode 100644 | ||
| @@ -0,0 +1,27 @@ | ||
| 1 | +# Mistral AI | |
| 2 | + | |
| 3 | +## You need to create an account at Mistral | |
| 4 | + | |
| 5 | +Go to [https://console.mistral.ai/](https://console.mistral.ai/) and create an account, then create an API key: | |
| 6 | + | |
| 7 | +Use your email: | |
| 8 | + | |
| 9 | + | |
| 10 | +Fill in the required information: | |
| 11 | + | |
| 12 | + | |
| 13 | +You will receive a code by email: | |
| 14 | + | |
| 15 | + | |
| 16 | +Enter it on the Mistral AI side for verification: | |
| 17 | + | |
| 18 | + | |
| 19 | +Then, once you are in Mistral Studio, you can create your key: | |
| 20 | + | |
| 21 | + | |
| 22 | +And see the list of your current keys: | |
| 23 | + | |
| 24 | + | |
| 25 | +**Copy your key somewhere, you will use it for the rest of the workshop**. | |
| 26 | + | |
| 27 | +Now let's move on to installing Docker Agent. | |
| new file mode 100644 | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | +# Mistral AI | ||
| 2 | + | ||
| 3 | +## You need to create an account at Mistral | ||
| 4 | + | ||
| 5 | +Go to [https://console.mistral.ai/](https://console.mistral.ai/) and create an account, then create an API key: | ||
| 6 | + | ||
| 7 | +Use your email: | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +Fill in the required information: | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +You will receive a code by email: | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +Enter it on the Mistral AI side for verification: | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +Then, once you are in Mistral Studio, you can create your key: | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +And see the list of your current keys: | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +**Copy your key somewhere, you will use it for the rest of the workshop**. | ||
| 26 | + | ||
| 27 | +Now let's move on to installing Docker Agent. | ||
added
01-mistral-ai/assets/mistral-account-01.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-01.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-01.png differ | Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-01.png differ | ||
added
01-mistral-ai/assets/mistral-account-02.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-02.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-02.png differ | Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-02.png differ | ||
added
01-mistral-ai/assets/mistral-account-03.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-03.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-03.png differ | Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-03.png differ | ||
added
01-mistral-ai/assets/mistral-account-04.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-04.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-04.png differ | Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-04.png differ | ||
added
01-mistral-ai/assets/mistral-account-05.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-05.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-05.png differ | Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-05.png differ | ||
added
01-mistral-ai/assets/mistral-account-06.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-06.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-06.png differ | Binary files /dev/null and b/01-mistral-ai/assets/mistral-account-06.png differ | ||
added
02-docker-agent/README.md +13 -0 | new file mode 100644 | ||
| @@ -0,0 +1,13 @@ | ||
| 1 | +# Install Docker Agent | |
| 2 | + | |
| 3 | +We are going to install the local version of Docker Agent (not the Docker Agent plugin version for Docker Desktop). | |
| 4 | + | |
| 5 | +You will find here the page describing the possible installations for your operating systems: [https://docker.github.io/docker-agent/getting-started/installation/](https://docker.github.io/docker-agent/getting-started/installation/) | |
| 6 | + | |
| 7 | +## On Windows | |
| 8 | + | |
| 9 | +- Go to: https://github.com/docker/docker-agent/releases and download the appropriate version of Docker Agent | |
| 10 | +- Rename it to docker-agent | |
| 11 | +- Add it to the PATH (ex: C:\Users\Philippe\docker-agent\) | |
| 12 | + | |
| 13 | +You probably need to restart VSCode (on Windows, don’t ask why) | |
| \ No newline at end of file | ||
| new file mode 100644 | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | +# Install Docker Agent | ||
| 2 | + | ||
| 3 | +We are going to install the local version of Docker Agent (not the Docker Agent plugin version for Docker Desktop). | ||
| 4 | + | ||
| 5 | +You will find here the page describing the possible installations for your operating systems: [https://docker.github.io/docker-agent/getting-started/installation/](https://docker.github.io/docker-agent/getting-started/installation/) | ||
| 6 | + | ||
| 7 | +## On Windows | ||
| 8 | + | ||
| 9 | +- Go to: https://github.com/docker/docker-agent/releases and download the appropriate version of Docker Agent | ||
| 10 | +- Rename it to docker-agent | ||
| 11 | +- Add it to the PATH (ex: C:\Users\Philippe\docker-agent\) | ||
| 12 | + | ||
| 13 | +You probably need to restart VSCode (on Windows, don’t ask why) | ||
| \ No newline at end of file | \ No newline at end of file | ||
added
03-first-agent/README.md +118 -0 | new file mode 100644 | ||
| @@ -0,0 +1,118 @@ | ||
| 1 | +# First contact with Docker Agent | |
| 2 | + | |
| 3 | +We work in the `./03-first-agent` folder. | |
| 4 | + | |
| 5 | +## Create a docker agent configuration file: `agent.yaml` | |
| 6 | + | |
| 7 | +```yaml | |
| 8 | +models: | |
| 9 | + mistral: | |
| 10 | + provider: mistral | |
| 11 | + model: ministral-3b-2512 | |
| 12 | + temperature: 0.7 | |
| 13 | + max_tokens: 8192 | |
| 14 | + | |
| 15 | +agents: | |
| 16 | + root: | |
| 17 | + model: mistral | |
| 18 | + description: Assistant using Mistral | |
| 19 | + instruction: | | |
| 20 | + You name is [Bob 🤓], You are a helpful assistant. | |
| 21 | + | |
| 22 | + welcome_message: | | |
| 23 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | |
| 24 | + | |
| 25 | + toolsets: | |
| 26 | + - type: filesystem | |
| 27 | + - type: shell | |
| 28 | +``` | |
| 29 | + | |
| 30 | +**Warning**: the `filesystem` and `shell` tools are enabled, so don't ask the agent for anything dangerous (or let me do the demo on my machine and don't take any risk 😀). | |
| 31 | + | |
| 32 | + | |
| 33 | +## Run Docker Agent | |
| 34 | + | |
| 35 | +```bash | |
| 36 | +export MISTRAL_API_KEY="your-api-key" | |
| 37 | +docker agent run agent.yaml | |
| 38 | +``` | |
| 39 | +> Docker knows how to recognize `MISTRAL_API_KEY` as the secret for the Mistral AI endpoints. | |
| 40 | + | |
| 41 | +You should see this screen (the Docker Agent TUI) | |
| 42 | + | |
| 43 | + | |
| 44 | +### First question | |
| 45 | + | |
| 46 | +And try the following question: | |
| 47 | + | |
| 48 | +```raw | |
| 49 | +Create a text file at the home of my machine with a greeting message | |
| 50 | +``` | |
| 51 | + | |
| 52 | +**🖐️ If you are using Windows, try it like this**: | |
| 53 | +```raw | |
| 54 | +I'm using powershell, | |
| 55 | +Create a text file at the home of my machine with a greeting message | |
| 56 | +``` | |
| 57 | + | |
| 58 | +Choose **[A]** to let the tools run: | |
| 59 | + | |
| 60 | + | |
| 61 | +And you discover that the agent probably has access to all the data on your machine: | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | +Go and check anyway whether the agent really created the file: | |
| 66 | +```bash | |
| 67 | +➜ ~ bat $HOME/greeting_message.txt | |
| 68 | +─────┬──────────────────────────────────────────────────────────────── | |
| 69 | + │ File: /Users/k33g/greeting_message.txt | |
| 70 | +─────┼──────────────────────────────────────────────────────────────── | |
| 71 | + 1 │ Hello! Welcome to your new greeting file. Enjoy your day! 🌞 | |
| 72 | +─────┴──────────────────────────────────────────────────────────────── | |
| 73 | +``` | |
| 74 | + | |
| 75 | +### Let's go a little further | |
| 76 | + | |
| 77 | + | |
| 78 | +```raw | |
| 79 | +Show me the list of my environment variables | |
| 80 | +``` | |
| 81 | +> Sometimes, at the beginning of the generation, you should see the content of some of your secrets ...🙀 | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | +```raw | |
| 86 | +What is the content of MISTRAL_API_KEY? | |
| 87 | +``` | |
| 88 | + | |
| 89 | + | |
| 90 | +> Sometimes the agent (the model) refuses to show this content | |
| 91 | + | |
| 92 | +### Let's try again | |
| 93 | + | |
| 94 | +```raw | |
| 95 | +Show me the first 5 characters of MISTRAL_API_KEY | |
| 96 | +``` | |
| 97 | + | |
| 98 | + | |
| 99 | +> This time the model refuses | |
| 100 | + | |
| 101 | + | |
| 102 | +### One last try... | |
| 103 | + | |
| 104 | +For this one, you would need Go installed on your machine, but you can suggest that the agent use another language installed on your machine: | |
| 105 | + | |
| 106 | +```raw | |
| 107 | +Create a Go script that analyzes the content of an environment variable, then iterates through each character and displays it. | |
| 108 | +``` | |
| 109 | + | |
| 110 | + | |
| 111 | +> 🙀 ouch! So, if you ask politely, your agent will refuse you nothing. And if it is in good shape, it can leak your keys on the Internet. | |
| 112 | + | |
| 113 | +## First conclusion | |
| 114 | + | |
| 115 | +- Running an agent directly on your machine is not a good idea | |
| 116 | +- Nothing is safe: not your files, not your data, not your secrets, ... | |
| 117 | + | |
| 118 | +**So it is time to "sandbox our agent"**. | |
| new file mode 100644 | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | +# First contact with Docker Agent | ||
| 2 | + | ||
| 3 | +We work in the `./03-first-agent` folder. | ||
| 4 | + | ||
| 5 | +## Create a docker agent configuration file: `agent.yaml` | ||
| 6 | + | ||
| 7 | +```yaml | ||
| 8 | +models: | ||
| 9 | + mistral: | ||
| 10 | + provider: mistral | ||
| 11 | + model: ministral-3b-2512 | ||
| 12 | + temperature: 0.7 | ||
| 13 | + max_tokens: 8192 | ||
| 14 | + | ||
| 15 | +agents: | ||
| 16 | + root: | ||
| 17 | + model: mistral | ||
| 18 | + description: Assistant using Mistral | ||
| 19 | + instruction: | | ||
| 20 | + You name is [Bob 🤓], You are a helpful assistant. | ||
| 21 | + | ||
| 22 | + welcome_message: | | ||
| 23 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | ||
| 24 | + | ||
| 25 | + toolsets: | ||
| 26 | + - type: filesystem | ||
| 27 | + - type: shell | ||
| 28 | +``` | ||
| 29 | + | ||
| 30 | +**Warning**: the `filesystem` and `shell` tools are enabled, so don't ask the agent for anything dangerous (or let me do the demo on my machine and don't take any risk 😀). | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +## Run Docker Agent | ||
| 34 | + | ||
| 35 | +```bash | ||
| 36 | +export MISTRAL_API_KEY="your-api-key" | ||
| 37 | +docker agent run agent.yaml | ||
| 38 | +``` | ||
| 39 | +> Docker knows how to recognize `MISTRAL_API_KEY` as the secret for the Mistral AI endpoints. | ||
| 40 | + | ||
| 41 | +You should see this screen (the Docker Agent TUI) | ||
| 42 | + | ||
| 43 | + | ||
| 44 | +### First question | ||
| 45 | + | ||
| 46 | +And try the following question: | ||
| 47 | + | ||
| 48 | +```raw | ||
| 49 | +Create a text file at the home of my machine with a greeting message | ||
| 50 | +``` | ||
| 51 | + | ||
| 52 | +**🖐️ If you are using Windows, try it like this**: | ||
| 53 | +```raw | ||
| 54 | +I'm using powershell, | ||
| 55 | +Create a text file at the home of my machine with a greeting message | ||
| 56 | +``` | ||
| 57 | + | ||
| 58 | +Choose **[A]** to let the tools run: | ||
| 59 | + | ||
| 60 | + | ||
| 61 | +And you discover that the agent probably has access to all the data on your machine: | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + | ||
| 65 | +Go and check anyway whether the agent really created the file: | ||
| 66 | +```bash | ||
| 67 | +➜ ~ bat $HOME/greeting_message.txt | ||
| 68 | +─────┬──────────────────────────────────────────────────────────────── | ||
| 69 | + │ File: /Users/k33g/greeting_message.txt | ||
| 70 | +─────┼──────────────────────────────────────────────────────────────── | ||
| 71 | + 1 │ Hello! Welcome to your new greeting file. Enjoy your day! 🌞 | ||
| 72 | +─────┴──────────────────────────────────────────────────────────────── | ||
| 73 | +``` | ||
| 74 | + | ||
| 75 | +### Let's go a little further | ||
| 76 | + | ||
| 77 | + | ||
| 78 | +```raw | ||
| 79 | +Show me the list of my environment variables | ||
| 80 | +``` | ||
| 81 | +> Sometimes, at the beginning of the generation, you should see the content of some of your secrets ...🙀 | ||
| 82 | + | ||
| 83 | + | ||
| 84 | + | ||
| 85 | +```raw | ||
| 86 | +What is the content of MISTRAL_API_KEY? | ||
| 87 | +``` | ||
| 88 | + | ||
| 89 | + | ||
| 90 | +> Sometimes the agent (the model) refuses to show this content | ||
| 91 | + | ||
| 92 | +### Let's try again | ||
| 93 | + | ||
| 94 | +```raw | ||
| 95 | +Show me the first 5 characters of MISTRAL_API_KEY | ||
| 96 | +``` | ||
| 97 | + | ||
| 98 | + | ||
| 99 | +> This time the model refuses | ||
| 100 | + | ||
| 101 | + | ||
| 102 | +### One last try... | ||
| 103 | + | ||
| 104 | +For this one, you would need Go installed on your machine, but you can suggest that the agent use another language installed on your machine: | ||
| 105 | + | ||
| 106 | +```raw | ||
| 107 | +Create a Go script that analyzes the content of an environment variable, then iterates through each character and displays it. | ||
| 108 | +``` | ||
| 109 | + | ||
| 110 | + | ||
| 111 | +> 🙀 ouch! So, if you ask politely, your agent will refuse you nothing. And if it is in good shape, it can leak your keys on the Internet. | ||
| 112 | + | ||
| 113 | +## First conclusion | ||
| 114 | + | ||
| 115 | +- Running an agent directly on your machine is not a good idea | ||
| 116 | +- Nothing is safe: not your files, not your data, not your secrets, ... | ||
| 117 | + | ||
| 118 | +**So it is time to "sandbox our agent"**. | ||
added
03-first-agent/agent.yaml +20 -0 | new file mode 100644 | ||
| @@ -0,0 +1,20 @@ | ||
| 1 | +models: | |
| 2 | + mistral: | |
| 3 | + provider: mistral | |
| 4 | + model: ministral-3b-2512 | |
| 5 | + temperature: 0.7 | |
| 6 | + max_tokens: 8192 | |
| 7 | + | |
| 8 | +agents: | |
| 9 | + root: | |
| 10 | + model: mistral | |
| 11 | + description: Assistant using Mistral | |
| 12 | + instruction: | | |
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | |
| 14 | + | |
| 15 | + welcome_message: | | |
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | |
| 17 | + | |
| 18 | + toolsets: | |
| 19 | + - type: filesystem | |
| 20 | + - type: shell | |
| new file mode 100644 | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | +models: | ||
| 2 | + mistral: | ||
| 3 | + provider: mistral | ||
| 4 | + model: ministral-3b-2512 | ||
| 5 | + temperature: 0.7 | ||
| 6 | + max_tokens: 8192 | ||
| 7 | + | ||
| 8 | +agents: | ||
| 9 | + root: | ||
| 10 | + model: mistral | ||
| 11 | + description: Assistant using Mistral | ||
| 12 | + instruction: | | ||
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | ||
| 14 | + | ||
| 15 | + welcome_message: | | ||
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | ||
| 17 | + | ||
| 18 | + toolsets: | ||
| 19 | + - type: filesystem | ||
| 20 | + - type: shell | ||
added
03-first-agent/assets/docker-agent-01.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-01.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-01.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-01.png differ | ||
added
03-first-agent/assets/docker-agent-02.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-02.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-02.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-02.png differ | ||
added
03-first-agent/assets/docker-agent-03.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-03.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-03.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-03.png differ | ||
added
03-first-agent/assets/docker-agent-04.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-04.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-04.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-04.png differ | ||
added
03-first-agent/assets/docker-agent-05.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-05.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-05.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-05.png differ | ||
added
03-first-agent/assets/docker-agent-06.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-06.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-06.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-06.png differ | ||
added
03-first-agent/assets/docker-agent-07.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-07.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/03-first-agent/assets/docker-agent-07.png differ | Binary files /dev/null and b/03-first-agent/assets/docker-agent-07.png differ | ||
added
04-sbx/README.md +61 -0 | new file mode 100644 | ||
| @@ -0,0 +1,61 @@ | ||
| 1 | +# Let's talk a little about `sbx` | |
| 2 | + | |
| 3 | +## Why you should use `sbx` | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | +## Prerequisites | |
| 8 | + | |
| 9 | +- **You need a Docker Account for using SBX** | |
| 10 | +- You need Docker Desktop (only or exercise 07) | |
| 11 | + | |
| 12 | + | |
| 13 | +## Install `sbx` | |
| 14 | + | |
| 15 | +Start by installing `sbx` by following these instructions: [https://docs.docker.com/ai/sandboxes/install/](https://docs.docker.com/ai/sandboxes/install/) | |
| 16 | + | |
| 17 | +If you haven't chosen a default preset, the CLI prompts you before it runs a sandbox. Running `sbx policy reset` clears the preset and prompts you to choose again: | |
| 18 | + | |
| 19 | +```raw | |
| 20 | +Initialize the global network policy for your sandboxes: | |
| 21 | + | |
| 22 | + Applies to all sandboxes, current and future — change it later with | |
| 23 | + "sbx policy allow/deny/rm". Kits, including built-in agent kits, may | |
| 24 | + also add per-sandbox rules. | |
| 25 | + | |
| 26 | + 1. Open - All network traffic allowed, no restrictions. | |
| 27 | + 2. Balanced - Default deny, with common dev sites allowed. | |
| 28 | + 3. Locked Down - All network traffic blocked unless you allow it. | |
| 29 | + | |
| 30 | + Use ↑/↓or 1-3 to navigate, Enter to confirm, Esc to cancel. | |
| 31 | +``` | |
| 32 | + | |
| 33 | +## Test your installation - First contact with `sbx` | |
| 34 | + | |
| 35 | +In the current folder, run the following command: | |
| 36 | + | |
| 37 | +```bash | |
| 38 | +sbx run shell . | |
| 39 | +``` | |
| 40 | + | |
| 41 | +Then try these commands: | |
| 42 | +```bash | |
| 43 | +uname | |
| 44 | +go version | |
| 45 | +node --version | |
| 46 | +cargo --version | |
| 47 | +``` | |
| 48 | + | |
| 49 | +In another terminal, type: | |
| 50 | +```bash | |
| 51 | +sbx ls | |
| 52 | +``` | |
| 53 | + | |
| 54 | +Then: | |
| 55 | +```bash | |
| 56 | +sbx | |
| 57 | +``` | |
| 58 | + | |
| 59 | +Stop and destroy your sandbox. | |
| 60 | + | |
| 61 | +**It is time to get serious**. | |
| new file mode 100644 | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | +# Let's talk a little about `sbx` | ||
| 2 | + | ||
| 3 | +## Why you should use `sbx` | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +## Prerequisites | ||
| 8 | + | ||
| 9 | +- **You need a Docker Account for using SBX** | ||
| 10 | +- You need Docker Desktop (only or exercise 07) | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +## Install `sbx` | ||
| 14 | + | ||
| 15 | +Start by installing `sbx` by following these instructions: [https://docs.docker.com/ai/sandboxes/install/](https://docs.docker.com/ai/sandboxes/install/) | ||
| 16 | + | ||
| 17 | +If you haven't chosen a default preset, the CLI prompts you before it runs a sandbox. Running `sbx policy reset` clears the preset and prompts you to choose again: | ||
| 18 | + | ||
| 19 | +```raw | ||
| 20 | +Initialize the global network policy for your sandboxes: | ||
| 21 | + | ||
| 22 | + Applies to all sandboxes, current and future — change it later with | ||
| 23 | + "sbx policy allow/deny/rm". Kits, including built-in agent kits, may | ||
| 24 | + also add per-sandbox rules. | ||
| 25 | + | ||
| 26 | + 1. Open - All network traffic allowed, no restrictions. | ||
| 27 | + 2. Balanced - Default deny, with common dev sites allowed. | ||
| 28 | + 3. Locked Down - All network traffic blocked unless you allow it. | ||
| 29 | + | ||
| 30 | + Use ↑/↓or 1-3 to navigate, Enter to confirm, Esc to cancel. | ||
| 31 | +``` | ||
| 32 | + | ||
| 33 | +## Test your installation - First contact with `sbx` | ||
| 34 | + | ||
| 35 | +In the current folder, run the following command: | ||
| 36 | + | ||
| 37 | +```bash | ||
| 38 | +sbx run shell . | ||
| 39 | +``` | ||
| 40 | + | ||
| 41 | +Then try these commands: | ||
| 42 | +```bash | ||
| 43 | +uname | ||
| 44 | +go version | ||
| 45 | +node --version | ||
| 46 | +cargo --version | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +In another terminal, type: | ||
| 50 | +```bash | ||
| 51 | +sbx ls | ||
| 52 | +``` | ||
| 53 | + | ||
| 54 | +Then: | ||
| 55 | +```bash | ||
| 56 | +sbx | ||
| 57 | +``` | ||
| 58 | + | ||
| 59 | +Stop and destroy your sandbox. | ||
| 60 | + | ||
| 61 | +**It is time to get serious**. | ||
added
04-sbx/assets/sbx-security-model.drawio.svg +71 -0 | new file mode 100644 | ||
| @@ -0,0 +1,71 @@ | ||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1120" height="694" viewBox="0 0 1120 694" content="<mxfile host="Electron" agent="make-diagram.mjs" type="device"><diagram name="sbx security model" id="diagram-1"><mxGraphModel dx="1000" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="826" math="0" shadow="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="● Runs on laptop&lt;br&gt;&lt;b&gt;● No Docker Desktop needed&lt;/b&gt;&lt;br&gt;● Full YOLO mode: no&lt;br&gt; permission prompts&lt;br&gt;● Agents can run anything" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=15;strokeWidth=2;align=left;verticalAlign=top;spacingLeft=16;spacingTop=10;" vertex="1" parent="1"><mxGeometry x="20" y="64" width="250" height="150" as="geometry"/></mxCell><mxCell id="3" value="" style="rounded=1;arcSize=9;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#64748b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="20" y="424" width="250" height="156" as="geometry"/></mxCell><mxCell id="4" value="&lt;b&gt;Host System&lt;/b&gt;" style="rounded=1;arcSize=3;whiteSpace=wrap;html=1;fillColor=#f3f4ee;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;verticalAlign=top;align=left;spacingLeft=20;spacingTop=10;" vertex="1" parent="1"><mxGeometry x="300" y="20" width="800" height="560" as="geometry"/></mxCell><mxCell id="5" value="&lt;b&gt;🔒 Sandbox VM&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#64748b&quot;&gt;hypervisor boundary&lt;/font&gt;" style="rounded=1;arcSize=3;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;verticalAlign=top;align=left;spacingLeft=20;spacingTop=10;" vertex="1" parent="1"><mxGeometry x="320" y="64" width="380" height="374" as="geometry"/></mxCell><mxCell id="6" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="226" as="sourcePoint"/><mxPoint x="750" y="226" as="targetPoint"/></mxGeometry></mxCell><mxCell id="7" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="284" as="sourcePoint"/><mxPoint x="750" y="284" as="targetPoint"/></mxGeometry></mxCell><mxCell id="8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="342" as="sourcePoint"/><mxPoint x="750" y="342" as="targetPoint"/></mxGeometry></mxCell><mxCell id="9" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="400" as="sourcePoint"/><mxPoint x="750" y="400" as="targetPoint"/></mxGeometry></mxCell><mxCell id="10" value="credentials" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="813" y="510" as="sourcePoint"/><mxPoint x="702" y="510" as="targetPoint"/></mxGeometry></mxCell><mxCell id="11" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="258" y="510" as="sourcePoint"/><mxPoint x="318" y="510" as="targetPoint"/></mxGeometry></mxCell><mxCell id="12" value="✓ allow" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#2e7d32;fontSize=14;fontColor=#2e7d32;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="410" y="552" as="sourcePoint"/><mxPoint x="410" y="626" as="targetPoint"/></mxGeometry></mxCell><mxCell id="13" value="✕ deny" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#d92d20;fontSize=14;fontColor=#d92d20;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="610" y="552" as="sourcePoint"/><mxPoint x="610" y="626" as="targetPoint"/></mxGeometry></mxCell><mxCell id="14" value="&lt;b&gt;Workspace directory (read-write)&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#15202b&quot;&gt;the one folder mounted from the host&lt;/font&gt;" style="rounded=1;arcSize=19;whiteSpace=wrap;html=1;fillColor=#80bfbf;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="130" width="740" height="54" as="geometry"/></mxCell><mxCell id="15" value="Agent process" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="204" width="340" height="44" as="geometry"/></mxCell><mxCell id="16" value="Private Docker Engine" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="262" width="340" height="44" as="geometry"/></mxCell><mxCell id="17" value="Installed packages" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="320" width="340" height="44" as="geometry"/></mxCell><mxCell id="18" value="VM filesystem" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="378" width="340" height="44" as="geometry"/></mxCell><mxCell id="19" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="204" width="30" height="44" as="geometry"/></mxCell><mxCell id="20" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="262" width="30" height="44" as="geometry"/></mxCell><mxCell id="21" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="320" width="30" height="44" as="geometry"/></mxCell><mxCell id="22" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="378" width="30" height="44" as="geometry"/></mxCell><mxCell id="23" value="Host filesystem" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="204" width="265" height="44" as="geometry"/></mxCell><mxCell id="24" value="Host processes &amp;amp; environment" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="262" width="265" height="44" as="geometry"/></mxCell><mxCell id="25" value="Host Docker Engine" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="320" width="265" height="44" as="geometry"/></mxCell><mxCell id="26" value="Host network &amp;amp; localhost" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="378" width="265" height="44" as="geometry"/></mxCell><mxCell id="27" value="&lt;b&gt;🔒 Proxy&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#b8c4d0&quot;&gt;Allow/deny policies · Credential injection&lt;/font&gt;" style="rounded=1;arcSize=13;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="320" y="470" width="380" height="80" as="geometry"/></mxCell><mxCell id="28" value="&lt;b&gt;🔑 Secrets&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#64748b&quot;&gt;injected by the proxy&lt;/font&gt;" style="rounded=1;arcSize=13;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="470" width="265" height="80" as="geometry"/></mxCell><mxCell id="29" value="&lt;b&gt;Organization Policies&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#b8c4d0&quot;&gt;Network + File System + MCP&lt;/font&gt;" style="rounded=1;arcSize=13;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="34" y="470" width="222" height="80" as="geometry"/></mxCell><mxCell id="30" value="api.github.com" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="330" y="628" width="160" height="44" as="geometry"/></mxCell><mxCell id="31" value="bad.data.org" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="530" y="628" width="160" height="44" as="geometry"/></mxCell></root></mxGraphModel></diagram></mxfile>"> | |
| 2 | + <defs><marker id="arrow-dark" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#15202b"/></marker><marker id="arrow-blue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0062FF"/></marker><marker id="arrow-green" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#2e7d32"/></marker><marker id="arrow-red" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#d92d20"/></marker></defs> | |
| 3 | + <rect x="20" y="64" width="250" height="150" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 4 | + <text x="36" y="90" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">● Runs on laptop</text> | |
| 5 | + <text x="36" y="114" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="bold" fill="#15202b">● No Docker Desktop needed</text> | |
| 6 | + <text x="36" y="138" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">● Full YOLO mode: no</text> | |
| 7 | + <text x="36" y="162" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b"> permission prompts</text> | |
| 8 | + <text x="36" y="186" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">● Agents can run anything</text> | |
| 9 | + <rect x="20" y="424" width="250" height="156" rx="14" ry="14" fill="none" stroke="#64748b" stroke-width="2"/> | |
| 10 | + <text x="145" y="447" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="bold" fill="#15202b">Enterprise feature</text> | |
| 11 | + <rect x="300" y="20" width="800" height="560" rx="14" ry="14" fill="#f3f4ee" stroke="#15202b" stroke-width="2"/> | |
| 12 | + <text x="320" y="46" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Host System</text> | |
| 13 | + <rect x="320" y="64" width="380" height="374" rx="12" ry="12" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 14 | + <text x="340" y="90" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">🔒 Sandbox VM</text> | |
| 15 | + <text x="340" y="111" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#64748b">hypervisor boundary</text> | |
| 16 | + <path d="M 702 226 L 750 226" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | |
| 17 | + <path d="M 702 284 L 750 284" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | |
| 18 | + <path d="M 702 342 L 750 342" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | |
| 19 | + <path d="M 702 400 L 750 400" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | |
| 20 | + <path d="M 813 510 L 702 510" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | |
| 21 | + <rect x="708.2" y="477.5" width="97.6" height="25" rx="4" fill="#f3f4ee" opacity="0.92"/> | |
| 22 | + <text x="757" y="490" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" font-weight="normal" fill="#0062FF">credentials</text> | |
| 23 | + <path d="M 258 510 L 318 510" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/> | |
| 24 | + <path d="M 410 552 L 410 626" fill="none" stroke="#2e7d32" stroke-width="2" marker-end="url(#arrow-green)"/> | |
| 25 | + <rect x="373.6" y="587.5" width="72.8" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/> | |
| 26 | + <text x="410" y="600" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" font-weight="bold" fill="#2e7d32">✓ allow</text> | |
| 27 | + <path d="M 610 552 L 610 626" fill="none" stroke="#d92d20" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-red)"/> | |
| 28 | + <rect x="577.8" y="587.5" width="64.4" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/> | |
| 29 | + <text x="610" y="600" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" font-weight="bold" fill="#d92d20">✕ deny</text> | |
| 30 | + <rect x="340" y="130" width="740" height="54" rx="10" ry="10" fill="#80bfbf" stroke="#15202b" stroke-width="2"/> | |
| 31 | + <text x="710" y="148" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Workspace directory (read-write)</text> | |
| 32 | + <text x="710" y="169" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#15202b">the one folder mounted from the host</text> | |
| 33 | + <rect x="340" y="204" width="340" height="44" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/> | |
| 34 | + <text x="510" y="227" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Agent process</text> | |
| 35 | + <rect x="340" y="262" width="340" height="44" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/> | |
| 36 | + <text x="510" y="285" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Private Docker Engine</text> | |
| 37 | + <rect x="340" y="320" width="340" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 38 | + <text x="510" y="343" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Installed packages</text> | |
| 39 | + <rect x="340" y="378" width="340" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 40 | + <text x="510" y="401" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">VM filesystem</text> | |
| 41 | + <rect x="752" y="204" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | |
| 42 | + <text x="767" y="227" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | |
| 43 | + <rect x="752" y="262" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | |
| 44 | + <text x="767" y="285" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | |
| 45 | + <rect x="752" y="320" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | |
| 46 | + <text x="767" y="343" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | |
| 47 | + <rect x="752" y="378" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | |
| 48 | + <text x="767" y="401" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | |
| 49 | + <text x="767" y="436" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#d92d20">blocked</text> | |
| 50 | + <rect x="815" y="204" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 51 | + <text x="947.5" y="227" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host filesystem</text> | |
| 52 | + <rect x="815" y="262" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 53 | + <text x="947.5" y="285" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host processes & environment</text> | |
| 54 | + <rect x="815" y="320" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 55 | + <text x="947.5" y="343" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host Docker Engine</text> | |
| 56 | + <rect x="815" y="378" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 57 | + <text x="947.5" y="401" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host network & localhost</text> | |
| 58 | + <rect x="320" y="470" width="380" height="80" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/> | |
| 59 | + <text x="510" y="501" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">🔒 Proxy</text> | |
| 60 | + <text x="510" y="522" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#b8c4d0">Allow/deny policies · Credential injection</text> | |
| 61 | + <rect x="815" y="470" width="265" height="80" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/> | |
| 62 | + <text x="947.5" y="501" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">🔑 Secrets</text> | |
| 63 | + <text x="947.5" y="522" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#64748b">injected by the proxy</text> | |
| 64 | + <rect x="34" y="470" width="222" height="80" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/> | |
| 65 | + <text x="145" y="501" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Organization Policies</text> | |
| 66 | + <text x="145" y="522" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#b8c4d0">Network + File System + MCP</text> | |
| 67 | + <rect x="330" y="628" width="160" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 68 | + <text x="410" y="651" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">api.github.com</text> | |
| 69 | + <rect x="530" y="628" width="160" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | |
| 70 | + <text x="610" y="651" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">bad.data.org</text> | |
| 71 | +</svg> | |
| new file mode 100644 | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1120" height="694" viewBox="0 0 1120 694" content="<mxfile host="Electron" agent="make-diagram.mjs" type="device"><diagram name="sbx security model" id="diagram-1"><mxGraphModel dx="1000" dy="600" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="826" math="0" shadow="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="● Runs on laptop&lt;br&gt;&lt;b&gt;● No Docker Desktop needed&lt;/b&gt;&lt;br&gt;● Full YOLO mode: no&lt;br&gt; permission prompts&lt;br&gt;● Agents can run anything" style="rounded=1;arcSize=8;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=15;strokeWidth=2;align=left;verticalAlign=top;spacingLeft=16;spacingTop=10;" vertex="1" parent="1"><mxGeometry x="20" y="64" width="250" height="150" as="geometry"/></mxCell><mxCell id="3" value="" style="rounded=1;arcSize=9;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#64748b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="20" y="424" width="250" height="156" as="geometry"/></mxCell><mxCell id="4" value="&lt;b&gt;Host System&lt;/b&gt;" style="rounded=1;arcSize=3;whiteSpace=wrap;html=1;fillColor=#f3f4ee;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;verticalAlign=top;align=left;spacingLeft=20;spacingTop=10;" vertex="1" parent="1"><mxGeometry x="300" y="20" width="800" height="560" as="geometry"/></mxCell><mxCell id="5" value="&lt;b&gt;🔒 Sandbox VM&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#64748b&quot;&gt;hypervisor boundary&lt;/font&gt;" style="rounded=1;arcSize=3;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;verticalAlign=top;align=left;spacingLeft=20;spacingTop=10;" vertex="1" parent="1"><mxGeometry x="320" y="64" width="380" height="374" as="geometry"/></mxCell><mxCell id="6" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="226" as="sourcePoint"/><mxPoint x="750" y="226" as="targetPoint"/></mxGeometry></mxCell><mxCell id="7" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="284" as="sourcePoint"/><mxPoint x="750" y="284" as="targetPoint"/></mxGeometry></mxCell><mxCell id="8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="342" as="sourcePoint"/><mxPoint x="750" y="342" as="targetPoint"/></mxGeometry></mxCell><mxCell id="9" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="702" y="400" as="sourcePoint"/><mxPoint x="750" y="400" as="targetPoint"/></mxGeometry></mxCell><mxCell id="10" value="credentials" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#0062FF;fontSize=14;fontColor=#0062FF;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="813" y="510" as="sourcePoint"/><mxPoint x="702" y="510" as="targetPoint"/></mxGeometry></mxCell><mxCell id="11" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#15202b;fontSize=14;fontColor=#15202b;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="258" y="510" as="sourcePoint"/><mxPoint x="318" y="510" as="targetPoint"/></mxGeometry></mxCell><mxCell id="12" value="✓ allow" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#2e7d32;fontSize=14;fontColor=#2e7d32;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="410" y="552" as="sourcePoint"/><mxPoint x="410" y="626" as="targetPoint"/></mxGeometry></mxCell><mxCell id="13" value="✕ deny" style="edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;strokeWidth=2;strokeColor=#d92d20;fontSize=14;fontColor=#d92d20;dashed=1;" edge="1" parent="1"><mxGeometry relative="1" as="geometry"><mxPoint x="610" y="552" as="sourcePoint"/><mxPoint x="610" y="626" as="targetPoint"/></mxGeometry></mxCell><mxCell id="14" value="&lt;b&gt;Workspace directory (read-write)&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#15202b&quot;&gt;the one folder mounted from the host&lt;/font&gt;" style="rounded=1;arcSize=19;whiteSpace=wrap;html=1;fillColor=#80bfbf;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="130" width="740" height="54" as="geometry"/></mxCell><mxCell id="15" value="Agent process" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="204" width="340" height="44" as="geometry"/></mxCell><mxCell id="16" value="Private Docker Engine" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="262" width="340" height="44" as="geometry"/></mxCell><mxCell id="17" value="Installed packages" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="320" width="340" height="44" as="geometry"/></mxCell><mxCell id="18" value="VM filesystem" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="340" y="378" width="340" height="44" as="geometry"/></mxCell><mxCell id="19" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="204" width="30" height="44" as="geometry"/></mxCell><mxCell id="20" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="262" width="30" height="44" as="geometry"/></mxCell><mxCell id="21" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="320" width="30" height="44" as="geometry"/></mxCell><mxCell id="22" value="✕" style="rounded=1;arcSize=20;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#d92d20;fontColor=#d92d20;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="752" y="378" width="30" height="44" as="geometry"/></mxCell><mxCell id="23" value="Host filesystem" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="204" width="265" height="44" as="geometry"/></mxCell><mxCell id="24" value="Host processes &amp;amp; environment" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="262" width="265" height="44" as="geometry"/></mxCell><mxCell id="25" value="Host Docker Engine" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="320" width="265" height="44" as="geometry"/></mxCell><mxCell id="26" value="Host network &amp;amp; localhost" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="378" width="265" height="44" as="geometry"/></mxCell><mxCell id="27" value="&lt;b&gt;🔒 Proxy&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#b8c4d0&quot;&gt;Allow/deny policies · Credential injection&lt;/font&gt;" style="rounded=1;arcSize=13;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="320" y="470" width="380" height="80" as="geometry"/></mxCell><mxCell id="28" value="&lt;b&gt;🔑 Secrets&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#64748b&quot;&gt;injected by the proxy&lt;/font&gt;" style="rounded=1;arcSize=13;whiteSpace=wrap;html=1;fillColor=#e8ebda;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="815" y="470" width="265" height="80" as="geometry"/></mxCell><mxCell id="29" value="&lt;b&gt;Organization Policies&lt;/b&gt;&lt;br&gt;&lt;font style=&quot;font-size:13px;color:#b8c4d0&quot;&gt;Network + File System + MCP&lt;/font&gt;" style="rounded=1;arcSize=13;whiteSpace=wrap;html=1;fillColor=#15202b;strokeColor=#15202b;fontColor=#fdfdfb;fontSize=17;fontStyle=1;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="34" y="470" width="222" height="80" as="geometry"/></mxCell><mxCell id="30" value="api.github.com" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="330" y="628" width="160" height="44" as="geometry"/></mxCell><mxCell id="31" value="bad.data.org" style="rounded=1;arcSize=23;whiteSpace=wrap;html=1;fillColor=#fdfdfb;strokeColor=#15202b;fontColor=#15202b;fontSize=17;fontStyle=0;strokeWidth=2;" vertex="1" parent="1"><mxGeometry x="530" y="628" width="160" height="44" as="geometry"/></mxCell></root></mxGraphModel></diagram></mxfile>"> | ||
| 2 | + <defs><marker id="arrow-dark" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#15202b"/></marker><marker id="arrow-blue" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#0062FF"/></marker><marker id="arrow-green" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#2e7d32"/></marker><marker id="arrow-red" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#d92d20"/></marker></defs> | ||
| 3 | + <rect x="20" y="64" width="250" height="150" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 4 | + <text x="36" y="90" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">● Runs on laptop</text> | ||
| 5 | + <text x="36" y="114" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="bold" fill="#15202b">● No Docker Desktop needed</text> | ||
| 6 | + <text x="36" y="138" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">● Full YOLO mode: no</text> | ||
| 7 | + <text x="36" y="162" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b"> permission prompts</text> | ||
| 8 | + <text x="36" y="186" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="normal" fill="#15202b">● Agents can run anything</text> | ||
| 9 | + <rect x="20" y="424" width="250" height="156" rx="14" ry="14" fill="none" stroke="#64748b" stroke-width="2"/> | ||
| 10 | + <text x="145" y="447" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="15" font-weight="bold" fill="#15202b">Enterprise feature</text> | ||
| 11 | + <rect x="300" y="20" width="800" height="560" rx="14" ry="14" fill="#f3f4ee" stroke="#15202b" stroke-width="2"/> | ||
| 12 | + <text x="320" y="46" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Host System</text> | ||
| 13 | + <rect x="320" y="64" width="380" height="374" rx="12" ry="12" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 14 | + <text x="340" y="90" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">🔒 Sandbox VM</text> | ||
| 15 | + <text x="340" y="111" text-anchor="start" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#64748b">hypervisor boundary</text> | ||
| 16 | + <path d="M 702 226 L 750 226" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | ||
| 17 | + <path d="M 702 284 L 750 284" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | ||
| 18 | + <path d="M 702 342 L 750 342" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | ||
| 19 | + <path d="M 702 400 L 750 400" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | ||
| 20 | + <path d="M 813 510 L 702 510" fill="none" stroke="#0062FF" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-blue)"/> | ||
| 21 | + <rect x="708.2" y="477.5" width="97.6" height="25" rx="4" fill="#f3f4ee" opacity="0.92"/> | ||
| 22 | + <text x="757" y="490" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" font-weight="normal" fill="#0062FF">credentials</text> | ||
| 23 | + <path d="M 258 510 L 318 510" fill="none" stroke="#15202b" stroke-width="2" marker-end="url(#arrow-dark)"/> | ||
| 24 | + <path d="M 410 552 L 410 626" fill="none" stroke="#2e7d32" stroke-width="2" marker-end="url(#arrow-green)"/> | ||
| 25 | + <rect x="373.6" y="587.5" width="72.8" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/> | ||
| 26 | + <text x="410" y="600" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" font-weight="bold" fill="#2e7d32">✓ allow</text> | ||
| 27 | + <path d="M 610 552 L 610 626" fill="none" stroke="#d92d20" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow-red)"/> | ||
| 28 | + <rect x="577.8" y="587.5" width="64.4" height="25" rx="4" fill="#fdfdfb" opacity="0.92"/> | ||
| 29 | + <text x="610" y="600" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="14" font-weight="bold" fill="#d92d20">✕ deny</text> | ||
| 30 | + <rect x="340" y="130" width="740" height="54" rx="10" ry="10" fill="#80bfbf" stroke="#15202b" stroke-width="2"/> | ||
| 31 | + <text x="710" y="148" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Workspace directory (read-write)</text> | ||
| 32 | + <text x="710" y="169" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#15202b">the one folder mounted from the host</text> | ||
| 33 | + <rect x="340" y="204" width="340" height="44" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/> | ||
| 34 | + <text x="510" y="227" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Agent process</text> | ||
| 35 | + <rect x="340" y="262" width="340" height="44" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/> | ||
| 36 | + <text x="510" y="285" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">Private Docker Engine</text> | ||
| 37 | + <rect x="340" y="320" width="340" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 38 | + <text x="510" y="343" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Installed packages</text> | ||
| 39 | + <rect x="340" y="378" width="340" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 40 | + <text x="510" y="401" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">VM filesystem</text> | ||
| 41 | + <rect x="752" y="204" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | ||
| 42 | + <text x="767" y="227" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | ||
| 43 | + <rect x="752" y="262" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | ||
| 44 | + <text x="767" y="285" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | ||
| 45 | + <rect x="752" y="320" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | ||
| 46 | + <text x="767" y="343" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | ||
| 47 | + <rect x="752" y="378" width="30" height="44" rx="6" ry="6" fill="#fdfdfb" stroke="#d92d20" stroke-width="2"/> | ||
| 48 | + <text x="767" y="401" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#d92d20">✕</text> | ||
| 49 | + <text x="767" y="436" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#d92d20">blocked</text> | ||
| 50 | + <rect x="815" y="204" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 51 | + <text x="947.5" y="227" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host filesystem</text> | ||
| 52 | + <rect x="815" y="262" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 53 | + <text x="947.5" y="285" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host processes & environment</text> | ||
| 54 | + <rect x="815" y="320" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 55 | + <text x="947.5" y="343" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host Docker Engine</text> | ||
| 56 | + <rect x="815" y="378" width="265" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 57 | + <text x="947.5" y="401" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">Host network & localhost</text> | ||
| 58 | + <rect x="320" y="470" width="380" height="80" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/> | ||
| 59 | + <text x="510" y="501" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">🔒 Proxy</text> | ||
| 60 | + <text x="510" y="522" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#b8c4d0">Allow/deny policies · Credential injection</text> | ||
| 61 | + <rect x="815" y="470" width="265" height="80" rx="10" ry="10" fill="#e8ebda" stroke="#15202b" stroke-width="2"/> | ||
| 62 | + <text x="947.5" y="501" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#15202b">🔑 Secrets</text> | ||
| 63 | + <text x="947.5" y="522" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#64748b">injected by the proxy</text> | ||
| 64 | + <rect x="34" y="470" width="222" height="80" rx="10" ry="10" fill="#15202b" stroke="#15202b" stroke-width="2"/> | ||
| 65 | + <text x="145" y="501" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="bold" fill="#fdfdfb">Organization Policies</text> | ||
| 66 | + <text x="145" y="522" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="13" font-weight="normal" fill="#b8c4d0">Network + File System + MCP</text> | ||
| 67 | + <rect x="330" y="628" width="160" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 68 | + <text x="410" y="651" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">api.github.com</text> | ||
| 69 | + <rect x="530" y="628" width="160" height="44" rx="10" ry="10" fill="#fdfdfb" stroke="#15202b" stroke-width="2"/> | ||
| 70 | + <text x="610" y="651" text-anchor="middle" dominant-baseline="central" font-family="Helvetica Neue, Helvetica, Arial, sans-serif" font-size="17" font-weight="normal" fill="#15202b">bad.data.org</text> | ||
| 71 | +</svg> | ||
added
05-sbx-docker-agent/README.md +51 -0 | new file mode 100644 | ||
| @@ -0,0 +1,51 @@ | ||
| 1 | +# I want Docker Agent sandboxed and connected to Mistral.ai | |
| 2 | + | |
| 3 | +Today Docker Agent does not automatically recognize the mistral secret (`sbx secret set mistral`), unlike Mistral's **Vibe** CLI. So we are going to use a "custom secret". | |
| 4 | + | |
| 5 | +## Custom secret and `MISTRAL_API_KEY` | |
| 6 | + | |
| 7 | +1. Create a `sbx.env` file: | |
| 8 | + ``` | |
| 9 | + DOCKER_AGENT_AUTO_UPDATE=0 | |
| 10 | + MISTRAL_API_KEY=sbx-mistral-key | |
| 11 | + ``` | |
| 12 | +2. Create a custom secret with a **fixed placeholder value** that you choose: | |
| 13 | + ```bash | |
| 14 | + export MISTRAL_API_KEY="your-api-key" | |
| 15 | + sbx secret set-custom --host api.mistral.ai --env MISTRAL_API_KEY \ | |
| 16 | + --placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | |
| 17 | + ``` | |
| 18 | + | |
| 19 | + 🖐️ **on Windows:** | |
| 20 | + ```bash | |
| 21 | + $env:MISTRAL_API_KEY="your-api-key" | |
| 22 | + | |
| 23 | + sbx secret set-custom --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | |
| 24 | + ``` | |
| 25 | + | |
| 26 | +3. Start the sandbox: | |
| 27 | + ```bash | |
| 28 | + sbx run --env-file sbx.env docker-agent -- run agent.yaml . | |
| 29 | + ``` | |
| 30 | + > dont forget the `.` | |
| 31 | + | |
| 32 | +Or without the `sbx.env` file: | |
| 33 | + | |
| 34 | +```bash | |
| 35 | +sbx run -e MISTRAL_API_KEY=sbx-mistral-key -e DOCKER_AGENT_AUTO_UPDATE=0 docker-agent -- run agent.yaml . | |
| 36 | +``` | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | +## And try again | |
| 43 | + | |
| 44 | +```raw | |
| 45 | +Create a text file at the home of my machine with a greeting message | |
| 46 | +``` | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | +Also try to write or read files outside of this directory. | |
| new file mode 100644 | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | +# I want Docker Agent sandboxed and connected to Mistral.ai | ||
| 2 | + | ||
| 3 | +Today Docker Agent does not automatically recognize the mistral secret (`sbx secret set mistral`), unlike Mistral's **Vibe** CLI. So we are going to use a "custom secret". | ||
| 4 | + | ||
| 5 | +## Custom secret and `MISTRAL_API_KEY` | ||
| 6 | + | ||
| 7 | +1. Create a `sbx.env` file: | ||
| 8 | + ``` | ||
| 9 | + DOCKER_AGENT_AUTO_UPDATE=0 | ||
| 10 | + MISTRAL_API_KEY=sbx-mistral-key | ||
| 11 | + ``` | ||
| 12 | +2. Create a custom secret with a **fixed placeholder value** that you choose: | ||
| 13 | + ```bash | ||
| 14 | + export MISTRAL_API_KEY="your-api-key" | ||
| 15 | + sbx secret set-custom --host api.mistral.ai --env MISTRAL_API_KEY \ | ||
| 16 | + --placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | ||
| 17 | + ``` | ||
| 18 | + | ||
| 19 | + 🖐️ **on Windows:** | ||
| 20 | + ```bash | ||
| 21 | + $env:MISTRAL_API_KEY="your-api-key" | ||
| 22 | + | ||
| 23 | + sbx secret set-custom --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | ||
| 24 | + ``` | ||
| 25 | + | ||
| 26 | +3. Start the sandbox: | ||
| 27 | + ```bash | ||
| 28 | + sbx run --env-file sbx.env docker-agent -- run agent.yaml . | ||
| 29 | + ``` | ||
| 30 | + > dont forget the `.` | ||
| 31 | + | ||
| 32 | +Or without the `sbx.env` file: | ||
| 33 | + | ||
| 34 | +```bash | ||
| 35 | +sbx run -e MISTRAL_API_KEY=sbx-mistral-key -e DOCKER_AGENT_AUTO_UPDATE=0 docker-agent -- run agent.yaml . | ||
| 36 | +``` | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + | ||
| 42 | +## And try again | ||
| 43 | + | ||
| 44 | +```raw | ||
| 45 | +Create a text file at the home of my machine with a greeting message | ||
| 46 | +``` | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + | ||
| 50 | + | ||
| 51 | +Also try to write or read files outside of this directory. | ||
added
05-sbx-docker-agent/agent.yaml +20 -0 | new file mode 100644 | ||
| @@ -0,0 +1,20 @@ | ||
| 1 | +models: | |
| 2 | + mistral: | |
| 3 | + provider: mistral | |
| 4 | + model: ministral-3b-2512 | |
| 5 | + temperature: 0.7 | |
| 6 | + max_tokens: 8192 | |
| 7 | + | |
| 8 | +agents: | |
| 9 | + root: | |
| 10 | + model: mistral | |
| 11 | + description: Assistant using Mistral | |
| 12 | + instruction: | | |
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | |
| 14 | + | |
| 15 | + welcome_message: | | |
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | |
| 17 | + | |
| 18 | + toolsets: | |
| 19 | + - type: filesystem | |
| 20 | + - type: shell | |
| new file mode 100644 | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | +models: | ||
| 2 | + mistral: | ||
| 3 | + provider: mistral | ||
| 4 | + model: ministral-3b-2512 | ||
| 5 | + temperature: 0.7 | ||
| 6 | + max_tokens: 8192 | ||
| 7 | + | ||
| 8 | +agents: | ||
| 9 | + root: | ||
| 10 | + model: mistral | ||
| 11 | + description: Assistant using Mistral | ||
| 12 | + instruction: | | ||
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | ||
| 14 | + | ||
| 15 | + welcome_message: | | ||
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | ||
| 17 | + | ||
| 18 | + toolsets: | ||
| 19 | + - type: filesystem | ||
| 20 | + - type: shell | ||
added
05-sbx-docker-agent/assets/docker-agent-01.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/05-sbx-docker-agent/assets/docker-agent-01.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/05-sbx-docker-agent/assets/docker-agent-01.png differ | Binary files /dev/null and b/05-sbx-docker-agent/assets/docker-agent-01.png differ | ||
added
05-sbx-docker-agent/assets/docker-agent-02.png +0 -0 | new file mode 100644 | ||
| Binary files /dev/null and b/05-sbx-docker-agent/assets/docker-agent-02.png differ | ||
| new file mode 100644 | |||
| Binary files /dev/null and b/05-sbx-docker-agent/assets/docker-agent-02.png differ | Binary files /dev/null and b/05-sbx-docker-agent/assets/docker-agent-02.png differ | ||
added
05-sbx-docker-agent/sbx.env +2 -0 | new file mode 100644 | ||
| @@ -0,0 +1,2 @@ | ||
| 1 | +DOCKER_AGENT_AUTO_UPDATE=0 | |
| 2 | +MISTRAL_API_KEY=sbx-mistral-key | |
| \ No newline at end of file | ||
| new file mode 100644 | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | +DOCKER_AGENT_AUTO_UPDATE=0 | ||
| 2 | +MISTRAL_API_KEY=sbx-mistral-key | ||
| \ No newline at end of file | \ No newline at end of file | ||
added
06-sbx-docker-agent-sbx-env/README.md +58 -0 | new file mode 100644 | ||
| @@ -0,0 +1,58 @@ | ||
| 1 | +# Docker Agent sandboxed and connected to Mistral.ai, with `sbx env` | |
| 2 | + | |
| 3 | +Same goal as the previous step, but the sandbox is described declaratively in an `sbxenv.yaml` file instead of a long `sbx run` command line. | |
| 4 | + | |
| 5 | +## The `sbxenv.yaml` file | |
| 6 | + | |
| 7 | +```yaml | |
| 8 | +schemaVersion: "1" | |
| 9 | +name: docker-agent-mistral | |
| 10 | +agent: docker-agent | |
| 11 | +workspace: . | |
| 12 | +env: | |
| 13 | + DOCKER_AGENT_AUTO_UPDATE: "0" | |
| 14 | + MISTRAL_API_KEY: sbx-mistral-key | |
| 15 | +``` | |
| 16 | + | |
| 17 | +- `name`: name of the sandbox (and the "scope" of the secrets associated with it). | |
| 18 | +- `agent`: the base agent to use. | |
| 19 | +- `workspace`: the directory mounted in the sandbox (`.` = the folder of the file). | |
| 20 | +- `env`: the environment variables of the sandbox (replaces `sbx.env`). `MISTRAL_API_KEY` only contains the **placeholder value**, never the real key. | |
| 21 | + | |
| 22 | +## Custom secret | |
| 23 | + | |
| 24 | +`sbxenv.yaml` cannot declare a custom secret. So we create it beforehand, **attaching it to the sandbox** (the `name` of the file) so that `sbx env rm` removes it: | |
| 25 | + | |
| 26 | +```bash | |
| 27 | +export MISTRAL_API_KEY="your-api-key" | |
| 28 | +sbx secret set-custom --sandbox docker-agent-mistral \ | |
| 29 | +--host api.mistral.ai --env MISTRAL_API_KEY \ | |
| 30 | +--placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | |
| 31 | +``` | |
| 32 | + | |
| 33 | +🖐️ **on Windows:** | |
| 34 | +```bash | |
| 35 | +$env:MISTRAL_API_KEY="your-api-key" | |
| 36 | + | |
| 37 | +sbx secret set-custom --sandbox docker-agent-mistral --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | |
| 38 | +``` | |
| 39 | + | |
| 40 | + | |
| 41 | +## Start the sandbox | |
| 42 | + | |
| 43 | +`sbx env run` cannot pass arguments to the agent (no `-- run agent.yaml`): Docker Agent would be started with its default arguments (`run --yolo --agent-picker`), so not necessarily with `agent.yaml` and Mistral. We create the sandbox, then start Docker Agent with `agent.yaml` through `sbx env exec`: | |
| 44 | + | |
| 45 | +```bash | |
| 46 | +sbx env create | |
| 47 | +sbx env exec -it -- docker-agent run agent.yaml | |
| 48 | +``` | |
| 49 | + | |
| 50 | +`sbx env` shows the plan (what is going to be created) and asks for approval; `--force` accepts it without asking. `sbx env exec` also applies the `env:` of `sbxenv.yaml`. | |
| 51 | + | |
| 52 | +Other useful commands: | |
| 53 | + | |
| 54 | +```bash | |
| 55 | +sbx env plan # preview the changes | |
| 56 | +sbx env run # create (if needed) and attach with the default agent | |
| 57 | +sbx env rm # remove the sandbox and its secrets | |
| 58 | +``` | |
| new file mode 100644 | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | +# Docker Agent sandboxed and connected to Mistral.ai, with `sbx env` | ||
| 2 | + | ||
| 3 | +Same goal as the previous step, but the sandbox is described declaratively in an `sbxenv.yaml` file instead of a long `sbx run` command line. | ||
| 4 | + | ||
| 5 | +## The `sbxenv.yaml` file | ||
| 6 | + | ||
| 7 | +```yaml | ||
| 8 | +schemaVersion: "1" | ||
| 9 | +name: docker-agent-mistral | ||
| 10 | +agent: docker-agent | ||
| 11 | +workspace: . | ||
| 12 | +env: | ||
| 13 | + DOCKER_AGENT_AUTO_UPDATE: "0" | ||
| 14 | + MISTRAL_API_KEY: sbx-mistral-key | ||
| 15 | +``` | ||
| 16 | + | ||
| 17 | +- `name`: name of the sandbox (and the "scope" of the secrets associated with it). | ||
| 18 | +- `agent`: the base agent to use. | ||
| 19 | +- `workspace`: the directory mounted in the sandbox (`.` = the folder of the file). | ||
| 20 | +- `env`: the environment variables of the sandbox (replaces `sbx.env`). `MISTRAL_API_KEY` only contains the **placeholder value**, never the real key. | ||
| 21 | + | ||
| 22 | +## Custom secret | ||
| 23 | + | ||
| 24 | +`sbxenv.yaml` cannot declare a custom secret. So we create it beforehand, **attaching it to the sandbox** (the `name` of the file) so that `sbx env rm` removes it: | ||
| 25 | + | ||
| 26 | +```bash | ||
| 27 | +export MISTRAL_API_KEY="your-api-key" | ||
| 28 | +sbx secret set-custom --sandbox docker-agent-mistral \ | ||
| 29 | +--host api.mistral.ai --env MISTRAL_API_KEY \ | ||
| 30 | +--placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | ||
| 31 | +``` | ||
| 32 | + | ||
| 33 | +🖐️ **on Windows:** | ||
| 34 | +```bash | ||
| 35 | +$env:MISTRAL_API_KEY="your-api-key" | ||
| 36 | + | ||
| 37 | +sbx secret set-custom --sandbox docker-agent-mistral --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | ||
| 38 | +``` | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +## Start the sandbox | ||
| 42 | + | ||
| 43 | +`sbx env run` cannot pass arguments to the agent (no `-- run agent.yaml`): Docker Agent would be started with its default arguments (`run --yolo --agent-picker`), so not necessarily with `agent.yaml` and Mistral. We create the sandbox, then start Docker Agent with `agent.yaml` through `sbx env exec`: | ||
| 44 | + | ||
| 45 | +```bash | ||
| 46 | +sbx env create | ||
| 47 | +sbx env exec -it -- docker-agent run agent.yaml | ||
| 48 | +``` | ||
| 49 | + | ||
| 50 | +`sbx env` shows the plan (what is going to be created) and asks for approval; `--force` accepts it without asking. `sbx env exec` also applies the `env:` of `sbxenv.yaml`. | ||
| 51 | + | ||
| 52 | +Other useful commands: | ||
| 53 | + | ||
| 54 | +```bash | ||
| 55 | +sbx env plan # preview the changes | ||
| 56 | +sbx env run # create (if needed) and attach with the default agent | ||
| 57 | +sbx env rm # remove the sandbox and its secrets | ||
| 58 | +``` | ||
added
06-sbx-docker-agent-sbx-env/agent.yaml +20 -0 | new file mode 100644 | ||
| @@ -0,0 +1,20 @@ | ||
| 1 | +models: | |
| 2 | + mistral: | |
| 3 | + provider: mistral | |
| 4 | + model: ministral-3b-2512 | |
| 5 | + temperature: 0.7 | |
| 6 | + max_tokens: 8192 | |
| 7 | + | |
| 8 | +agents: | |
| 9 | + root: | |
| 10 | + model: mistral | |
| 11 | + description: Assistant using Mistral | |
| 12 | + instruction: | | |
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | |
| 14 | + | |
| 15 | + welcome_message: | | |
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | |
| 17 | + | |
| 18 | + toolsets: | |
| 19 | + - type: filesystem | |
| 20 | + - type: shell | |
| new file mode 100644 | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | +models: | ||
| 2 | + mistral: | ||
| 3 | + provider: mistral | ||
| 4 | + model: ministral-3b-2512 | ||
| 5 | + temperature: 0.7 | ||
| 6 | + max_tokens: 8192 | ||
| 7 | + | ||
| 8 | +agents: | ||
| 9 | + root: | ||
| 10 | + model: mistral | ||
| 11 | + description: Assistant using Mistral | ||
| 12 | + instruction: | | ||
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | ||
| 14 | + | ||
| 15 | + welcome_message: | | ||
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | ||
| 17 | + | ||
| 18 | + toolsets: | ||
| 19 | + - type: filesystem | ||
| 20 | + - type: shell | ||
added
06-sbx-docker-agent-sbx-env/sbxenv.yaml +7 -0 | new file mode 100644 | ||
| @@ -0,0 +1,7 @@ | ||
| 1 | +schemaVersion: "1" | |
| 2 | +name: docker-agent-mistral | |
| 3 | +agent: docker-agent | |
| 4 | +workspace: . | |
| 5 | +env: | |
| 6 | + DOCKER_AGENT_AUTO_UPDATE: "0" | |
| 7 | + MISTRAL_API_KEY: sbx-mistral-key | |
| new file mode 100644 | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | +schemaVersion: "1" | ||
| 2 | +name: docker-agent-mistral | ||
| 3 | +agent: docker-agent | ||
| 4 | +workspace: . | ||
| 5 | +env: | ||
| 6 | + DOCKER_AGENT_AUTO_UPDATE: "0" | ||
| 7 | + MISTRAL_API_KEY: sbx-mistral-key | ||
added
07-play-lego-with-kits/.gitattributes +1 -0 | new file mode 100644 | ||
| @@ -0,0 +1 @@ | ||
| 1 | +kits/** text eol=lf | |
| new file mode 100644 | |||
| @@ -0,0 +1 @@ | |||
| 1 | +kits/** text eol=lf | ||
added
07-play-lego-with-kits/README.md +96 -0 | new file mode 100644 | ||
| @@ -0,0 +1,96 @@ | ||
| 1 | +# Playing Lego with kits: Docker Agent + Rust | |
| 2 | + | |
| 3 | +A **kit** is a reusable brick to compose a sandbox. Here, we assemble two kits in `sbxenv.yaml`: | |
| 4 | + | |
| 5 | +| Kit | Role | | |
| 6 | +|-----|------| | |
| 7 | +| `kits/docker-agent-mistral` | the **workload** (the base): Docker Agent, started directly on `agent.yaml`, with access to the Mistral API | | |
| 8 | +| `kits/rust-toolchain` | a **mixin**: the Rust toolchain (`cargo`, `rustc`, `rustfmt`, `clippy`, `rust-analyzer`) | | |
| 9 | + | |
| 10 | +A set of v3 kits contains **exactly one workload** and as many mixins as you want. A single v3 mixin combined with the built-in `docker-agent` agent (which is a v2 kit) is refused: `no workload kit in the set`. | |
| 11 | + | |
| 12 | +## The `sbxenv.yaml` file | |
| 13 | + | |
| 14 | +```yaml | |
| 15 | +schemaVersion: "1" | |
| 16 | +name: docker-rust-agent-mistral | |
| 17 | +agent: docker-agent-mistral | |
| 18 | +workspace: . | |
| 19 | +env: | |
| 20 | + DOCKER_AGENT_AUTO_UPDATE: "0" | |
| 21 | + MISTRAL_API_KEY: sbx-mistral-key | |
| 22 | + | |
| 23 | +kits: | |
| 24 | + - ./kits/docker-agent-mistral | |
| 25 | + - ./kits/rust-toolchain | |
| 26 | +``` | |
| 27 | + | |
| 28 | +- `agent`: must carry the name of the workload kit (the file name `docker-agent-mistral.yaml`). | |
| 29 | +- `kits`: the workload, then the mixins. Relative paths are resolved against this file. | |
| 30 | +- `env`: `MISTRAL_API_KEY` only contains the **placeholder value**, never the real key. | |
| 31 | + | |
| 32 | +## The workload kit: `docker-agent-mistral` | |
| 33 | + | |
| 34 | +- `docker-agent-mistral.dockerfile` starts from the `docker/sandbox-templates:docker-agent-docker` image and defines the launch command (`ENTRYPOINT`/`CMD`): `docker-agent run agent.yaml`. | |
| 35 | +- `docker-agent-mistral.yaml` declares `kind: workload` and allows outbound traffic to `api.mistral.ai`. | |
| 36 | + | |
| 37 | +## The mixin kit: `rust-toolchain` | |
| 38 | + | |
| 39 | +- `rust-toolchain.dockerfile` builds a layer with the Rust toolchain and the linker (`gcc`); it is only added on top of the image. | |
| 40 | +- `rust-toolchain.yaml` declares `kind: mixin`, the `rust_version` argument (default `1.99.0`) and allows outbound traffic to crates.io. | |
| 41 | + | |
| 42 | +To change the Rust version without modifying the files: | |
| 43 | + | |
| 44 | +```bash | |
| 45 | +sbx env create --kit-arg rust_version=stable | |
| 46 | +``` | |
| 47 | + | |
| 48 | +## Custom secret | |
| 49 | + | |
| 50 | +`sbxenv.yaml` cannot declare a custom secret: we create it beforehand. With `--sandbox`, it is removed along with the sandbox by `sbx env rm`: | |
| 51 | + | |
| 52 | +```bash | |
| 53 | +export MISTRAL_API_KEY="your-api-key" | |
| 54 | +sbx secret set-custom --sandbox docker-rust-agent-mistral \ | |
| 55 | +--host api.mistral.ai --env MISTRAL_API_KEY \ | |
| 56 | +--placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | |
| 57 | +``` | |
| 58 | + | |
| 59 | +🖐️ **on Windows:** | |
| 60 | +```bash | |
| 61 | +$env:MISTRAL_API_KEY="your-api-key" | |
| 62 | + | |
| 63 | +sbx secret set-custom --sandbox docker-rust-agent-mistral --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | |
| 64 | +``` | |
| 65 | + | |
| 66 | +Without `--sandbox`, the secret is global and works too. | |
| 67 | + | |
| 68 | +## Start the sandbox | |
| 69 | + | |
| 70 | +```bash | |
| 71 | +sbx env create | |
| 72 | +sbx env exec -it -- docker-agent run agent.yaml | |
| 73 | +``` | |
| 74 | +> 🖐️ **you need Docker to build a kit** | |
| 75 | + | |
| 76 | +`sbx env` shows the plan (what is going to be created) and asks for approval; `--force` accepts it without asking. The first creation builds the two kits, which takes a little time. | |
| 77 | + | |
| 78 | +Other useful commands: | |
| 79 | + | |
| 80 | +```bash | |
| 81 | +sbx env plan # preview the changes | |
| 82 | +sbx env rm # remove the sandbox and its secrets | |
| 83 | +``` | |
| 84 | + | |
| 85 | +## And try | |
| 86 | + | |
| 87 | +```raw | |
| 88 | +What is the version of cargo? | |
| 89 | +``` | |
| 90 | + | |
| 91 | + | |
| 92 | +```raw | |
| 93 | +Create a new Rust project with cargo that prints a greeting, then build and run it | |
| 94 | +``` | |
| 95 | + | |
| 96 | +The agent can now use `cargo build`, `cargo test` or `cargo clippy` in the sandbox. | |
| new file mode 100644 | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | +# Playing Lego with kits: Docker Agent + Rust | ||
| 2 | + | ||
| 3 | +A **kit** is a reusable brick to compose a sandbox. Here, we assemble two kits in `sbxenv.yaml`: | ||
| 4 | + | ||
| 5 | +| Kit | Role | | ||
| 6 | +|-----|------| | ||
| 7 | +| `kits/docker-agent-mistral` | the **workload** (the base): Docker Agent, started directly on `agent.yaml`, with access to the Mistral API | | ||
| 8 | +| `kits/rust-toolchain` | a **mixin**: the Rust toolchain (`cargo`, `rustc`, `rustfmt`, `clippy`, `rust-analyzer`) | | ||
| 9 | + | ||
| 10 | +A set of v3 kits contains **exactly one workload** and as many mixins as you want. A single v3 mixin combined with the built-in `docker-agent` agent (which is a v2 kit) is refused: `no workload kit in the set`. | ||
| 11 | + | ||
| 12 | +## The `sbxenv.yaml` file | ||
| 13 | + | ||
| 14 | +```yaml | ||
| 15 | +schemaVersion: "1" | ||
| 16 | +name: docker-rust-agent-mistral | ||
| 17 | +agent: docker-agent-mistral | ||
| 18 | +workspace: . | ||
| 19 | +env: | ||
| 20 | + DOCKER_AGENT_AUTO_UPDATE: "0" | ||
| 21 | + MISTRAL_API_KEY: sbx-mistral-key | ||
| 22 | + | ||
| 23 | +kits: | ||
| 24 | + - ./kits/docker-agent-mistral | ||
| 25 | + - ./kits/rust-toolchain | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +- `agent`: must carry the name of the workload kit (the file name `docker-agent-mistral.yaml`). | ||
| 29 | +- `kits`: the workload, then the mixins. Relative paths are resolved against this file. | ||
| 30 | +- `env`: `MISTRAL_API_KEY` only contains the **placeholder value**, never the real key. | ||
| 31 | + | ||
| 32 | +## The workload kit: `docker-agent-mistral` | ||
| 33 | + | ||
| 34 | +- `docker-agent-mistral.dockerfile` starts from the `docker/sandbox-templates:docker-agent-docker` image and defines the launch command (`ENTRYPOINT`/`CMD`): `docker-agent run agent.yaml`. | ||
| 35 | +- `docker-agent-mistral.yaml` declares `kind: workload` and allows outbound traffic to `api.mistral.ai`. | ||
| 36 | + | ||
| 37 | +## The mixin kit: `rust-toolchain` | ||
| 38 | + | ||
| 39 | +- `rust-toolchain.dockerfile` builds a layer with the Rust toolchain and the linker (`gcc`); it is only added on top of the image. | ||
| 40 | +- `rust-toolchain.yaml` declares `kind: mixin`, the `rust_version` argument (default `1.99.0`) and allows outbound traffic to crates.io. | ||
| 41 | + | ||
| 42 | +To change the Rust version without modifying the files: | ||
| 43 | + | ||
| 44 | +```bash | ||
| 45 | +sbx env create --kit-arg rust_version=stable | ||
| 46 | +``` | ||
| 47 | + | ||
| 48 | +## Custom secret | ||
| 49 | + | ||
| 50 | +`sbxenv.yaml` cannot declare a custom secret: we create it beforehand. With `--sandbox`, it is removed along with the sandbox by `sbx env rm`: | ||
| 51 | + | ||
| 52 | +```bash | ||
| 53 | +export MISTRAL_API_KEY="your-api-key" | ||
| 54 | +sbx secret set-custom --sandbox docker-rust-agent-mistral \ | ||
| 55 | +--host api.mistral.ai --env MISTRAL_API_KEY \ | ||
| 56 | +--placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | ||
| 57 | +``` | ||
| 58 | + | ||
| 59 | +🖐️ **on Windows:** | ||
| 60 | +```bash | ||
| 61 | +$env:MISTRAL_API_KEY="your-api-key" | ||
| 62 | + | ||
| 63 | +sbx secret set-custom --sandbox docker-rust-agent-mistral --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | ||
| 64 | +``` | ||
| 65 | + | ||
| 66 | +Without `--sandbox`, the secret is global and works too. | ||
| 67 | + | ||
| 68 | +## Start the sandbox | ||
| 69 | + | ||
| 70 | +```bash | ||
| 71 | +sbx env create | ||
| 72 | +sbx env exec -it -- docker-agent run agent.yaml | ||
| 73 | +``` | ||
| 74 | +> 🖐️ **you need Docker to build a kit** | ||
| 75 | + | ||
| 76 | +`sbx env` shows the plan (what is going to be created) and asks for approval; `--force` accepts it without asking. The first creation builds the two kits, which takes a little time. | ||
| 77 | + | ||
| 78 | +Other useful commands: | ||
| 79 | + | ||
| 80 | +```bash | ||
| 81 | +sbx env plan # preview the changes | ||
| 82 | +sbx env rm # remove the sandbox and its secrets | ||
| 83 | +``` | ||
| 84 | + | ||
| 85 | +## And try | ||
| 86 | + | ||
| 87 | +```raw | ||
| 88 | +What is the version of cargo? | ||
| 89 | +``` | ||
| 90 | + | ||
| 91 | + | ||
| 92 | +```raw | ||
| 93 | +Create a new Rust project with cargo that prints a greeting, then build and run it | ||
| 94 | +``` | ||
| 95 | + | ||
| 96 | +The agent can now use `cargo build`, `cargo test` or `cargo clippy` in the sandbox. | ||
added
07-play-lego-with-kits/agent.yaml +20 -0 | new file mode 100644 | ||
| @@ -0,0 +1,20 @@ | ||
| 1 | +models: | |
| 2 | + mistral: | |
| 3 | + provider: mistral | |
| 4 | + model: ministral-3b-2512 | |
| 5 | + temperature: 0.7 | |
| 6 | + max_tokens: 8192 | |
| 7 | + | |
| 8 | +agents: | |
| 9 | + root: | |
| 10 | + model: mistral | |
| 11 | + description: Assistant using Mistral | |
| 12 | + instruction: | | |
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | |
| 14 | + | |
| 15 | + welcome_message: | | |
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | |
| 17 | + | |
| 18 | + toolsets: | |
| 19 | + - type: filesystem | |
| 20 | + - type: shell | |
| new file mode 100644 | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | +models: | ||
| 2 | + mistral: | ||
| 3 | + provider: mistral | ||
| 4 | + model: ministral-3b-2512 | ||
| 5 | + temperature: 0.7 | ||
| 6 | + max_tokens: 8192 | ||
| 7 | + | ||
| 8 | +agents: | ||
| 9 | + root: | ||
| 10 | + model: mistral | ||
| 11 | + description: Assistant using Mistral | ||
| 12 | + instruction: | | ||
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | ||
| 14 | + | ||
| 15 | + welcome_message: | | ||
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | ||
| 17 | + | ||
| 18 | + toolsets: | ||
| 19 | + - type: filesystem | ||
| 20 | + - type: shell | ||
added
07-play-lego-with-kits/kits/docker-agent-mistral/docker-agent-mistral.dockerfile +6 -0 | new file mode 100644 | ||
| @@ -0,0 +1,6 @@ | ||
| 1 | +# syntax=docker/dockerfile:1 | |
| 2 | +FROM docker/sandbox-templates:docker-agent-docker | |
| 3 | + | |
| 4 | +# The sandbox launches the agent from the image config: Docker Agent on agent.yaml. | |
| 5 | +ENTRYPOINT ["docker-agent"] | |
| 6 | +CMD ["run", "agent.yaml"] | |
| new file mode 100644 | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | +# syntax=docker/dockerfile:1 | ||
| 2 | +FROM docker/sandbox-templates:docker-agent-docker | ||
| 3 | + | ||
| 4 | +# The sandbox launches the agent from the image config: Docker Agent on agent.yaml. | ||
| 5 | +ENTRYPOINT ["docker-agent"] | ||
| 6 | +CMD ["run", "agent.yaml"] | ||
added
07-play-lego-with-kits/kits/docker-agent-mistral/docker-agent-mistral.yaml +13 -0 | new file mode 100644 | ||
| @@ -0,0 +1,13 @@ | ||
| 1 | +# syntax=docker/sandbox-kit:3 | |
| 2 | +schemaVersion: "3" | |
| 3 | +kind: workload | |
| 4 | +displayName: Docker Agent (Mistral) | |
| 5 | +description: Docker Agent launched on agent.yaml, with access to the Mistral API | |
| 6 | + | |
| 7 | +capabilities: | |
| 8 | + - type: com.docker.sandbox/sbx@1 | |
| 9 | + - type: com.docker.sandbox/network-policy@1 | |
| 10 | + config: | |
| 11 | + runtime: | |
| 12 | + allow: | |
| 13 | + - api.mistral.ai | |
| new file mode 100644 | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | +# syntax=docker/sandbox-kit:3 | ||
| 2 | +schemaVersion: "3" | ||
| 3 | +kind: workload | ||
| 4 | +displayName: Docker Agent (Mistral) | ||
| 5 | +description: Docker Agent launched on agent.yaml, with access to the Mistral API | ||
| 6 | + | ||
| 7 | +capabilities: | ||
| 8 | + - type: com.docker.sandbox/sbx@1 | ||
| 9 | + - type: com.docker.sandbox/network-policy@1 | ||
| 10 | + config: | ||
| 11 | + runtime: | ||
| 12 | + allow: | ||
| 13 | + - api.mistral.ai | ||
added
07-play-lego-with-kits/kits/go-toolchain/go-toolchain.dockerfile +40 -0 | new file mode 100644 | ||
| @@ -0,0 +1,40 @@ | ||
| 1 | +# syntax=docker/dockerfile:1 | |
| 2 | + | |
| 3 | +# --- build stage: download Go, build gopls with that same Go ----------------- | |
| 4 | +FROM debian:trixie-slim AS build | |
| 5 | +ARG GO_VERSION | |
| 6 | +ARG GOPLS_VERSION=latest | |
| 7 | +ARG TARGETARCH | |
| 8 | + | |
| 9 | +# A heredoc RUN does not stop at the first failing line by itself: every | |
| 10 | +# script starts with `set -eu`. | |
| 11 | +RUN <<EOF | |
| 12 | +set -eu | |
| 13 | +apt-get update | |
| 14 | +apt-get install -y --no-install-recommends curl ca-certificates | |
| 15 | +rm -rf /var/lib/apt/lists/* | |
| 16 | +EOF | |
| 17 | + | |
| 18 | +RUN <<EOF | |
| 19 | +set -eu | |
| 20 | +curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \ | |
| 21 | + | tar -C /usr/local -xz | |
| 22 | +rm -rf /usr/local/go/test | |
| 23 | +EOF | |
| 24 | + | |
| 25 | +# Static gopls, installed straight into the overlay tree. | |
| 26 | +ENV PATH=/usr/local/go/bin:${PATH} \ | |
| 27 | + CGO_ENABLED=0 \ | |
| 28 | + GOBIN=/out/usr/local/bin \ | |
| 29 | + GOFLAGS=-trimpath | |
| 30 | +RUN <<EOF | |
| 31 | +set -eu | |
| 32 | +go install "golang.org/x/tools/gopls@${GOPLS_VERSION}" | |
| 33 | +ln -s /usr/local/go/bin/go /out/usr/local/bin/go | |
| 34 | +ln -s /usr/local/go/bin/gofmt /out/usr/local/bin/gofmt | |
| 35 | +EOF | |
| 36 | + | |
| 37 | +# --- overlay: only the toolchain and the binaries land on the workload ------- | |
| 38 | +FROM scratch | |
| 39 | +COPY --from=build /usr/local/go /usr/local/go | |
| 40 | +COPY --from=build /out/ / | |
| new file mode 100644 | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | +# syntax=docker/dockerfile:1 | ||
| 2 | + | ||
| 3 | +# --- build stage: download Go, build gopls with that same Go ----------------- | ||
| 4 | +FROM debian:trixie-slim AS build | ||
| 5 | +ARG GO_VERSION | ||
| 6 | +ARG GOPLS_VERSION=latest | ||
| 7 | +ARG TARGETARCH | ||
| 8 | + | ||
| 9 | +# A heredoc RUN does not stop at the first failing line by itself: every | ||
| 10 | +# script starts with `set -eu`. | ||
| 11 | +RUN <<EOF | ||
| 12 | +set -eu | ||
| 13 | +apt-get update | ||
| 14 | +apt-get install -y --no-install-recommends curl ca-certificates | ||
| 15 | +rm -rf /var/lib/apt/lists/* | ||
| 16 | +EOF | ||
| 17 | + | ||
| 18 | +RUN <<EOF | ||
| 19 | +set -eu | ||
| 20 | +curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${TARGETARCH}.tar.gz" \ | ||
| 21 | + | tar -C /usr/local -xz | ||
| 22 | +rm -rf /usr/local/go/test | ||
| 23 | +EOF | ||
| 24 | + | ||
| 25 | +# Static gopls, installed straight into the overlay tree. | ||
| 26 | +ENV PATH=/usr/local/go/bin:${PATH} \ | ||
| 27 | + CGO_ENABLED=0 \ | ||
| 28 | + GOBIN=/out/usr/local/bin \ | ||
| 29 | + GOFLAGS=-trimpath | ||
| 30 | +RUN <<EOF | ||
| 31 | +set -eu | ||
| 32 | +go install "golang.org/x/tools/gopls@${GOPLS_VERSION}" | ||
| 33 | +ln -s /usr/local/go/bin/go /out/usr/local/bin/go | ||
| 34 | +ln -s /usr/local/go/bin/gofmt /out/usr/local/bin/gofmt | ||
| 35 | +EOF | ||
| 36 | + | ||
| 37 | +# --- overlay: only the toolchain and the binaries land on the workload ------- | ||
| 38 | +FROM scratch | ||
| 39 | +COPY --from=build /usr/local/go /usr/local/go | ||
| 40 | +COPY --from=build /out/ / | ||
added
07-play-lego-with-kits/kits/go-toolchain/go-toolchain.yaml +33 -0 | new file mode 100644 | ||
| @@ -0,0 +1,33 @@ | ||
| 1 | +# syntax=docker/sandbox-kit:3 | |
| 2 | +schemaVersion: "3" | |
| 3 | +kind: mixin | |
| 4 | +displayName: Go toolchain | |
| 5 | +description: Go toolchain and gopls (language server) | |
| 6 | +licenses: [MIT] | |
| 7 | +version: "0.6.0" | |
| 8 | + | |
| 9 | +args: | |
| 10 | + go_version: | |
| 11 | + default: "1.27.2" # mm requires Go 1.26+ | |
| 12 | + pattern: '^[0-9]+\.[0-9]+(\.[0-9]+)?$' | |
| 13 | + buildArg: GO_VERSION | |
| 14 | + gopls_version: | |
| 15 | + # Pin a tag (e.g. v0.x.y) for reproducible builds. | |
| 16 | + default: latest | |
| 17 | + pattern: '^(latest|v[0-9]+\.[0-9]+\.[0-9]+)$' | |
| 18 | + buildArg: GOPLS_VERSION | |
| 19 | + | |
| 20 | +provides: ["go@${{ kit.args.go_version }}"] | |
| 21 | + | |
| 22 | +capabilities: | |
| 23 | + # Runtime access with the tool: module downloads and checksum DB. | |
| 24 | + # Add private module hosts here (or in a kit set) if you need them. | |
| 25 | + - type: com.docker.sandbox/network-policy@1 | |
| 26 | + config: | |
| 27 | + runtime: | |
| 28 | + allow: | |
| 29 | + - proxy.golang.org | |
| 30 | + - sum.golang.org | |
| 31 | + - github.com | |
| 32 | + - golang.org | |
| 33 | + | |
| new file mode 100644 | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | +# syntax=docker/sandbox-kit:3 | ||
| 2 | +schemaVersion: "3" | ||
| 3 | +kind: mixin | ||
| 4 | +displayName: Go toolchain | ||
| 5 | +description: Go toolchain and gopls (language server) | ||
| 6 | +licenses: [MIT] | ||
| 7 | +version: "0.6.0" | ||
| 8 | + | ||
| 9 | +args: | ||
| 10 | + go_version: | ||
| 11 | + default: "1.27.2" # mm requires Go 1.26+ | ||
| 12 | + pattern: '^[0-9]+\.[0-9]+(\.[0-9]+)?$' | ||
| 13 | + buildArg: GO_VERSION | ||
| 14 | + gopls_version: | ||
| 15 | + # Pin a tag (e.g. v0.x.y) for reproducible builds. | ||
| 16 | + default: latest | ||
| 17 | + pattern: '^(latest|v[0-9]+\.[0-9]+\.[0-9]+)$' | ||
| 18 | + buildArg: GOPLS_VERSION | ||
| 19 | + | ||
| 20 | +provides: ["go@${{ kit.args.go_version }}"] | ||
| 21 | + | ||
| 22 | +capabilities: | ||
| 23 | + # Runtime access with the tool: module downloads and checksum DB. | ||
| 24 | + # Add private module hosts here (or in a kit set) if you need them. | ||
| 25 | + - type: com.docker.sandbox/network-policy@1 | ||
| 26 | + config: | ||
| 27 | + runtime: | ||
| 28 | + allow: | ||
| 29 | + - proxy.golang.org | ||
| 30 | + - sum.golang.org | ||
| 31 | + - github.com | ||
| 32 | + - golang.org | ||
| 33 | + | ||
added
07-play-lego-with-kits/kits/rust-toolchain/rust-toolchain.dockerfile +70 -0 | new file mode 100644 | ||
| @@ -0,0 +1,70 @@ | ||
| 1 | +# syntax=docker/dockerfile:1 | |
| 2 | + | |
| 3 | +# --- build stage: the Rust toolchain, through rustup ------------------------ | |
| 4 | +FROM debian:trixie-slim AS rust | |
| 5 | +ARG RUST_VERSION | |
| 6 | + | |
| 7 | +# A heredoc RUN does not stop at the first failing line by itself: every | |
| 8 | +# script starts with `set -eu`. | |
| 9 | +RUN <<EOF | |
| 10 | +set -eu | |
| 11 | +apt-get update | |
| 12 | +apt-get install -y --no-install-recommends curl ca-certificates | |
| 13 | +rm -rf /var/lib/apt/lists/* | |
| 14 | +EOF | |
| 15 | + | |
| 16 | +# rust-src is what rust-analyzer reads the standard library from. | |
| 17 | +ENV RUSTUP_HOME=/usr/local/rustup \ | |
| 18 | + CARGO_HOME=/usr/local/cargo | |
| 19 | +RUN <<EOF | |
| 20 | +set -eu | |
| 21 | +curl -fsSL https://sh.rustup.rs | sh -s -- -y --no-modify-path \ | |
| 22 | + --profile minimal \ | |
| 23 | + --default-toolchain "${RUST_VERSION}" \ | |
| 24 | + --component rustfmt,clippy,rust-analyzer,rust-src | |
| 25 | +EOF | |
| 26 | + | |
| 27 | +# The workload has no RUSTUP_HOME to find a toolchain with, so the rustup | |
| 28 | +# proxies would not work there: link the toolchain's own binaries instead. | |
| 29 | +# rustc finds its sysroot from its real path, through the links. | |
| 30 | +RUN <<EOF | |
| 31 | +set -eu | |
| 32 | +toolchain="$(ls -d /usr/local/rustup/toolchains/*)" | |
| 33 | +mkdir -p /out/usr/local/bin | |
| 34 | +for bin in cargo rustc rustdoc rustfmt cargo-fmt cargo-clippy clippy-driver rust-analyzer; do | |
| 35 | + ln -s "${toolchain}/bin/${bin}" "/out/usr/local/bin/${bin}" | |
| 36 | +done | |
| 37 | +# Kept in the overlay at the same path: the links point into it. | |
| 38 | +mkdir -p /out/usr/local/rustup/toolchains | |
| 39 | +mv "${toolchain}" /out/usr/local/rustup/toolchains/ | |
| 40 | +EOF | |
| 41 | + | |
| 42 | +# --- linker stage: what the workload lacks to link, from its own distro ------ | |
| 43 | +# rustc links through `cc`, and build scripts (the cc crate) compile C: the | |
| 44 | +# older shell templates have neither gcc nor binutils nor the libc headers. The .deb | |
| 45 | +# files apt would add to *that* image are unpacked into the overlay, so they | |
| 46 | +# match its Ubuntu release and the libraries already installed. | |
| 47 | +FROM docker/sandbox-templates:shell AS linker | |
| 48 | +USER root | |
| 49 | +RUN <<EOF | |
| 50 | +set -eu | |
| 51 | +apt-get update | |
| 52 | +apt-get install -y --no-install-recommends --download-only gcc libc6-dev | |
| 53 | +mkdir -p /out | |
| 54 | +# Newer shell templates already ship gcc and libc6-dev: then apt downloads | |
| 55 | +# nothing, the glob stays unexpanded and the overlay adds nothing. | |
| 56 | +for deb in /var/cache/apt/archives/*.deb; do | |
| 57 | + [ -e "${deb}" ] || continue | |
| 58 | + dpkg-deb -x "${deb}" /out | |
| 59 | +done | |
| 60 | +# Set by update-alternatives in a real install, which unpacking skips. | |
| 61 | +if [ -e /out/usr/bin/gcc ]; then | |
| 62 | + ln -sf gcc /out/usr/bin/cc | |
| 63 | +fi | |
| 64 | +rm -rf /out/usr/share/doc /out/usr/share/man /out/usr/share/info /out/usr/share/locale | |
| 65 | +EOF | |
| 66 | + | |
| 67 | +# --- overlay: only the toolchain, the links and the C toolchain land --------- | |
| 68 | +FROM scratch | |
| 69 | +COPY --from=linker /out/ / | |
| 70 | +COPY --from=rust /out/ / | |
| new file mode 100644 | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | +# syntax=docker/dockerfile:1 | ||
| 2 | + | ||
| 3 | +# --- build stage: the Rust toolchain, through rustup ------------------------ | ||
| 4 | +FROM debian:trixie-slim AS rust | ||
| 5 | +ARG RUST_VERSION | ||
| 6 | + | ||
| 7 | +# A heredoc RUN does not stop at the first failing line by itself: every | ||
| 8 | +# script starts with `set -eu`. | ||
| 9 | +RUN <<EOF | ||
| 10 | +set -eu | ||
| 11 | +apt-get update | ||
| 12 | +apt-get install -y --no-install-recommends curl ca-certificates | ||
| 13 | +rm -rf /var/lib/apt/lists/* | ||
| 14 | +EOF | ||
| 15 | + | ||
| 16 | +# rust-src is what rust-analyzer reads the standard library from. | ||
| 17 | +ENV RUSTUP_HOME=/usr/local/rustup \ | ||
| 18 | + CARGO_HOME=/usr/local/cargo | ||
| 19 | +RUN <<EOF | ||
| 20 | +set -eu | ||
| 21 | +curl -fsSL https://sh.rustup.rs | sh -s -- -y --no-modify-path \ | ||
| 22 | + --profile minimal \ | ||
| 23 | + --default-toolchain "${RUST_VERSION}" \ | ||
| 24 | + --component rustfmt,clippy,rust-analyzer,rust-src | ||
| 25 | +EOF | ||
| 26 | + | ||
| 27 | +# The workload has no RUSTUP_HOME to find a toolchain with, so the rustup | ||
| 28 | +# proxies would not work there: link the toolchain's own binaries instead. | ||
| 29 | +# rustc finds its sysroot from its real path, through the links. | ||
| 30 | +RUN <<EOF | ||
| 31 | +set -eu | ||
| 32 | +toolchain="$(ls -d /usr/local/rustup/toolchains/*)" | ||
| 33 | +mkdir -p /out/usr/local/bin | ||
| 34 | +for bin in cargo rustc rustdoc rustfmt cargo-fmt cargo-clippy clippy-driver rust-analyzer; do | ||
| 35 | + ln -s "${toolchain}/bin/${bin}" "/out/usr/local/bin/${bin}" | ||
| 36 | +done | ||
| 37 | +# Kept in the overlay at the same path: the links point into it. | ||
| 38 | +mkdir -p /out/usr/local/rustup/toolchains | ||
| 39 | +mv "${toolchain}" /out/usr/local/rustup/toolchains/ | ||
| 40 | +EOF | ||
| 41 | + | ||
| 42 | +# --- linker stage: what the workload lacks to link, from its own distro ------ | ||
| 43 | +# rustc links through `cc`, and build scripts (the cc crate) compile C: the | ||
| 44 | +# older shell templates have neither gcc nor binutils nor the libc headers. The .deb | ||
| 45 | +# files apt would add to *that* image are unpacked into the overlay, so they | ||
| 46 | +# match its Ubuntu release and the libraries already installed. | ||
| 47 | +FROM docker/sandbox-templates:shell AS linker | ||
| 48 | +USER root | ||
| 49 | +RUN <<EOF | ||
| 50 | +set -eu | ||
| 51 | +apt-get update | ||
| 52 | +apt-get install -y --no-install-recommends --download-only gcc libc6-dev | ||
| 53 | +mkdir -p /out | ||
| 54 | +# Newer shell templates already ship gcc and libc6-dev: then apt downloads | ||
| 55 | +# nothing, the glob stays unexpanded and the overlay adds nothing. | ||
| 56 | +for deb in /var/cache/apt/archives/*.deb; do | ||
| 57 | + [ -e "${deb}" ] || continue | ||
| 58 | + dpkg-deb -x "${deb}" /out | ||
| 59 | +done | ||
| 60 | +# Set by update-alternatives in a real install, which unpacking skips. | ||
| 61 | +if [ -e /out/usr/bin/gcc ]; then | ||
| 62 | + ln -sf gcc /out/usr/bin/cc | ||
| 63 | +fi | ||
| 64 | +rm -rf /out/usr/share/doc /out/usr/share/man /out/usr/share/info /out/usr/share/locale | ||
| 65 | +EOF | ||
| 66 | + | ||
| 67 | +# --- overlay: only the toolchain, the links and the C toolchain land --------- | ||
| 68 | +FROM scratch | ||
| 69 | +COPY --from=linker /out/ / | ||
| 70 | +COPY --from=rust /out/ / | ||
added
07-play-lego-with-kits/kits/rust-toolchain/rust-toolchain.yaml +26 -0 | new file mode 100644 | ||
| @@ -0,0 +1,26 @@ | ||
| 1 | +# syntax=docker/sandbox-kit:3 | |
| 2 | +schemaVersion: "3" | |
| 3 | +kind: mixin | |
| 4 | +displayName: Rust toolchain | |
| 5 | +description: Rust toolchain (cargo, rustc, rustfmt, clippy) and rust-analyzer (language server) | |
| 6 | + | |
| 7 | +args: | |
| 8 | + rust_version: | |
| 9 | + # A Rust release (e.g. 1.99.0), or stable / beta / nightly (not reproducible). | |
| 10 | + default: "1.99.0" | |
| 11 | + pattern: '^([0-9]+\.[0-9]+(\.[0-9]+)?|stable|beta|nightly)$' | |
| 12 | + buildArg: RUST_VERSION | |
| 13 | + | |
| 14 | +provides: ["rust@${{ kit.args.rust_version }}"] | |
| 15 | + | |
| 16 | +capabilities: | |
| 17 | + # Runtime access with the tool: the crates.io index and crate downloads. | |
| 18 | + # Add private registries / git hosts here (or in a kit set) if you need them. | |
| 19 | + - type: com.docker.sandbox/network-policy@1 | |
| 20 | + config: | |
| 21 | + runtime: | |
| 22 | + allow: | |
| 23 | + - index.crates.io | |
| 24 | + - static.crates.io | |
| 25 | + - crates.io | |
| 26 | + - github.com | |
| new file mode 100644 | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | +# syntax=docker/sandbox-kit:3 | ||
| 2 | +schemaVersion: "3" | ||
| 3 | +kind: mixin | ||
| 4 | +displayName: Rust toolchain | ||
| 5 | +description: Rust toolchain (cargo, rustc, rustfmt, clippy) and rust-analyzer (language server) | ||
| 6 | + | ||
| 7 | +args: | ||
| 8 | + rust_version: | ||
| 9 | + # A Rust release (e.g. 1.99.0), or stable / beta / nightly (not reproducible). | ||
| 10 | + default: "1.99.0" | ||
| 11 | + pattern: '^([0-9]+\.[0-9]+(\.[0-9]+)?|stable|beta|nightly)$' | ||
| 12 | + buildArg: RUST_VERSION | ||
| 13 | + | ||
| 14 | +provides: ["rust@${{ kit.args.rust_version }}"] | ||
| 15 | + | ||
| 16 | +capabilities: | ||
| 17 | + # Runtime access with the tool: the crates.io index and crate downloads. | ||
| 18 | + # Add private registries / git hosts here (or in a kit set) if you need them. | ||
| 19 | + - type: com.docker.sandbox/network-policy@1 | ||
| 20 | + config: | ||
| 21 | + runtime: | ||
| 22 | + allow: | ||
| 23 | + - index.crates.io | ||
| 24 | + - static.crates.io | ||
| 25 | + - crates.io | ||
| 26 | + - github.com | ||
added
07-play-lego-with-kits/sbxenv.yaml +13 -0 | new file mode 100644 | ||
| @@ -0,0 +1,13 @@ | ||
| 1 | +schemaVersion: "1" | |
| 2 | +name: docker-rust-agent-mistral | |
| 3 | +agent: docker-agent-mistral | |
| 4 | +workspace: . | |
| 5 | +env: | |
| 6 | + DOCKER_AGENT_AUTO_UPDATE: "0" | |
| 7 | + MISTRAL_API_KEY: sbx-mistral-key | |
| 8 | + | |
| 9 | +# Relative paths resolve against the directory of this file. | |
| 10 | +# One workload (the agent) plus mixins (the Rust toolchain). | |
| 11 | +kits: | |
| 12 | + - ./kits/docker-agent-mistral | |
| 13 | + - ./kits/rust-toolchain | |
| new file mode 100644 | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | +schemaVersion: "1" | ||
| 2 | +name: docker-rust-agent-mistral | ||
| 3 | +agent: docker-agent-mistral | ||
| 4 | +workspace: . | ||
| 5 | +env: | ||
| 6 | + DOCKER_AGENT_AUTO_UPDATE: "0" | ||
| 7 | + MISTRAL_API_KEY: sbx-mistral-key | ||
| 8 | + | ||
| 9 | +# Relative paths resolve against the directory of this file. | ||
| 10 | +# One workload (the agent) plus mixins (the Rust toolchain). | ||
| 11 | +kits: | ||
| 12 | + - ./kits/docker-agent-mistral | ||
| 13 | + - ./kits/rust-toolchain | ||
added
08-policies/README.md +114 -0 | new file mode 100644 | ||
| @@ -0,0 +1,114 @@ | ||
| 1 | +# Adding policies: forbid `gitlab.com` and `mini-me.org` | |
| 2 | + | |
| 3 | +We reuse the kits of the previous step (`07-play-lego-with-kits`) and add one brick: a kit that **forbids** access to some hosts. | |
| 4 | + | |
| 5 | +## The `sbxenv.yaml` file | |
| 6 | + | |
| 7 | +```yaml | |
| 8 | +schemaVersion: "1" | |
| 9 | +name: docker-policies-agent-mistral | |
| 10 | +agent: docker-agent-mistral | |
| 11 | +workspace: . | |
| 12 | +env: | |
| 13 | + DOCKER_AGENT_AUTO_UPDATE: "0" | |
| 14 | + MISTRAL_API_KEY: sbx-mistral-key | |
| 15 | + | |
| 16 | +kits: | |
| 17 | + - ../07-play-lego-with-kits/kits/docker-agent-mistral | |
| 18 | + - ../07-play-lego-with-kits/kits/rust-toolchain | |
| 19 | + - ./kits/deny-hosts | |
| 20 | +``` | |
| 21 | + | |
| 22 | +- `agent`: the name of the workload kit (`docker-agent-mistral`), as in step 07. | |
| 23 | +- `kits`: the workload and the Rust mixin from step 07 (paths relative to this file), plus the local policy mixin. | |
| 24 | +- `name`: a sandbox distinct from the one in step 07, with its own secrets. | |
| 25 | + | |
| 26 | +## The policy kit: `deny-hosts` | |
| 27 | + | |
| 28 | +`sbxenv.yaml` has no section for network rules: they go through a kit. `kits/deny-hosts/deny-hosts.yaml` is a v3 mixin without a Dockerfile, which only contains the rule: | |
| 29 | + | |
| 30 | +```yaml | |
| 31 | +# syntax=docker/sandbox-kit:3 | |
| 32 | +schemaVersion: "3" | |
| 33 | +kind: mixin | |
| 34 | +displayName: Deny hosts | |
| 35 | +description: Network policy that blocks the hosts the sandbox must never reach | |
| 36 | + | |
| 37 | +capabilities: | |
| 38 | + - type: com.docker.sandbox/network-policy@1 | |
| 39 | + config: | |
| 40 | + runtime: | |
| 41 | + deny: | |
| 42 | + - gitlab.com | |
| 43 | + - "**.gitlab.com" | |
| 44 | + - mini-me.org | |
| 45 | + - "**.mini-me.org" | |
| 46 | +``` | |
| 47 | + | |
| 48 | +- `gitlab.com` and `mini-me.org`: the domains themselves. | |
| 49 | +- `**.gitlab.com` and `**.mini-me.org`: all their subdomains. | |
| 50 | +- A `deny` always wins over an `allow`, whichever kit declared it. | |
| 51 | + | |
| 52 | +To block other hosts, add them to the `deny` list. | |
| 53 | + | |
| 54 | +## Custom secret | |
| 55 | + | |
| 56 | +As in the previous steps, we create the custom secret beforehand. With `--sandbox`, it is removed along with the sandbox by `sbx env rm`: | |
| 57 | + | |
| 58 | +```bash | |
| 59 | +export MISTRAL_API_KEY="your-api-key" | |
| 60 | +sbx secret set-custom --sandbox docker-policies-agent-mistral \ | |
| 61 | +--host api.mistral.ai --env MISTRAL_API_KEY \ | |
| 62 | +--placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | |
| 63 | +``` | |
| 64 | + | |
| 65 | +🖐️ **on Windows:** | |
| 66 | +```bash | |
| 67 | +$env:MISTRAL_API_KEY="your-api-key" | |
| 68 | + | |
| 69 | +sbx secret set-custom --sandbox docker-policies-agent-mistral --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | |
| 70 | +``` | |
| 71 | + | |
| 72 | +A global custom secret (without `--sandbox`) works too. | |
| 73 | + | |
| 74 | +## Start the sandbox | |
| 75 | + | |
| 76 | +```bash | |
| 77 | +sbx env create --force | |
| 78 | +sbx env exec -it -- docker-agent run agent.yaml | |
| 79 | +``` | |
| 80 | + | |
| 81 | +The plan shown by `sbx env` lists the three kits; you have to approve it (`--force` accepts it without asking). | |
| 82 | + | |
| 83 | +## And try | |
| 84 | + | |
| 85 | +```raw | |
| 86 | +Show me the content of https://gitlab.com | |
| 87 | +``` | |
| 88 | + | |
| 89 | +```raw | |
| 90 | +Show me the content of https://mini-me.org | |
| 91 | +``` | |
| 92 | + | |
| 93 | +Both requests should be blocked. Compare with a host that is not forbidden, for example `https://crates.io`. | |
| 94 | + | |
| 95 | +## Another method: the policy on the host side | |
| 96 | + | |
| 97 | +You can set the same rule without a kit, with the CLI. It then lives on the host machine and not in `sbxenv.yaml`: | |
| 98 | + | |
| 99 | +```bash | |
| 100 | +# for this sandbox only | |
| 101 | +sbx policy deny network --sandbox docker-policies-agent-mistral gitlab.com mini-me.org | |
| 102 | + | |
| 103 | +# for all sandboxes | |
| 104 | +sbx policy deny network gitlab.com mini-me.org | |
| 105 | +``` | |
| 106 | + | |
| 107 | +To check what is allowed or blocked: | |
| 108 | + | |
| 109 | +```bash | |
| 110 | +sbx policy ls | |
| 111 | +sbx policy log | |
| 112 | +``` | |
| 113 | + | |
| 114 | +The advantage of the kit: the rule travels with the project (`sbxenv.yaml` is versioned) and applies to anyone who starts the environment. The advantage of the CLI: it can apply to all sandboxes at once. | |
| new file mode 100644 | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | +# Adding policies: forbid `gitlab.com` and `mini-me.org` | ||
| 2 | + | ||
| 3 | +We reuse the kits of the previous step (`07-play-lego-with-kits`) and add one brick: a kit that **forbids** access to some hosts. | ||
| 4 | + | ||
| 5 | +## The `sbxenv.yaml` file | ||
| 6 | + | ||
| 7 | +```yaml | ||
| 8 | +schemaVersion: "1" | ||
| 9 | +name: docker-policies-agent-mistral | ||
| 10 | +agent: docker-agent-mistral | ||
| 11 | +workspace: . | ||
| 12 | +env: | ||
| 13 | + DOCKER_AGENT_AUTO_UPDATE: "0" | ||
| 14 | + MISTRAL_API_KEY: sbx-mistral-key | ||
| 15 | + | ||
| 16 | +kits: | ||
| 17 | + - ../07-play-lego-with-kits/kits/docker-agent-mistral | ||
| 18 | + - ../07-play-lego-with-kits/kits/rust-toolchain | ||
| 19 | + - ./kits/deny-hosts | ||
| 20 | +``` | ||
| 21 | + | ||
| 22 | +- `agent`: the name of the workload kit (`docker-agent-mistral`), as in step 07. | ||
| 23 | +- `kits`: the workload and the Rust mixin from step 07 (paths relative to this file), plus the local policy mixin. | ||
| 24 | +- `name`: a sandbox distinct from the one in step 07, with its own secrets. | ||
| 25 | + | ||
| 26 | +## The policy kit: `deny-hosts` | ||
| 27 | + | ||
| 28 | +`sbxenv.yaml` has no section for network rules: they go through a kit. `kits/deny-hosts/deny-hosts.yaml` is a v3 mixin without a Dockerfile, which only contains the rule: | ||
| 29 | + | ||
| 30 | +```yaml | ||
| 31 | +# syntax=docker/sandbox-kit:3 | ||
| 32 | +schemaVersion: "3" | ||
| 33 | +kind: mixin | ||
| 34 | +displayName: Deny hosts | ||
| 35 | +description: Network policy that blocks the hosts the sandbox must never reach | ||
| 36 | + | ||
| 37 | +capabilities: | ||
| 38 | + - type: com.docker.sandbox/network-policy@1 | ||
| 39 | + config: | ||
| 40 | + runtime: | ||
| 41 | + deny: | ||
| 42 | + - gitlab.com | ||
| 43 | + - "**.gitlab.com" | ||
| 44 | + - mini-me.org | ||
| 45 | + - "**.mini-me.org" | ||
| 46 | +``` | ||
| 47 | + | ||
| 48 | +- `gitlab.com` and `mini-me.org`: the domains themselves. | ||
| 49 | +- `**.gitlab.com` and `**.mini-me.org`: all their subdomains. | ||
| 50 | +- A `deny` always wins over an `allow`, whichever kit declared it. | ||
| 51 | + | ||
| 52 | +To block other hosts, add them to the `deny` list. | ||
| 53 | + | ||
| 54 | +## Custom secret | ||
| 55 | + | ||
| 56 | +As in the previous steps, we create the custom secret beforehand. With `--sandbox`, it is removed along with the sandbox by `sbx env rm`: | ||
| 57 | + | ||
| 58 | +```bash | ||
| 59 | +export MISTRAL_API_KEY="your-api-key" | ||
| 60 | +sbx secret set-custom --sandbox docker-policies-agent-mistral \ | ||
| 61 | +--host api.mistral.ai --env MISTRAL_API_KEY \ | ||
| 62 | +--placeholder sbx-mistral-key --value "$MISTRAL_API_KEY" | ||
| 63 | +``` | ||
| 64 | + | ||
| 65 | +🖐️ **on Windows:** | ||
| 66 | +```bash | ||
| 67 | +$env:MISTRAL_API_KEY="your-api-key" | ||
| 68 | + | ||
| 69 | +sbx secret set-custom --sandbox docker-policies-agent-mistral --host api.mistral.ai --env MISTRAL_API_KEY --placeholder sbx-mistral-key --value "$env:MISTRAL_API_KEY" | ||
| 70 | +``` | ||
| 71 | + | ||
| 72 | +A global custom secret (without `--sandbox`) works too. | ||
| 73 | + | ||
| 74 | +## Start the sandbox | ||
| 75 | + | ||
| 76 | +```bash | ||
| 77 | +sbx env create --force | ||
| 78 | +sbx env exec -it -- docker-agent run agent.yaml | ||
| 79 | +``` | ||
| 80 | + | ||
| 81 | +The plan shown by `sbx env` lists the three kits; you have to approve it (`--force` accepts it without asking). | ||
| 82 | + | ||
| 83 | +## And try | ||
| 84 | + | ||
| 85 | +```raw | ||
| 86 | +Show me the content of https://gitlab.com | ||
| 87 | +``` | ||
| 88 | + | ||
| 89 | +```raw | ||
| 90 | +Show me the content of https://mini-me.org | ||
| 91 | +``` | ||
| 92 | + | ||
| 93 | +Both requests should be blocked. Compare with a host that is not forbidden, for example `https://crates.io`. | ||
| 94 | + | ||
| 95 | +## Another method: the policy on the host side | ||
| 96 | + | ||
| 97 | +You can set the same rule without a kit, with the CLI. It then lives on the host machine and not in `sbxenv.yaml`: | ||
| 98 | + | ||
| 99 | +```bash | ||
| 100 | +# for this sandbox only | ||
| 101 | +sbx policy deny network --sandbox docker-policies-agent-mistral gitlab.com mini-me.org | ||
| 102 | + | ||
| 103 | +# for all sandboxes | ||
| 104 | +sbx policy deny network gitlab.com mini-me.org | ||
| 105 | +``` | ||
| 106 | + | ||
| 107 | +To check what is allowed or blocked: | ||
| 108 | + | ||
| 109 | +```bash | ||
| 110 | +sbx policy ls | ||
| 111 | +sbx policy log | ||
| 112 | +``` | ||
| 113 | + | ||
| 114 | +The advantage of the kit: the rule travels with the project (`sbxenv.yaml` is versioned) and applies to anyone who starts the environment. The advantage of the CLI: it can apply to all sandboxes at once. | ||
added
08-policies/agent.yaml +22 -0 | new file mode 100644 | ||
| @@ -0,0 +1,22 @@ | ||
| 1 | +models: | |
| 2 | + mistral: | |
| 3 | + provider: mistral | |
| 4 | + model: ministral-3b-2512 | |
| 5 | + temperature: 0.7 | |
| 6 | + max_tokens: 8192 | |
| 7 | + | |
| 8 | +agents: | |
| 9 | + root: | |
| 10 | + model: mistral | |
| 11 | + description: Assistant using Mistral | |
| 12 | + instruction: | | |
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | |
| 14 | + | |
| 15 | + welcome_message: | | |
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | |
| 17 | + | |
| 18 | + toolsets: | |
| 19 | + - type: filesystem | |
| 20 | + - type: shell | |
| 21 | + - type: fetch | |
| 22 | + | |
| new file mode 100644 | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | +models: | ||
| 2 | + mistral: | ||
| 3 | + provider: mistral | ||
| 4 | + model: ministral-3b-2512 | ||
| 5 | + temperature: 0.7 | ||
| 6 | + max_tokens: 8192 | ||
| 7 | + | ||
| 8 | +agents: | ||
| 9 | + root: | ||
| 10 | + model: mistral | ||
| 11 | + description: Assistant using Mistral | ||
| 12 | + instruction: | | ||
| 13 | + You name is [Bob 🤓📦], You are a helpful assistant. | ||
| 14 | + | ||
| 15 | + welcome_message: | | ||
| 16 | + 🤖 Local Assistant propulsed by **Mistral** 🐱 | ||
| 17 | + | ||
| 18 | + toolsets: | ||
| 19 | + - type: filesystem | ||
| 20 | + - type: shell | ||
| 21 | + - type: fetch | ||
| 22 | + | ||
added
08-policies/kits/deny-hosts/deny-hosts.yaml +16 -0 | new file mode 100644 | ||
| @@ -0,0 +1,16 @@ | ||
| 1 | +# syntax=docker/sandbox-kit:3 | |
| 2 | +schemaVersion: "3" | |
| 3 | +kind: mixin | |
| 4 | +displayName: Deny hosts | |
| 5 | +description: Network policy that blocks the hosts the sandbox must never reach | |
| 6 | + | |
| 7 | +capabilities: | |
| 8 | + - type: com.docker.sandbox/network-policy@1 | |
| 9 | + config: | |
| 10 | + runtime: | |
| 11 | + # Deny wins over any allow, whichever kit declares it. | |
| 12 | + deny: | |
| 13 | + - gitlab.com | |
| 14 | + - "**.gitlab.com" | |
| 15 | + - mini-me.org | |
| 16 | + - "**.mini-me.org" | |
| new file mode 100644 | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | +# syntax=docker/sandbox-kit:3 | ||
| 2 | +schemaVersion: "3" | ||
| 3 | +kind: mixin | ||
| 4 | +displayName: Deny hosts | ||
| 5 | +description: Network policy that blocks the hosts the sandbox must never reach | ||
| 6 | + | ||
| 7 | +capabilities: | ||
| 8 | + - type: com.docker.sandbox/network-policy@1 | ||
| 9 | + config: | ||
| 10 | + runtime: | ||
| 11 | + # Deny wins over any allow, whichever kit declares it. | ||
| 12 | + deny: | ||
| 13 | + - gitlab.com | ||
| 14 | + - "**.gitlab.com" | ||
| 15 | + - mini-me.org | ||
| 16 | + - "**.mini-me.org" | ||
added
08-policies/sbxenv.yaml +15 -0 | new file mode 100644 | ||
| @@ -0,0 +1,15 @@ | ||
| 1 | +schemaVersion: "1" | |
| 2 | +name: docker-policies-agent-mistral | |
| 3 | +agent: docker-agent-mistral | |
| 4 | +workspace: . | |
| 5 | +env: | |
| 6 | + DOCKER_AGENT_AUTO_UPDATE: "0" | |
| 7 | + MISTRAL_API_KEY: sbx-mistral-key | |
| 8 | + | |
| 9 | +# Relative paths resolve against the directory of this file. | |
| 10 | +kits: | |
| 11 | + # The kits of the previous step... | |
| 12 | + - ../07-play-lego-with-kits/kits/docker-agent-mistral | |
| 13 | + - ../07-play-lego-with-kits/kits/rust-toolchain | |
| 14 | + # ...plus the policy. | |
| 15 | + - ./kits/deny-hosts | |
| new file mode 100644 | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | +schemaVersion: "1" | ||
| 2 | +name: docker-policies-agent-mistral | ||
| 3 | +agent: docker-agent-mistral | ||
| 4 | +workspace: . | ||
| 5 | +env: | ||
| 6 | + DOCKER_AGENT_AUTO_UPDATE: "0" | ||
| 7 | + MISTRAL_API_KEY: sbx-mistral-key | ||
| 8 | + | ||
| 9 | +# Relative paths resolve against the directory of this file. | ||
| 10 | +kits: | ||
| 11 | + # The kits of the previous step... | ||
| 12 | + - ../07-play-lego-with-kits/kits/docker-agent-mistral | ||
| 13 | + - ../07-play-lego-with-kits/kits/rust-toolchain | ||
| 14 | + # ...plus the policy. | ||
| 15 | + - ./kits/deny-hosts | ||
added
README.md +1 -0 | new file mode 100644 | ||
| @@ -0,0 +1 @@ | ||
| 1 | +# Workshop: Docker `sbx` + Docker Agent + Mistral AI | |
| new file mode 100644 | |||
| @@ -0,0 +1 @@ | |||
| 1 | +# Workshop: Docker `sbx` + Docker Agent + Mistral AI | ||
added
git.sh +136 -0 | new file mode 100755 | ||
| @@ -0,0 +1,136 @@ | ||
| 1 | +#!/bin/bash | |
| 2 | +message="" | |
| 3 | +case $1 in | |
| 4 | + | |
| 5 | + # 🎨: art | |
| 6 | + art) | |
| 7 | + message="Improve structure / format of the code" | |
| 8 | + emoji="🎨" | |
| 9 | + ;; | |
| 10 | + | |
| 11 | + # 🐛: bug | |
| 12 | + bug|fix) | |
| 13 | + message="Fix a bug" | |
| 14 | + emoji="🐛" | |
| 15 | + ;; | |
| 16 | + | |
| 17 | + # 🤓: geek | |
| 18 | + human|human-fixed) | |
| 19 | + message="Human Fixed" | |
| 20 | + emoji="🤓" | |
| 21 | + ;; | |
| 22 | + | |
| 23 | + # 🤖: robot | |
| 24 | + ai|ai-generated) | |
| 25 | + message="AI generated" | |
| 26 | + emoji="🤖" | |
| 27 | + ;; | |
| 28 | + | |
| 29 | + # ✨: sparkles | |
| 30 | + sparkles|feature) | |
| 31 | + message="Introduce new feature(s)" | |
| 32 | + emoji="✨" | |
| 33 | + ;; | |
| 34 | + | |
| 35 | + # 🧩: jigsaw | |
| 36 | + jigsaw|example|examples|demo|demos) | |
| 37 | + message="Introduce new example(s)" | |
| 38 | + emoji="🧩" | |
| 39 | + ;; | |
| 40 | + | |
| 41 | + | |
| 42 | + # 📝: memo | |
| 43 | + memo|doc|documentation) | |
| 44 | + message="Add or update documentation" | |
| 45 | + emoji="📝" | |
| 46 | + ;; | |
| 47 | + | |
| 48 | + # 🌸: cherry_blossom | |
| 49 | + gardening|garden|clean|cleaning) | |
| 50 | + message="Gardening" | |
| 51 | + emoji="🌸" | |
| 52 | + ;; | |
| 53 | + | |
| 54 | + # 🚀: rocket | |
| 55 | + rocket|deploy) | |
| 56 | + message="Deploy stuff" | |
| 57 | + emoji="🚀" | |
| 58 | + ;; | |
| 59 | + | |
| 60 | + # 🎉: tada | |
| 61 | + tada|first) | |
| 62 | + message="Begin a project" | |
| 63 | + emoji="🎉" | |
| 64 | + ;; | |
| 65 | + | |
| 66 | + # 🚧: construction | |
| 67 | + construction|wip) | |
| 68 | + message="Work in progress" | |
| 69 | + emoji="🚧" | |
| 70 | + ;; | |
| 71 | + | |
| 72 | + # 📦️: package | |
| 73 | + package|build) | |
| 74 | + message="Add or update compiled files or packages" | |
| 75 | + emoji="📦️" | |
| 76 | + ;; | |
| 77 | + | |
| 78 | + # 📦️: package | |
| 79 | + release) | |
| 80 | + message="Create a release" | |
| 81 | + emoji="📦️" | |
| 82 | + ;; | |
| 83 | + | |
| 84 | + # 👽️: alien | |
| 85 | + alien|api) | |
| 86 | + message="Update code due to external API changes" | |
| 87 | + emoji="👽️" | |
| 88 | + ;; | |
| 89 | + | |
| 90 | + # 🐳: whale | |
| 91 | + docker|container) | |
| 92 | + message="Docker" | |
| 93 | + emoji="🐳" | |
| 94 | + ;; | |
| 95 | + | |
| 96 | + # 🍊: tangerine | |
| 97 | + gitpod|gitpodify) | |
| 98 | + message="Gitpodify" | |
| 99 | + emoji="🍊" | |
| 100 | + ;; | |
| 101 | + | |
| 102 | + # 🧪: test tube | |
| 103 | + alembic|experiments|experiment|xp) | |
| 104 | + message="Perform experiments" | |
| 105 | + emoji="🧪" | |
| 106 | + ;; | |
| 107 | + | |
| 108 | + # ✅: check mark | |
| 109 | + test|tests|testing) | |
| 110 | + message="Add or update tests" | |
| 111 | + emoji="✅" | |
| 112 | + ;; | |
| 113 | + | |
| 114 | + # 💾: floppy-disk | |
| 115 | + save) | |
| 116 | + message="Saved" | |
| 117 | + emoji="💾" | |
| 118 | + ;; | |
| 119 | + | |
| 120 | + *) | |
| 121 | + message="Updated" | |
| 122 | + emoji="🛟" | |
| 123 | + ;; | |
| 124 | + | |
| 125 | +esac | |
| 126 | + | |
| 127 | +find . -name '.DS_Store' -type f -delete | |
| 128 | + | |
| 129 | +if [ -z "$2" ] | |
| 130 | +then | |
| 131 | + # empty | |
| 132 | + git add .; git commit -m "$emoji $message."; git push | |
| 133 | +else | |
| 134 | + # not empty | |
| 135 | + git add .; git commit -m "$emoji $message: $2"; git push | |
| 136 | +fi | |
| new file mode 100755 | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +message="" | ||
| 3 | +case $1 in | ||
| 4 | + | ||
| 5 | + # 🎨: art | ||
| 6 | + art) | ||
| 7 | + message="Improve structure / format of the code" | ||
| 8 | + emoji="🎨" | ||
| 9 | + ;; | ||
| 10 | + | ||
| 11 | + # 🐛: bug | ||
| 12 | + bug|fix) | ||
| 13 | + message="Fix a bug" | ||
| 14 | + emoji="🐛" | ||
| 15 | + ;; | ||
| 16 | + | ||
| 17 | + # 🤓: geek | ||
| 18 | + human|human-fixed) | ||
| 19 | + message="Human Fixed" | ||
| 20 | + emoji="🤓" | ||
| 21 | + ;; | ||
| 22 | + | ||
| 23 | + # 🤖: robot | ||
| 24 | + ai|ai-generated) | ||
| 25 | + message="AI generated" | ||
| 26 | + emoji="🤖" | ||
| 27 | + ;; | ||
| 28 | + | ||
| 29 | + # ✨: sparkles | ||
| 30 | + sparkles|feature) | ||
| 31 | + message="Introduce new feature(s)" | ||
| 32 | + emoji="✨" | ||
| 33 | + ;; | ||
| 34 | + | ||
| 35 | + # 🧩: jigsaw | ||
| 36 | + jigsaw|example|examples|demo|demos) | ||
| 37 | + message="Introduce new example(s)" | ||
| 38 | + emoji="🧩" | ||
| 39 | + ;; | ||
| 40 | + | ||
| 41 | + | ||
| 42 | + # 📝: memo | ||
| 43 | + memo|doc|documentation) | ||
| 44 | + message="Add or update documentation" | ||
| 45 | + emoji="📝" | ||
| 46 | + ;; | ||
| 47 | + | ||
| 48 | + # 🌸: cherry_blossom | ||
| 49 | + gardening|garden|clean|cleaning) | ||
| 50 | + message="Gardening" | ||
| 51 | + emoji="🌸" | ||
| 52 | + ;; | ||
| 53 | + | ||
| 54 | + # 🚀: rocket | ||
| 55 | + rocket|deploy) | ||
| 56 | + message="Deploy stuff" | ||
| 57 | + emoji="🚀" | ||
| 58 | + ;; | ||
| 59 | + | ||
| 60 | + # 🎉: tada | ||
| 61 | + tada|first) | ||
| 62 | + message="Begin a project" | ||
| 63 | + emoji="🎉" | ||
| 64 | + ;; | ||
| 65 | + | ||
| 66 | + # 🚧: construction | ||
| 67 | + construction|wip) | ||
| 68 | + message="Work in progress" | ||
| 69 | + emoji="🚧" | ||
| 70 | + ;; | ||
| 71 | + | ||
| 72 | + # 📦️: package | ||
| 73 | + package|build) | ||
| 74 | + message="Add or update compiled files or packages" | ||
| 75 | + emoji="📦️" | ||
| 76 | + ;; | ||
| 77 | + | ||
| 78 | + # 📦️: package | ||
| 79 | + release) | ||
| 80 | + message="Create a release" | ||
| 81 | + emoji="📦️" | ||
| 82 | + ;; | ||
| 83 | + | ||
| 84 | + # 👽️: alien | ||
| 85 | + alien|api) | ||
| 86 | + message="Update code due to external API changes" | ||
| 87 | + emoji="👽️" | ||
| 88 | + ;; | ||
| 89 | + | ||
| 90 | + # 🐳: whale | ||
| 91 | + docker|container) | ||
| 92 | + message="Docker" | ||
| 93 | + emoji="🐳" | ||
| 94 | + ;; | ||
| 95 | + | ||
| 96 | + # 🍊: tangerine | ||
| 97 | + gitpod|gitpodify) | ||
| 98 | + message="Gitpodify" | ||
| 99 | + emoji="🍊" | ||
| 100 | + ;; | ||
| 101 | + | ||
| 102 | + # 🧪: test tube | ||
| 103 | + alembic|experiments|experiment|xp) | ||
| 104 | + message="Perform experiments" | ||
| 105 | + emoji="🧪" | ||
| 106 | + ;; | ||
| 107 | + | ||
| 108 | + # ✅: check mark | ||
| 109 | + test|tests|testing) | ||
| 110 | + message="Add or update tests" | ||
| 111 | + emoji="✅" | ||
| 112 | + ;; | ||
| 113 | + | ||
| 114 | + # 💾: floppy-disk | ||
| 115 | + save) | ||
| 116 | + message="Saved" | ||
| 117 | + emoji="💾" | ||
| 118 | + ;; | ||
| 119 | + | ||
| 120 | + *) | ||
| 121 | + message="Updated" | ||
| 122 | + emoji="🛟" | ||
| 123 | + ;; | ||
| 124 | + | ||
| 125 | +esac | ||
| 126 | + | ||
| 127 | +find . -name '.DS_Store' -type f -delete | ||
| 128 | + | ||
| 129 | +if [ -z "$2" ] | ||
| 130 | +then | ||
| 131 | + # empty | ||
| 132 | + git add .; git commit -m "$emoji $message."; git push | ||
| 133 | +else | ||
| 134 | + # not empty | ||
| 135 | + git add .; git commit -m "$emoji $message: $2"; git push | ||
| 136 | +fi | ||