Skip to content

Latest commit

 

History

History
862 lines (679 loc) · 31.3 KB

File metadata and controls

862 lines (679 loc) · 31.3 KB

Configuration Reference

The service uses two configuration sources:

  1. YAML config file (config_v2.py models) — non-secret service configuration: project definitions, integrations, dispatch backend, prompts, polling settings
  2. Environment variables (config/ package / Settings) — secrets and runtime overrides: tokens, connection strings, auth credentials

Secrets never go in the YAML file. The YAML file path is set via the CONFIG_FILE env var (default: config.yaml).


Config v2 YAML Format

The YAML config file uses version: 2 and is validated by Pydantic models in config_v2.py. Generate the JSON Schema with mapping-helper schema. See config.example.yaml for a documented example.

Top-Level Structure

version: 2                    # Required — must be 2

gitlab:
  url: https://gitlab.example.com  # Required — GitLab instance URL

dispatch:
  backend: local              # local | k8s | aca (default: local)

copilot:
  model: gpt-4                # Default model for Copilot sessions
  plugins: []                 # Copilot CLI plugins
  marketplaces: []            # Custom marketplace URLs (audit-logged at startup)

server:
  log_level: info
  clone_dir: null             # Base directory for repo clones
  shutdown_timeout: 30        # Graceful shutdown timeout (seconds)
  webhook_ip_allowlist: []    # CIDR ranges allowed to send webhooks (empty = all)
  trusted_proxies: []         # Reverse proxy CIDRs for X-Forwarded-For

prompts:                      # Prompt overrides and suffixes
  system: null
  review_suffix: null
  # ... (system_suffix, review, coding, coding_suffix, discussion, discussion_suffix)

defaults:                     # Applied to every project unless overridden
  target_branch: main
  credential_ref: default
  resolution_behavior: suggest  # auto-resolve | suggest | off
  webhook: true
  poll:
    enabled: false
    interval: 30
    lookback_minutes: 60
    review_on_push: true

projects:                     # GitLab project definitions
  - repo: group/my-project
    credential_ref: default   # Override credential alias
    target_branch: main       # Override target branch
    resolution_behavior: suggest
    webhook: true
    poll:
      enabled: false
    copilot:                  # Per-project Copilot overrides
      model: gpt-4o
    integrations:             # References to named integrations
      - my-jira

integrations:                 # Named integration configurations
  - name: my-jira
    type: jira
    project_key: PROJ
    trigger_status: "AI Ready"
    in_progress_status: "In Progress"
    in_review_status: "In Review"

Validation

  • mapping-helper validate-v2 config.yaml — full Pydantic validation
  • mapping-helper schema > config.schema.json — generate JSON Schema
  • Cross-field validators: integration refs must point to defined integrations, no duplicate repos

Config Delivery

Environment Config Path
Local ./config.yaml (default)
K8s Helm ConfigMap → /etc/copilot-agent/config.yaml
ACA Terraform-rendered secret/volume

Environment Variables (v1)

Every environment variable in the config/ package, grouped by category.


Core Settings

