# VPS Control contributor guide ## Purpose and architecture VPS Control monitors and performs a deliberately small set of administrative actions on systemd-based Linux VPS hosts. `agent/` is a Rust daemon installed on each VPS. `control-plane/backend/` is the Go API and polling service, `control-plane/frontend/` is the React UI, and PostgreSQL is the only durable metrics/audit store. Browsers never contact agents directly. ## Security invariants - DO NOT add arbitrary command execution. - DO NOT expose the agent publicly by default. - DO NOT disable authentication for convenience. - DO NOT store plaintext credentials in source control or the database. - DO NOT allow arbitrary systemd service names. - DO NOT mutate unmanaged firewall rules. - DO NOT write unbounded logs, local state, or queues. - DO NOT add heavyweight Agent dependencies without a measured justification. - Never pass user input to `sh -c`, `bash -c`, `eval`, or equivalent APIs. - Agent subprocess arguments are separate argv values and must be validated. - Sensitive values must be redacted from logs and audit records. Any privileged operation requires: 1. input validation; 2. allow-listing; 3. an audit event; 4. a bounded timeout; 5. explicit error handling. The v1 agent is unprivileged. Read-only commands are permitted by the systemd sandbox. Fail2Ban and systemd writes require narrowly scoped sudoers/polkit rules installed by an administrator; firewall mutation is intentionally disabled until the separately reviewed helper/rollback subsystem is enabled. ## Repository layout - `agent/`: Rust daemon, unit tests, systemd packaging. - `control-plane/backend/`: Go API, auth/RBAC, polling, audit, migrations. - `control-plane/frontend/`: React/Vite UI. - `docs/`: architecture, security, deployment, development. - `scripts/`: lifecycle script for the agent. - `examples/`: safe configuration examples. Keep module ownership narrow. JSON API fields use `snake_case`; URLs are under `/v1` on the agent and `/api/v1` on the control plane. Errors are JSON objects with an `error` string and an optional stable `code`. ## Commands ```bash # Agent cargo fmt --manifest-path agent/Cargo.toml --check cargo clippy --manifest-path agent/Cargo.toml --all-targets -- -D warnings cargo test --manifest-path agent/Cargo.toml cargo build --manifest-path agent/Cargo.toml --release # Control-plane backend cd control-plane/backend && gofmt -w . && go vet ./... && go test ./... # Frontend cd control-plane/frontend && npm ci && npm run lint && npm run typecheck npm test -- --run && npm run build # Deployment docker compose -f control-plane/docker-compose.yml config docker compose -f control-plane/docker-compose.yml build ``` Ordinary tests must not require root, nftables, Fail2Ban, WireGuard, or a live PostgreSQL instance. Put host-dependent tests behind explicit integration tags. ## Resource and coding rules The agent targets <=30 MiB idle RSS, a 64 MiB systemd limit, near-zero idle CPU, and negligible disk writes. Prefer `/proc` and `/sys`, collect expensive data on demand, bound request bodies/concurrency/timeouts, and do not cache history on the VPS. Production logging is `info` to journald and successful polls are not logged. Rust must be formatted, clippy-clean, avoid `unsafe` unless documented, and keep blocking OS work out of async executor threads. Go handlers must enforce auth and RBAC before reading request bodies for mutations. React code must be typed and must not bypass the backend. ## Release process CI lints, tests, builds both Linux agent targets, emits `vps-agent-linux-{amd64,arm64}` plus `SHA256SUMS`, validates Compose, and builds containers. Release publication is a manual approval step. Update the changelog, version, checksums/signature, compatibility notes, and rollback instructions.