Skip to content

Instantly share code, notes, and snippets.

@r33drichards
Last active December 31, 2025 17:52
Show Gist options
  • Select an option

  • Save r33drichards/2816b76ea1069884f5bdd06e73352617 to your computer and use it in GitHub Desktop.

Select an option

Save r33drichards/2816b76ea1069884f5bdd06e73352617 to your computer and use it in GitHub Desktop.

Container Registry Proxy for CUA Cloud

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.

What It Does

  • 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.

How It Works

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
Loading

Architecture Overview

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
Loading

Path Rewriting Flow

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]
Loading

Testing Locally

Prerequisites

  • Docker
  • Go 1.22+ (or use the provided shell.nix)
  • Python 3.12+ (or use the provided shell.nix)
  • Nix (optional, for reproducible environments)

1. Clone Both Repos

# 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-benchmarks

2. Start the Test Infrastructure (Cloud Repo)

cd 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.go

3. Install cua-bench CLI (cua-bench Repo)

cd 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 .

4. Set Up Test Authentication

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

5. Test Image Push

# Pull a small test image
docker pull alpine:latest

# Push through the API proxy
cb agent push alpine:latest --registry http://localhost:8080

Expected 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

6. Verify Image in Registry

# Check the registry catalog
curl http://localhost:5000/v2/_catalog

Expected output:

{"repositories":["test-workspace/alpine"]}

The image is stored with the workspace namespace test-workspace/ prefix.

7. Test with cua-bench Agent Loop Image

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/_catalog

Expected output:

{"repositories":["test-workspace/alpine","test-workspace/cua-bench"]}

Clean Up

cd cloud
docker compose -f docker-compose.registry.yml down -v

CLI Commands

cb login

Authenticate with CUA Cloud:

cb login                    # Opens browser for OAuth
cb login --force            # Force re-authentication
cb login --auth-url <url>   # Custom auth endpoint

cb agent push

Push 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 endpoint

API Details

Authentication

flowchart 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]
Loading

The proxy uses HTTP Basic Auth:

  • Username: _token (literal string)
  • Password: Workspace API key (e.g., sk_cua-api01_...)

Endpoints

Endpoint Description
GET /v2/ Version check (returns 401 to trigger auth)
* /v2/{repo}/* All registry operations (proxied with namespace)

Path Rewriting

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:...

Error Responses

{
  "errors": [
    {"code": "UNAUTHORIZED", "message": "authentication required"}
  ]
}

Configuration

Go API (cloud repo)

Environment Variable Description Default
REGISTRY_URL Internal registry URL http://localhost:5000

Python CLI (cua-bench repo)

Environment Variable Description Default
CUA_API_URL API proxy URL https://api.cua.ai

Token is stored at: ~/.config/cua-bench/token.json

Pull Requests / Commits

Future Integration

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
Loading

This is plumbing - low-level infrastructure. Expected porcelain integrations:

  1. cb run --provider cua-cloud - Could auto-build and push agent loop image before starting session
  2. cb deploy - Could handle building, pushing, and deploying in one command
  3. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment