Agent and game protocols
Extend the per-game sidecar while keeping its authenticated contract, filesystem boundary, and capabilities explicit.
The agent is a per-pod HTTP/HTTPS sidecar running inside every game pod. It translates dashboard requests into game-protocol actions (RCON, file I/O, container logs, player queries) and reports liveness, resource usage, and player metrics back to the operator via Kubernetes API patches.
Unsupported capabilities must disappear or degrade safely—not emit a request that cannot succeed.
Agent surface
The sidecar serves authenticated operational endpoints with health and metrics as narrow unauthenticated exceptions.
Authentication and mTLS
Production uses operator-managed mTLS; bearer token is compatibility-only for development.
- mTLS (preferred): Agent listens on TLS, requires client certificate signed by
--tls-client-ca. All protected routes verify the certificate. - Bearer token (fallback): Shared-secret token mounted from a per-pod Secret. Used only when TLS is not configured.
- Unauthenticated exceptions:
GET /healthz(liveness probe) andGET /metrics(Prometheus, on a separate plain HTTP listener).
File operations boundary
All file operations are confined to the --data-root (typically /data PVC):
- No path traversal (
..sequences rejected) - No symlink escape (symbolic links pointing outside the root are rejected)
- Dotfile access restricted
- Temp files used for atomic writes: write fails halfway → only temp file is removed, pre-existing file untouched
Game protocols
Adapters normalize RCON, PTY, log files, moderation, status, and graceful stop across games without agent code changes.
Request/response contracts
All game-facing operations follow strict contracts:
- RCON replies: Bounded at 10–16394 bytes (packet header + 4096-character max Minecraft chunk at worst-case UTF-8 length). Over-limit or under-size packets rejected as malformed.
- Players query: Returns
{ online, max, players[], asOf, capabilities }. When unknown (RCON disabled or unrecognized format),online/maxare-1, never0. - Moderation (kick/ban/unban): Template-driven; a single
commanderrenders each action from the module’s declared capabilities. Returns{ ok, raw? }or501 Not Implementedif unsupported. - Quiesce/unquiesce: Response is
{ quiesced: true/false, reason? }. Unsupported games degrade gracefully withquiesced: falseand a reason (e.g., “game does not support save sequences”).
Extend safely
Update OpenAPI, handlers, API proxy, safety libraries, and protocol tests as one wire-contract change.
Adding a new protocol handler
-
Declare the new RCON protocol in the wire-protocol factory (
agent/internal/rcon/):- Implement the
Exec(cmd) (string, error)interface - Handle connection lifecycle (dial, auth, command dispatch, response parsing)
- Include unit tests for edge cases (malformed packets, timeouts, connection drops)
- Implement the
-
Update the module schema (
docs/gametemplate-schema.md):- Add the new protocol name to
spec.capabilities.console.protocolenum - Document default ports and expected configuration
- Add the new protocol name to
-
Update the API proxy (
api/internal/handlers/):- If the new protocol needs API-level handling (e.g., special auth token parsing), extend the agent request builder
- Add integration tests against a real agent instance
-
Update the OpenAPI contract (
agent/openapi.yaml):- Document the new behavior in endpoint descriptions, if it differs from the standard RCON contract
-
Run the test suite (
cd agent && go test ./...):- Unit tests exercise protocol parsing, edge cases, and error handling
- E2E tests (
test/e2e/) verify the new protocol with a real game server on Kind
Capability-driven extension
Module capabilities are the contract between the operator and the agent. To add support for a new game feature:
-
Extend
GameTemplate.spec.capabilitiesin the module’stemplate.yaml:- Add new fields under
players,status,actions,quiesce, orlifecycle - The agent unmarshals this JSON blob into
caps.Specat startup
- Add new fields under
-
Update the agent handler if the new capability is a new type (e.g., a new game-status metric format):
- Handlers read from
caps.Specand adapt their behavior accordingly - No agent deployment needed for new instances of existing capability types (e.g., a new RCON action command)
- Handlers read from
-
Test the module (
gp-module validateandgp-module preview):- Dry-run the module against a test GameServer CRD
- Verify the agent’s capability unmarshaling succeeds and the handler adapts correctly
AGENT CONTRACT
Safety invariants
- Every request is authenticated: All protected routes gate on mTLS cert or bearer token.
- Path confinement is consolidated:
ConfinePath(rootDir, untrustedName)is the single validation point for all filesystem operations. It rejects..,/, symlink escape, and confines all operations within rootDir. - Partial uploads never linger: Write to temp file, rename to target only on success. Failed writes don’t truncate pre-existing files.
- RCON connection errors are graceful: Lost RCON →
502 Bad Gateway, not a crash. Handlers catch and return appropriate status. - Module capabilities drive behavior: New games require no agent code change — they declare their capabilities in the module’s template.
- Gameaction validation is independent: Both the API (stdin pod-attach) and the agent (RCON) call
gameaction.Resolve()independently to validate action inputs (no control characters, 512-char cap, required-ness checks).
References
agent/openapi.yaml— Partial machine-readable HTTP contract documenting the endpoints, security schemes, and request/response schemas.agent/specs.md— Full specification of agent architecture, dependencies, and security model.docs/architecture.md— System overview and the “operator is authoritative” design principle.docs/security.md— Auth model, threat boundaries, and module-trust relationship.