This feature adds a Docker Registry API v2 proxy to the CUA Cloud API, allowing users to push Docker images through the API with automatic workspace-based namespacing.
- Authenticates image pushes using workspace API keys (same keys used for the REST API)
- Automatically namespaces images by workspace slug (e.g.,
myimage:latest→{workspace_slug}/myimage:latest) - Proxies requests to an internal Docker registry, keeping the registry private
This is a plumbing command - a low-level building block. It will likely be integrated into higher-level porcelain commands like cb run --provider cua-cloud which may automatically build and push the agent loop image before starting a session.
sequenceDiagram
participant CLI as cb agent push
participant API as Go API Proxy
participant DB as PostgreSQL
participant Registry as Docker Registry
CLI->>API: POST /v2/cua-bench/blobs/uploads/<br/>Authorization: Basic _token:<api_key>
API->>DB: Validate API key
DB-->>API: Workspace (slug: "acme-corp")
API->>API: Rewrite path:<br/>/v2/cua-bench/... → /v2/acme-corp/cua-bench/...
API->>Registry: POST /v2/acme-corp/cua-bench/blobs/uploads/
Registry-->>API: 202 Accepted
API-->>CLI: 202 Accepted
flowchart LR
subgraph Client
A[cb agent push]
end
subgraph "CUA Cloud"
B[Go API<br/>:8080]
C[(PostgreSQL)]
D[Docker Registry<br/>:5000]
end
A -->|"Basic Auth<br/>_token:api_key"| B
B -->|Validate API Key| C
B -->|"Proxy + Namespace<br/>/v2/{slug}/..."| D
flowchart TD
A[Incoming Request<br/>/v2/cua-bench/manifests/latest] --> B{API Key Valid?}
B -->|No| C[401 Unauthorized]
B -->|Yes| D[Lookup Workspace]
D --> E[Get Slug: acme-corp]
E --> F[Rewrite Path<br/>/v2/acme-corp/cua-bench/manifests/latest]
F --> G[Proxy to Registry]
G --> H[Store as acme-corp/cua-bench]
- Docker
- Go 1.22+ (or use the provided
shell.nix) - Python 3.12+ (or use the provided
shell.nix) - Nix (optional, for reproducible environments)
# Clone cloud repo (Go API)
git clone https://github.com/trycua/cloud.git
cd cloud
git checkout feat/container-registry-proxy
# Clone cua-bench repo (Python CLI) in a separate directory
cd ..
git clone https://github.com/trycua/cua-bench.git
cd cua-bench
git checkout f-trycua/understand-benchmarkscd cloud
# Option A: Use nix-shell (recommended)
nix-shell
# Option B: Ensure Go is installed manually
# Start postgres and registry
docker compose -f docker-compose.registry.yml up -d postgres registry
# Wait for postgres to be healthy
sleep 10
# Verify test data was created
docker exec cua-postgres psql -U postgres -d cua -c "SELECT * FROM api_key;"
# Should show: test-api-key-12345
# Start the Go API
cd src/services/api
PORT=8080 \
ENVIRONMENT=development \
POSTGRES_URL='postgresql://postgres:postgres@localhost:5433/cua' \
REGISTRY_URL='http://localhost:5000' \
CLERK_SECRET_KEY=dummy \
go run ./cmd/server/main.gocd cua-bench
# Option A: Use nix-shell (recommended - handles Python + libstdc++)
nix-shell
# Option B: Use virtualenv manually
python3 -m venv .venv
source .venv/bin/activate
pip install -e .For local testing, create a token file with the test API key:
mkdir -p ~/.config/cua-bench
echo '{"token": "test-api-key-12345"}' > ~/.config/cua-bench/token.json# Pull a small test image
docker pull alpine:latest
# Push through the API proxy
cb agent push alpine:latest --registry http://localhost:8080Expected output:
Tagging image...
Source: alpine:latest
Target: localhost:8080/alpine:latest
Pushing through API proxy...
Endpoint: http://localhost:8080
f6b4fb944634: Pushed
latest: digest: sha256:... size: 1025
✓ Successfully pushed localhost:8080/alpine:latest
# Check the registry catalog
curl http://localhost:5000/v2/_catalogExpected output:
{"repositories":["test-workspace/alpine"]}The image is stored with the workspace namespace test-workspace/ prefix.
cd cua-bench
# Build the agent loop image
docker build -t cua-bench:latest .
# Push through proxy (default image is cua-bench:latest)
cb agent push --registry http://localhost:8080
# Verify
curl http://localhost:5000/v2/_catalogExpected output:
{"repositories":["test-workspace/alpine","test-workspace/cua-bench"]}cd cloud
docker compose -f docker-compose.registry.yml down -vAuthenticate with CUA Cloud:
cb login # Opens browser for OAuth
cb login --force # Force re-authentication
cb login --auth-url <url> # Custom auth endpointPush Docker images to CUA registry:
cb agent push # Push cua-bench:latest (default)
cb agent push myimage:v1 # Push specific image
cb agent push --registry http://... # Custom API endpointflowchart LR
A[Docker Client] -->|"Authorization: Basic base64(_token:sk_cua-api01_xxx)"| B[API Proxy]
B -->|Extract password as API key| C{Validate}
C -->|Valid| D[Proxy Request]
C -->|Invalid| E[401 Unauthorized]
The proxy uses HTTP Basic Auth:
- Username:
_token(literal string) - Password: Workspace API key (e.g.,
sk_cua-api01_...)
| Endpoint | Description |
|---|---|
GET /v2/ |
Version check (returns 401 to trigger auth) |
* /v2/{repo}/* |
All registry operations (proxied with namespace) |
All paths are rewritten to include the workspace slug:
| Original Path | Rewritten Path |
|---|---|
/v2/cua-bench/manifests/latest |
/v2/{workspace_slug}/cua-bench/manifests/latest |
/v2/cua-bench/blobs/sha256:... |
/v2/{workspace_slug}/cua-bench/blobs/sha256:... |
{
"errors": [
{"code": "UNAUTHORIZED", "message": "authentication required"}
]
}| Environment Variable | Description | Default |
|---|---|---|
REGISTRY_URL |
Internal registry URL | http://localhost:5000 |
| Environment Variable | Description | Default |
|---|---|---|
CUA_API_URL |
API proxy URL | https://api.cua.ai |
Token is stored at: ~/.config/cua-bench/token.json
- Cloud (Go API): https://github.com/trycua/cloud/pull/684
- cua-bench (Python CLI): Merged into
f-trycua/understand-benchmarks- commit f2114c4
flowchart TD
subgraph "Porcelain (Future)"
A[cb run --provider cua-cloud]
B[cb deploy]
C[CI/CD Pipeline]
end
subgraph "Plumbing (This PR)"
D[cb login]
E[cb agent push]
F[Registry Proxy API]
end
A --> D
A --> E
B --> E
C --> E
E --> F
This is plumbing - low-level infrastructure. Expected porcelain integrations:
cb run --provider cua-cloud- Could auto-build and push agent loop image before starting sessioncb deploy- Could handle building, pushing, and deploying in one command- CI/CD pipelines - Push custom environment images as part of build process
The CLI commands (cb login, cb agent push) provide the building blocks for these higher-level workflows.