Docker Setup

The project supports containerized deployment with Docker Compose, offering both development and production configurations.

Prerequisites

Container Architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Nginx Proxy   │────│  Django App     │────│   MySQL DB      │
│   (Production)  │    │  (Web/API)      │    │   (Data)        │
└─────────────────┘    └─────────────────┘    └─────────────────┘

Development container (Dockerfile.dev): Python 3.11 with Chrome, Firefox, WebDrivers, dev tools, and live code reloading via volume mounts.

Production container (Dockerfile.prod): Multi-stage build with Gunicorn, health checks, and security hardening.

Quick Start

Development

cp .env.sample .env
# Edit .env with your API keys and settings

docker-compose --profile development up --build

# Access: http://localhost:8000
# Admin: http://localhost:8000/admin

The development web and cron containers use the committed main.settings_dev module, so a local untracked main/settings.py file is not required for Docker Compose.

Local Agent Console

The agent-local profile runs the local visual agent stack that was previously kept in a separate dockerized workspace. It is intended for this computer only. All exposed ports are bound to 127.0.0.1. When testing the embedded Django page, open LTI through 127.0.0.1 rather than localhost so the local console cookie remains same-site in the iframe.

# Optional: configure a model key for autonomous Computer Use runs.
cp .env.agent-local.example .env.agent-local
# Edit .env.agent-local locally. Do not commit it.

docker compose --profile development --profile agent-local up --build

# Django tester console entry point, after signing in through Django/admin
open http://127.0.0.1:8000/local-agent-console

# Direct local operator console, useful for debugging the dev stack
open http://127.0.0.1:13020

# noVNC desktop
open http://127.0.0.1:16901/vnc.html

If the Django development stack is already running, docker compose --profile agent-local up --build is enough to start only the local agent services. The first supported rollout is authenticated dev access through /local-agent-console; the same Django-owned route is the target model for later LTI dev/prod access. The Django admin also exposes /admin/local-agent-console/ as a staff shortcut to the same health and service links.

The LTI-owned local stack intentionally uses host ports 13020, 12222, 15901, and 16901 so it can run beside the older standalone dockerized prototype if that prototype is still active on this computer. The VM API is not published as a host port; the local console proxies authenticated VM API calls over the Docker network. SSH, VNC, and VM API secrets are generated into the agent_api_secrets Docker volume at VM startup. Credential values are not returned by the local console API by default; set LOCAL_AGENT_SHOW_CREDENTIALS=1 in .env.agent-local only for local debugging on this computer.

The local console can start deterministic VM commands without a model key. A real autonomous task requires ANTHROPIC_API_KEY or a future configured model credential in .env.agent-local.

Local runner bridge

Phase 3C adds an outbound runner bridge that keeps the local VM private while letting LTI own run state, progress events, and artifacts. After creating an ApiClient with lti:read and lti:runner:write scopes, set the local LTI_AGENT_API_TOKEN and console token in .env.agent-local, then run one polling cycle with:

python manage.py create_api_client \
  --name albert-mac-local-runner \
  --scope lti:read \
  --scope lti:runner:write \
  --confirm-print-token

Run the command only in a trusted interactive shell because it prints the raw bearer token exactly once.

python agent_runtime/runner_bridge.py --once

Omit --once to keep polling. The bridge leases one pending runner-compatible execution. Manual-AI work starts the existing local console task API. Contracted E2E work runs ordered read-only API or declarative Selenium browser steps directly and never opens the local visual console. Both paths post redacted progress logs as text artifacts and complete through /agent-api/v1/agentic-qa/.... Screenshot evidence for this slice should be sent as structured payload; runner-supplied external URLs and multipart file uploads are not part of the runner bridge contract yet. After each terminal console task, the bridge requests /api/agent/screenshot from the local console and records the screenshot filename/proxy_url as a structured screenshot artifact payload in LTI. Use LTI_AGENT_POLL_INTERVAL_SECONDS to tune polling cadence, LTI_AGENT_LEASE_SECONDS to set the LTI lease, and LTI_AGENT_TASK_TIMEOUT_SECONDS to cap a single local console task. The bridge reads runner and console tokens only from environment variables so bearer tokens do not appear in shell history or process listings. The bridge requires the lease to be longer than the task timeout; when the timeout is reached, the bridge posts an error event and completes the execution as blocked with the timeout in the log artifact. While a console task is still running, the bridge renews the LTI lease before completion so another runner cannot reclaim the same execution mid-task. For operator smoke checks that must prove the runner actually claimed work, run python agent_runtime/runner_bridge.py --once --require-execution; it exits with code 2 if no pending LTI execution is available. The bridge redacts common bearer-token, DR-token, password, and secret patterns before sending event messages or log artifacts; LTI applies the same redaction again before durable storage.

Generate the deterministic acceptance smoke matrix before creating its run:

python manage.py generate_scenario_matrix --output /tmp/lti-scenario-matrix.json
python manage.py generate_scenario_matrix --apply

Generation requires the acceptance target manifest. It inventories current LTI list-language and donation-form configuration, reports unsafe forms as blocked, and does not call an external service. Apply mode is idempotent. The first catalog intentionally contains only read-only frontend and FRAPI health checks; signature and payment mutations remain disabled until their data and cleanup contracts are approved.

The unauthenticated report payload intentionally stays high-level: execution status, redacted summary fields, timestamps, artifact counts, artifact types, and redaction status. Runner IDs, raw artifact payloads, file paths, and external evidence URLs stay in the authenticated API/admin surfaces.

This Phase 3C runner path stores evidence only in database text/payload fields; it does not introduce new FileField/media writes for runner artifacts.

Production

cp .env.sample .env.prod
# Configure production values

docker-compose --profile production up --build -d

# Access via Nginx: http://localhost

Environment Variables

# Database
DB_HOST=db
DB_NAME=cgo_testing_interface
DB_USER=db
DB_PASSWORD=your_secure_password

# Django
DJANGO_SECRET_KEY=your_secret_key_here
DEBUG=0
ALLOWED_HOSTS=your-domain.com,localhost

# External APIs
STRIPE_API_KEY=sk_test_...
ASANA_ACCESS_TOKEN=...
EMAIL_PASSWORD=app_specific_password

Common Operations

# Run tests inside container
docker-compose exec web-dev python manage.py test
docker-compose exec web-dev behave features/

# Database management
docker-compose exec web-dev python manage.py migrate --fake-initial
docker-compose exec web-dev python manage.py createsuperuser
docker-compose exec db mysql -u db -p cgo_testing_interface

# Update production
git pull origin main
docker-compose --profile production up --build -d

# Database backup
docker-compose exec db mysqldump -u root -p cgo_testing_interface > backup.sql

# Restore
docker-compose exec -T db mysql -u root -p cgo_testing_interface < backup.sql

# Logs
docker-compose logs -f web-prod

Troubleshooting

Database connection error: Check docker-compose ps db, restart with docker-compose restart db.

Selenium tests fail: Verify Chrome is installed: docker-compose exec web-dev google-chrome --version.

File Structure

├── Dockerfile.dev          # Development container
├── Dockerfile.prod         # Production container
├── agent_runtime/          # Local visual agent VM and operator console
├── docker-compose.yml      # Service orchestration
├── .env.sample                  # Environment template
└── Docker/
    ├── mysql/init/01-init.sql   # DB initialization
    └── nginx/nginx.conf         # Reverse proxy config

For the full Configuration reference, see the configuration page.