From c4cb0e88459b031cb8eceb122baddcb59f56771d Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Thu, 12 Feb 2026 12:39:37 +0000 Subject: [PATCH 1/7] feat: add AI Bridge Proxy support to copilot module --- registry/coder-labs/modules/copilot/README.md | 31 ++++- .../modules/copilot/copilot.tftest.hcl | 113 ++++++++++++++++++ registry/coder-labs/modules/copilot/main.tf | 32 +++++ .../modules/copilot/scripts/start.sh | 38 ++++++ 4 files changed, 213 insertions(+), 1 deletion(-) diff --git a/registry/coder-labs/modules/copilot/README.md b/registry/coder-labs/modules/copilot/README.md index 76b8f025c..5bc494a28 100644 --- a/registry/coder-labs/modules/copilot/README.md +++ b/registry/coder-labs/modules/copilot/README.md @@ -3,7 +3,7 @@ display_name: Copilot CLI description: GitHub Copilot CLI agent for AI-powered terminal assistance icon: ../../../../.icons/github.svg verified: false -tags: [agent, copilot, ai, github, tasks] +tags: [agent, copilot, ai, github, tasks, aibridge] --- # Copilot @@ -164,6 +164,35 @@ module "copilot" { } ``` +### Usage with AI Bridge Proxy + +[AI Bridge Proxy](https://coder.com/docs/ai-coder/ai-bridge/ai-bridge-proxy) routes Copilot traffic through [AI Bridge](https://coder.com/docs/ai-coder/ai-bridge) for centralized LLM management and governance. +The proxy environment variables are scoped to the Copilot process only and do not affect other workspace traffic. + +```tf +module "aibridge-proxy" { + source = "registry.coder.com/coder/aibridge-proxy/coder" + version = "1.0.0" + agent_id = coder_agent.main.id + proxy_url = "https://aiproxy.example.com" +} + +module "copilot" { + source = "registry.coder.com/coder-labs/copilot/coder" + version = "0.4.0" + agent_id = coder_agent.main.id + workdir = "/home/coder/projects" + enable_aibridge_proxy = true + aibridge_proxy_auth_url = module.aibridge-proxy.proxy_auth_url + aibridge_proxy_cert_path = module.aibridge-proxy.cert_path +} +``` + +> [!NOTE] +> AI Bridge Proxy is a Premium Coder feature that requires [AI Bridge](https://coder.com/docs/ai-coder/ai-bridge) to be enabled. +> See the [AI Bridge Proxy setup guide](https://coder.com/docs/ai-coder/ai-bridge/ai-bridge-proxy/setup) for details on configuring the proxy on your Coder deployment. +> GitHub authentication is still required for Copilot as the proxy authenticates with AI Bridge using the Coder session token, but does not replace GitHub authentication. + ## Authentication The module supports multiple authentication methods (in priority order): diff --git a/registry/coder-labs/modules/copilot/copilot.tftest.hcl b/registry/coder-labs/modules/copilot/copilot.tftest.hcl index 185c019ba..8ef7148d4 100644 --- a/registry/coder-labs/modules/copilot/copilot.tftest.hcl +++ b/registry/coder-labs/modules/copilot/copilot.tftest.hcl @@ -234,3 +234,116 @@ run "app_slug_is_consistent" { error_message = "module_dir_name should be '.copilot-module'" } } + +run "aibridge_proxy_defaults" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder" + } + + assert { + condition = var.enable_aibridge_proxy == false + error_message = "enable_aibridge_proxy should default to false" + } + + assert { + condition = var.aibridge_proxy_auth_url == "" + error_message = "aibridge_proxy_auth_url should default to empty" + } + + assert { + condition = var.aibridge_proxy_cert_path == "" + error_message = "aibridge_proxy_cert_path should default to empty" + } +} + +run "aibridge_proxy_enabled" { + command = plan + + variables { + agent_id = "test-agent-aibridge-proxy" + workdir = "/home/coder" + enable_aibridge_proxy = true + aibridge_proxy_auth_url = "https://coder:mock-token@aiproxy.example.com" + aibridge_proxy_cert_path = "/tmp/aibridge-proxy/ca-cert.pem" + } + + assert { + condition = var.enable_aibridge_proxy == true + error_message = "AI Bridge Proxy should be enabled" + } + + assert { + condition = var.aibridge_proxy_auth_url == "https://coder:mock-token@aiproxy.example.com" + error_message = "AI Bridge Proxy auth URL should match the input variable" + } + + assert { + condition = var.aibridge_proxy_cert_path == "/tmp/aibridge-proxy/ca-cert.pem" + error_message = "AI Bridge Proxy cert path should match the input variable" + } +} + +run "aibridge_proxy_validation_missing_proxy_auth_url" { + command = plan + + variables { + agent_id = "test-agent-validation" + workdir = "/home/coder" + enable_aibridge_proxy = true + aibridge_proxy_auth_url = "" + aibridge_proxy_cert_path = "/tmp/aibridge-proxy/ca-cert.pem" + } + + expect_failures = [ + var.enable_aibridge_proxy, + ] +} + +run "aibridge_proxy_validation_missing_cert_path" { + command = plan + + variables { + agent_id = "test-agent-validation" + workdir = "/home/coder" + enable_aibridge_proxy = true + aibridge_proxy_auth_url = "https://coder:mock-token@aiproxy.example.com" + aibridge_proxy_cert_path = "" + } + + expect_failures = [ + var.enable_aibridge_proxy, + ] +} + +run "aibridge_proxy_with_copilot_config" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder" + copilot_model = "gpt-5" + github_token = "ghp_test123" + allow_all_tools = true + enable_aibridge_proxy = true + aibridge_proxy_auth_url = "https://coder:mock-token@aiproxy.example.com" + aibridge_proxy_cert_path = "/tmp/aibridge-proxy/ca-cert.pem" + } + + assert { + condition = var.enable_aibridge_proxy == true + error_message = "AI Bridge Proxy should be enabled" + } + + assert { + condition = length(resource.coder_env.github_token) == 1 + error_message = "github_token environment variable should be set alongside proxy" + } + + assert { + condition = length(resource.coder_env.copilot_model) == 1 + error_message = "copilot_model environment variable should be set alongside proxy" + } +} diff --git a/registry/coder-labs/modules/copilot/main.tf b/registry/coder-labs/modules/copilot/main.tf index 218184d75..492b99a75 100644 --- a/registry/coder-labs/modules/copilot/main.tf +++ b/registry/coder-labs/modules/copilot/main.tf @@ -173,6 +173,35 @@ variable "post_install_script" { default = null } +variable "enable_aibridge_proxy" { + type = bool + description = "Route Copilot traffic through AI Bridge Proxy. See https://coder.com/docs/ai-coder/ai-bridge/ai-bridge-proxy" + default = false + + validation { + condition = !var.enable_aibridge_proxy || length(var.aibridge_proxy_auth_url) > 0 + error_message = "aibridge_proxy_auth_url is required when enable_aibridge_proxy is true." + } + + validation { + condition = !var.enable_aibridge_proxy || length(var.aibridge_proxy_cert_path) > 0 + error_message = "aibridge_proxy_cert_path is required when enable_aibridge_proxy is true." + } +} + +variable "aibridge_proxy_auth_url" { + type = string + description = "AI Bridge Proxy URL with authentication. Use the proxy_auth_url output from the aibridge-proxy module." + default = "" + sensitive = true +} + +variable "aibridge_proxy_cert_path" { + type = string + description = "Path to the AI Bridge Proxy CA certificate. Use the cert_path output from the aibridge-proxy module." + default = "" +} + data "coder_workspace" "me" {} data "coder_workspace_owner" "me" {} @@ -279,6 +308,9 @@ module "agentapi" { ARG_TRUSTED_DIRECTORIES='${join(",", var.trusted_directories)}' \ ARG_EXTERNAL_AUTH_ID='${var.external_auth_id}' \ ARG_RESUME_SESSION='${var.resume_session}' \ + ARG_ENABLE_AIBRIDGE_PROXY='${var.enable_aibridge_proxy}' \ + ARG_AIBRIDGE_PROXY_AUTH_URL='${var.aibridge_proxy_auth_url}' \ + ARG_AIBRIDGE_PROXY_CERT_PATH='${var.aibridge_proxy_cert_path}' \ /tmp/start.sh EOT diff --git a/registry/coder-labs/modules/copilot/scripts/start.sh b/registry/coder-labs/modules/copilot/scripts/start.sh index 98341e9bc..57f5c60c8 100644 --- a/registry/coder-labs/modules/copilot/scripts/start.sh +++ b/registry/coder-labs/modules/copilot/scripts/start.sh @@ -22,6 +22,9 @@ ARG_DENY_TOOLS=${ARG_DENY_TOOLS:-} ARG_TRUSTED_DIRECTORIES=${ARG_TRUSTED_DIRECTORIES:-} ARG_EXTERNAL_AUTH_ID=${ARG_EXTERNAL_AUTH_ID:-github} ARG_RESUME_SESSION=${ARG_RESUME_SESSION:-true} +ARG_ENABLE_AIBRIDGE_PROXY=${ARG_ENABLE_AIBRIDGE_PROXY:-false} +ARG_AIBRIDGE_PROXY_AUTH_URL=${ARG_AIBRIDGE_PROXY_AUTH_URL:-} +ARG_AIBRIDGE_PROXY_CERT_PATH=${ARG_AIBRIDGE_PROXY_CERT_PATH:-} validate_copilot_installation() { if ! command_exists copilot; then @@ -118,6 +121,40 @@ setup_github_authentication() { return 0 } +setup_aibridge_proxy() { + if [ "$ARG_ENABLE_AIBRIDGE_PROXY" != "true" ]; then + return 0 + fi + + echo "Setting up AI Bridge Proxy..." + + if [ -z "$ARG_AIBRIDGE_PROXY_AUTH_URL" ]; then + echo "ERROR: AI Bridge Proxy is enabled but no proxy auth URL provided." + exit 1 + fi + + if [ -z "$ARG_AIBRIDGE_PROXY_CERT_PATH" ]; then + echo "ERROR: AI Bridge Proxy is enabled but no certificate path provided." + exit 1 + fi + + if [ ! -f "$ARG_AIBRIDGE_PROXY_CERT_PATH" ]; then + echo "ERROR: AI Bridge Proxy certificate not found at $ARG_AIBRIDGE_PROXY_CERT_PATH." + echo " Ensure the aibridge-proxy module has completed setup." + exit 1 + fi + + # Set proxy environment variables scoped to this process tree only. + # These are inherited by the agentapi/copilot process below, + # but do not affect other workspace processes, avoiding routing + # unnecessary traffic through the proxy. + export HTTPS_PROXY="$ARG_AIBRIDGE_PROXY_AUTH_URL" + export NODE_EXTRA_CA_CERTS="$ARG_AIBRIDGE_PROXY_CERT_PATH" + + echo "✓ AI Bridge Proxy configured" + echo " CA certificate: $ARG_AIBRIDGE_PROXY_CERT_PATH" +} + start_agentapi() { echo "Starting in directory: $ARG_WORKDIR" cd "$ARG_WORKDIR" @@ -157,5 +194,6 @@ start_agentapi() { } setup_github_authentication +setup_aibridge_proxy validate_copilot_installation start_agentapi From ea328d1ea73987be7dd2658c92059436ea5ff33e Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 13 Feb 2026 11:14:24 +0000 Subject: [PATCH 2/7] chore: update terraform version >=1.9 --- registry/coder-labs/modules/copilot/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder-labs/modules/copilot/main.tf b/registry/coder-labs/modules/copilot/main.tf index 492b99a75..78e836496 100644 --- a/registry/coder-labs/modules/copilot/main.tf +++ b/registry/coder-labs/modules/copilot/main.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.9" required_providers { coder = { source = "coder/coder" From cfc128dc60973d71a288c233ddf40e6a7bafe7db Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 13 Feb 2026 13:44:10 +0000 Subject: [PATCH 3/7] feat: wait for aibridge-proxy setup before starting copilot --- registry/coder-labs/modules/copilot/scripts/start.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/registry/coder-labs/modules/copilot/scripts/start.sh b/registry/coder-labs/modules/copilot/scripts/start.sh index 57f5c60c8..836603ac3 100644 --- a/registry/coder-labs/modules/copilot/scripts/start.sh +++ b/registry/coder-labs/modules/copilot/scripts/start.sh @@ -128,6 +128,14 @@ setup_aibridge_proxy() { echo "Setting up AI Bridge Proxy..." + # Wait for the aibridge-proxy module to finish. + # Uses startup coordination to block until aibridge-proxy-setup signals completion. + if command -v coder > /dev/null 2>&1; then + coder exp sync want "copilot-aibridge" "aibridge-proxy-setup" || true + coder exp sync start "copilot-aibridge" || true + trap 'coder exp sync complete "copilot-aibridge" > /dev/null 2>&1 || true' EXIT + fi + if [ -z "$ARG_AIBRIDGE_PROXY_AUTH_URL" ]; then echo "ERROR: AI Bridge Proxy is enabled but no proxy auth URL provided." exit 1 From 7d7a39938c767a903fa4ec81475003b57f8d68ca Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 13 Feb 2026 13:50:29 +0000 Subject: [PATCH 4/7] docs: update README --- registry/coder-labs/modules/copilot/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/registry/coder-labs/modules/copilot/README.md b/registry/coder-labs/modules/copilot/README.md index 5bc494a28..212cc40db 100644 --- a/registry/coder-labs/modules/copilot/README.md +++ b/registry/coder-labs/modules/copilot/README.md @@ -193,6 +193,10 @@ module "copilot" { > See the [AI Bridge Proxy setup guide](https://coder.com/docs/ai-coder/ai-bridge/ai-bridge-proxy/setup) for details on configuring the proxy on your Coder deployment. > GitHub authentication is still required for Copilot as the proxy authenticates with AI Bridge using the Coder session token, but does not replace GitHub authentication. +> [!IMPORTANT] +> When using AI Bridge Proxy, enable [startup coordination](https://coder.com/docs/admin/templates/startup-coordination) by setting `CODER_AGENT_SOCKET_SERVER_ENABLED=true` in the workspace container environment. +> This ensures the Copilot module waits for the `aibridge-proxy` module to complete before starting. Without it, the Copilot start script may fail if the certificate is not yet available. + ## Authentication The module supports multiple authentication methods (in priority order): From f415d6c86cdc05220f602726ad4a35fefc9cf63d Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 27 Feb 2026 12:53:28 +0000 Subject: [PATCH 5/7] chore: address comments --- .../coder-labs/modules/copilot/copilot.tftest.hcl | 8 ++++---- registry/coder-labs/modules/copilot/main.tf | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/registry/coder-labs/modules/copilot/copilot.tftest.hcl b/registry/coder-labs/modules/copilot/copilot.tftest.hcl index 8ef7148d4..0ff2379a0 100644 --- a/registry/coder-labs/modules/copilot/copilot.tftest.hcl +++ b/registry/coder-labs/modules/copilot/copilot.tftest.hcl @@ -249,13 +249,13 @@ run "aibridge_proxy_defaults" { } assert { - condition = var.aibridge_proxy_auth_url == "" - error_message = "aibridge_proxy_auth_url should default to empty" + condition = var.aibridge_proxy_auth_url == null + error_message = "aibridge_proxy_auth_url should default to null" } assert { - condition = var.aibridge_proxy_cert_path == "" - error_message = "aibridge_proxy_cert_path should default to empty" + condition = var.aibridge_proxy_cert_path == null + error_message = "aibridge_proxy_cert_path should default to null" } } diff --git a/registry/coder-labs/modules/copilot/main.tf b/registry/coder-labs/modules/copilot/main.tf index 78e836496..2837961f5 100644 --- a/registry/coder-labs/modules/copilot/main.tf +++ b/registry/coder-labs/modules/copilot/main.tf @@ -179,12 +179,12 @@ variable "enable_aibridge_proxy" { default = false validation { - condition = !var.enable_aibridge_proxy || length(var.aibridge_proxy_auth_url) > 0 + condition = !var.enable_aibridge_proxy || (var.aibridge_proxy_auth_url != null && length(var.aibridge_proxy_auth_url) > 0) error_message = "aibridge_proxy_auth_url is required when enable_aibridge_proxy is true." } validation { - condition = !var.enable_aibridge_proxy || length(var.aibridge_proxy_cert_path) > 0 + condition = !var.enable_aibridge_proxy || (var.aibridge_proxy_cert_path != null && length(var.aibridge_proxy_cert_path) > 0) error_message = "aibridge_proxy_cert_path is required when enable_aibridge_proxy is true." } } @@ -192,14 +192,14 @@ variable "enable_aibridge_proxy" { variable "aibridge_proxy_auth_url" { type = string description = "AI Bridge Proxy URL with authentication. Use the proxy_auth_url output from the aibridge-proxy module." - default = "" + default = null sensitive = true } variable "aibridge_proxy_cert_path" { type = string description = "Path to the AI Bridge Proxy CA certificate. Use the cert_path output from the aibridge-proxy module." - default = "" + default = null } data "coder_workspace" "me" {} @@ -309,8 +309,8 @@ module "agentapi" { ARG_EXTERNAL_AUTH_ID='${var.external_auth_id}' \ ARG_RESUME_SESSION='${var.resume_session}' \ ARG_ENABLE_AIBRIDGE_PROXY='${var.enable_aibridge_proxy}' \ - ARG_AIBRIDGE_PROXY_AUTH_URL='${var.aibridge_proxy_auth_url}' \ - ARG_AIBRIDGE_PROXY_CERT_PATH='${var.aibridge_proxy_cert_path}' \ + ARG_AIBRIDGE_PROXY_AUTH_URL='${var.aibridge_proxy_auth_url != null ? var.aibridge_proxy_auth_url : ""}' \ + ARG_AIBRIDGE_PROXY_CERT_PATH='${var.aibridge_proxy_cert_path != null ? var.aibridge_proxy_cert_path : ""}' \ /tmp/start.sh EOT From 23a1af57f1be8960265c2df2bc926c0e419de49c Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 27 Feb 2026 13:18:51 +0000 Subject: [PATCH 6/7] chore: improve readme --- registry/coder-labs/modules/copilot/README.md | 2 +- registry/coder-labs/modules/copilot/scripts/start.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder-labs/modules/copilot/README.md b/registry/coder-labs/modules/copilot/README.md index 212cc40db..711173bb1 100644 --- a/registry/coder-labs/modules/copilot/README.md +++ b/registry/coder-labs/modules/copilot/README.md @@ -195,7 +195,7 @@ module "copilot" { > [!IMPORTANT] > When using AI Bridge Proxy, enable [startup coordination](https://coder.com/docs/admin/templates/startup-coordination) by setting `CODER_AGENT_SOCKET_SERVER_ENABLED=true` in the workspace container environment. -> This ensures the Copilot module waits for the `aibridge-proxy` module to complete before starting. Without it, the Copilot start script may fail if the certificate is not yet available. +> This ensures the Copilot module waits for the `aibridge-proxy` module to complete before starting. Without it, the Copilot start script may fail if the AI Bridge Proxy setup has not completed in time. ## Authentication diff --git a/registry/coder-labs/modules/copilot/scripts/start.sh b/registry/coder-labs/modules/copilot/scripts/start.sh index 836603ac3..021cd26aa 100644 --- a/registry/coder-labs/modules/copilot/scripts/start.sh +++ b/registry/coder-labs/modules/copilot/scripts/start.sh @@ -148,7 +148,7 @@ setup_aibridge_proxy() { if [ ! -f "$ARG_AIBRIDGE_PROXY_CERT_PATH" ]; then echo "ERROR: AI Bridge Proxy certificate not found at $ARG_AIBRIDGE_PROXY_CERT_PATH." - echo " Ensure the aibridge-proxy module has completed setup." + echo " Ensure the aibridge-proxy module has successfully completed setup." exit 1 fi From 7f900574bab93bb26eacabcd0f13b4662b9650bd Mon Sep 17 00:00:00 2001 From: Susana Cardoso Ferreira Date: Fri, 27 Feb 2026 13:25:13 +0000 Subject: [PATCH 7/7] chore: redirect coder exp sync output to reduce noise in logs --- registry/coder-labs/modules/copilot/scripts/start.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder-labs/modules/copilot/scripts/start.sh b/registry/coder-labs/modules/copilot/scripts/start.sh index 021cd26aa..0aecb1feb 100644 --- a/registry/coder-labs/modules/copilot/scripts/start.sh +++ b/registry/coder-labs/modules/copilot/scripts/start.sh @@ -131,8 +131,8 @@ setup_aibridge_proxy() { # Wait for the aibridge-proxy module to finish. # Uses startup coordination to block until aibridge-proxy-setup signals completion. if command -v coder > /dev/null 2>&1; then - coder exp sync want "copilot-aibridge" "aibridge-proxy-setup" || true - coder exp sync start "copilot-aibridge" || true + coder exp sync want "copilot-aibridge" "aibridge-proxy-setup" > /dev/null 2>&1 || true + coder exp sync start "copilot-aibridge" > /dev/null 2>&1 || true trap 'coder exp sync complete "copilot-aibridge" > /dev/null 2>&1 || true' EXIT fi