This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Sockguard is a Docker socket proxy written in Go. It sits between Docker API consumers (Traefik, drydock, Portainer, etc.) and the Docker socket, filtering requests by HTTP method, path, and request body content on POST /containers/create, exec create/start, image pull, build, POST /volumes/create, POST /secrets/create, POST /configs/create, service create/update, swarm init/join/update, and plugin pull/upgrade/set/create. Any remaining body-bearing write path that Sockguard still cannot safely constrain stays behind the blind-write opt-in instead of being silently allowed. Default-deny posture, structured logging, per-client policy profiles, owner-label isolation, and read-side visibility/redaction make it the most comprehensive Docker socket security layer available.
This is a monorepo with three workspaces:
app/— Go proxy (the core binary). Built with Go 1.26, uses stdlibnet/http/httputil.ReverseProxyfor proxying, Cobra+Viper for CLI/config.website/— Next.js landing page at getsockguard.com. Hosts the benchmarks + feature pages.docs/— Fumadocs documentation site served undergetsockguard.com/docs(thedocs/Next.js app is built withbasePath: "/docs", thenwebsite/package.json'sprebuildscript copies its static export intowebsite/public/docs/so the marketing site serves it as a subpath).
Turborepo orchestrates the TypeScript workspaces. The Go app is built independently.
# Go proxy — run from app/
go build -o sockguard ./cmd/sockguard/ # Build binary
go test ./... # All tests with coverage
go test -fuzz=FuzzPathMatch ./internal/filter/ # Fuzz tests
golangci-lint run # Lint
# TypeScript workspaces — run from repo root
npm run dev # Dev servers for all TS workspaces
npm run build # Build all TS workspaces
npx biome check . # Lint all TS/JS
npx biome check --fix . # Lint + autofix
npx biome format --write . # Format
# Docker
docker build -t sockguard:dev .The proxy is a middleware chain built on net/http:
Listener (Unix socket or TCP)
→ Access Logger
→ Health Interceptor (/health)
→ Rule Evaluator (method + path matching)
→ httputil.ReverseProxy → Docker socket
Rules are defined in YAML and compiled to matchers at startup:
rules:
- match: { method: GET, path: "/containers/**" }
action: allowPath patterns use glob syntax. Before matching, Sockguard canonicalizes policy paths by percent-decoding escaped separators and dot segments, cleaning dot segments with Go's path.Clean, and stripping Docker API version prefixes such as /v1.45/.
Rules evaluate in order — first match wins. No match = deny (default-deny).
Env vars like CONTAINERS=1, POST=0, ALLOW_START=1 are automatically converted to equivalent rules for drop-in migration from Tecnativa/LinuxServer socket proxies.
YAML config file + env var overrides via Viper. Precedence: CLI flags > env vars > config file > defaults.
Env vars use SOCKGUARD_ prefix with underscore nesting: SOCKGUARD_LISTEN_SOCKET=/var/run/sockguard.sock.
- Table-driven tests with
testing.Tandhttptest - Fuzz tests for filter matching and config parsing
- Integration tests using
httptest.NewServeras mock Docker daemon - No external test dependencies — stdlib only
Gitmoji + Conventional Commits: <emoji> <type>(<scope>): <description>
| Emoji | Type | Use |
|---|---|---|
| ✨ | feat |
New feature |
| 🐛 | fix |
Bug fix |
| 📝 | docs |
Documentation |
| ♻️ | refactor |
Refactor |
| ✅ | test |
Tests |
| 🔧 | chore |
Config/tooling |
| 🔒 | security |
Security fix |
| ⚡ | perf |
Performance |
See lefthook.yml for exact commands. The pre-push pipeline is piped (sequential, fail-fast): clean-tree, GoReleaser snapshot dry-run, golangci-lint, go test -race, fuzz smoke, npm dedupe --dry-run, knip, biome, npm test, turbo build, and zizmor.
- The proxy's request hot path — filtering, proxying, logging — uses only the Go stdlib. The binary's direct external dependencies are Cobra+Viper (CLI/config), fsnotify (config hot-reload), and sigstore/sigstore-go (image-trust and signed-policy-bundle verification).
- Container image is Wolfi-based (Chainguard) for near-zero CVEs and built-in SBOM/provenance.
- Biome is a direct devDependency in the root workspace for TS/JS linting.
.planning/is gitignored — local-only working notes; never reference its contents in committed files.- CHANGELOG and README updates should be atomic with each logical change.
- Roadmap summary lives in
README.md(committed). Local-only longer-form notes live under.planning/and stay gitignored.