cf-integration 0.2.0

Integration and conformance harness for ContextForge control-plane and data-plane services
Documentation
# Integration overlay for cf-controlplane + cf-dataplane.
#
# Usage from this repo:
#   export CF_INTEGRATION_ROOT="$PWD"
#   export CF_DATAPLANE_IMAGE="ghcr.io/contextforge-org/contextforge-data-plane:latest"
#   export CF_DATAPLANE_PLATFORM="linux/amd64"
#   # Or let `cf-integration stack up --topology dataplane` resolve `auto`.
#   docker compose \
#     -f /path/to/cf-controlplane/docker-compose.yml \
#     -f "$CF_INTEGRATION_ROOT/docker/docker-compose.cf-dataplane.yaml" \
#     up

services:
  # cf-controlplane's upstream compose service key is gateway; expose it as
  # cf-controlplane on mcpnet. DATAPLANE_PUBLISHER is the only behavioral
  # change to the upstream gateway: it publishes virtual server configs to
  # Redis for cf-dataplane.
  gateway:
    networks:
      mcpnet:
        aliases:
          - cf-controlplane
    environment:
      DATAPLANE_PUBLISHER: "true"
      # Short snapshot interval so runtime-created users/servers reach the
      # dataplane quickly in functional runs; raise for load benchmarks.
      # Requires a control-plane image with configurable publisher interval;
      # older images ignore the variable (60s behavior).
      DATAPLANE_PUBLISHER_INTERVAL_SECONDS: ${CF_DATAPLANE_PUBLISHER_INTERVAL_SECONDS:-2}

  dataplane:
    image: ${CF_DATAPLANE_IMAGE:?Set CF_DATAPLANE_IMAGE to the cf-dataplane image tag}
    pull_policy: ${CF_DATAPLANE_PULL_POLICY:-always}
    platform: ${CF_DATAPLANE_PLATFORM:?Set CF_DATAPLANE_PLATFORM to the cf-dataplane image platform}
    labels:
      name: cf-dataplane
    restart: unless-stopped
    networks:
      mcpnet:
        aliases:
          - cf-dataplane
    extra_hosts:
      - host.docker.internal:host-gateway
    expose:
      - "4445"
    environment:
      CONTEXTFORGE_DATA_PLANE_ADDRESS: 0.0.0.0:4445
      CONTEXTFORGE_DATA_PLANE_REDIS_HOSTNAME: redis
      CONTEXTFORGE_DATA_PLANE_REDIS_PORT: "6379"
      CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE: plain-text
      CONTEXTFORGE_DATA_PLANE_TOKEN_SECRET: ${JWT_SECRET_KEY:-my-test-key-but-now-longer-than-32-bytes}
      # The published image currently includes its non-production `with_tools`
      # bootstrap routes, whose clap model requires an RSA signing-key path.
      # This harness never exposes or calls those routes and uses control-plane
      # catalog tokens, so satisfy the unused path without adding a test key.
      CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY: /dev/null
      CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE: plain-text-or-tls
      # These two MCP transport settings intentionally retain the historical
      # prefix in the current dataplane configuration contract.
      CONTEXTFORGE_GATEWAY_RS_MCP_ALLOWED_HOSTS: ${CF_DATAPLANE_MCP_ALLOWED_HOSTS:-127.0.0.1:${NGINX_PORT:-8080},localhost:${NGINX_PORT:-8080},nginx}
      CONTEXTFORGE_GATEWAY_RS_MCP_ALLOWED_ORIGINS: ${CF_DATAPLANE_MCP_ALLOWED_ORIGINS:-http://127.0.0.1:${NGINX_PORT:-8080},http://localhost:${NGINX_PORT:-8080}}
      # Disable the per-subject config cache for functional runs: its sliding
      # TTL freezes stale configs under steady traffic (retry loops renew it
      # forever), hiding servers created after first contact. Set to 60 to
      # restore the image default for load benchmarks.
      CONTEXTFORGE_DATA_PLANE_USER_CONFIG_CACHE_EXPIRY_SECONDS: ${CF_DATAPLANE_USER_CONFIG_CACHE_EXPIRY_SECONDS:-0}
      RUST_LOG: ${CF_DATAPLANE_LOG:-info}
    depends_on:
      redis:
        condition: service_started
    deploy:
      replicas: 1

  nginx:
    volumes:
      - ${CF_INTEGRATION_ROOT:?Set CF_INTEGRATION_ROOT to the integration harness root}/docker/nginx.cf-dataplane.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      gateway:
        condition: service_healthy
      dataplane:
        condition: service_started