Skip to content

Commit 7f8109b

Browse files
kerthcetclaude
andauthored
chore: drop make install (#46)
* docs: add an end-to-end Quick Start, drop `make install` - `make install` was advertised in `make help`, the README and the Rust-import error but never existed. Drop it rather than add it: from source the package is just `pip install .`, and in a checkout `make dev` is the fix. - README: a Quick Start that builds both halves and runs a command on one machine, then Installation, then Usage (direct and tunnel mode). - Call the Python side the "server" everywhere, matching `Server` and `--server-url`; there is no separate controller program since #42. - Fix the install.sh version-pin example (v0.1.0 does not exist). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kerthcet <kerthcet@gmail.com> * release: v0.2.0 Bump protocol, server, daemon and the Python package to 0.2.0, along with the sandd-protocol dependency pin and Cargo.lock. Point the docs and the release Dockerfiles at v0.2.0. Their defaults were broken: Dockerfile.daemon-tunnel-release pinned v0.1.0, which was never released, and Dockerfile.server-tunnel-release pinned PyPI 0.0.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: kerthcet <kerthcet@gmail.com> --------- Signed-off-by: kerthcet <kerthcet@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1e8545b commit 7f8109b

16 files changed

Lines changed: 97 additions & 61 deletions

‎Cargo.lock‎

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Makefile‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@ MATURIN := .venv/bin/maturin
55
# Pinned so lint results don't shift when ruff changes its default rule set.
66
RUFF_VERSION := ruff==0.15.15
77

8-
.PHONY: help build install dev test clean daemon-build daemon-release test-e2e test-e2e-tunnel docker-build docker-down
8+
.PHONY: help build dev test clean daemon-build daemon-release test-e2e test-e2e-tunnel docker-build docker-down
99

1010
help:
1111
@echo "SandD - Sandbox Daemon - Build Commands"
1212
@echo ""
1313
@echo " make build - Build Python package (debug mode)"
14-
@echo " make install - Install Python package locally"
1514
@echo " make dev - Install in development mode with hot reload"
1615
@echo " make test - Run unit and integration tests (fast, no Docker)"
1716
@echo " make test-e2e - Run direct-mode end-to-end tests with Docker (slow)"

‎README.md‎

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,63 @@ Rust-powered WebSocket server with Python API for remote command execution and i
5959
└───────┘ └───────┘ └───────┘
6060
```
6161

62+
## Quick Start
63+
64+
Run a server and a daemon on one machine and execute a command. You need Rust
65+
(https://rustup.rs) and Python 3.8+.
66+
67+
**1. Build both from source:**
68+
69+
```bash
70+
git clone https://github.com/InftyAI/SandD
71+
cd SandD
72+
pip install . # server: the `sandd` Python package
73+
make daemon-release # daemon: ./target/release/sandd
74+
```
75+
76+
**2. Terminal 1, start the server:**
77+
78+
```python
79+
from sandd import Server
80+
81+
server = Server() # listens on 0.0.0.0:8765
82+
print("waiting for worker-1...")
83+
server.wait_for_daemon("worker-1", timeout=120)
84+
85+
result = server.exec("worker-1", "uname -a")
86+
print(result.stdout)
87+
```
88+
89+
**3. Terminal 2, start a daemon:**
90+
91+
```bash
92+
./target/release/sandd --server-url ws://127.0.0.1:8765/ws --daemon-id worker-1
93+
```
94+
95+
Terminal 1 prints the daemon's `uname -a`. On real machines, run the daemon on each
96+
worker with `ws://<server-ip>:8765/ws`; workers dial out, so only the server's
97+
port needs to be reachable.
98+
6299
## Installation
63100

64-
### Python Package (Controller)
101+
The server is a Python package (`from sandd import Server`); the daemon is a
102+
separate binary, also named `sandd`, that runs on each worker.
103+
104+
### Server (Python package)
65105

66-
Install from PyPI:
106+
From PyPI:
67107
```bash
68108
pip install sandd
69109
```
70110

71-
Or build from source:
111+
From source (needs Rust):
72112
```bash
73113
git clone https://github.com/InftyAI/SandD
74114
cd SandD
75-
make install
115+
pip install .
76116
```
77117

78-
### Daemon Binary (Worker)
118+
### Daemon (worker binary)
79119

80120
#### Quick Install
81121

@@ -87,10 +127,10 @@ curl -fsSL https://raw.githubusercontent.com/InftyAI/SandD/main/hack/scripts/ins
87127
curl -fsSL https://raw.githubusercontent.com/InftyAI/SandD/main/hack/scripts/install.sh | sudo bash -s -- --tunnel
88128
```
89129

90-
This installs the latest release. To pin a specific version:
130+
This installs the latest release to `/usr/local/bin/sandd`. To pin a specific version:
91131

92132
```bash
93-
curl -fsSL https://raw.githubusercontent.com/InftyAI/SandD/main/hack/scripts/install.sh | sudo bash -s -- --version v0.1.0
133+
curl -fsSL https://raw.githubusercontent.com/InftyAI/SandD/main/hack/scripts/install.sh | sudo bash -s -- --version v0.2.0
94134
```
95135

96136
#### Alternative Methods
@@ -104,21 +144,20 @@ cargo install sandd
104144
```bash
105145
git clone https://github.com/InftyAI/SandD
106146
cd SandD
107-
make daemon-release
108-
# Binary at: ./target/release/sandd
147+
make daemon-release # binary at ./target/release/sandd
148+
# or put it on your PATH (~/.cargo/bin/sandd):
149+
cargo install --path sandd
109150
```
110151

111152
**Build from the main branch:**
112153
```bash
113154
cargo install --git https://github.com/InftyAI/SandD sandd
114155
```
115156

116-
## Quick Start
157+
## Usage
117158

118159
### Direct Mode (Development)
119160

120-
**Start controller:**
121-
122161
```python
123162
from sandd import Server
124163

@@ -129,18 +168,8 @@ result = server.exec("worker-1", "hostname")
129168
print(result.stdout)
130169
```
131170

132-
**Start daemon:**
133-
134171
```bash
135-
# Direct mode
136-
sandd --server-url ws://controller-ip:8765/ws --daemon-id worker-1
137-
138-
# Tunnel mode
139-
sandd --server-url ws://10.200.0.1:8765/ws \
140-
--daemon-id worker-1 \
141-
--tunnel \
142-
--tunnel-authkey YOUR_KEY \
143-
--tunnel-server http://headscale:8080
172+
sandd --server-url ws://server-ip:8765/ws --daemon-id worker-1
144173
```
145174

146175
### Tunnel Mode (Production)
@@ -160,6 +189,14 @@ server = Server(connect="tunnel", tunnel_config=config)
160189
# ✓ No public IPs required
161190
```
162191

192+
```bash
193+
sandd --server-url ws://10.200.0.1:8765/ws \
194+
--daemon-id worker-1 \
195+
--tunnel \
196+
--tunnel-authkey YOUR_KEY \
197+
--tunnel-server http://headscale:8080
198+
```
199+
163200
In a cluster, don't bake a key into your image — mint one per start from a key
164201
broker (`$SANDD_KEYBROKER_URL`) and take the headscale URL from
165202
`$SANDD_TUNNEL_SERVER`:
@@ -174,13 +211,13 @@ See [Tunnel Mode Guide](./docs/proposals/TUNNEL.md) for setup instructions.
174211

175212
## Security
176213

177-
SandD does not authenticate daemons yet. The controller accepts any client that
214+
SandD does not authenticate daemons yet. The server accepts any client that
178215
speaks the `sandd.v1` protocol, and a daemon can register under any id, so anyone who
179-
can reach the controller's port can join and receive commands meant for that id.
216+
can reach the server's port can join and receive commands meant for that id.
180217

181-
- **Direct mode:** run the controller only on a trusted network.
218+
- **Direct mode:** run the server only on a trusted network.
182219
- **Tunnel mode:** only nodes admitted to your Headscale mesh can reach the
183-
controller, and traffic is encrypted with WireGuard. The `authkey` is a Headscale
220+
server, and traffic is encrypted with WireGuard. The `authkey` is a Headscale
184221
key for joining the mesh, not a SandD credential.
185222

186223
Daemon authentication and authorization with Keycloak is planned (see
@@ -198,7 +235,7 @@ Daemon authentication and authorization with Keycloak is planned (see
198235
## Roadmap
199236

200237
- [ ] **Authentication & Authorization** - Keycloak-issued tokens for daemons (see [Security](#security))
201-
- [ ] **File Transfer** - Upload and download files between controller and workers
238+
- [ ] **File Transfer** - Upload and download files between server and workers
202239
- [ ] **Audit Logging** - Track all commands, sessions, and file transfers
203240
- [ ] **Metrics** - Prometheus-compatible metrics for monitoring
204241
- [ ] **Resource Limits** - CPU/memory/timeout controls per daemon

‎docs/ARCHITECTURE.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ Forward raw SSH traffic through WebSocket to daemon's sshd.
5656

5757
### Future: Authentication
5858

59-
Today the controller admits any client that speaks `sandd.v1`, and a daemon can
59+
Today the server admits any client that speaks `sandd.v1`, and a daemon can
6060
register under any id. Run it on a trusted network, or in tunnel mode, where only mesh
6161
members can reach it.
6262

6363
The plan is to use Keycloak for authentication and authorization:
6464

6565
- The daemon gets an access token from Keycloak and sends it as
6666
`Authorization: Bearer <token>` on the WebSocket upgrade.
67-
- The controller verifies the token against Keycloak's JWKS endpoint before upgrading,
67+
- The server verifies the token against Keycloak's JWKS endpoint before upgrading,
6868
and rejects a bad one with HTTP 401.
6969
- The token's claims decide which daemon id the connection registers as, and what it
7070
is allowed to do.

‎docs/DEVELOP.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ SandD/
1717
├── protocol/ # Shared message types (sandd-protocol crate)
1818
│ └── src/lib.rs
1919
│
20-
├── server/ # Controller: Rust WebSocket server + PyO3 bindings
20+
├── server/ # Server: Rust WebSocket server + PyO3 bindings
2121
│ ├── src/
2222
│ │ ├── lib.rs # Crate root
2323
│ │ ├── server.rs # WebSocket server (axum): /ws, /stats, /health
@@ -77,7 +77,7 @@ make daemon-build
7777
### 3. Try It
7878

7979
```bash
80-
# Terminal 1: start a controller
80+
# Terminal 1: start a server
8181
python3 -c "
8282
from sandd import Server
8383
server = Server()
@@ -183,7 +183,7 @@ tunnel stack. `make test` runs `-m "not e2e"`.
183183
RUST_LOG=debug ./target/debug/sandd --server-url ws://127.0.0.1:8765/ws
184184
```
185185

186-
**Controller logs:** `Server(verbose=True)` (the default) logs at INFO; set
186+
**Server logs:** `Server(verbose=True)` (the default) logs at INFO; set
187187
`RUST_LOG=sandbox_server=debug` for more.
188188

189189
## Known Issues & Limitations
@@ -192,7 +192,7 @@ RUST_LOG=debug ./target/debug/sandd --server-url ws://127.0.0.1:8765/ws
192192
`Server.download_file` exist, and the protocol messages are defined, but the
193193
feature is unfinished: don't rely on either call.
194194
2. **No daemon authentication.** Any client that speaks `sandd.v1` can register as any
195-
daemon id. Run the controller on a trusted network or in tunnel mode. See
195+
daemon id. Run the server on a trusted network or in tunnel mode. See
196196
[ARCHITECTURE.md](ARCHITECTURE.md#future-authentication).
197197

198198
### Warnings
@@ -248,10 +248,10 @@ Use a `feat:`, `fix:` or `chore:` prefix, as in the existing history.
248248
### User Issues
249249

250250
**Daemon won't connect:**
251-
- Check the controller is up: `curl http://controller-host:8765/health`
251+
- Check the server is up: `curl http://server-host:8765/health`
252252
- Verify firewall allows outbound WebSocket connections
253253
- Check daemon logs: `RUST_LOG=info ./target/release/sandd ...`
254-
- Check what the controller sees: `curl http://controller-host:8765/stats`
254+
- Check what the server sees: `curl http://server-host:8765/stats`
255255

256256
**Commands timing out:**
257257
- Increase `timeout` parameter in `exec()` (in seconds)

‎hack/docker/Dockerfile.daemon-tunnel-release‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
# Downloads pre-built binary from GitHub releases
33
#
44
# Build: docker build -f hack/docker/Dockerfile.daemon-tunnel-release \
5-
# --build-arg SANDD_VERSION=v0.1.0 \
6-
# -t inftyai/sandd-tunnel:v0.1.0 .
7-
# Run: docker run --cap-add NET_ADMIN --device /dev/net/tun inftyai/sandd-tunnel:v0.1.0
5+
# --build-arg SANDD_VERSION=v0.2.0 \
6+
# -t inftyai/sandd-tunnel:v0.2.0 .
7+
# Run: docker run --cap-add NET_ADMIN --device /dev/net/tun inftyai/sandd-tunnel:v0.2.0
88

99
FROM debian:bookworm-slim
1010

@@ -23,7 +23,7 @@ RUN apt-get update && apt-get install -y \
2323
RUN curl -fsSL https://tailscale.com/install.sh | sh
2424

2525
# Download pre-built daemon binary from GitHub releases
26-
ARG SANDD_VERSION=v0.1.0
26+
ARG SANDD_VERSION=v0.2.0
2727
ARG TARGETOS=linux
2828
ARG TARGETARCH=amd64
2929

‎hack/docker/Dockerfile.server-tunnel-release‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
# Uses published PyPI package instead of building from source
33
#
44
# Build: docker build -f hack/docker/Dockerfile.server-tunnel-release \
5-
# --build-arg SANDD_VERSION=0.1.0 \
6-
# -t inftyai/sandd-server-tunnel:v0.1.0 .
7-
# Run: docker run --cap-add NET_ADMIN --device /dev/net/tun inftyai/sandd-server-tunnel:v0.1.0
5+
# --build-arg SANDD_VERSION=0.2.0 \
6+
# -t inftyai/sandd-server-tunnel:v0.2.0 .
7+
# Run: docker run --cap-add NET_ADMIN --device /dev/net/tun inftyai/sandd-server-tunnel:v0.2.0
88

99
FROM python:3.11-slim-bookworm
1010

@@ -23,7 +23,7 @@ RUN apt-get update && apt-get install -y \
2323
RUN curl -fsSL https://tailscale.com/install.sh | sh
2424

2525
# Install SandD from PyPI (specify version or use latest)
26-
ARG SANDD_VERSION=0.0.0
26+
ARG SANDD_VERSION=0.2.0
2727
RUN pip install --no-cache-dir sandd==${SANDD_VERSION}
2828

2929
# Create directory for Tailscale state

‎hack/docker/README.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This directory contains Docker-related files for building and testing SandD.
1515

1616
- **`Dockerfile.server-tunnel-release`** - Server with Tailscale (uses PyPI release)
1717
- Use: Production deployments
18-
- Build: `docker build -f hack/docker/Dockerfile.server-tunnel-release --build-arg SANDD_VERSION=0.1.0 -t inftyai/sandd-server-tunnel:v0.1.0 .`
18+
- Build: `docker build -f hack/docker/Dockerfile.server-tunnel-release --build-arg SANDD_VERSION=0.2.0 -t inftyai/sandd-server-tunnel:v0.2.0 .`
1919

2020
#### Daemon (Worker) Images
2121

@@ -25,7 +25,7 @@ This directory contains Docker-related files for building and testing SandD.
2525

2626
- **`Dockerfile.daemon-tunnel-release`** - Daemon with Tailscale (uses GitHub release)
2727
- Use: Production deployments
28-
- Build: `docker build -f hack/docker/Dockerfile.daemon-tunnel-release --build-arg SANDD_VERSION=v0.1.0 -t inftyai/sandd-tunnel:v0.1.0 .`
28+
- Build: `docker build -f hack/docker/Dockerfile.daemon-tunnel-release --build-arg SANDD_VERSION=v0.2.0 -t inftyai/sandd-tunnel:v0.2.0 .`
2929

3030
#### Test Images (Direct Mode)
3131

@@ -68,7 +68,7 @@ Overridable variables: `SERVER_TUNNEL_IMG`, `SERVER_TUNNEL_TAG`, `PLATFORMS`,
6868

6969
```bash
7070
make docker-push-server-tunnel \
71-
SERVER_TUNNEL_IMG=myrepo/sandd-server-tunnel SERVER_TUNNEL_TAG=v0.1.0
71+
SERVER_TUNNEL_IMG=myrepo/sandd-server-tunnel SERVER_TUNNEL_TAG=v0.2.0
7272
```
7373

7474
To iterate locally you need a **runnable** image, which a multi-platform build cannot

‎protocol/Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "sandd-protocol"
3-
version = "0.0.1"
3+
version = "0.2.0"
44
edition = "2021"
55
license = "Apache-2.0"
66
description = "Shared wire protocol types for the SandD sandbox daemon and controller."

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "maturin"
44

55
[project]
66
name = "sandd"
7-
version = "0.0.1"
7+
version = "0.2.0"
88
description = "A lightweight sandbox daemon for secure agent execution in isolated environments."
99
readme = {file = "README.md", content-type = "text/markdown"}
1010
requires-python = ">=3.8"

0 commit comments

Comments
 (0)