- The shared control-plane PostgreSQL is reachable only by the master or validator control-plane process that owns the deployment; its URL comes from
BASE_DATABASE_URLor a Docker secret. - Challenges never receive master, validator, or central control-plane PostgreSQL credentials. Each challenge gets only its own SQLite database on its
/dataSwarm volume (CHALLENGE_DATABASE_URL=sqlite+aiosqlite:////data/challenge.sqlite3). - The submitter never receives master DB credentials.
- Internal challenge calls require per-challenge shared tokens.
- The public proxy strips sensitive headers and blocks internal challenge paths.
- Agent Challenge env and launch proxy routes preserve only
X-Hotkey,X-Signature,X-Nonce, andX-Timestampfor signed miner actions.
The production boundary is stricter than local development:
- Dev, test, and local runs may use SQLite for master state. Production control-plane state must use PostgreSQL from a Docker secret or an explicit
BASE_DATABASE_URL; SQLite is rejected. - Challenge runtime state is always SQLite on the challenge
/datavolume. - Dev and local challenge images may be local, mutable, or
latest. Production images must carry a tag and asha256digest: SemVer tags for pinned releases,latest@sha256:<digest>reserved for the autonomous update channel. Untagged references and missing digests are rejected. - Production image allowlists must be scoped to a registry and namespace such as
ghcr.io/baseintelligence/. Broad prefixes such asbaseintelligence/are development-only.
First-party deployments use Docker Swarm rolling service updates. Challenge services run on the manager node (node.role==manager); broker-dispatched evaluation jobs run on workers constrained by node.labels.base.workload==cpu or ==gpu. Broker-created challenge jobs never receive the host Docker socket.
Broker GPU placement is expressed only through Swarm node labels and generic resources. A positive broker gpu_count becomes --generic-resource NVIDIA-GPU=<N> on a job constrained to node.labels.base.workload==gpu; the case-sensitive name NVIDIA-GPU must match the worker daemon.json advertisement. Omitted or None stays CPU-only. Challenge metadata, labels, environment values, and device IDs carry no placement semantics. Network isolation uses encrypted overlay networks (MTU 1450); a job requesting network: none attaches to a dedicated internal encrypted overlay with no external routes, because Swarm services cannot attach to the predefined none network.
The control-plane database credential is written only into a Docker secret and must never appear in stdout, stderr, service definitions, docs evidence, or support logs. Challenge services receive only per-challenge runtime secrets. The /data volume is retained by default when a challenge is removed; manual deletion is an explicit, destructive purge.
A Swarm service cannot run --privileged or --gpus, so docker service create never emits them. A challenge that legitimately needs a privileged Docker-in-Docker job uses the capability-gated escape hatch: instead of a Swarm service, the broker runs the job as a direct local docker run on a worker. The escape hatch is the only path that grants privilege, it is gated per challenge, and the DinD container owns its own /var/lib/docker volume rather than the host Docker socket.
Swarm service resources map CPU and memory to --limit-cpu/--limit-memory and PID ceilings to --limit-pids. docker service create supports neither --memory-swap nor --security-opt, so swap limits are not emitted and no-new-privileges is enforced daemon-wide via daemon.json. If production needs swap ceilings, enforce them with daemon or cgroup configuration and document that policy in the node runbook.
Broker archive uploads are untrusted input: the Swarm broker path rejects absolute paths, parent traversal, links, and device members before extraction, and malformed broker images are rejected before any service is created.
Broker job cleanup is two-layered. The broker /v1/docker/cleanup path removes the Swarm service (docker service rm) and releases the workload and GPU ledger entries on success and failure. The manager-only supervisor timeout-reaper independently reaps jobs that exceed their timeout, so a crashed or unreachable challenge cannot leak long-running services. Evidence should prove cleanup without storing archive payloads, bearer credentials, private keys, or credentialed database URLs.
Admin tokens, challenge tokens, the control-plane database URL, registry credentials, and wallet material must come from files, environment variables, or Docker secrets. Swarm secrets are mounted at /run/secrets/base/<name>, and value-bearing secrets reach docker secret create via stdin, never as argv. Never store clear-text secrets in registry metadata responses, docs, or evidence files.
Agent Challenge miner env values are per-submission secrets owned by the challenge, not by the BASE registry. They are master-validator scoped, encrypted at rest by Agent Challenge, injected into the Harbor/Terminal-Bench runtime, and cannot be retrieved after submission. The BASE proxy forwards the request body to the challenge but must not parse, persist, log, registry-serialize, or evidence-capture submitted env values. Public responses expose metadata only: env keys, count, empty confirmation, lock state, and timestamps.
If a challenge fails health checks or get_weights, its contribution is zero for that epoch; the master does not auto-disable it.
For public challenge requests, transport failures at ingress, the BASE proxy, or challenge service discovery become safe 502 responses. Challenge-origin non-2xx responses pass through when safe. User interfaces should render unavailable copy and must not display raw text such as BASE request failed with status 502.