GITLAB_URL

  • Type: str
  • Required: ✅ Yes
  • Description: GitLab instance URL (e.g., https://gitlab.example.com)
  • Validation: Must be valid URL

GITLAB_TOKEN

  • Type: str
  • Required: ✅ Yes
  • Description: GitLab API token with api scope. Recommended: Use project access tokens scoped to specific projects for least-privilege access, rather than personal access tokens.
  • Security: Read/write access to all allowed projects, webhook processing
  • Validation: Non-empty string

GITLAB_WEBHOOK_SECRET

  • Type: str | None
  • Required: ❌ No (required for webhook mode, optional for polling-only)
  • Default: None
  • Description: Secret for validating webhook payloads via HMAC (X-Gitlab-Token header). When not set, the /webhook endpoint returns 403.
  • Security: Must match GitLab webhook configuration when using webhooks

Authentication (LLM)

At least one of these must be set:

GITHUB_TOKEN

  • Type: str | None
  • Required: ⚠️ If not using BYOK
  • Default: None
  • Description: GitHub token for Copilot auth. Accepts PATs with copilot scope, fine-grained PATs, or GitHub App installation tokens. Recommended: Use GitHub App tokens for automated rotation and audit trails.
  • Security: Authorizes Copilot API access
  • Validation: Cross-checked with COPILOT_PROVIDER_TYPE in _check_auth()

COPILOT_PROVIDER_TYPE

  • Type: str | None
  • Required: ⚠️ If not using GitHub Copilot
  • Default: None
  • Options: "azure", "openai", or None for Copilot
  • Description: BYOK provider type (Bring Your Own Key)

COPILOT_PROVIDER_BASE_URL

  • Type: str | None
  • Required: ❌ No (required if COPILOT_PROVIDER_TYPE is set)
  • Default: None
  • Description: BYOK provider base URL (e.g., https://api.openai.com/v1)

COPILOT_PROVIDER_API_KEY

  • Type: str | None
  • Required: ❌ No (required if COPILOT_PROVIDER_TYPE is set)
  • Default: None
  • Description: BYOK provider API key
  • Security: Stored in Kubernetes Secret, passed as env var

COPILOT_MODEL

  • Type: str
  • Required: ❌ No
  • Default: "gpt-4"
  • Description: Model to use for reviews and coding tasks

Server Settings

HOST

  • Type: str
  • Required: ❌ No
  • Default: "0.0.0.0"
  • Description: Server bind host

PORT

  • Type: int
  • Required: ❌ No
  • Default: 8000
  • Description: Server bind port

LOG_LEVEL

  • Type: str
  • Required: ❌ No
  • Default: "info"
  • Options: "debug", "info", "warning", "error"
  • Description: Log level for structlog

AGENT_GITLAB_USERNAME

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Deprecated: ⚠️ Agent identity is now auto-discovered via GET /user using the existing GITLAB_TOKEN. The CredentialRegistry lazily resolves and caches the agent's AgentIdentity (immutable user_id + username) per credential on first use. No new env vars are needed.
  • Description: Previously used for loop prevention (skips self-authored notes). Retained for backward compatibility but no longer required.
  • Example: "copilot-agent"

CLONE_DIR

  • Type: str | None
  • Required: ❌ No
  • Default: None (uses system temp dir)
  • Description: Base directory for repo clones (useful for persistent volumes)

AUTO_MERGE_ENABLED

  • Type: bool
  • Required: ❌ No
  • Default: false
  • Description: When false (default), coding tasks create Draft MRs that require manual un-drafting before merge. When true, MRs are created as ready-to-merge.

ADMIN_TOKEN

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Description: Separate authentication token for the /config/reload endpoint. When set, the endpoint requires an X-Admin-Token header matching this value. When not set, falls back to X-Gitlab-Token (webhook secret) for backward compatibility.
  • Security: Generate with openssl rand -hex 32. Use a unique value distinct from GITLAB_WEBHOOK_SECRET — separating these tokens limits blast radius if either is leaked.

PROMPT_STRATEGY

  • Type: str
  • Required: ❌ No
  • Default: "file-based"
  • Options: "inline", "file-based"
  • Description: Controls how MR context (diff, description, discussions) is passed to the LLM. "file-based" (default) writes context to files and instructs the agent to read them via filesystem access + git diff, producing shorter prompts. "inline" embeds all context directly in the prompt for backward compatibility.

Task Execution

TASK_EXECUTOR

  • Type: Literal["local", "kubernetes", "container_apps"]
  • Required: ❌ No
  • Default: "local"
  • Options: "local" (in-process), "kubernetes" (K8s Jobs), "container_apps" (Azure Container Apps Jobs)
  • Description: Task executor backend

Copilot CLI Plugins

COPILOT_PLUGINS

  • Type: str | list[str]
  • Required: ❌ No
  • Default: []
  • Description: Copilot CLI plugins to install at runtime. Accepts comma-separated string ("plugin-a, plugin-b") or JSON array ('["plugin-a", "plugin-b"]'). Each spec can be a marketplace plugin name (name@marketplace), GitHub repo (owner/repo), Git URL, or local path (./my-plugin).
  • Example: "my-jira-plugin@awesome-copilot, ./local-plugin"

COPILOT_PLUGIN_MARKETPLACES

  • Type: str | list[str]
  • Required: ❌ No
  • Default: []
  • Description: Custom plugin marketplace URLs or paths to register before plugin installation. Accepts comma-separated string or JSON array. Each entry can be a GitHub repo (owner/repo), Git URL, or local filesystem path.
  • Example: "my-org/our-plugins, /opt/local-marketplace"

Dispatch Backend

All remote executors (kubernetes, container_apps) use Azure Storage Queue + Blob for dispatch (Claim Check pattern). KEDA ScaledJob watches the queue and triggers Job pods automatically.

DISPATCH_BACKEND

  • Type: Literal["azure_storage"]
  • Required: ❌ No
  • Default: "azure_storage"
  • Description: Dispatch backend for task queue and result storage. Tasks are dispatched via Azure Storage Queue (Claim Check: params blob + queue message). Results stored as blobs.

AZURE_STORAGE_CONNECTION_STRING

  • Type: str | None
  • Required: ⚠️ Required for K8s/Azurite deployments (unless URL-based auth is used)
  • Default: None
  • Description: Azure Storage connection string. Used with Azurite (local K8s) or real Azure Storage. Overrides URL-based auth when set.
  • Example: "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=...;BlobEndpoint=http://azurite:10000/devstoreaccount1;QueueEndpoint=http://azurite:10001/devstoreaccount1"

AZURE_STORAGE_ACCOUNT_URL

  • Type: str | None
  • Required: ⚠️ Required for ACA (managed identity auth) unless AZURE_STORAGE_CONNECTION_STRING is set
  • Default: None
  • Description: Azure Blob Storage account URL for DefaultAzureCredential auth
  • Example: "https://mystorageaccount.blob.core.windows.net"

AZURE_STORAGE_QUEUE_URL

  • Type: str | None
  • Required: ⚠️ Required for ACA (managed identity auth) unless AZURE_STORAGE_CONNECTION_STRING is set
  • Default: None
  • Description: Azure Queue Storage endpoint URL for DefaultAzureCredential auth
  • Example: "https://mystorageaccount.queue.core.windows.net"

TASK_QUEUE_NAME

  • Type: str
  • Required: ❌ No
  • Default: "task-queue"
  • Description: Azure Storage Queue name for task dispatch

TASK_BLOB_CONTAINER

  • Type: str
  • Required: ❌ No
  • Default: "task-data"
  • Description: Azure Blob container name for params and result blobs

Kubernetes Executor Settings

Only used when TASK_EXECUTOR=kubernetes.

K8S_NAMESPACE

  • Type: str
  • Required: ❌ No
  • Default: "default"
  • Description: Kubernetes namespace for Jobs

K8S_JOB_IMAGE

  • Type: str
  • Required: ⚠️ Yes if TASK_EXECUTOR=kubernetes
  • Default: ""
  • Description: Docker image for Job pods (must include agent code)
  • Example: "ghcr.io/peteroden/gitlab-copilot-agent:latest"

K8S_JOB_CPU_LIMIT

  • Type: str
  • Required: ❌ No
  • Default: "1"
  • Description: CPU limit for Job pods (K8s resource format)
  • Example: "2", "500m"

K8S_JOB_MEMORY_LIMIT

  • Type: str
  • Required: ❌ No
  • Default: "1Gi"
  • Description: Memory limit for Job pods (K8s resource format)
  • Example: "2Gi", "512Mi"

K8S_JOB_TIMEOUT

  • Type: int
  • Required: ❌ No
  • Default: 600
  • Description: Job timeout in seconds (10 minutes)

K8S_JOB_HOST_ALIASES

  • Type: str
  • Required: ❌ No
  • Default: "" (empty — no host aliases)
  • Description: JSON-encoded array of hostAliases for Job pods. Each entry must have ip and hostnames keys. Useful for environments with custom DNS (air-gapped, k3d dev).
  • Format: [{"ip": "10.0.0.1", "hostnames": ["host.local", "api.local"]}]
  • Validation: JSON structure validated at startup (must be array of objects with ip and hostnames)
  • Helm Value: Auto-generated from hostAliases value (serialized to JSON)

K8S_SECRET_NAME

  • Type: str | None
  • Required: ❌ No (but recommended for K8s deployments)
  • Default: None
  • Description: K8s Secret name for mounting Job pod credentials via secretKeyRef. When set, sensitive env vars (GITLAB_TOKEN, GITHUB_TOKEN, COPILOT_PROVIDER_API_KEY, GITLAB_WEBHOOK_SECRET) are referenced from this Secret instead of passed as plaintext. A startup warning is logged when running the K8s executor without this configured.
  • Helm Value: Auto-set to the chart's Secret name

K8S_CONFIGMAP_NAME

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Description: K8s ConfigMap name for mounting Job pod non-sensitive config via configMapKeyRef. When set, config values (DISPATCH_BACKEND, COPILOT_MODEL, COPILOT_PROVIDER_TYPE, COPILOT_PROVIDER_BASE_URL, TASK_QUEUE_NAME, TASK_BLOB_CONTAINER) are referenced from this ConfigMap.
  • Helm Value: Auto-set to the chart's ConfigMap name

K8S_JOB_INSTANCE_LABEL

  • Type: str
  • Required: ❌ No
  • Default: "" (empty)
  • Description: Helm release instance label added to Job pods as app.kubernetes.io/instance. Used by NetworkPolicies to scope access to pods within the same Helm release.
  • Helm Value: Auto-set to {{ .Release.Name }}

Azure Container Apps Executor Settings

Only used when TASK_EXECUTOR=container_apps.

ACA_SUBSCRIPTION_ID

  • Type: str | None
  • Required: ⚠️ Yes if TASK_EXECUTOR=container_apps
  • Description: Azure subscription ID containing the Container Apps Job

ACA_RESOURCE_GROUP

  • Type: str | None
  • Required: ⚠️ Yes if TASK_EXECUTOR=container_apps
  • Description: Resource group containing the Container Apps Job

ACA_JOB_NAME

  • Type: str | None
  • Required: ⚠️ Yes if TASK_EXECUTOR=container_apps
  • Description: Name of the Container Apps Job resource to trigger

ACA_JOB_TIMEOUT

  • Type: int
  • Required: ❌ No
  • Default: 600
  • Description: Maximum execution time in seconds before timeout

Validation: If TASK_EXECUTOR=container_apps, all three ACA settings (ACA_SUBSCRIPTION_ID, ACA_RESOURCE_GROUP, ACA_JOB_NAME) must be set. A ValueError is raised at startup if any are missing.


Project Allowlist

GITLAB_PROJECTS

  • Type: str | None
  • Required: ⚠️ Yes if GITLAB_POLL=true
  • Default: None
  • Description: Comma-separated GitLab project paths or IDs to scope webhook and poller
  • Format: "group/project1,group/project2,12345"
  • Validation: Each entry resolved to numeric ID at startup; required when GITLAB_POLL=true

GitLab Polling

GITLAB_POLL

  • Type: bool
  • Required: ❌ No
  • Default: False
  • Description: Enable GitLab API polling for MR and note discovery (alternative to webhooks)

GITLAB_POLL_INTERVAL

  • Type: int
  • Required: ❌ No
  • Default: 30
  • Description: Polling interval in seconds

GITLAB_POLL_LOOKBACK

  • Type: int
  • Required: ❌ No
  • Default: 60
  • Description: Minutes to look back on startup for recently created or updated MRs. The deduplication store prevents re-reviewing the same commit, so a generous lookback is safe.

GITLAB_REVIEW_ON_PUSH

  • Type: bool
  • Required: ❌ No
  • Default: True
  • Description: When true (default), the agent re-reviews an MR each time a new commit is pushed. When false, each MR is reviewed only once regardless of subsequent commits. Useful for reducing noise when developers iterate frequently on an MR.

RESOLUTION_BEHAVIOR

  • Type: str
  • Required: ❌ No
  • Default: "suggest"
  • Description: Controls how the agent handles its prior feedback that has been addressed by new commits or developer replies. Three modes:
    • auto-resolve: Resolves the thread via GitLab API with an acknowledgment reply (✅)
    • suggest: Posts an acknowledgment reply but leaves the thread open for manual review (default)
    • off: Takes no action on addressed feedback
  • Per-project override: Yes, via resolution_behavior in mapping YAML bindings
  • Note: Partially addressed feedback is never auto-resolved regardless of this setting

Jira Integration

All optional — service runs review-only without these.

JIRA_URL

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Description: Jira instance URL (e.g., https://company.atlassian.net)

JIRA_EMAIL

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Description: Jira user email for basic auth

JIRA_API_TOKEN

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Description: Jira API token or PAT
  • Security: Stored in Kubernetes Secret

JIRA_TRIGGER_STATUS

  • Type: str
  • Required: ❌ No
  • Default: "AI Ready"
  • Description: Jira status that triggers the agent
  • Note: The demo provisioner (scripts/demo_provision.py) auto-creates this status on the Jira board

JIRA_IN_PROGRESS_STATUS

  • Type: str
  • Required: ❌ No
  • Default: "In Progress"
  • Description: Status to transition to after agent picks up issue

JIRA_IN_REVIEW_STATUS

  • Type: str
  • Required: ❌ No
  • Default: "In Review"
  • Description: Status to transition to after MR creation

JIRA_POLL_INTERVAL

  • Type: int
  • Required: ❌ No
  • Default: 30
  • Description: Poll interval in seconds

JIRA_PROJECT_MAP

  • Type: str | None
  • Required: ❌ No
  • Default: None
  • Description: JSON string mapping Jira project keys to GitLab projects
  • Format: See Jira Project Map Format below

Jira Activation Logic: All of JIRA_URL, JIRA_EMAIL, JIRA_API_TOKEN, and JIRA_PROJECT_MAP must be set. The Settings.jira property returns JiraSettings if all required fields are present, else None.


Telemetry

OTEL_EXPORTER_OTLP_ENDPOINT

  • Type: str (not in Settings model, read directly by telemetry/ package)
  • Required: ❌ No
  • Default: Unset (telemetry disabled)
  • Description: OTLP gRPC endpoint for traces, metrics, and logs
  • Example: "http://otel-collector:4317"
  • Behavior:
    • If unset, init_telemetry() is a no-op — zero overhead
    • If set but collector is unreachable, the service starts normally and logs otel_collector_unavailable. A background task probes the endpoint every 30s and logs otel_collector_connected when the collector becomes available.
    • OTEL SDK retry messages are suppressed (routed through structlog at WARNING level only for persistent failures). No unstructured retry spam in the console.

SERVICE_VERSION

  • Type: str (not in Settings model)
  • Required: ❌ No
  • Default: "0.1.0"
  • Description: Service version for OTEL resource attributes

DEPLOYMENT_ENV

  • Type: str (not in Settings model)
  • Required: ❌ No
  • Default: ""
  • Description: Deployment environment label (e.g., "production", "staging")

Jira Project Map Format

The project map uses a rendered JSON format for the JIRA_PROJECT_MAP env var. This is typically generated from a YAML source file using the mapping-helper CLI.

YAML Source Format (recommended)

Create a mappings.yaml file:

defaults:
  target_branch: main
  credential_ref: default
  trigger_status: "AI Ready"       # optional — this is the default
  in_progress_status: "In Progress"
  in_review_status: "In Review"

bindings:
  - jira_project: PROJ
    repo: group/project
  - jira_project: OPS
    repo: platform/tools
    target_branch: develop
    credential_ref: platform_team
    trigger_status: "Ready for Dev"   # per-project override
    in_review_status: "Code Review"   # per-project override

Per-Project Jira Status Overrides

The three Jira workflow statuses can be set at the defaults level (applied to every binding) or overridden per binding:

Field Default Description
trigger_status "AI Ready" Status that causes the poller to pick up the issue
in_progress_status "In Progress" Status the agent transitions to when it starts work
in_review_status "In Review" Status the agent transitions to after creating an MR

The global env vars JIRA_TRIGGER_STATUS, JIRA_IN_PROGRESS_STATUS, and JIRA_IN_REVIEW_STATUS act as a fallback when no YAML mapping is used. When a YAML mapping is present the per-binding (or per-defaults) values always take precedence.

Per-Project Resolution Behavior

The resolution_behavior can be overridden per binding in the YAML mapping file:

defaults:
  resolution_behavior: suggest  # default for all projects

bindings:
  - jira_project: PROJ
    repo: group/service-a
    resolution_behavior: auto-resolve  # this team wants auto-resolution
  - jira_project: OPS
    repo: group/platform-tools
    resolution_behavior: "off"  # this team manages threads manually

When a YAML mapping is present, the per-binding value takes precedence over the RESOLUTION_BEHAVIOR env var.

Rendered JSON (env var value)

Generate with mapping-helper render-json mappings.yaml:

{
  "mappings": {
    "PROJ": {
      "repo": "group/project",
      "target_branch": "main",
      "credential_ref": "default"
    },
    "OPS": {
      "repo": "platform/tools",
      "target_branch": "develop",
      "credential_ref": "platform_team"
    }
  }
}

Fields

  • Jira project key (e.g., "PROJ"): Top-level keys in mappings
  • repo (str): GitLab repo path (e.g., group/project)
  • target_branch (str): Default MR target branch
  • credential_ref (str): Credential alias — "default" uses GITLAB_TOKEN, named aliases use GITLAB_TOKEN__<ALIAS> (e.g., credential_ref: platform_teamGITLAB_TOKEN__PLATFORM_TEAM)

CLI Commands

# Validate YAML syntax and semantics
mapping-helper validate mappings.yaml

# Show human-readable summary
mapping-helper show mappings.yaml

# Render JSON for JIRA_PROJECT_MAP env var
mapping-helper render-json mappings.yaml

Named Credentials

Set additional GitLab tokens as env vars with the GITLAB_TOKEN__ prefix:

GITLAB_TOKEN=glpat-default-token        # Used by credential_ref: default
GITLAB_TOKEN__PLATFORM_TEAM=glpat-other  # Used by credential_ref: platform_team

Alias matching is case-insensitive. Startup fails fast if a binding references an unknown alias.

Adding a Per-Project GitLab Token

Create a project access token in GitLab (Settings → Access Tokens) with these settings:

Role: Developer (minimum). Guest and Reporter are insufficient — the agent needs Developer-level access to list merge requests, post comments, push code, and resolve threads.

Scopes:

Scope Required for
api MR details, discussions, posting comments, resolving threads
read_repository Git clone for code review and discussion context
write_repository Git push for coding tasks (commit changes from @mention requests)

When deploying to Azure Container Apps, three files need updating:

  1. GitHub Actions secret — create GITLAB_TOKEN__<ALIAS> (double underscore) in repo settings (use environment-scoped secrets if the token is env-specific)
  2. deploy.yml — add the KV entry to TF_VAR_kv_bootstrap_secrets:
    TF_VAR_kv_bootstrap_secrets: >-
      {
        ...existing entries...,
        "gitlab-token--<alias>": "${{ secrets.GITLAB_TOKEN__<ALIAS> }}"
      }
    The KV name uses hyphens (gitlab-token--<alias>). The ACA env var transform (upper + replace("-","_")) produces GITLAB_TOKEN__<ALIAS>.
  3. <env>.tfvars — set credential_ref in the project binding:
    {"repo":"group/project","target_branch":"main","credential_ref":"<alias>"}

The agent auto-discovers its identity per token via GET /user — no username configuration needed.

Hot-Reload

Update mappings at runtime without restart:

mapping-helper render-json updated-mappings.yaml | \
  curl -X POST http://localhost:8000/config/reload \
    -H 'Content-Type: application/json' \
    -H 'X-Gitlab-Token: <webhook-secret>' \
    -d @-

The endpoint atomically swaps the registry and clears dedup state. New credentials (GITLAB_TOKEN__* env vars) require a container restart.


Validation Summary

Validator Condition Error
_check_auth() Neither GITHUB_TOKEN nor COPILOT_PROVIDER_TYPE set "Either GITHUB_TOKEN or COPILOT_PROVIDER_TYPE must be set"
_check_azure_storage() dispatch_backend='azure_storage' and no AZURE_STORAGE_CONNECTION_STRING and missing AZURE_STORAGE_ACCOUNT_URL or AZURE_STORAGE_QUEUE_URL "dispatch_backend='azure_storage' requires: ... (or set AZURE_STORAGE_CONNECTION_STRING)"
_check_aca_resources() TASK_EXECUTOR=container_apps and missing ACA settings "Container Apps executor requires: ..."
_check_auth() GITLAB_POLL=true and GITLAB_PROJECTS is empty "GITLAB_PROJECTS is required when GITLAB_POLL=true"

Configuration Examples

Minimal (Webhook-Only, In-Memory)

GITLAB_URL=https://gitlab.example.com
GITLAB_TOKEN=glpat-xxxxx
GITLAB_WEBHOOK_SECRET=my-secret
GITHUB_TOKEN=ghp_xxxxx

Webhook + GitLab Poller (In-Memory)

GITLAB_URL=https://gitlab.example.com
GITLAB_TOKEN=glpat-xxxxx
GITLAB_WEBHOOK_SECRET=my-secret
GITHUB_TOKEN=ghp_xxxxx
GITLAB_POLL=true
GITLAB_POLL_INTERVAL=60
GITLAB_PROJECTS="group/project1,group/project2"
AGENT_GITLAB_USERNAME=copilot-agent

Production (K8s Jobs + Azure Storage Queue + Jira + OTEL)

GITLAB_URL=https://gitlab.example.com
GITLAB_TOKEN=glpat-xxxxx
GITLAB_WEBHOOK_SECRET=my-secret
GITHUB_TOKEN=ghp_xxxxx

TASK_EXECUTOR=kubernetes
K8S_NAMESPACE=copilot-agent
K8S_JOB_IMAGE=ghcr.io/peteroden/gitlab-copilot-agent:v1.0.0
K8S_JOB_CPU_LIMIT=2
K8S_JOB_MEMORY_LIMIT=2Gi
K8S_JOB_TIMEOUT=900

DISPATCH_BACKEND=azure_storage
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;...  # Azurite
# Or for real Azure: AZURE_STORAGE_ACCOUNT_URL + AZURE_STORAGE_QUEUE_URL (managed identity)

GITLAB_POLL=true
GITLAB_POLL_INTERVAL=30
GITLAB_PROJECTS="group/infra,group/app"
AGENT_GITLAB_USERNAME=copilot-agent

JIRA_URL=https://company.atlassian.net
JIRA_EMAIL=bot@example.com
JIRA_API_TOKEN=xxxxx
JIRA_TRIGGER_STATUS="AI Ready"
JIRA_IN_PROGRESS_STATUS="In Progress"
JIRA_IN_REVIEW_STATUS="In Review"
JIRA_POLL_INTERVAL=30
JIRA_PROJECT_MAP='{"mappings":{"PROJ":{"repo":"group/project","target_branch":"main","credential_ref":"default"}}}'

RESOLUTION_BEHAVIOR=suggest

OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
SERVICE_VERSION=1.0.0
DEPLOYMENT_ENV=production

BYOK (Azure OpenAI)

GITLAB_URL=https://gitlab.example.com
GITLAB_TOKEN=glpat-xxxxx
GITLAB_WEBHOOK_SECRET=my-secret

COPILOT_PROVIDER_TYPE=azure
COPILOT_PROVIDER_BASE_URL=https://my-resource.openai.azure.com
COPILOT_PROVIDER_API_KEY=xxxxx
COPILOT_MODEL=gpt-4

Security Considerations

Secrets

All tokens/keys should be:

  • Stored in Kubernetes Secrets (or External Secrets Operator for production)
  • Mounted as environment variables (Helm chart handles this)
  • Never committed to code
  • Rotated regularly (quarterly recommended)

Rotation procedure: Update the token value in your K8s Secret (or secrets manager) and restart pods. All credentials are stateless env vars — no migration needed.

Least Privilege

  • GITLAB_TOKEN: Scope to specific projects if possible (use project access tokens)
  • GITHUB_TOKEN: Minimal scope (copilot only)
  • JIRA_API_TOKEN: Read issue, transition, add comment (no admin)

Network Isolation

  • Azure Storage (Azurite): NetworkPolicies restrict access to agent and job pods only
  • OTEL Collector: internal endpoint only
  • Job pods: egress restricted to GitLab, Copilot API, Azure Storage, and DNS via NetworkPolicy

Helm Values Mapping

Helm values.yaml maps to env vars via configmap.yaml and secret.yaml:

Helm Value Env Var Secret?
gitlab.url GITLAB_URL
gitlab.token GITLAB_TOKEN
gitlab.webhookSecret GITLAB_WEBHOOK_SECRET ✅ (optional for polling-only)
github.token GITHUB_TOKEN
controller.copilotProviderType COPILOT_PROVIDER_TYPE
controller.copilotProviderBaseUrl COPILOT_PROVIDER_BASE_URL
controller.copilotProviderApiKey COPILOT_PROVIDER_API_KEY
controller.copilotPlugins COPILOT_PLUGINS
controller.copilotPluginMarketplaces COPILOT_PLUGIN_MARKETPLACES
controller.copilotModel COPILOT_MODEL
controller.taskExecutor TASK_EXECUTOR
controller.dispatchBackend DISPATCH_BACKEND
azurite.enabled AZURE_STORAGE_CONNECTION_STRING (auto-generated) ✅ (connection string)
(auto) K8S_SECRET_NAME
(auto) K8S_CONFIGMAP_NAME
(auto) K8S_JOB_INSTANCE_LABEL
telemetry.otlpEndpoint OTEL_EXPORTER_OTLP_ENDPOINT
telemetry.environment DEPLOYMENT_ENV
jira.url JIRA_URL
jira.email JIRA_EMAIL
jira.apiToken JIRA_API_TOKEN
jira.projectMap JIRA_PROJECT_MAP
jira.triggerStatus JIRA_TRIGGER_STATUS
jira.inProgressStatus JIRA_IN_PROGRESS_STATUS
jira.inReviewStatus JIRA_IN_REVIEW_STATUS
jira.pollInterval JIRA_POLL_INTERVAL
controller.resolutionBehavior RESOLUTION_BEHAVIOR
extraEnv (arbitrary key-value pairs)
hostAliases K8S_JOB_HOST_ALIASES (JSON for Job pods)
hostAliases Pod /etc/hosts entries (controller pod)

See helm/gitlab-copilot-agent/values.yaml for full reference.


Testing-Only Configuration

These settings are used exclusively for E2E testing and must never be enabled in production.

ALLOW_HTTP_CLONE

  • Type: str
  • Required: ❌ No
  • Default: unset (HTTP clone disabled)
  • Description: When set to true, 1, or yes, allows git clone over HTTP instead of requiring HTTPS. Used by E2E tests with mock git servers.
  • ⚠️ Security: Never enable in production — disables TLS verification for clone URLs.

extraEnv (Helm)

  • Type: map
  • Default: {}
  • Description: Arbitrary key-value pairs injected into the ConfigMap. Empty values are skipped. Used to pass test-only env vars like ALLOW_HTTP_CLONE without adding them to the chart schema.

hostAliases (Helm)

  • Type: list
  • Default: []
  • Description: Pod-level /etc/hosts entries. Used in E2E tests to resolve host.k3d.internal to the Docker host gateway IP so the agent pod can reach mock services running on the host.