From 2b459f7e56b41e48681799c45c0e15bebfca27f1 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Mon, 13 Apr 2026 08:45:57 +0530 Subject: [PATCH 01/53] feat(boundary): add boundary module with installation and configuration scripts --- registry/coder/modules/boundary/README.md | 48 +++++++++ .../modules/boundary/boundary.tftest.hcl | 50 +++++++++ registry/coder/modules/boundary/main.tf | 59 ++++++++++ .../coder/modules/boundary/scripts/install.sh | 102 ++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 registry/coder/modules/boundary/README.md create mode 100644 registry/coder/modules/boundary/boundary.tftest.hcl create mode 100644 registry/coder/modules/boundary/main.tf create mode 100644 registry/coder/modules/boundary/scripts/install.sh diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md new file mode 100644 index 000000000..fee40e8f7 --- /dev/null +++ b/registry/coder/modules/boundary/README.md @@ -0,0 +1,48 @@ +--- +display_name: Boundary +description: Configures boundary for network isolation in Coder workspaces +icon: ../../../../.icons/coder.svg +verified: true +tags: [boundary, coder, AI, agents] +--- + +# Boundary + +Configures boundary to enable network isolation for workspace processes in Coder. + +```tf +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "1.0.0" + agent_id = coder_agent.main.id +} +``` + +## Examples + +### Compile from source + +```tf +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "1.0.0" + agent_id = coder_agent.main.id + compile_boundary_from_source = true + boundary_version = "main" +} +``` + +### Use release binary + +```tf +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "1.0.0" + agent_id = coder_agent.main.id + use_boundary_directly = true + boundary_version = "latest" +} +``` diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl new file mode 100644 index 000000000..f399f9e05 --- /dev/null +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -0,0 +1,50 @@ +# Test for boundary module + +run "plan_with_required_vars" { + command = plan + + variables { + agent_id = "test-agent-id" + } + + # Verify the coder_script resource is created with correct agent_id + assert { + condition = coder_script.boundary_script.agent_id == "test-agent-id" + error_message = "boundary_script agent_id should match the input variable" + } + + assert { + condition = coder_script.boundary_script.display_name == "Boundary Installation Script" + error_message = "display_name should be 'Boundary Installation Script'" + } +} + +run "plan_with_compile_from_source" { + command = plan + + variables { + agent_id = "test-agent-id" + compile_boundary_from_source = true + boundary_version = "main" + } + + assert { + condition = coder_script.boundary_script.agent_id == "test-agent-id" + error_message = "boundary_script agent_id should match the input variable" + } +} + +run "plan_with_use_directly" { + command = plan + + variables { + agent_id = "test-agent-id" + use_boundary_directly = true + boundary_version = "latest" + } + + assert { + condition = coder_script.boundary_script.agent_id == "test-agent-id" + error_message = "boundary_script agent_id should match the input variable" + } +} diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf new file mode 100644 index 000000000..82c33285a --- /dev/null +++ b/registry/coder/modules/boundary/main.tf @@ -0,0 +1,59 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.5" + } + } +} + +# Add required variables for your modules and remove any unneeded variables +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "boundary_version" { + type = string + description = "Boundary version. When use_boundary_directly is true, a release version should be provided or 'latest' for the latest release. When compile_boundary_from_source is true, a valid git reference should be provided (tag, commit, branch)." + default = "latest" +} + +variable "compile_boundary_from_source" { + type = bool + description = "Whether to compile boundary from source instead of using the official install script." + default = false +} + +variable "use_boundary_directly" { + type = bool + description = "Whether to use boundary binary directly instead of `coder boundary` subcommand. When false (default), uses `coder boundary` subcommand. When true, installs and uses boundary binary from release." + default = false +} + +locals { + boundary_script = file("${path.module}/scripts/install.sh") + module_directory = "$HOME/.coder-modules/coder/boundary" + boundary_script_destination = "${local.module_directory}/install.sh" +} + +resource "coder_script" "boundary_script" { + agent_id = var.agent_id + display_name = "Boundary Installation Script" + script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + mkdir -p "$(dirname "${local.boundary_script_destination}")" + echo -n '${base64encode(local.boundary_script)}' | base64 -d > "${local.boundary_script_destination}" + chmod +x "${local.boundary_script_destination}" + + ARG_BOUNDARY_VERSION="${var.boundary_version}" \ + ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ + ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ + ARG_MODULE_DIR="${local.module_directory}" \ + "${local.boundary_script_destination}" +EOT +} diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh new file mode 100644 index 000000000..10a71c172 --- /dev/null +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Exports AGENTAPI_BOUNDARY_PREFIX for use by module start scripts. + +set -o nounset +BOUNDARY_VERSION="${ARG_BOUNDARY_VERSION:-latest}" +COMPILE_BOUNDARY_FROM_SOURCE="${ARG_COMPILE_BOUNDARY_FROM_SOURCE:-false}" +USE_BOUNDARY_DIRECTLY="${ARG_USE_BOUNDARY_DIRECTLY:-false}" +MODULE_DIR="${ARG_MODULE_DIR:-}" +set +o nounset + +validate_boundary_subcommand() { + if hash coder; then + if coder boundary --help > /dev/null 2>&1; then + return 0 + else + echo "Error: 'coder' command found but does not support 'boundary' subcommand. Please enable install_boundary." + exit 1 + fi + else + echo "Error: 'coder' command not found. boundary cannot be enabled." >&2 + exit 1 + fi +} + +# Install boundary binary if needed. +# Uses one of three strategies: +# 1. Compile from source (compile_boundary_from_source=true) +# 2. Install from release (use_boundary_directly=true) +# 3. Use coder boundary subcommand (default, no installation needed) +install_boundary() { + if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]]; then + echo "Compiling boundary from source (version: ${BOUNDARY_VERSION})" + + # Remove existing boundary directory to allow re-running safely + if [[ -d boundary ]]; then + rm -rf boundary + fi + + echo "Cloning boundary repository" + git clone https://github.com/coder/boundary.git + cd boundary || exit 1 + git checkout "${BOUNDARY_VERSION}" + + make build + + sudo cp boundary /usr/local/bin/ + sudo chmod +x /usr/local/bin/boundary + cd - || exit 1 + elif [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then + echo "Installing boundary using official install script (version: ${BOUNDARY_VERSION})" + curl -fsSL https://raw.githubusercontent.com/coder/boundary/main/install.sh | bash -s -- --version "${BOUNDARY_VERSION}" + else + validate_boundary_subcommand + echo "Using coder boundary subcommand (provided by Coder)" + fi +} + +# Set up boundary: install, write config, create wrapper script. +# Exports AGENTAPI_BOUNDARY_PREFIX pointing to the wrapper script. +setup_boundary() { + local module_path="${MODULE_DIR}" + + echo "Setting up coder boundary..." + + # Install boundary binary if needed + install_boundary + + # Determine which boundary command to use and create wrapper script + BOUNDARY_WRAPPER_SCRIPT="${module_path}/boundary-wrapper.sh" + + if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]] || [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then + # Use boundary binary directly (from compilation or release installation) + cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' +#!/usr/bin/env bash +set -euo pipefail +exec boundary -- "$@" +WRAPPER_EOF + else + # Use coder boundary subcommand (default) + # Copy coder binary to strip CAP_NET_ADMIN capabilities. + # This is necessary because boundary doesn't work with privileged binaries + # (you can't launch privileged binaries inside network namespaces unless + # you have sys_admin). + CODER_NO_CAPS="${module_path}/coder-no-caps" + if ! cp "$(command -v coder)" "${CODER_NO_CAPS}"; then + echo "Error: Failed to copy coder binary to ${CODER_NO_CAPS}. boundary cannot be enabled." >&2 + exit 1 + fi + cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' +#!/usr/bin/env bash +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "${SCRIPT_DIR}/coder-no-caps" boundary -- "$@" +WRAPPER_EOF + fi + + chmod +x "${BOUNDARY_WRAPPER_SCRIPT}" + export AGENTAPI_BOUNDARY_PREFIX="${BOUNDARY_WRAPPER_SCRIPT}" + echo "boundary wrapper configured: ${AGENTAPI_BOUNDARY_PREFIX}" +} + +setup_boundary \ No newline at end of file From e4e059be4ada3387d3e82a10a2620cc103326ab7 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Mon, 13 Apr 2026 08:54:07 +0530 Subject: [PATCH 02/53] chore: bun fmt --- registry/coder/modules/boundary/boundary.tftest.hcl | 4 ++-- registry/coder/modules/boundary/scripts/install.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index f399f9e05..f728b5efe 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -38,9 +38,9 @@ run "plan_with_use_directly" { command = plan variables { - agent_id = "test-agent-id" + agent_id = "test-agent-id" use_boundary_directly = true - boundary_version = "latest" + boundary_version = "latest" } assert { diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 10a71c172..383a70d4b 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -99,4 +99,4 @@ WRAPPER_EOF echo "boundary wrapper configured: ${AGENTAPI_BOUNDARY_PREFIX}" } -setup_boundary \ No newline at end of file +setup_boundary From 12ca1b10abd11216877612bfa2c95c86817eaa0e Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 14 Apr 2026 16:37:41 +0530 Subject: [PATCH 03/53] feat(boundary): enhance installation with wrapper script and pre/post install hooks --- registry/coder/modules/boundary/README.md | 45 ++++++++++++++++++- registry/coder/modules/boundary/main.tf | 42 +++++++++++++++-- .../coder/modules/boundary/scripts/install.sh | 6 ++- 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index fee40e8f7..d2581becc 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -8,7 +8,14 @@ tags: [boundary, coder, AI, agents] # Boundary -Configures boundary to enable network isolation for workspace processes in Coder. +Installs boundary for network isolation in Coder workspaces. + +This module: + +- Installs boundary (via coder subcommand, direct installation, or compilation from source) +- Creates a wrapper script at `$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh` +- Exports `AGENTAPI_BOUNDARY_PREFIX` as a workspace environment variable +- Provides the wrapper path via the `boundary_wrapper_path` output ```tf module "boundary" { @@ -19,6 +26,42 @@ module "boundary" { } ``` +## Usage + +The `AGENTAPI_BOUNDARY_PREFIX` environment variable is automatically available to all +workspace processes. Start scripts should check for this variable and use it to prefix +commands that should run in network isolation: + +```bash +if [ -n "${AGENTAPI_BOUNDARY_PREFIX:-}" ]; then + # Run command with boundary wrapper + "${AGENTAPI_BOUNDARY_PREFIX}" my-command --args +else + # Run command normally + my-command --args +fi +``` + +Alternatively, you can use the module output to access the wrapper path in Terraform: + +```tf +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "1.0.0" + agent_id = coder_agent.main.id +} + +resource "coder_script" "my_app" { + agent_id = coder_agent.main.id + script = <<-EOT + # Access the boundary wrapper path + WRAPPER="${module.boundary[0].boundary_wrapper_path}" + "$WRAPPER" my-command --args + EOT +} +``` + ## Examples ### Compile from source diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 82c33285a..63245679d 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -33,16 +33,34 @@ variable "use_boundary_directly" { default = false } +variable "pre_install_script" { + type = string + description = "Custom script to run before installing Codex." + default = null +} + +variable "post_install_script" { + type = string + description = "Custom script to run after installing Codex." + default = null +} + locals { boundary_script = file("${path.module}/scripts/install.sh") module_directory = "$HOME/.coder-modules/coder/boundary" boundary_script_destination = "${local.module_directory}/install.sh" + boundary_wrapper_path = "${local.module_directory}/boundary-wrapper.sh" } -resource "coder_script" "boundary_script" { - agent_id = var.agent_id - display_name = "Boundary Installation Script" - script = <<-EOT +module "coder_utils" { + source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=feat/coder-utils-optional-install-start" + # version = "1.0.1" + agent_id = var.agent_id + agent_name = "coder_boundary" + module_directory = local.module_directory + pre_install_script = var.pre_install_script + post_install_script = var.post_install_script + install_script = <<-EOT #!/bin/bash set -o errexit set -o pipefail @@ -54,6 +72,22 @@ resource "coder_script" "boundary_script" { ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ ARG_MODULE_DIR="${local.module_directory}" \ + ARG_BOUNDARY_WRAPPER_PATH="${local.boundary_wrapper_path}" \ "${local.boundary_script_destination}" EOT } + +resource "coder_env" "agentapi_boundary_prefix" { + agent_id = var.agent_id + name = "AGENTAPI_BOUNDARY_PREFIX" + value = local.boundary_wrapper_path +} + +output "boundary_wrapper_path" { + description = "Path to the boundary wrapper script." + value = local.boundary_wrapper_path +} + +output "sync_script_names" { + value = module.coder_utils +} diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 383a70d4b..bb520f278 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -6,6 +6,7 @@ BOUNDARY_VERSION="${ARG_BOUNDARY_VERSION:-latest}" COMPILE_BOUNDARY_FROM_SOURCE="${ARG_COMPILE_BOUNDARY_FROM_SOURCE:-false}" USE_BOUNDARY_DIRECTLY="${ARG_USE_BOUNDARY_DIRECTLY:-false}" MODULE_DIR="${ARG_MODULE_DIR:-}" +BOUNDARY_WRAPPER_PATH="${ARG_BOUNDARY_WRAPPER_PATH:-}" set +o nounset validate_boundary_subcommand() { @@ -13,7 +14,7 @@ validate_boundary_subcommand() { if coder boundary --help > /dev/null 2>&1; then return 0 else - echo "Error: 'coder' command found but does not support 'boundary' subcommand. Please enable install_boundary." + echo "Error: 'coder' command found but does not support 'boundary' subcommand. Set use_boundary_directly=true or compile_boundary_from_source=true." exit 1 fi else @@ -59,6 +60,7 @@ install_boundary() { # Exports AGENTAPI_BOUNDARY_PREFIX pointing to the wrapper script. setup_boundary() { local module_path="${MODULE_DIR}" + local wrapper_path="${BOUNDARY_WRAPPER_PATH}" echo "Setting up coder boundary..." @@ -66,7 +68,7 @@ setup_boundary() { install_boundary # Determine which boundary command to use and create wrapper script - BOUNDARY_WRAPPER_SCRIPT="${module_path}/boundary-wrapper.sh" + BOUNDARY_WRAPPER_SCRIPT="${wrapper_path}" if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]] || [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then # Use boundary binary directly (from compilation or release installation) From 0a7aa716dafcaebd55783ced3fb3f63f8f10166e Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 14 Apr 2026 22:57:16 +0530 Subject: [PATCH 04/53] feat(boundary): add tests and mock scripts for boundary module installation and execution --- .../modules/boundary/boundary.tftest.hcl | 105 +++++++- registry/coder/modules/boundary/main.test.ts | 237 ++++++++++++++++++ registry/coder/modules/boundary/main.tf | 15 +- .../boundary/testdata/boundary-mock.sh | 32 +++ .../modules/boundary/testdata/coder-mock.sh | 40 +++ 5 files changed, 415 insertions(+), 14 deletions(-) create mode 100644 registry/coder/modules/boundary/main.test.ts create mode 100644 registry/coder/modules/boundary/testdata/boundary-mock.sh create mode 100644 registry/coder/modules/boundary/testdata/coder-mock.sh diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index f728b5efe..838bad071 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -7,15 +7,32 @@ run "plan_with_required_vars" { agent_id = "test-agent-id" } - # Verify the coder_script resource is created with correct agent_id + # Verify the coder_env resource is created with correct agent_id assert { - condition = coder_script.boundary_script.agent_id == "test-agent-id" - error_message = "boundary_script agent_id should match the input variable" + condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" + error_message = "agentapi_boundary_prefix agent_id should match the input variable" } assert { - condition = coder_script.boundary_script.display_name == "Boundary Installation Script" - error_message = "display_name should be 'Boundary Installation Script'" + condition = coder_env.agentapi_boundary_prefix.name == "AGENTAPI_BOUNDARY_PREFIX" + error_message = "Environment variable name should be 'AGENTAPI_BOUNDARY_PREFIX'" + } + + assert { + condition = coder_env.agentapi_boundary_prefix.value == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + error_message = "Environment variable value should be the boundary wrapper path" + } + + # Verify the boundary_wrapper_path output + assert { + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + error_message = "boundary_wrapper_path output should be correct" + } + + # Verify the sync_script_names output contains the install script name + assert { + condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + error_message = "sync_script_names should contain the install script name" } } @@ -29,8 +46,18 @@ run "plan_with_compile_from_source" { } assert { - condition = coder_script.boundary_script.agent_id == "test-agent-id" - error_message = "boundary_script agent_id should match the input variable" + condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" + error_message = "agentapi_boundary_prefix agent_id should match the input variable" + } + + assert { + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + error_message = "boundary_wrapper_path output should be correct" + } + + assert { + condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + error_message = "sync_script_names should contain the install script name" } } @@ -44,7 +71,67 @@ run "plan_with_use_directly" { } assert { - condition = coder_script.boundary_script.agent_id == "test-agent-id" - error_message = "boundary_script agent_id should match the input variable" + condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" + error_message = "agentapi_boundary_prefix agent_id should match the input variable" + } + + assert { + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + error_message = "boundary_wrapper_path output should be correct" + } + + assert { + condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + error_message = "sync_script_names should contain the install script name" + } +} + +run "plan_with_custom_hooks" { + command = plan + + variables { + agent_id = "test-agent-id" + pre_install_script = "echo 'Before install'" + post_install_script = "echo 'After install'" + } + + assert { + condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" + error_message = "agentapi_boundary_prefix agent_id should match the input variable" + } + + assert { + condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + error_message = "sync_script_names should contain the install script name" + } + + # Verify pre and post install script names are set + assert { + condition = output.sync_script_names.script_names.pre_install == "coder_boundary-pre_install_script" + error_message = "sync_script_names should contain the pre_install script name" + } + + assert { + condition = output.sync_script_names.script_names.post_install == "coder_boundary-post_install_script" + error_message = "sync_script_names should contain the post_install script name" + } +} + +run "plan_with_custom_module_directory" { + command = plan + + variables { + agent_id = "test-agent-id" + module_directory = "/custom/path" + } + + assert { + condition = coder_env.agentapi_boundary_prefix.value == "/custom/path/boundary-wrapper.sh" + error_message = "Environment variable should use custom module directory" + } + + assert { + condition = output.boundary_wrapper_path == "/custom/path/boundary-wrapper.sh" + error_message = "boundary_wrapper_path output should use custom module directory" } } diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts new file mode 100644 index 000000000..dad00faf6 --- /dev/null +++ b/registry/coder/modules/boundary/main.test.ts @@ -0,0 +1,237 @@ +import { + test, + afterEach, + describe, + setDefaultTimeout, + beforeAll, + expect, +} from "bun:test"; +import { + execContainer, + readFileContainer, + runTerraformInit, + runTerraformApply, + testRequiredVariables, +} from "~test"; +import { + loadTestFile, + writeExecutable, + setup as setupUtil, + execModuleScript, + extractCoderEnvVars, +} from "../agentapi/test-util"; + +let cleanupFunctions: (() => Promise)[] = []; +const registerCleanup = (cleanup: () => Promise) => { + cleanupFunctions.push(cleanup); +}; +afterEach(async () => { + const cleanupFnsCopy = cleanupFunctions.slice().reverse(); + cleanupFunctions = []; + for (const cleanup of cleanupFnsCopy) { + try { + await cleanup(); + } catch (error) { + console.error("Error during cleanup:", error); + } + } +}); + +interface SetupProps { + moduleVariables?: Record; + skipCoderMock?: boolean; +} + +const setup = async ( + props?: SetupProps, +): Promise<{ id: string; coderEnvVars: Record }> => { + const { id, coderEnvVars } = await setupUtil({ + moduleDir: import.meta.dir, + moduleVariables: { + ...props?.moduleVariables, + }, + registerCleanup, + skipAgentAPIMock: true, // boundary module doesn't need agentapi mock + }); + + // Create a mock coder binary with boundary subcommand support + if (!props?.skipCoderMock) { + await writeExecutable({ + containerId: id, + filePath: "/usr/bin/coder", + content: await loadTestFile(import.meta.dir, "coder-mock.sh"), + }); + } + + return { id, coderEnvVars }; +}; + +setDefaultTimeout(60 * 1000); + +describe("boundary", async () => { + beforeAll(async () => { + await runTerraformInit(import.meta.dir); + }); + + testRequiredVariables(import.meta.dir, { + agent_id: "test-agent-id", + }); + + test("terraform-state-basic", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "test-agent-id", + }); + + const resources = state.resources; + + // Verify coder_env resource for AGENTAPI_BOUNDARY_PREFIX + const boundaryEnv = resources.find( + (r) => r.type === "coder_env" && r.name === "agentapi_boundary_prefix", + ); + expect(boundaryEnv).toBeDefined(); + expect(boundaryEnv?.instances[0]?.attributes.name).toBe( + "AGENTAPI_BOUNDARY_PREFIX", + ); + expect(boundaryEnv?.instances[0]?.attributes.value).toBe( + "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", + ); + + // Verify the outputs are set correctly + const coderEnvVars = extractCoderEnvVars(state); + expect(coderEnvVars["AGENTAPI_BOUNDARY_PREFIX"]).toBe( + "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", + ); + }); + + test("terraform-state-custom-module-directory", async () => { + const customDir = "/custom/boundary/path"; + const state = await runTerraformApply(import.meta.dir, { + agent_id: "test-agent-id", + module_directory: customDir, + }); + + const coderEnvVars = extractCoderEnvVars(state); + expect(coderEnvVars["AGENTAPI_BOUNDARY_PREFIX"]).toBe( + `${customDir}/boundary-wrapper.sh`, + ); + }); + + test("happy-path-coder-subcommand", async () => { + const { id } = await setup(); + await execModuleScript(id); + + // Verify the wrapper script was created + const wrapperContent = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh", + ); + expect(wrapperContent).toContain("#!/usr/bin/env bash"); + expect(wrapperContent).toContain("coder-no-caps"); + expect(wrapperContent).toContain("boundary"); + + // Verify the wrapper script is executable + const statResult = await execContainer(id, [ + "stat", + "-c", + "%a", + "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh", + ]); + expect(statResult.stdout.trim()).toMatch(/7[0-9][0-9]/); // Should be executable (7xx) + + // Verify coder-no-caps binary was created + const coderNoCapsResult = await execContainer(id, [ + "test", + "-f", + "/home/coder/.coder-modules/coder/boundary/coder-no-caps", + ]); + expect(coderNoCapsResult.exitCode).toBe(0); + + // Check install log + const installLog = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/install.log", + ); + expect(installLog).toContain("Using coder boundary subcommand"); + expect(installLog).toContain("boundary wrapper configured"); + }); + + // Note: Tests for use_boundary_directly and compile_from_source are skipped + // because they require network access (downloading boundary) or compilation + // which are too slow for unit tests. These modes are tested manually. + + test("custom-hooks", async () => { + const preInstallMarker = "pre-install-executed"; + const postInstallMarker = "post-install-executed"; + + const { id } = await setup({ + moduleVariables: { + pre_install_script: `#!/bin/bash\necho '${preInstallMarker}'`, + post_install_script: `#!/bin/bash\necho '${postInstallMarker}'`, + }, + }); + await execModuleScript(id); + + // Verify pre-install script ran + const preInstallLog = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/pre_install.log", + ); + expect(preInstallLog).toContain(preInstallMarker); + + // Verify post-install script ran + const postInstallLog = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/post_install.log", + ); + expect(postInstallLog).toContain(postInstallMarker); + + // Verify main install still ran + const installLog = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/install.log", + ); + expect(installLog).toContain("boundary wrapper configured"); + }); + + test("env-var-set-correctly", async () => { + const { id, coderEnvVars } = await setup(); + + // Verify AGENTAPI_BOUNDARY_PREFIX is in the coder env vars + expect(coderEnvVars["AGENTAPI_BOUNDARY_PREFIX"]).toBe( + "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", + ); + }); + + test("wrapper-script-execution", async () => { + const { id } = await setup(); + await execModuleScript(id); + + // Try executing the wrapper script with --help + const wrapperResult = await execContainer(id, [ + "bash", + "-c", + "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh --help", + ]); + + // The mock should respond with help text + expect(wrapperResult.stdout).toContain("boundary"); + }); + + test("installation-idempotency", async () => { + const { id } = await setup(); + + // Run the installation twice + await execModuleScript(id); + const firstInstallLog = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/install.log", + ); + + // Run again + const secondRun = await execModuleScript(id); + expect(secondRun.exitCode).toBe(0); + + // Both runs should succeed + expect(firstInstallLog).toContain("boundary wrapper configured"); + }); +}); diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 63245679d..04f90a11e 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -45,11 +45,16 @@ variable "post_install_script" { default = null } +variable "module_directory" { + type = string + description = "Directory where the boundary module scripts will be located. Default is $HOME/.coder-modules/coder/boundary." + default = "$HOME/.coder-modules/coder/boundary" +} + locals { boundary_script = file("${path.module}/scripts/install.sh") - module_directory = "$HOME/.coder-modules/coder/boundary" - boundary_script_destination = "${local.module_directory}/install.sh" - boundary_wrapper_path = "${local.module_directory}/boundary-wrapper.sh" + boundary_script_destination = "${var.module_directory}/install.sh" + boundary_wrapper_path = "${var.module_directory}/boundary-wrapper.sh" } module "coder_utils" { @@ -57,7 +62,7 @@ module "coder_utils" { # version = "1.0.1" agent_id = var.agent_id agent_name = "coder_boundary" - module_directory = local.module_directory + module_directory = var.module_directory pre_install_script = var.pre_install_script post_install_script = var.post_install_script install_script = <<-EOT @@ -71,7 +76,7 @@ module "coder_utils" { ARG_BOUNDARY_VERSION="${var.boundary_version}" \ ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ - ARG_MODULE_DIR="${local.module_directory}" \ + ARG_MODULE_DIR="${var.module_directory}" \ ARG_BOUNDARY_WRAPPER_PATH="${local.boundary_wrapper_path}" \ "${local.boundary_script_destination}" EOT diff --git a/registry/coder/modules/boundary/testdata/boundary-mock.sh b/registry/coder/modules/boundary/testdata/boundary-mock.sh new file mode 100644 index 000000000..2efe8199f --- /dev/null +++ b/registry/coder/modules/boundary/testdata/boundary-mock.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Mock boundary binary for testing +# Handles: boundary [--help | -- ] + +if [[ "$1" == "--help" ]]; then + cat << 'EOF' +boundary - Network isolation tool + +Usage: + boundary [flags] -- [args...] + +Examples: + boundary -- curl https://example.com + boundary -- npm install + +Flags: + -h, --help help for boundary +EOF + exit 0 +fi + +# Handle command execution after -- +if [[ "$1" == "--" ]]; then + shift + # Execute the command that follows + exec "$@" +fi + +# If no -- separator, just print help +echo "Error: Expected '--' separator before command" +exit 1 diff --git a/registry/coder/modules/boundary/testdata/coder-mock.sh b/registry/coder/modules/boundary/testdata/coder-mock.sh new file mode 100644 index 000000000..38598378d --- /dev/null +++ b/registry/coder/modules/boundary/testdata/coder-mock.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Mock coder command for testing boundary module +# Handles: coder boundary [--help | -- ] + +if [[ "$1" == "boundary" ]]; then + shift + + # Handle --help flag + if [[ "$1" == "--help" ]]; then + cat << 'EOF' +boundary - Run commands in network isolation + +Usage: + coder boundary [flags] -- [args...] + +Examples: + coder boundary -- curl https://example.com + coder boundary -- npm install + +Flags: + -h, --help help for boundary +EOF + exit 0 + fi + + # Handle command execution after -- + if [[ "$1" == "--" ]]; then + shift + # Execute the command that follows + exec "$@" + fi + + # If no -- separator, just print help + echo "Error: Expected '--' separator before command" + exit 1 +fi + +echo "Mock coder: Unknown command: $*" +exit 1 From 8dc8c8b8e0f1b96a1007e16c709241ee47ce4f74 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 14 Apr 2026 23:28:14 +0530 Subject: [PATCH 05/53] docs: update README with script synchronization details for boundary module --- registry/coder/modules/boundary/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index d2581becc..c02470d09 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -62,6 +62,16 @@ resource "coder_script" "my_app" { } ``` +### Script Synchronization + +The `sync_script_names` output provides script names that can be used with `coder exp sync` to coordinate script execution. This is useful when your scripts need to wait for boundary installation to complete before running. + +Available sync script names: + +- `sync_script_names.script_names.pre_install` - Pre-installation script (if configured) +- `sync_script_names.script_names.install` - Main boundary installation script +- `sync_script_names.script_names.post_install` - Post-installation script (if configured) + ## Examples ### Compile from source From d9d0b3c87fd008cb6378c29d1418764a15bac719 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 14 Apr 2026 18:19:50 +0000 Subject: [PATCH 06/53] fix(boundary): fix test failures caused by script path collision and missing mock support Three root causes: 1. boundary_script_destination used 'install.sh' - same filename that coder-utils writes to. This caused the running script to overwrite itself, corrupting bash's incremental read and producing empty install.log / no wrapper. Fix: rename to 'boundary-install.sh'. 2. coder-mock.sh didn't handle 'coder exp sync' commands used by coder-utils for script ordering. With set -o errexit, scripts failed immediately. Fix: add exp sync as no-op (exit 0). 3. Test setup used setupUtil which only extracts ONE coder_script, but coder-utils creates multiple (pre_install, install, post_install). Fix: extract all coder_scripts from terraform state and run them sequentially in lifecycle order. 4. wrapper-script-execution test called 'wrapper.sh --help' which the mock couldn't handle after the '--' separator (tried to exec '--help'). Fix: test with 'echo boundary-test' instead. --- registry/coder/modules/boundary/main.test.ts | 74 +++++++++++++++---- registry/coder/modules/boundary/main.tf | 2 +- .../modules/boundary/testdata/coder-mock.sh | 6 ++ 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index dad00faf6..028fb0ecb 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -12,11 +12,12 @@ import { runTerraformInit, runTerraformApply, testRequiredVariables, + runContainer, + removeContainer, } from "~test"; import { loadTestFile, writeExecutable, - setup as setupUtil, execModuleScript, extractCoderEnvVars, } from "../agentapi/test-util"; @@ -45,16 +46,20 @@ interface SetupProps { const setup = async ( props?: SetupProps, ): Promise<{ id: string; coderEnvVars: Record }> => { - const { id, coderEnvVars } = await setupUtil({ - moduleDir: import.meta.dir, - moduleVariables: { - ...props?.moduleVariables, - }, - registerCleanup, - skipAgentAPIMock: true, // boundary module doesn't need agentapi mock + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + ...props?.moduleVariables, }); - // Create a mock coder binary with boundary subcommand support + const coderEnvVars = extractCoderEnvVars(state); + const id = await runContainer("codercom/enterprise-node:latest"); + registerCleanup(async () => { + await removeContainer(id); + }); + + await execContainer(id, ["bash", "-c", "mkdir -p /home/coder/project"]); + + // Create a mock coder binary with boundary subcommand and exp sync support if (!props?.skipCoderMock) { await writeExecutable({ containerId: id, @@ -63,6 +68,49 @@ const setup = async ( }); } + // Extract ALL coder_scripts from the state (coder-utils creates multiple) + const allScripts = state.resources + .filter((r) => r.type === "coder_script") + .map((r) => ({ + name: r.name, + script: r.instances[0].attributes.script as string, + })); + + // Run scripts in lifecycle order + const executionOrder = [ + "pre_install_script", + "install_script", + "post_install_script", + ]; + const orderedScripts = executionOrder + .map((name) => allScripts.find((s) => s.name === name)) + .filter((s): s is NonNullable => s != null); + + // Write each script individually and create a combined runner + const scriptPaths: string[] = []; + for (const s of orderedScripts) { + const scriptPath = `/home/coder/${s.name}.sh`; + await writeExecutable({ + containerId: id, + filePath: scriptPath, + content: s.script, + }); + scriptPaths.push(scriptPath); + } + + const combinedScript = [ + "#!/bin/bash", + "set -o errexit", + "set -o pipefail", + ...scriptPaths.map((p) => `bash "${p}"`), + ].join("\n"); + + await writeExecutable({ + containerId: id, + filePath: "/home/coder/script.sh", + content: combinedScript, + }); + return { id, coderEnvVars }; }; @@ -206,15 +254,15 @@ describe("boundary", async () => { const { id } = await setup(); await execModuleScript(id); - // Try executing the wrapper script with --help + // Try executing the wrapper script with a command const wrapperResult = await execContainer(id, [ "bash", "-c", - "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh --help", + "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh echo boundary-test", ]); - // The mock should respond with help text - expect(wrapperResult.stdout).toContain("boundary"); + // The mock executes the command after -- separator + expect(wrapperResult.stdout).toContain("boundary-test"); }); test("installation-idempotency", async () => { diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 04f90a11e..5e122c83f 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -53,7 +53,7 @@ variable "module_directory" { locals { boundary_script = file("${path.module}/scripts/install.sh") - boundary_script_destination = "${var.module_directory}/install.sh" + boundary_script_destination = "${var.module_directory}/boundary-install.sh" boundary_wrapper_path = "${var.module_directory}/boundary-wrapper.sh" } diff --git a/registry/coder/modules/boundary/testdata/coder-mock.sh b/registry/coder/modules/boundary/testdata/coder-mock.sh index 38598378d..c75bfbb4a 100644 --- a/registry/coder/modules/boundary/testdata/coder-mock.sh +++ b/registry/coder/modules/boundary/testdata/coder-mock.sh @@ -2,6 +2,12 @@ # Mock coder command for testing boundary module # Handles: coder boundary [--help | -- ] +# Handles: coder exp sync [want|start|complete] (no-op for testing) + +# Handle exp sync commands (no-op for testing) +if [[ "$1" == "exp" ]] && [[ "$2" == "sync" ]]; then + exit 0 +fi if [[ "$1" == "boundary" ]]; then shift From ce15e063395dfe3659ef71e04f409f3294e05119 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 14 Apr 2026 23:54:49 +0530 Subject: [PATCH 07/53] chore: description fix --- registry/coder/modules/boundary/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 5e122c83f..71d22eed3 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -35,13 +35,13 @@ variable "use_boundary_directly" { variable "pre_install_script" { type = string - description = "Custom script to run before installing Codex." + description = "Custom script to run before installing Boundary." default = null } variable "post_install_script" { type = string - description = "Custom script to run after installing Codex." + description = "Custom script to run after installing Boundary." default = null } From 946204db2344d57d4f69262d72c594658652bd69 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 14 Apr 2026 18:29:13 +0000 Subject: [PATCH 08/53] chore(boundary): remove unused boundary-mock.sh --- .../boundary/testdata/boundary-mock.sh | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 registry/coder/modules/boundary/testdata/boundary-mock.sh diff --git a/registry/coder/modules/boundary/testdata/boundary-mock.sh b/registry/coder/modules/boundary/testdata/boundary-mock.sh deleted file mode 100644 index 2efe8199f..000000000 --- a/registry/coder/modules/boundary/testdata/boundary-mock.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# Mock boundary binary for testing -# Handles: boundary [--help | -- ] - -if [[ "$1" == "--help" ]]; then - cat << 'EOF' -boundary - Network isolation tool - -Usage: - boundary [flags] -- [args...] - -Examples: - boundary -- curl https://example.com - boundary -- npm install - -Flags: - -h, --help help for boundary -EOF - exit 0 -fi - -# Handle command execution after -- -if [[ "$1" == "--" ]]; then - shift - # Execute the command that follows - exec "$@" -fi - -# If no -- separator, just print help -echo "Error: Expected '--' separator before command" -exit 1 From 8b889316c766765fb1aee3ddb1d19ac2784b4999 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 15 Apr 2026 00:00:36 +0530 Subject: [PATCH 09/53] fix(boundary): improve command check for 'coder' to handle errors more gracefully --- registry/coder/modules/boundary/scripts/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index bb520f278..23b30a279 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -10,11 +10,11 @@ BOUNDARY_WRAPPER_PATH="${ARG_BOUNDARY_WRAPPER_PATH:-}" set +o nounset validate_boundary_subcommand() { - if hash coder; then + if command -v coder > /dev/null 2>&1; then if coder boundary --help > /dev/null 2>&1; then return 0 else - echo "Error: 'coder' command found but does not support 'boundary' subcommand. Set use_boundary_directly=true or compile_boundary_from_source=true." + echo "Error: 'coder' command found but does not support 'boundary' subcommand. Set use_boundary_directly=true or compile_boundary_from_source=true." >&2 exit 1 fi else From f45b2e93054e85483e69b527674b8542a45a1852 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 15 Apr 2026 20:57:57 +0530 Subject: [PATCH 10/53] fix(boundary): remove unnecessary argument passing in boundary wrapper scripts --- registry/coder/modules/boundary/README.md | 5 +---- registry/coder/modules/boundary/scripts/install.sh | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index c02470d09..e6fcb2eda 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -35,10 +35,7 @@ commands that should run in network isolation: ```bash if [ -n "${AGENTAPI_BOUNDARY_PREFIX:-}" ]; then # Run command with boundary wrapper - "${AGENTAPI_BOUNDARY_PREFIX}" my-command --args -else - # Run command normally - my-command --args + "${AGENTAPI_BOUNDARY_PREFIX}" --config "./config.yaml" --other-args -- ai-agent fi ``` diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 23b30a279..9e4cd359b 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -75,7 +75,7 @@ setup_boundary() { cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail -exec boundary -- "$@" +exec boundary "$@" WRAPPER_EOF else # Use coder boundary subcommand (default) @@ -92,7 +92,7 @@ WRAPPER_EOF #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "${SCRIPT_DIR}/coder-no-caps" boundary -- "$@" +exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" WRAPPER_EOF fi From 81df58f9b73d13c8437674440ff0071017959c3c Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Wed, 15 Apr 2026 16:23:49 +0000 Subject: [PATCH 11/53] fix: add '--' separator in boundary wrapper scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The boundary command (both 'coder boundary' and standalone 'boundary') expects a '--' separator before the command to execute. The wrapper scripts were passing arguments directly without this separator, causing the wrapper-script-execution test to fail. 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/scripts/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 9e4cd359b..23b30a279 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -75,7 +75,7 @@ setup_boundary() { cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail -exec boundary "$@" +exec boundary -- "$@" WRAPPER_EOF else # Use coder boundary subcommand (default) @@ -92,7 +92,7 @@ WRAPPER_EOF #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" +exec "${SCRIPT_DIR}/coder-no-caps" boundary -- "$@" WRAPPER_EOF fi From f081d871d1e4f8fb946be9db9fafc1ee4a49ffe3 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Wed, 15 Apr 2026 16:35:21 +0000 Subject: [PATCH 12/53] Revert "fix: add '--' separator in boundary wrapper scripts" This reverts commit 81df58f9b73d13c8437674440ff0071017959c3c. --- registry/coder/modules/boundary/scripts/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 23b30a279..9e4cd359b 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -75,7 +75,7 @@ setup_boundary() { cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail -exec boundary -- "$@" +exec boundary "$@" WRAPPER_EOF else # Use coder boundary subcommand (default) @@ -92,7 +92,7 @@ WRAPPER_EOF #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "${SCRIPT_DIR}/coder-no-caps" boundary -- "$@" +exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" WRAPPER_EOF fi From ec2e16fddc9c10cb321b197b609687a96ab9c2fd Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Wed, 15 Apr 2026 16:35:51 +0000 Subject: [PATCH 13/53] fix(tests): update mock and test to not require '--' separator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The boundary wrapper scripts pass arguments directly without a '--' separator. Updated the coder mock to match this behavior and adjusted the test comment accordingly. 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/main.test.ts | 2 +- .../coder/modules/boundary/testdata/coder-mock.sh | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index 028fb0ecb..48590d449 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -261,7 +261,7 @@ describe("boundary", async () => { "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh echo boundary-test", ]); - // The mock executes the command after -- separator + // The wrapper passes the command directly to the boundary command expect(wrapperResult.stdout).toContain("boundary-test"); }); diff --git a/registry/coder/modules/boundary/testdata/coder-mock.sh b/registry/coder/modules/boundary/testdata/coder-mock.sh index c75bfbb4a..892420047 100644 --- a/registry/coder/modules/boundary/testdata/coder-mock.sh +++ b/registry/coder/modules/boundary/testdata/coder-mock.sh @@ -1,7 +1,7 @@ #!/bin/bash # Mock coder command for testing boundary module -# Handles: coder boundary [--help | -- ] +# Handles: coder boundary [--help | ] # Handles: coder exp sync [want|start|complete] (no-op for testing) # Handle exp sync commands (no-op for testing) @@ -30,16 +30,8 @@ EOF exit 0 fi - # Handle command execution after -- - if [[ "$1" == "--" ]]; then - shift - # Execute the command that follows - exec "$@" - fi - - # If no -- separator, just print help - echo "Error: Expected '--' separator before command" - exit 1 + # Execute the remaining arguments as a command + exec "$@" fi echo "Mock coder: Unknown command: $*" From 920f954a80df7ae9591c4aba9ab82b77528d2281 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 10:59:06 +0530 Subject: [PATCH 14/53] feat(boundary): refactor boundary wrapper setup to use BOUNDARY_WRAPPER_PATH --- registry/coder/modules/boundary/main.tf | 4 ++-- registry/coder/modules/boundary/scripts/install.sh | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 71d22eed3..3e9fbe87e 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -82,9 +82,9 @@ module "coder_utils" { EOT } -resource "coder_env" "agentapi_boundary_prefix" { +resource "coder_env" "boundary_wrapper_path" { agent_id = var.agent_id - name = "AGENTAPI_BOUNDARY_PREFIX" + name = "BOUNDARY_WRAPPER_PATH" value = local.boundary_wrapper_path } diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 9e4cd359b..862ef4baa 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -60,19 +60,15 @@ install_boundary() { # Exports AGENTAPI_BOUNDARY_PREFIX pointing to the wrapper script. setup_boundary() { local module_path="${MODULE_DIR}" - local wrapper_path="${BOUNDARY_WRAPPER_PATH}" echo "Setting up coder boundary..." # Install boundary binary if needed install_boundary - # Determine which boundary command to use and create wrapper script - BOUNDARY_WRAPPER_SCRIPT="${wrapper_path}" - if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]] || [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then # Use boundary binary directly (from compilation or release installation) - cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' + cat > "${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail exec boundary "$@" @@ -88,7 +84,7 @@ WRAPPER_EOF echo "Error: Failed to copy coder binary to ${CODER_NO_CAPS}. boundary cannot be enabled." >&2 exit 1 fi - cat > "${BOUNDARY_WRAPPER_SCRIPT}" << 'WRAPPER_EOF' + cat > "${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -96,8 +92,7 @@ exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" WRAPPER_EOF fi - chmod +x "${BOUNDARY_WRAPPER_SCRIPT}" - export AGENTAPI_BOUNDARY_PREFIX="${BOUNDARY_WRAPPER_SCRIPT}" + chmod +x "${BOUNDARY_WRAPPER_PATH}" echo "boundary wrapper configured: ${AGENTAPI_BOUNDARY_PREFIX}" } From d2e528d1b4b58a0a8537dd2c686388d8a99bfd8b Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 05:31:42 +0000 Subject: [PATCH 15/53] fix(tests): rename AGENTAPI_BOUNDARY_PREFIX to BOUNDARY_WRAPPER_PATH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update README and tests to match the env var and resource rename from the latest code changes. 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 8 ++++---- registry/coder/modules/boundary/main.test.ts | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index e6fcb2eda..34a0f7fc8 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -14,7 +14,7 @@ This module: - Installs boundary (via coder subcommand, direct installation, or compilation from source) - Creates a wrapper script at `$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh` -- Exports `AGENTAPI_BOUNDARY_PREFIX` as a workspace environment variable +- Exports `BOUNDARY_WRAPPER_PATH` as a workspace environment variable - Provides the wrapper path via the `boundary_wrapper_path` output ```tf @@ -28,14 +28,14 @@ module "boundary" { ## Usage -The `AGENTAPI_BOUNDARY_PREFIX` environment variable is automatically available to all +The `BOUNDARY_WRAPPER_PATH` environment variable is automatically available to all workspace processes. Start scripts should check for this variable and use it to prefix commands that should run in network isolation: ```bash -if [ -n "${AGENTAPI_BOUNDARY_PREFIX:-}" ]; then +if [ -n "${BOUNDARY_WRAPPER_PATH:-}" ]; then # Run command with boundary wrapper - "${AGENTAPI_BOUNDARY_PREFIX}" --config "./config.yaml" --other-args -- ai-agent + "${BOUNDARY_WRAPPER_PATH}" my-command --args fi ``` diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index 48590d449..64bf59d36 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -132,13 +132,13 @@ describe("boundary", async () => { const resources = state.resources; - // Verify coder_env resource for AGENTAPI_BOUNDARY_PREFIX + // Verify coder_env resource for BOUNDARY_WRAPPER_PATH const boundaryEnv = resources.find( - (r) => r.type === "coder_env" && r.name === "agentapi_boundary_prefix", + (r) => r.type === "coder_env" && r.name === "boundary_wrapper_path", ); expect(boundaryEnv).toBeDefined(); expect(boundaryEnv?.instances[0]?.attributes.name).toBe( - "AGENTAPI_BOUNDARY_PREFIX", + "BOUNDARY_WRAPPER_PATH", ); expect(boundaryEnv?.instances[0]?.attributes.value).toBe( "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", @@ -146,7 +146,7 @@ describe("boundary", async () => { // Verify the outputs are set correctly const coderEnvVars = extractCoderEnvVars(state); - expect(coderEnvVars["AGENTAPI_BOUNDARY_PREFIX"]).toBe( + expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", ); }); @@ -159,7 +159,7 @@ describe("boundary", async () => { }); const coderEnvVars = extractCoderEnvVars(state); - expect(coderEnvVars["AGENTAPI_BOUNDARY_PREFIX"]).toBe( + expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( `${customDir}/boundary-wrapper.sh`, ); }); @@ -244,8 +244,8 @@ describe("boundary", async () => { test("env-var-set-correctly", async () => { const { id, coderEnvVars } = await setup(); - // Verify AGENTAPI_BOUNDARY_PREFIX is in the coder env vars - expect(coderEnvVars["AGENTAPI_BOUNDARY_PREFIX"]).toBe( + // Verify BOUNDARY_WRAPPER_PATH is in the coder env vars + expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", ); }); From 74c49477cb7d8f099b765cb20a000f92c6bda714 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 05:34:06 +0000 Subject: [PATCH 16/53] fix: rename remaining AGENTAPI_BOUNDARY_PREFIX references to BOUNDARY_WRAPPER_PATH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update install.sh comments/echo, and boundary.tftest.hcl resource references to match the env var rename. 🤖 Generated by Coder Agents --- .../modules/boundary/boundary.tftest.hcl | 24 +++++++++---------- .../coder/modules/boundary/scripts/install.sh | 6 ++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index 838bad071..c38aac0f6 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -9,17 +9,17 @@ run "plan_with_required_vars" { # Verify the coder_env resource is created with correct agent_id assert { - condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" - error_message = "agentapi_boundary_prefix agent_id should match the input variable" + condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" + error_message = "boundary_wrapper_path agent_id should match the input variable" } assert { - condition = coder_env.agentapi_boundary_prefix.name == "AGENTAPI_BOUNDARY_PREFIX" - error_message = "Environment variable name should be 'AGENTAPI_BOUNDARY_PREFIX'" + condition = coder_env.boundary_wrapper_path.name == "BOUNDARY_WRAPPER_PATH" + error_message = "Environment variable name should be 'BOUNDARY_WRAPPER_PATH'" } assert { - condition = coder_env.agentapi_boundary_prefix.value == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + condition = coder_env.boundary_wrapper_path.value == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" error_message = "Environment variable value should be the boundary wrapper path" } @@ -46,8 +46,8 @@ run "plan_with_compile_from_source" { } assert { - condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" - error_message = "agentapi_boundary_prefix agent_id should match the input variable" + condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" + error_message = "boundary_wrapper_path agent_id should match the input variable" } assert { @@ -71,8 +71,8 @@ run "plan_with_use_directly" { } assert { - condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" - error_message = "agentapi_boundary_prefix agent_id should match the input variable" + condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" + error_message = "boundary_wrapper_path agent_id should match the input variable" } assert { @@ -96,8 +96,8 @@ run "plan_with_custom_hooks" { } assert { - condition = coder_env.agentapi_boundary_prefix.agent_id == "test-agent-id" - error_message = "agentapi_boundary_prefix agent_id should match the input variable" + condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" + error_message = "boundary_wrapper_path agent_id should match the input variable" } assert { @@ -126,7 +126,7 @@ run "plan_with_custom_module_directory" { } assert { - condition = coder_env.agentapi_boundary_prefix.value == "/custom/path/boundary-wrapper.sh" + condition = coder_env.boundary_wrapper_path.value == "/custom/path/boundary-wrapper.sh" error_message = "Environment variable should use custom module directory" } diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 862ef4baa..089ea5323 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Exports AGENTAPI_BOUNDARY_PREFIX for use by module start scripts. +# Exports BOUNDARY_WRAPPER_PATH for use by module start scripts. set -o nounset BOUNDARY_VERSION="${ARG_BOUNDARY_VERSION:-latest}" @@ -57,7 +57,7 @@ install_boundary() { } # Set up boundary: install, write config, create wrapper script. -# Exports AGENTAPI_BOUNDARY_PREFIX pointing to the wrapper script. +# Exports BOUNDARY_WRAPPER_PATH pointing to the wrapper script. setup_boundary() { local module_path="${MODULE_DIR}" @@ -93,7 +93,7 @@ WRAPPER_EOF fi chmod +x "${BOUNDARY_WRAPPER_PATH}" - echo "boundary wrapper configured: ${AGENTAPI_BOUNDARY_PREFIX}" + echo "boundary wrapper configured: ${BOUNDARY_WRAPPER_PATH}" } setup_boundary From b16208f87b8792b65216a43a3566615d92d31544 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 11:08:28 +0530 Subject: [PATCH 17/53] feat(boundary): update coder_utils module source and version, add display name prefix --- registry/coder/modules/boundary/main.tf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 3e9fbe87e..18016fe16 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -58,10 +58,11 @@ locals { } module "coder_utils" { - source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=feat/coder-utils-optional-install-start" - # version = "1.0.1" + source = "registry.coder.com/coder/coder-utils/coder" + version = "1.1.0" agent_id = var.agent_id agent_name = "coder_boundary" + display_name_prefix = "Boundary" module_directory = var.module_directory pre_install_script = var.pre_install_script post_install_script = var.post_install_script @@ -94,5 +95,5 @@ output "boundary_wrapper_path" { } output "sync_script_names" { - value = module.coder_utils + value = module.coder_utils.scripts } From f22770de9469fb8f6328c5f92ced8d9aa1b72d09 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 11:12:51 +0530 Subject: [PATCH 18/53] feat(boundary): update command execution example to include config and log level options --- registry/coder/modules/boundary/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 34a0f7fc8..ea28dc138 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -35,7 +35,7 @@ commands that should run in network isolation: ```bash if [ -n "${BOUNDARY_WRAPPER_PATH:-}" ]; then # Run command with boundary wrapper - "${BOUNDARY_WRAPPER_PATH}" my-command --args + "${BOUNDARY_WRAPPER_PATH}" --config=~/.config/coder_boundary/config.yaml --log-level=info -- my-command --args fi ``` @@ -54,7 +54,7 @@ resource "coder_script" "my_app" { script = <<-EOT # Access the boundary wrapper path WRAPPER="${module.boundary[0].boundary_wrapper_path}" - "$WRAPPER" my-command --args + "$WRAPPER" ~/.config/coder_boundary/config.yaml -- my-command --args EOT } ``` From 06b039f81121c22c1e64454facd88eb72dd05138 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 05:53:12 +0000 Subject: [PATCH 19/53] fix(tests): update sync_script_names assertions for flat list output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sync_script_names output changed from an object with .script_names.install to a flat list of script name strings. Updated boundary.tftest.hcl to use contains() and README to document the actual script name values. 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 10 +++++----- registry/coder/modules/boundary/boundary.tftest.hcl | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index ea28dc138..f0419ada6 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -61,13 +61,13 @@ resource "coder_script" "my_app" { ### Script Synchronization -The `sync_script_names` output provides script names that can be used with `coder exp sync` to coordinate script execution. This is useful when your scripts need to wait for boundary installation to complete before running. +The `sync_script_names` output provides a list of script names that can be used with `coder exp sync` to coordinate script execution. This is useful when your scripts need to wait for boundary installation to complete before running. -Available sync script names: +The list may contain the following script names: -- `sync_script_names.script_names.pre_install` - Pre-installation script (if configured) -- `sync_script_names.script_names.install` - Main boundary installation script -- `sync_script_names.script_names.post_install` - Post-installation script (if configured) +- `coder_boundary-pre_install_script` - Pre-installation script (if configured) +- `coder_boundary-install_script` - Main boundary installation script +- `coder_boundary-post_install_script` - Post-installation script (if configured) ## Examples diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index c38aac0f6..5f24cbb3e 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -31,7 +31,7 @@ run "plan_with_required_vars" { # Verify the sync_script_names output contains the install script name assert { - condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + condition = contains(output.sync_script_names, "coder_boundary-install_script") error_message = "sync_script_names should contain the install script name" } } @@ -56,7 +56,7 @@ run "plan_with_compile_from_source" { } assert { - condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + condition = contains(output.sync_script_names, "coder_boundary-install_script") error_message = "sync_script_names should contain the install script name" } } @@ -81,7 +81,7 @@ run "plan_with_use_directly" { } assert { - condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + condition = contains(output.sync_script_names, "coder_boundary-install_script") error_message = "sync_script_names should contain the install script name" } } @@ -101,18 +101,18 @@ run "plan_with_custom_hooks" { } assert { - condition = output.sync_script_names.script_names.install == "coder_boundary-install_script" + condition = contains(output.sync_script_names, "coder_boundary-install_script") error_message = "sync_script_names should contain the install script name" } # Verify pre and post install script names are set assert { - condition = output.sync_script_names.script_names.pre_install == "coder_boundary-pre_install_script" + condition = contains(output.sync_script_names, "coder_boundary-pre_install_script") error_message = "sync_script_names should contain the pre_install script name" } assert { - condition = output.sync_script_names.script_names.post_install == "coder_boundary-post_install_script" + condition = contains(output.sync_script_names, "coder_boundary-post_install_script") error_message = "sync_script_names should contain the post_install script name" } } From fef86ab7af1e408fddf32c9d6b4e9c6db0469bab Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 05:56:07 +0000 Subject: [PATCH 20/53] docs: set module version to 0.0.1 in README examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index f0419ada6..4f858575e 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -21,7 +21,7 @@ This module: module "boundary" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/boundary/coder" - version = "1.0.0" + version = "0.0.1" agent_id = coder_agent.main.id } ``` @@ -45,7 +45,7 @@ Alternatively, you can use the module output to access the wrapper path in Terra module "boundary" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/boundary/coder" - version = "1.0.0" + version = "0.0.1" agent_id = coder_agent.main.id } From 9f16eca5b5eb3898711690722bc529b305600a11 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 12:13:49 +0530 Subject: [PATCH 21/53] feat(boundary): update boundary wrapper path and output name in module documentation --- registry/coder/modules/boundary/README.md | 6 +++--- registry/coder/modules/boundary/main.tf | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 4f858575e..56167718a 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -3,7 +3,7 @@ display_name: Boundary description: Configures boundary for network isolation in Coder workspaces icon: ../../../../.icons/coder.svg verified: true -tags: [boundary, coder, AI, agents] +tags: [boundary, ai, agents, firewall] --- # Boundary @@ -13,7 +13,7 @@ Installs boundary for network isolation in Coder workspaces. This module: - Installs boundary (via coder subcommand, direct installation, or compilation from source) -- Creates a wrapper script at `$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh` +- Creates a wrapper script at `$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh` - Exports `BOUNDARY_WRAPPER_PATH` as a workspace environment variable - Provides the wrapper path via the `boundary_wrapper_path` output @@ -54,7 +54,7 @@ resource "coder_script" "my_app" { script = <<-EOT # Access the boundary wrapper path WRAPPER="${module.boundary[0].boundary_wrapper_path}" - "$WRAPPER" ~/.config/coder_boundary/config.yaml -- my-command --args + "$WRAPPER" --config=~/.config/coder_boundary/config.yaml -- my-command --args EOT } ``` diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 18016fe16..795457777 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -54,12 +54,12 @@ variable "module_directory" { locals { boundary_script = file("${path.module}/scripts/install.sh") boundary_script_destination = "${var.module_directory}/boundary-install.sh" - boundary_wrapper_path = "${var.module_directory}/boundary-wrapper.sh" + boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } module "coder_utils" { source = "registry.coder.com/coder/coder-utils/coder" - version = "1.1.0" + version = "1.2.0" agent_id = var.agent_id agent_name = "coder_boundary" display_name_prefix = "Boundary" @@ -94,6 +94,6 @@ output "boundary_wrapper_path" { value = local.boundary_wrapper_path } -output "sync_script_names" { +output "scripts" { value = module.coder_utils.scripts } From dc95e455baf348e7e8c3437d7701195664d3309c Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 06:50:12 +0000 Subject: [PATCH 22/53] fix(tests): update paths for scripts/ and logs/ directories, rename output to scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wrapper path: boundary-wrapper.sh → scripts/boundary-wrapper.sh - Log paths: *.log → logs/*.log - Output renamed: sync_script_names → scripts - Updated boundary.tftest.hcl, main.test.ts, and README.md 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 2 +- .../modules/boundary/boundary.tftest.hcl | 38 +++++++++---------- registry/coder/modules/boundary/main.test.ts | 24 ++++++------ 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 56167718a..68a0bde60 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -61,7 +61,7 @@ resource "coder_script" "my_app" { ### Script Synchronization -The `sync_script_names` output provides a list of script names that can be used with `coder exp sync` to coordinate script execution. This is useful when your scripts need to wait for boundary installation to complete before running. +The `scripts` output provides a list of script names that can be used with `coder exp sync` to coordinate script execution. This is useful when your scripts need to wait for boundary installation to complete before running. The list may contain the following script names: diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index 5f24cbb3e..2a280c377 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -19,20 +19,20 @@ run "plan_with_required_vars" { } assert { - condition = coder_env.boundary_wrapper_path.value == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + condition = coder_env.boundary_wrapper_path.value == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "Environment variable value should be the boundary wrapper path" } # Verify the boundary_wrapper_path output assert { - condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should be correct" } - # Verify the sync_script_names output contains the install script name + # Verify the scripts output contains the install script name assert { - condition = contains(output.sync_script_names, "coder_boundary-install_script") - error_message = "sync_script_names should contain the install script name" + condition = contains(output.scripts, "coder_boundary-install_script") + error_message = "scripts should contain the install script name" } } @@ -51,13 +51,13 @@ run "plan_with_compile_from_source" { } assert { - condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should be correct" } assert { - condition = contains(output.sync_script_names, "coder_boundary-install_script") - error_message = "sync_script_names should contain the install script name" + condition = contains(output.scripts, "coder_boundary-install_script") + error_message = "scripts should contain the install script name" } } @@ -76,13 +76,13 @@ run "plan_with_use_directly" { } assert { - condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh" + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should be correct" } assert { - condition = contains(output.sync_script_names, "coder_boundary-install_script") - error_message = "sync_script_names should contain the install script name" + condition = contains(output.scripts, "coder_boundary-install_script") + error_message = "scripts should contain the install script name" } } @@ -101,19 +101,19 @@ run "plan_with_custom_hooks" { } assert { - condition = contains(output.sync_script_names, "coder_boundary-install_script") - error_message = "sync_script_names should contain the install script name" + condition = contains(output.scripts, "coder_boundary-install_script") + error_message = "scripts should contain the install script name" } # Verify pre and post install script names are set assert { - condition = contains(output.sync_script_names, "coder_boundary-pre_install_script") - error_message = "sync_script_names should contain the pre_install script name" + condition = contains(output.scripts, "coder_boundary-pre_install_script") + error_message = "scripts should contain the pre_install script name" } assert { - condition = contains(output.sync_script_names, "coder_boundary-post_install_script") - error_message = "sync_script_names should contain the post_install script name" + condition = contains(output.scripts, "coder_boundary-post_install_script") + error_message = "scripts should contain the post_install script name" } } @@ -126,12 +126,12 @@ run "plan_with_custom_module_directory" { } assert { - condition = coder_env.boundary_wrapper_path.value == "/custom/path/boundary-wrapper.sh" + condition = coder_env.boundary_wrapper_path.value == "/custom/path/scripts/boundary-wrapper.sh" error_message = "Environment variable should use custom module directory" } assert { - condition = output.boundary_wrapper_path == "/custom/path/boundary-wrapper.sh" + condition = output.boundary_wrapper_path == "/custom/path/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should use custom module directory" } } diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index 64bf59d36..e02d035ee 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -141,13 +141,13 @@ describe("boundary", async () => { "BOUNDARY_WRAPPER_PATH", ); expect(boundaryEnv?.instances[0]?.attributes.value).toBe( - "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", + "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); // Verify the outputs are set correctly const coderEnvVars = extractCoderEnvVars(state); expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( - "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", + "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); }); @@ -160,7 +160,7 @@ describe("boundary", async () => { const coderEnvVars = extractCoderEnvVars(state); expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( - `${customDir}/boundary-wrapper.sh`, + `${customDir}/scripts/boundary-wrapper.sh`, ); }); @@ -171,7 +171,7 @@ describe("boundary", async () => { // Verify the wrapper script was created const wrapperContent = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh", + "/home/coder/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); expect(wrapperContent).toContain("#!/usr/bin/env bash"); expect(wrapperContent).toContain("coder-no-caps"); @@ -182,7 +182,7 @@ describe("boundary", async () => { "stat", "-c", "%a", - "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh", + "/home/coder/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ]); expect(statResult.stdout.trim()).toMatch(/7[0-9][0-9]/); // Should be executable (7xx) @@ -197,7 +197,7 @@ describe("boundary", async () => { // Check install log const installLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/install.log", + "/home/coder/.coder-modules/coder/boundary/logs/install.log", ); expect(installLog).toContain("Using coder boundary subcommand"); expect(installLog).toContain("boundary wrapper configured"); @@ -222,21 +222,21 @@ describe("boundary", async () => { // Verify pre-install script ran const preInstallLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/pre_install.log", + "/home/coder/.coder-modules/coder/boundary/logs/pre_install.log", ); expect(preInstallLog).toContain(preInstallMarker); // Verify post-install script ran const postInstallLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/post_install.log", + "/home/coder/.coder-modules/coder/boundary/logs/post_install.log", ); expect(postInstallLog).toContain(postInstallMarker); // Verify main install still ran const installLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/install.log", + "/home/coder/.coder-modules/coder/boundary/logs/install.log", ); expect(installLog).toContain("boundary wrapper configured"); }); @@ -246,7 +246,7 @@ describe("boundary", async () => { // Verify BOUNDARY_WRAPPER_PATH is in the coder env vars expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( - "$HOME/.coder-modules/coder/boundary/boundary-wrapper.sh", + "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); }); @@ -258,7 +258,7 @@ describe("boundary", async () => { const wrapperResult = await execContainer(id, [ "bash", "-c", - "/home/coder/.coder-modules/coder/boundary/boundary-wrapper.sh echo boundary-test", + "/home/coder/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh echo boundary-test", ]); // The wrapper passes the command directly to the boundary command @@ -272,7 +272,7 @@ describe("boundary", async () => { await execModuleScript(id); const firstInstallLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/install.log", + "/home/coder/.coder-modules/coder/boundary/logs/install.log", ); // Run again From bb21940e16d985fa1068d3d657d0271734f42dd2 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 06:53:32 +0000 Subject: [PATCH 23/53] fix: create scripts/ directory before writing boundary wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrapper path moved to scripts/boundary-wrapper.sh but install.sh never created the scripts/ subdirectory, causing a 'No such file or directory' error at runtime. 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/scripts/install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 089ea5323..311ad90ad 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -66,6 +66,9 @@ setup_boundary() { # Install boundary binary if needed install_boundary + # Ensure the wrapper script directory exists. + mkdir -p "$(dirname "${BOUNDARY_WRAPPER_PATH}")" + if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]] || [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then # Use boundary binary directly (from compilation or release installation) cat > "${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' From 74e58dcd7de6e72664154e2573abefc5c3296072 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 06:57:53 +0000 Subject: [PATCH 24/53] fix: resolve coder-no-caps path in wrapper script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrapper script moved to scripts/ but coder-no-caps remains in the module root. Updated the wrapper to use ${SCRIPT_DIR}/../coder-no-caps so it correctly resolves the binary path. 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/scripts/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index 311ad90ad..c6a4a1b45 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -91,7 +91,7 @@ WRAPPER_EOF #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" +exec "${SCRIPT_DIR}/../coder-no-caps" boundary "$@" WRAPPER_EOF fi From cf1d1ab079e8975950119ab3d79e6b7738cc16d5 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 07:02:24 +0000 Subject: [PATCH 25/53] refactor: move all scripts into scripts/ subdirectory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - boundary-install.sh → scripts/boundary-install.sh - coder-no-caps → scripts/coder-no-caps - Wrapper script now references coder-no-caps in the same directory - Updated test path for coder-no-caps 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/main.test.ts | 2 +- registry/coder/modules/boundary/main.tf | 2 +- registry/coder/modules/boundary/scripts/install.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index e02d035ee..c6744f7c4 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -190,7 +190,7 @@ describe("boundary", async () => { const coderNoCapsResult = await execContainer(id, [ "test", "-f", - "/home/coder/.coder-modules/coder/boundary/coder-no-caps", + "/home/coder/.coder-modules/coder/boundary/scripts/coder-no-caps", ]); expect(coderNoCapsResult.exitCode).toBe(0); diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 795457777..bc1107a04 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -53,7 +53,7 @@ variable "module_directory" { locals { boundary_script = file("${path.module}/scripts/install.sh") - boundary_script_destination = "${var.module_directory}/boundary-install.sh" + boundary_script_destination = "${var.module_directory}/scripts/boundary-install.sh" boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh index c6a4a1b45..5dc3c6938 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh @@ -82,7 +82,7 @@ WRAPPER_EOF # This is necessary because boundary doesn't work with privileged binaries # (you can't launch privileged binaries inside network namespaces unless # you have sys_admin). - CODER_NO_CAPS="${module_path}/coder-no-caps" + CODER_NO_CAPS="${module_path}/scripts/coder-no-caps" if ! cp "$(command -v coder)" "${CODER_NO_CAPS}"; then echo "Error: Failed to copy coder binary to ${CODER_NO_CAPS}. boundary cannot be enabled." >&2 exit 1 @@ -91,7 +91,7 @@ WRAPPER_EOF #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "${SCRIPT_DIR}/../coder-no-caps" boundary "$@" +exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" WRAPPER_EOF fi From 155362f538d962d162c6c0699424c53b54acaf69 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 21:27:56 +0530 Subject: [PATCH 26/53] feat(boundary): update boundary script destination and simplify execution --- registry/coder/modules/boundary/main.tf | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index bc1107a04..d5f80aafa 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -53,7 +53,6 @@ variable "module_directory" { locals { boundary_script = file("${path.module}/scripts/install.sh") - boundary_script_destination = "${var.module_directory}/scripts/boundary-install.sh" boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } @@ -70,16 +69,14 @@ module "coder_utils" { #!/bin/bash set -o errexit set -o pipefail - mkdir -p "$(dirname "${local.boundary_script_destination}")" - echo -n '${base64encode(local.boundary_script)}' | base64 -d > "${local.boundary_script_destination}" - chmod +x "${local.boundary_script_destination}" + chmod +x "${local.boundary_script}" ARG_BOUNDARY_VERSION="${var.boundary_version}" \ ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ ARG_MODULE_DIR="${var.module_directory}" \ ARG_BOUNDARY_WRAPPER_PATH="${local.boundary_wrapper_path}" \ - "${local.boundary_script_destination}" + "${local.boundary_script}" EOT } From 3aa6333beec7998076ce897f3cc9b997e54d5188 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 21:31:11 +0530 Subject: [PATCH 27/53] feat(boundary): rename local variables for clarity in main.tf --- registry/coder/modules/boundary/main.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index d5f80aafa..fc665c1ef 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -52,8 +52,8 @@ variable "module_directory" { } locals { - boundary_script = file("${path.module}/scripts/install.sh") - boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" + boundary_script_path = "${path.module}/scripts/install.sh" + boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } module "coder_utils" { @@ -69,14 +69,14 @@ module "coder_utils" { #!/bin/bash set -o errexit set -o pipefail - chmod +x "${local.boundary_script}" + chmod +x "${local.boundary_script_path}" ARG_BOUNDARY_VERSION="${var.boundary_version}" \ ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ ARG_MODULE_DIR="${var.module_directory}" \ ARG_BOUNDARY_WRAPPER_PATH="${local.boundary_wrapper_path}" \ - "${local.boundary_script}" + "${local.boundary_script_path}" EOT } From fbaaab5cb634fd507892bf67a68b65f9607be820 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 22:05:00 +0530 Subject: [PATCH 28/53] debug --- registry/coder/modules/boundary/main.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index fc665c1ef..1bd282fca 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -57,8 +57,7 @@ locals { } module "coder_utils" { - source = "registry.coder.com/coder/coder-utils/coder" - version = "1.2.0" + source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=matifali/coder-utils-nest-scripts" agent_id = var.agent_id agent_name = "coder_boundary" display_name_prefix = "Boundary" From 5953687d7f5da725190034077eafcc8096dfb966 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 22:09:11 +0530 Subject: [PATCH 29/53] debug --- registry/coder/modules/boundary/main.tf | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 1bd282fca..6cb6ddfbc 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -52,7 +52,8 @@ variable "module_directory" { } locals { - boundary_script_path = "${path.module}/scripts/install.sh" + boundary_script = file("${path.module}/scripts/install.sh") + boundary_script_destination = "${var.module_directory}/scripts/boundary-install.sh" boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } @@ -68,14 +69,16 @@ module "coder_utils" { #!/bin/bash set -o errexit set -o pipefail - chmod +x "${local.boundary_script_path}" + mkdir -p "$(dirname "${local.boundary_script_destination}")" + echo -n '${base64encode(local.boundary_script)}' | base64 -d > "${local.boundary_script_destination}" + chmod +x "${local.boundary_script_destination}" ARG_BOUNDARY_VERSION="${var.boundary_version}" \ ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ ARG_MODULE_DIR="${var.module_directory}" \ ARG_BOUNDARY_WRAPPER_PATH="${local.boundary_wrapper_path}" \ - "${local.boundary_script_path}" + "${local.boundary_script_destination}" EOT } From 3bb1a3b4b0b7040d173f066877a13b34a70c724a Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Thu, 23 Apr 2026 16:51:57 +0000 Subject: [PATCH 30/53] refactor: rename boundary-install.sh to install.sh, fix coder-utils ref MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Destination script renamed to scripts/install.sh for consistency - Fixed coder-utils module source (stale branch ref → main) 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 6cb6ddfbc..65f610cd1 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -53,12 +53,12 @@ variable "module_directory" { locals { boundary_script = file("${path.module}/scripts/install.sh") - boundary_script_destination = "${var.module_directory}/scripts/boundary-install.sh" + boundary_script_destination = "${var.module_directory}/scripts/install.sh" boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } module "coder_utils" { - source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=matifali/coder-utils-nest-scripts" + source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=main" agent_id = var.agent_id agent_name = "coder_boundary" display_name_prefix = "Boundary" From f3c2c55bf1b423cd6c24d8c1c5a7940dd09dd7ce Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 22:24:10 +0530 Subject: [PATCH 31/53] bun fmt --- registry/coder/modules/boundary/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 65f610cd1..ce52bc8b5 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -54,7 +54,7 @@ variable "module_directory" { locals { boundary_script = file("${path.module}/scripts/install.sh") boundary_script_destination = "${var.module_directory}/scripts/install.sh" - boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" + boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" } module "coder_utils" { From 5dd0370b048f09e07d34139aa7110ae98a9e22e9 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 22:30:37 +0530 Subject: [PATCH 32/53] feat(boundary): update coder-utils source and adjust config paths in README --- registry/coder/modules/boundary/README.md | 4 ++-- registry/coder/modules/boundary/main.tf | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 68a0bde60..c136c6400 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -35,7 +35,7 @@ commands that should run in network isolation: ```bash if [ -n "${BOUNDARY_WRAPPER_PATH:-}" ]; then # Run command with boundary wrapper - "${BOUNDARY_WRAPPER_PATH}" --config=~/.config/coder_boundary/config.yaml --log-level=info -- my-command --args + "${BOUNDARY_WRAPPER_PATH}" --config=~/.coder-modules/coder/boundary/config.yaml --log-level=info -- my-command --args fi ``` @@ -54,7 +54,7 @@ resource "coder_script" "my_app" { script = <<-EOT # Access the boundary wrapper path WRAPPER="${module.boundary[0].boundary_wrapper_path}" - "$WRAPPER" --config=~/.config/coder_boundary/config.yaml -- my-command --args + "$WRAPPER" --config=~/.coder-modules/coder/boundary/config.yaml -- my-command --args EOT } ``` diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index ce52bc8b5..f837868c1 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -58,7 +58,8 @@ locals { } module "coder_utils" { - source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=main" + source = "registry.coder.com/coder/coder-utils/coder" + version = "1.3.0" agent_id = var.agent_id agent_name = "coder_boundary" display_name_prefix = "Boundary" From 4dd01761b59744655196d5020f937a05b0778c15 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 23 Apr 2026 22:32:37 +0530 Subject: [PATCH 33/53] docs: update README to include link for boundary installation --- registry/coder/modules/boundary/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index c136c6400..86ac1b1d2 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -8,7 +8,7 @@ tags: [boundary, ai, agents, firewall] # Boundary -Installs boundary for network isolation in Coder workspaces. +Installs [boundary](https://coder.com/docs/ai-coder/agent-firewall) for network isolation in Coder workspaces. This module: From d79446a192908e9d1085eb9476b60f15dc32e499 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Fri, 24 Apr 2026 16:12:59 +0000 Subject: [PATCH 34/53] refactor: convert install.sh to tftpl template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Renamed scripts/install.sh → scripts/install.sh.tftpl - Use templatefile() to inject variables at plan time instead of base64-encoding the script and passing env vars at runtime - Removed boundary_script/boundary_script_destination locals - Fixed /home/coder expansion in MODULE_DIR and BOUNDARY_WRAPPER_PATH (double quotes for shell expansion) - Updated custom module_directory test paths to match coder-utils validation pattern ($HOME/.coder-modules//) - Updated script name references (coder_boundary → coder-boundary) - Fixed coder-utils source to use branch ref 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 6 +- .../modules/boundary/boundary.tftest.hcl | 18 +++--- registry/coder/modules/boundary/main.test.ts | 2 +- registry/coder/modules/boundary/main.tf | 31 ++++------ .../scripts/{install.sh => install.sh.tftpl} | 56 +++++++++---------- 5 files changed, 50 insertions(+), 63 deletions(-) rename registry/coder/modules/boundary/scripts/{install.sh => install.sh.tftpl} (56%) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 86ac1b1d2..a99b414b0 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -65,9 +65,9 @@ The `scripts` output provides a list of script names that can be used with `code The list may contain the following script names: -- `coder_boundary-pre_install_script` - Pre-installation script (if configured) -- `coder_boundary-install_script` - Main boundary installation script -- `coder_boundary-post_install_script` - Post-installation script (if configured) +- `coder-boundary-pre_install_script` - Pre-installation script (if configured) +- `coder-boundary-install_script` - Main boundary installation script +- `coder-boundary-post_install_script` - Post-installation script (if configured) ## Examples diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index 2a280c377..91ee4a089 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -31,7 +31,7 @@ run "plan_with_required_vars" { # Verify the scripts output contains the install script name assert { - condition = contains(output.scripts, "coder_boundary-install_script") + condition = contains(output.scripts, "coder-boundary-install_script") error_message = "scripts should contain the install script name" } } @@ -56,7 +56,7 @@ run "plan_with_compile_from_source" { } assert { - condition = contains(output.scripts, "coder_boundary-install_script") + condition = contains(output.scripts, "coder-boundary-install_script") error_message = "scripts should contain the install script name" } } @@ -81,7 +81,7 @@ run "plan_with_use_directly" { } assert { - condition = contains(output.scripts, "coder_boundary-install_script") + condition = contains(output.scripts, "coder-boundary-install_script") error_message = "scripts should contain the install script name" } } @@ -101,18 +101,18 @@ run "plan_with_custom_hooks" { } assert { - condition = contains(output.scripts, "coder_boundary-install_script") + condition = contains(output.scripts, "coder-boundary-install_script") error_message = "scripts should contain the install script name" } # Verify pre and post install script names are set assert { - condition = contains(output.scripts, "coder_boundary-pre_install_script") + condition = contains(output.scripts, "coder-boundary-pre_install_script") error_message = "scripts should contain the pre_install script name" } assert { - condition = contains(output.scripts, "coder_boundary-post_install_script") + condition = contains(output.scripts, "coder-boundary-post_install_script") error_message = "scripts should contain the post_install script name" } } @@ -122,16 +122,16 @@ run "plan_with_custom_module_directory" { variables { agent_id = "test-agent-id" - module_directory = "/custom/path" + module_directory = "$HOME/.coder-modules/custom/boundary" } assert { - condition = coder_env.boundary_wrapper_path.value == "/custom/path/scripts/boundary-wrapper.sh" + condition = coder_env.boundary_wrapper_path.value == "$HOME/.coder-modules/custom/boundary/scripts/boundary-wrapper.sh" error_message = "Environment variable should use custom module directory" } assert { - condition = output.boundary_wrapper_path == "/custom/path/scripts/boundary-wrapper.sh" + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/custom/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should use custom module directory" } } diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index c6744f7c4..cadd9a84a 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -152,7 +152,7 @@ describe("boundary", async () => { }); test("terraform-state-custom-module-directory", async () => { - const customDir = "/custom/boundary/path"; + const customDir = "$HOME/.coder-modules/custom/boundary"; const state = await runTerraformApply(import.meta.dir, { agent_id: "test-agent-id", module_directory: customDir, diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index f837868c1..d7d086496 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -52,35 +52,24 @@ variable "module_directory" { } locals { - boundary_script = file("${path.module}/scripts/install.sh") - boundary_script_destination = "${var.module_directory}/scripts/install.sh" - boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" + boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" + install_script = templatefile("${path.module}/scripts/install.sh.tftpl", { + BOUNDARY_VERSION = var.boundary_version + COMPILE_BOUNDARY_FROM_SOURCE = tostring(var.compile_boundary_from_source) + USE_BOUNDARY_DIRECTLY = tostring(var.use_boundary_directly) + MODULE_DIR = var.module_directory + BOUNDARY_WRAPPER_PATH = local.boundary_wrapper_path + }) } module "coder_utils" { - source = "registry.coder.com/coder/coder-utils/coder" - version = "1.3.0" + source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=35C4n0r/feat-boundary-module" agent_id = var.agent_id - agent_name = "coder_boundary" display_name_prefix = "Boundary" module_directory = var.module_directory pre_install_script = var.pre_install_script post_install_script = var.post_install_script - install_script = <<-EOT - #!/bin/bash - set -o errexit - set -o pipefail - mkdir -p "$(dirname "${local.boundary_script_destination}")" - echo -n '${base64encode(local.boundary_script)}' | base64 -d > "${local.boundary_script_destination}" - chmod +x "${local.boundary_script_destination}" - - ARG_BOUNDARY_VERSION="${var.boundary_version}" \ - ARG_COMPILE_BOUNDARY_FROM_SOURCE="${var.compile_boundary_from_source}" \ - ARG_USE_BOUNDARY_DIRECTLY="${var.use_boundary_directly}" \ - ARG_MODULE_DIR="${var.module_directory}" \ - ARG_BOUNDARY_WRAPPER_PATH="${local.boundary_wrapper_path}" \ - "${local.boundary_script_destination}" -EOT + install_script = local.install_script } resource "coder_env" "boundary_wrapper_path" { diff --git a/registry/coder/modules/boundary/scripts/install.sh b/registry/coder/modules/boundary/scripts/install.sh.tftpl similarity index 56% rename from registry/coder/modules/boundary/scripts/install.sh rename to registry/coder/modules/boundary/scripts/install.sh.tftpl index 5dc3c6938..60702a5e3 100644 --- a/registry/coder/modules/boundary/scripts/install.sh +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -1,13 +1,14 @@ #!/bin/bash -# Exports BOUNDARY_WRAPPER_PATH for use by module start scripts. +# Sets up boundary for network isolation in Coder workspaces. -set -o nounset -BOUNDARY_VERSION="${ARG_BOUNDARY_VERSION:-latest}" -COMPILE_BOUNDARY_FROM_SOURCE="${ARG_COMPILE_BOUNDARY_FROM_SOURCE:-false}" -USE_BOUNDARY_DIRECTLY="${ARG_USE_BOUNDARY_DIRECTLY:-false}" -MODULE_DIR="${ARG_MODULE_DIR:-}" -BOUNDARY_WRAPPER_PATH="${ARG_BOUNDARY_WRAPPER_PATH:-}" -set +o nounset +set -o errexit +set -o pipefail + +BOUNDARY_VERSION='${BOUNDARY_VERSION}' +COMPILE_BOUNDARY_FROM_SOURCE='${COMPILE_BOUNDARY_FROM_SOURCE}' +USE_BOUNDARY_DIRECTLY='${USE_BOUNDARY_DIRECTLY}' +MODULE_DIR="${MODULE_DIR}" +BOUNDARY_WRAPPER_PATH="${BOUNDARY_WRAPPER_PATH}" validate_boundary_subcommand() { if command -v coder > /dev/null 2>&1; then @@ -29,8 +30,8 @@ validate_boundary_subcommand() { # 2. Install from release (use_boundary_directly=true) # 3. Use coder boundary subcommand (default, no installation needed) install_boundary() { - if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]]; then - echo "Compiling boundary from source (version: ${BOUNDARY_VERSION})" + if [[ "$${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]]; then + echo "Compiling boundary from source (version: $${BOUNDARY_VERSION})" # Remove existing boundary directory to allow re-running safely if [[ -d boundary ]]; then @@ -40,38 +41,35 @@ install_boundary() { echo "Cloning boundary repository" git clone https://github.com/coder/boundary.git cd boundary || exit 1 - git checkout "${BOUNDARY_VERSION}" + git checkout "$${BOUNDARY_VERSION}" make build sudo cp boundary /usr/local/bin/ sudo chmod +x /usr/local/bin/boundary cd - || exit 1 - elif [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then - echo "Installing boundary using official install script (version: ${BOUNDARY_VERSION})" - curl -fsSL https://raw.githubusercontent.com/coder/boundary/main/install.sh | bash -s -- --version "${BOUNDARY_VERSION}" + elif [[ "$${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then + echo "Installing boundary using official install script (version: $${BOUNDARY_VERSION})" + curl -fsSL https://raw.githubusercontent.com/coder/boundary/main/install.sh | bash -s -- --version "$${BOUNDARY_VERSION}" else validate_boundary_subcommand echo "Using coder boundary subcommand (provided by Coder)" fi } -# Set up boundary: install, write config, create wrapper script. -# Exports BOUNDARY_WRAPPER_PATH pointing to the wrapper script. +# Set up boundary: install, create wrapper script. setup_boundary() { - local module_path="${MODULE_DIR}" - echo "Setting up coder boundary..." # Install boundary binary if needed install_boundary # Ensure the wrapper script directory exists. - mkdir -p "$(dirname "${BOUNDARY_WRAPPER_PATH}")" + mkdir -p "$(dirname "$${BOUNDARY_WRAPPER_PATH}")" - if [[ "${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]] || [[ "${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then + if [[ "$${COMPILE_BOUNDARY_FROM_SOURCE}" = "true" ]] || [[ "$${USE_BOUNDARY_DIRECTLY}" = "true" ]]; then # Use boundary binary directly (from compilation or release installation) - cat > "${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' + cat > "$${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail exec boundary "$@" @@ -82,21 +80,21 @@ WRAPPER_EOF # This is necessary because boundary doesn't work with privileged binaries # (you can't launch privileged binaries inside network namespaces unless # you have sys_admin). - CODER_NO_CAPS="${module_path}/scripts/coder-no-caps" - if ! cp "$(command -v coder)" "${CODER_NO_CAPS}"; then - echo "Error: Failed to copy coder binary to ${CODER_NO_CAPS}. boundary cannot be enabled." >&2 + CODER_NO_CAPS="$${MODULE_DIR}/scripts/coder-no-caps" + if ! cp "$(command -v coder)" "$${CODER_NO_CAPS}"; then + echo "Error: Failed to copy coder binary to $${CODER_NO_CAPS}. boundary cannot be enabled." >&2 exit 1 fi - cat > "${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' + cat > "$${BOUNDARY_WRAPPER_PATH}" << 'WRAPPER_EOF' #!/usr/bin/env bash set -euo pipefail -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -exec "${SCRIPT_DIR}/coder-no-caps" boundary "$@" +SCRIPT_DIR="$(cd "$(dirname "$${BASH_SOURCE[0]}")" && pwd)" +exec "$${SCRIPT_DIR}/coder-no-caps" boundary "$@" WRAPPER_EOF fi - chmod +x "${BOUNDARY_WRAPPER_PATH}" - echo "boundary wrapper configured: ${BOUNDARY_WRAPPER_PATH}" + chmod +x "$${BOUNDARY_WRAPPER_PATH}" + echo "boundary wrapper configured: $${BOUNDARY_WRAPPER_PATH}" } setup_boundary From 6d828dfb220f239da088f32b700d67350efef504 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Fri, 24 Apr 2026 16:17:40 +0000 Subject: [PATCH 35/53] style: run bun fmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/main.tf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index d7d086496..11d7983d1 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -54,11 +54,11 @@ variable "module_directory" { locals { boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" install_script = templatefile("${path.module}/scripts/install.sh.tftpl", { - BOUNDARY_VERSION = var.boundary_version - COMPILE_BOUNDARY_FROM_SOURCE = tostring(var.compile_boundary_from_source) - USE_BOUNDARY_DIRECTLY = tostring(var.use_boundary_directly) - MODULE_DIR = var.module_directory - BOUNDARY_WRAPPER_PATH = local.boundary_wrapper_path + BOUNDARY_VERSION = var.boundary_version + COMPILE_BOUNDARY_FROM_SOURCE = tostring(var.compile_boundary_from_source) + USE_BOUNDARY_DIRECTLY = tostring(var.use_boundary_directly) + MODULE_DIR = var.module_directory + BOUNDARY_WRAPPER_PATH = local.boundary_wrapper_path }) } From 12183e5c80817e70e94847ed4a17752cddaeb719 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Fri, 24 Apr 2026 22:10:48 +0530 Subject: [PATCH 36/53] feat(boundary): update coder-utils source to registry and specify version --- registry/coder/modules/boundary/main.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 11d7983d1..18ec0814e 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -63,7 +63,8 @@ locals { } module "coder_utils" { - source = "git::https://github.com/coder/registry.git//registry/coder/modules/coder-utils?ref=35C4n0r/feat-boundary-module" + source = "registry.coder.com/coder/coder-utils/coder" + version = "0.0.1" agent_id = var.agent_id display_name_prefix = "Boundary" module_directory = var.module_directory From 256953e2bbcc7450796fc1ac44227e5905c5a02e Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Fri, 24 Apr 2026 16:49:56 +0000 Subject: [PATCH 37/53] docs: fix version in README examples to 0.0.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index a99b414b0..85629e9ad 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -77,7 +77,7 @@ The list may contain the following script names: module "boundary" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/boundary/coder" - version = "1.0.0" + version = "0.0.1" agent_id = coder_agent.main.id compile_boundary_from_source = true boundary_version = "main" @@ -90,7 +90,7 @@ module "boundary" { module "boundary" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/boundary/coder" - version = "1.0.0" + version = "0.0.1" agent_id = coder_agent.main.id use_boundary_directly = true boundary_version = "latest" From 3a2dbd651e796d5a91111069f1a364f70c85cd1d Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Mon, 27 Apr 2026 16:20:42 +0000 Subject: [PATCH 38/53] docs: add config.yaml, Claude Code example, fix main.tf comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove scaffold comment from main.tf - Add description to 'scripts' output - Add sample config.yaml with allowlist skeleton - Add Configuration section to README with coder_script example - Add Claude Code + boundary example showing coder exp sync wait pattern and $BOUNDARY_WRAPPER_PATH -- claude launcher - Simplify usage examples to use -- separator without config flags 🤖 Generated by Coder Agents --- registry/coder/modules/boundary/README.md | 79 ++++++++++++++++++++- registry/coder/modules/boundary/config.yaml | 10 +++ registry/coder/modules/boundary/main.tf | 4 +- 3 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 registry/coder/modules/boundary/config.yaml diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 85629e9ad..284c57799 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -26,6 +26,29 @@ module "boundary" { } ``` +## Configuration + +Boundary reads its policy from a `config.yaml` file. A sample is included in +this module at [`config.yaml`](./config.yaml). Copy it into your template +directory and customize the `allowlist` for the domains your agent needs. + +See the [Agent Firewall docs](https://coder.com/docs/ai-coder/agent-firewall) +for the full config reference. + +To write the config into the workspace at startup, use a `coder_script`: + +```tf +resource "coder_script" "boundary_config" { + agent_id = coder_agent.main.id + display_name = "Boundary Config" + run_on_start = true + script = <<-EOT + mkdir -p ~/.config/coder_boundary + cp ${path.module}/config.yaml ~/.config/coder_boundary/config.yaml + EOT +} +``` + ## Usage The `BOUNDARY_WRAPPER_PATH` environment variable is automatically available to all @@ -35,7 +58,7 @@ commands that should run in network isolation: ```bash if [ -n "${BOUNDARY_WRAPPER_PATH:-}" ]; then # Run command with boundary wrapper - "${BOUNDARY_WRAPPER_PATH}" --config=~/.coder-modules/coder/boundary/config.yaml --log-level=info -- my-command --args + "${BOUNDARY_WRAPPER_PATH}" -- my-command --args fi ``` @@ -54,7 +77,7 @@ resource "coder_script" "my_app" { script = <<-EOT # Access the boundary wrapper path WRAPPER="${module.boundary[0].boundary_wrapper_path}" - "$WRAPPER" --config=~/.coder-modules/coder/boundary/config.yaml -- my-command --args + "$WRAPPER" -- my-command --args EOT } ``` @@ -71,6 +94,58 @@ The list may contain the following script names: ## Examples +### With Claude Code + +Use boundary alongside the `claude-code` module to run Claude in a +network-isolated environment. The `coder_script` below waits for both +modules to finish installing before launching Claude behind the boundary +wrapper. + +```tf +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "0.0.1" + agent_id = coder_agent.main.id +} + +module "claude_code" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/claude-code/coder" + version = "5.3.0" + agent_id = coder_agent.main.id +} + +# Write boundary config into the workspace. +resource "coder_script" "boundary_config" { + agent_id = coder_agent.main.id + display_name = "Boundary Config" + run_on_start = true + script = <<-EOT + mkdir -p ~/.config/coder_boundary + cp ${path.module}/config.yaml ~/.config/coder_boundary/config.yaml + EOT +} + +# Launch Claude behind the boundary wrapper after both modules +# have finished installing. +resource "coder_script" "claude_with_boundary" { + agent_id = coder_agent.main.id + display_name = "Claude (Boundary)" + run_on_start = true + script = <<-EOT + # Wait for boundary and claude-code install scripts to complete. + coder exp sync want claude-boundary \ + ${join(" ", module.boundary[0].scripts)} \ + ${join(" ", module.claude_code[0].scripts)} + coder exp sync start claude-boundary + + # Run Claude inside the boundary wrapper. + "$BOUNDARY_WRAPPER_PATH" -- claude + EOT +} +``` + ### Compile from source ```tf diff --git a/registry/coder/modules/boundary/config.yaml b/registry/coder/modules/boundary/config.yaml new file mode 100644 index 000000000..1ce874106 --- /dev/null +++ b/registry/coder/modules/boundary/config.yaml @@ -0,0 +1,10 @@ +# Boundary configuration for network isolation. +# Copy this file into your template directory and customize the allowlist +# for your agent's needs. See https://coder.com/docs/ai-coder/agent-firewall +# for the full reference. +allowlist: + - "domain=dev.coder.com" # Replace with your Coder deployment domain +jail_type: nsjail +log_dir: /tmp/boundary_logs +proxy_port: 8087 +log_level: warn diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 18ec0814e..7e83936ab 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -9,7 +9,6 @@ terraform { } } -# Add required variables for your modules and remove any unneeded variables variable "agent_id" { type = string description = "The ID of a Coder agent." @@ -85,5 +84,6 @@ output "boundary_wrapper_path" { } output "scripts" { - value = module.coder_utils.scripts + description = "List of script names for coder exp sync coordination." + value = module.coder_utils.scripts } From 266eb1dab1d0d8dd99dda358f2af73d9ef405bea Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 02:58:23 +0000 Subject: [PATCH 39/53] feat(boundary): add boundary_config and boundary_config_path variables - Add boundary_config (string) for inline config content - Add boundary_config_path (string) for external config file path - Cross-variable validation (mutually exclusive, requires TF >= 1.9) - Ship comprehensive default config based on Coder dogfood allowlist - Write config to ~/.config/coder_boundary/config.yaml by default - Export BOUNDARY_CONFIG env var pointing to the effective config path - Add boundary_config_path output - Tests: 13 pass, 67 assertions (8 HCL plan tests pass) --- registry/coder/modules/boundary/README.md | 76 ++++--- .../modules/boundary/boundary.tftest.hcl | 72 ++++++ registry/coder/modules/boundary/config.yaml | 215 +++++++++++++++++- registry/coder/modules/boundary/main.test.ts | 99 ++++++++ registry/coder/modules/boundary/main.tf | 44 +++- .../modules/boundary/scripts/install.sh.tftpl | 22 +- 6 files changed, 492 insertions(+), 36 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 284c57799..c8acaaca4 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -14,8 +14,9 @@ This module: - Installs boundary (via coder subcommand, direct installation, or compilation from source) - Creates a wrapper script at `$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh` -- Exports `BOUNDARY_WRAPPER_PATH` as a workspace environment variable -- Provides the wrapper path via the `boundary_wrapper_path` output +- Writes a default boundary config to `~/.config/coder_boundary/config.yaml` (customizable) +- Exports `BOUNDARY_WRAPPER_PATH` and `BOUNDARY_CONFIG` as workspace environment variables +- Provides the wrapper path and config path via outputs ```tf module "boundary" { @@ -28,27 +29,59 @@ module "boundary" { ## Configuration -Boundary reads its policy from a `config.yaml` file. A sample is included in -this module at [`config.yaml`](./config.yaml). Copy it into your template -directory and customize the `allowlist` for the domains your agent needs. +The module ships with a comprehensive default config based on the +[Coder dogfood allowlist](./config.yaml). It covers Anthropic services, +version control, package managers, container registries, cloud platforms, +and common development tools. -See the [Agent Firewall docs](https://coder.com/docs/ai-coder/agent-firewall) -for the full config reference. +By default the config is written to `~/.config/coder_boundary/config.yaml` +and the `BOUNDARY_CONFIG` env var points there. You can override it in two +ways: + +### Inline config -To write the config into the workspace at startup, use a `coder_script`: +Pass the full YAML content directly: ```tf -resource "coder_script" "boundary_config" { - agent_id = coder_agent.main.id - display_name = "Boundary Config" - run_on_start = true - script = <<-EOT - mkdir -p ~/.config/coder_boundary - cp ${path.module}/config.yaml ~/.config/coder_boundary/config.yaml - EOT +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "0.0.1" + agent_id = coder_agent.main.id + + boundary_config = <<-YAML + allowlist: + - domain=your-deployment.coder.com + - domain=api.anthropic.com + log_dir: /tmp/boundary_logs + proxy_port: 8087 + log_level: warn + YAML } ``` +### External config file + +Point to an existing config file in the workspace. The module will not +write any config and `BOUNDARY_CONFIG` will point to your path: + +```tf +module "boundary" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/boundary/coder" + version = "0.0.1" + agent_id = coder_agent.main.id + + boundary_config_path = "/workspace/my-boundary-config.yaml" +} +``` + +> **Note:** `boundary_config` and `boundary_config_path` are mutually +> exclusive — setting both produces a validation error. + +See the [Agent Firewall docs](https://coder.com/docs/ai-coder/agent-firewall) +for the full config reference. + ## Usage The `BOUNDARY_WRAPPER_PATH` environment variable is automatically available to all @@ -116,17 +149,6 @@ module "claude_code" { agent_id = coder_agent.main.id } -# Write boundary config into the workspace. -resource "coder_script" "boundary_config" { - agent_id = coder_agent.main.id - display_name = "Boundary Config" - run_on_start = true - script = <<-EOT - mkdir -p ~/.config/coder_boundary - cp ${path.module}/config.yaml ~/.config/coder_boundary/config.yaml - EOT -} - # Launch Claude behind the boundary wrapper after both modules # have finished installing. resource "coder_script" "claude_with_boundary" { diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index 91ee4a089..a43ef7b4e 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -23,12 +23,29 @@ run "plan_with_required_vars" { error_message = "Environment variable value should be the boundary wrapper path" } + # Verify BOUNDARY_CONFIG env var with default config path + assert { + condition = coder_env.boundary_config.name == "BOUNDARY_CONFIG" + error_message = "Environment variable name should be 'BOUNDARY_CONFIG'" + } + + assert { + condition = coder_env.boundary_config.value == "$HOME/.config/coder_boundary/config.yaml" + error_message = "BOUNDARY_CONFIG should default to ~/.config/coder_boundary/config.yaml" + } + # Verify the boundary_wrapper_path output assert { condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should be correct" } + # Verify boundary_config_path output defaults to the managed path + assert { + condition = output.boundary_config_path == "$HOME/.config/coder_boundary/config.yaml" + error_message = "boundary_config_path output should default to managed config path" + } + # Verify the scripts output contains the install script name assert { condition = contains(output.scripts, "coder-boundary-install_script") @@ -135,3 +152,58 @@ run "plan_with_custom_module_directory" { error_message = "boundary_wrapper_path output should use custom module directory" } } + +run "plan_with_inline_boundary_config" { + command = plan + + variables { + agent_id = "test-agent-id" + boundary_config = "allowlist:\n - domain=example.com\nlog_level: debug\n" + } + + # BOUNDARY_CONFIG should still point to the managed path since we write + # the inline content there. + assert { + condition = coder_env.boundary_config.value == "$HOME/.config/coder_boundary/config.yaml" + error_message = "BOUNDARY_CONFIG should point to managed config path when using inline config" + } + + assert { + condition = output.boundary_config_path == "$HOME/.config/coder_boundary/config.yaml" + error_message = "boundary_config_path output should point to managed config path" + } +} + +run "plan_with_boundary_config_path" { + command = plan + + variables { + agent_id = "test-agent-id" + boundary_config_path = "/workspace/my-boundary-config.yaml" + } + + # BOUNDARY_CONFIG should point to the user-provided path. + assert { + condition = coder_env.boundary_config.value == "/workspace/my-boundary-config.yaml" + error_message = "BOUNDARY_CONFIG should point to user-provided config path" + } + + assert { + condition = output.boundary_config_path == "/workspace/my-boundary-config.yaml" + error_message = "boundary_config_path output should point to user-provided path" + } +} + +run "plan_with_both_configs_should_fail" { + command = plan + + variables { + agent_id = "test-agent-id" + boundary_config = "allowlist: []" + boundary_config_path = "/workspace/config.yaml" + } + + expect_failures = [ + var.boundary_config, + ] +} diff --git a/registry/coder/modules/boundary/config.yaml b/registry/coder/modules/boundary/config.yaml index 1ce874106..0dde4452f 100644 --- a/registry/coder/modules/boundary/config.yaml +++ b/registry/coder/modules/boundary/config.yaml @@ -1,10 +1,211 @@ -# Boundary configuration for network isolation. -# Copy this file into your template directory and customize the allowlist -# for your agent's needs. See https://coder.com/docs/ai-coder/agent-firewall -# for the full reference. allowlist: - - "domain=dev.coder.com" # Replace with your Coder deployment domain -jail_type: nsjail + # Your Coder deployment domain (required — replace with your own). + - domain=your-deployment.coder.com + + # Anthropic Services + - domain=api.anthropic.com + - domain=statsig.anthropic.com + - domain=claude.ai + + # Version Control + - domain=github.com + - domain=www.github.com + - domain=api.github.com + - domain=raw.githubusercontent.com + - domain=objects.githubusercontent.com + - domain=codeload.github.com + - domain=avatars.githubusercontent.com + - domain=camo.githubusercontent.com + - domain=gist.github.com + - domain=gitlab.com + - domain=www.gitlab.com + - domain=registry.gitlab.com + - domain=bitbucket.org + - domain=www.bitbucket.org + - domain=api.bitbucket.org + + # Container Registries + - domain=registry-1.docker.io + - domain=auth.docker.io + - domain=index.docker.io + - domain=hub.docker.com + - domain=www.docker.com + - domain=production.cloudflare.docker.com + - domain=download.docker.com + - domain=*.gcr.io + - domain=ghcr.io + - domain=mcr.microsoft.com + - domain=*.data.mcr.microsoft.com + + # Cloud Platforms + - domain=cloud.google.com + - domain=accounts.google.com + - domain=gcloud.google.com + - domain=*.googleapis.com + - domain=storage.googleapis.com + - domain=compute.googleapis.com + - domain=container.googleapis.com + - domain=azure.com + - domain=portal.azure.com + - domain=microsoft.com + - domain=www.microsoft.com + - domain=*.microsoftonline.com + - domain=packages.microsoft.com + - domain=dotnet.microsoft.com + - domain=dot.net + - domain=visualstudio.com + - domain=dev.azure.com + - domain=oracle.com + - domain=www.oracle.com + - domain=java.com + - domain=www.java.com + - domain=java.net + - domain=www.java.net + - domain=download.oracle.com + - domain=yum.oracle.com + + # Package Managers - JavaScript/Node + - domain=registry.npmjs.org + - domain=www.npmjs.com + - domain=www.npmjs.org + - domain=npmjs.com + - domain=npmjs.org + - domain=yarnpkg.com + - domain=registry.yarnpkg.com + + # Package Managers - Python + - domain=pypi.org + - domain=www.pypi.org + - domain=files.pythonhosted.org + - domain=pythonhosted.org + - domain=test.pypi.org + - domain=pypi.python.org + - domain=pypa.io + - domain=www.pypa.io + + # Package Managers - Ruby + - domain=rubygems.org + - domain=www.rubygems.org + - domain=api.rubygems.org + - domain=index.rubygems.org + - domain=ruby-lang.org + - domain=www.ruby-lang.org + - domain=rubyforge.org + - domain=www.rubyforge.org + - domain=rubyonrails.org + - domain=www.rubyonrails.org + - domain=rvm.io + - domain=get.rvm.io + + # Package Managers - Rust + - domain=crates.io + - domain=www.crates.io + - domain=static.crates.io + - domain=rustup.rs + - domain=static.rust-lang.org + - domain=www.rust-lang.org + + # Package Managers - Go + - domain=proxy.golang.org + - domain=sum.golang.org + - domain=index.golang.org + - domain=golang.org + - domain=www.golang.org + - domain=go.dev + - domain=dl.google.com + - domain=goproxy.io + - domain=pkg.go.dev + + # Package Managers - JVM + - domain=maven.org + - domain=repo.maven.org + - domain=central.maven.org + - domain=repo1.maven.org + - domain=jcenter.bintray.com + - domain=gradle.org + - domain=www.gradle.org + - domain=services.gradle.org + - domain=spring.io + - domain=repo.spring.io + + # Package Managers - Other Languages + - domain=packagist.org + - domain=www.packagist.org + - domain=repo.packagist.org + - domain=nuget.org + - domain=www.nuget.org + - domain=api.nuget.org + - domain=pub.dev + - domain=api.pub.dev + - domain=hex.pm + - domain=www.hex.pm + - domain=cpan.org + - domain=www.cpan.org + - domain=metacpan.org + - domain=www.metacpan.org + - domain=api.metacpan.org + - domain=cocoapods.org + - domain=www.cocoapods.org + - domain=cdn.cocoapods.org + - domain=haskell.org + - domain=www.haskell.org + - domain=hackage.haskell.org + - domain=swift.org + - domain=www.swift.org + + # Linux Distributions + - domain=archive.ubuntu.com + - domain=security.ubuntu.com + - domain=ubuntu.com + - domain=www.ubuntu.com + - domain=*.ubuntu.com + - domain=ppa.launchpad.net + - domain=launchpad.net + - domain=www.launchpad.net + + # Development Tools & Platforms + - domain=dl.k8s.io + - domain=pkgs.k8s.io + - domain=k8s.io + - domain=www.k8s.io + - domain=releases.hashicorp.com + - domain=apt.releases.hashicorp.com + - domain=rpm.releases.hashicorp.com + - domain=archive.releases.hashicorp.com + - domain=hashicorp.com + - domain=www.hashicorp.com + - domain=repo.anaconda.com + - domain=conda.anaconda.org + - domain=anaconda.org + - domain=www.anaconda.com + - domain=anaconda.com + - domain=continuum.io + - domain=apache.org + - domain=www.apache.org + - domain=archive.apache.org + - domain=downloads.apache.org + - domain=eclipse.org + - domain=www.eclipse.org + - domain=download.eclipse.org + - domain=nodejs.org + - domain=www.nodejs.org + + # Cloud Services & Monitoring + - domain=statsig.com + - domain=www.statsig.com + - domain=api.statsig.com + - domain=*.sentry.io + + # Content Delivery & Mirrors + - domain=*.sourceforge.net + - domain=packagecloud.io + - domain=*.packagecloud.io + + # Schema & Configuration + - domain=json-schema.org + - domain=www.json-schema.org + - domain=json.schemastore.org + - domain=www.schemastore.org log_dir: /tmp/boundary_logs -proxy_port: 8087 log_level: warn +proxy_port: 8087 diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index cadd9a84a..8c18d5c26 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -144,11 +144,24 @@ describe("boundary", async () => { "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); + // Verify coder_env resource for BOUNDARY_CONFIG + const configEnv = resources.find( + (r) => r.type === "coder_env" && r.name === "boundary_config", + ); + expect(configEnv).toBeDefined(); + expect(configEnv?.instances[0]?.attributes.name).toBe("BOUNDARY_CONFIG"); + expect(configEnv?.instances[0]?.attributes.value).toBe( + "$HOME/.config/coder_boundary/config.yaml", + ); + // Verify the outputs are set correctly const coderEnvVars = extractCoderEnvVars(state); expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); + expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( + "$HOME/.config/coder_boundary/config.yaml", + ); }); test("terraform-state-custom-module-directory", async () => { @@ -164,6 +177,32 @@ describe("boundary", async () => { ); }); + test("terraform-state-inline-config", async () => { + const inlineConfig = + "allowlist:\n - domain=example.com\nlog_level: debug\n"; + const state = await runTerraformApply(import.meta.dir, { + agent_id: "test-agent-id", + boundary_config: inlineConfig, + }); + + const coderEnvVars = extractCoderEnvVars(state); + // Inline config still writes to the managed path. + expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( + "$HOME/.config/coder_boundary/config.yaml", + ); + }); + + test("terraform-state-config-path", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "test-agent-id", + boundary_config_path: "/workspace/my-config.yaml", + }); + + const coderEnvVars = extractCoderEnvVars(state); + // BOUNDARY_CONFIG should point to the user-provided path. + expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe("/workspace/my-config.yaml"); + }); + test("happy-path-coder-subcommand", async () => { const { id } = await setup(); await execModuleScript(id); @@ -194,15 +233,70 @@ describe("boundary", async () => { ]); expect(coderNoCapsResult.exitCode).toBe(0); + // Verify default boundary config was written + const configContent = await readFileContainer( + id, + "/home/coder/.config/coder_boundary/config.yaml", + ); + expect(configContent).toContain("allowlist:"); + expect(configContent).toContain("domain=api.anthropic.com"); + expect(configContent).toContain("proxy_port: 8087"); + // Check install log const installLog = await readFileContainer( id, "/home/coder/.coder-modules/coder/boundary/logs/install.log", ); expect(installLog).toContain("Using coder boundary subcommand"); + expect(installLog).toContain("Boundary config written to"); expect(installLog).toContain("boundary wrapper configured"); }); + test("inline-config-written", async () => { + const customConfig = + "allowlist:\n - domain=custom.example.com\nlog_level: info\n"; + const { id } = await setup({ + moduleVariables: { + boundary_config: customConfig, + }, + }); + await execModuleScript(id); + + // Verify the inline config was written + const configContent = await readFileContainer( + id, + "/home/coder/.config/coder_boundary/config.yaml", + ); + expect(configContent).toContain("domain=custom.example.com"); + expect(configContent).toContain("log_level: info"); + }); + + test("config-path-skips-write", async () => { + const { id } = await setup({ + moduleVariables: { + boundary_config_path: "/workspace/external-config.yaml", + }, + }); + await execModuleScript(id); + + // Verify NO config was written to the default path + const checkResult = await execContainer(id, [ + "test", + "-f", + "/home/coder/.config/coder_boundary/config.yaml", + ]); + expect(checkResult.exitCode).not.toBe(0); + + // Check install log confirms skip + const installLog = await readFileContainer( + id, + "/home/coder/.coder-modules/coder/boundary/logs/install.log", + ); + expect(installLog).toContain( + "Using external boundary config, skipping config write", + ); + }); + // Note: Tests for use_boundary_directly and compile_from_source are skipped // because they require network access (downloading boundary) or compilation // which are too slow for unit tests. These modes are tested manually. @@ -248,6 +342,11 @@ describe("boundary", async () => { expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", ); + + // Verify BOUNDARY_CONFIG is in the coder env vars + expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( + "$HOME/.config/coder_boundary/config.yaml", + ); }); test("wrapper-script-execution", async () => { diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 7e83936ab..bda84756d 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0" + required_version = ">= 1.9" required_providers { coder = { @@ -32,6 +32,23 @@ variable "use_boundary_directly" { default = false } +variable "boundary_config" { + type = string + description = "Inline boundary configuration content (YAML). Overrides the module's default config. Mutually exclusive with boundary_config_path." + default = null + + validation { + condition = !(var.boundary_config != null && var.boundary_config_path != null) + error_message = "Only one of boundary_config or boundary_config_path may be set." + } +} + +variable "boundary_config_path" { + type = string + description = "Path to an existing boundary config file in the workspace. When set, no config is written and BOUNDARY_CONFIG points to this path. Mutually exclusive with boundary_config." + default = null +} + variable "pre_install_script" { type = string description = "Custom script to run before installing Boundary." @@ -52,12 +69,26 @@ variable "module_directory" { locals { boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" + + # Config handling: resolve which config content to write and where + # BOUNDARY_CONFIG points to. + default_boundary_config = file("${path.module}/config.yaml") + boundary_config_content = var.boundary_config != null ? var.boundary_config : local.default_boundary_config + boundary_config_dir = "$HOME/.config/coder_boundary" + boundary_config_file_path = "${local.boundary_config_dir}/config.yaml" + effective_boundary_config_path = var.boundary_config_path != null ? var.boundary_config_path : local.boundary_config_file_path + write_boundary_config = var.boundary_config_path == null + install_script = templatefile("${path.module}/scripts/install.sh.tftpl", { BOUNDARY_VERSION = var.boundary_version COMPILE_BOUNDARY_FROM_SOURCE = tostring(var.compile_boundary_from_source) USE_BOUNDARY_DIRECTLY = tostring(var.use_boundary_directly) MODULE_DIR = var.module_directory BOUNDARY_WRAPPER_PATH = local.boundary_wrapper_path + WRITE_BOUNDARY_CONFIG = tostring(local.write_boundary_config) + BOUNDARY_CONFIG_CONTENT = local.write_boundary_config ? local.boundary_config_content : "" + BOUNDARY_CONFIG_DIR = local.boundary_config_dir + BOUNDARY_CONFIG_FILE = local.boundary_config_file_path }) } @@ -78,11 +109,22 @@ resource "coder_env" "boundary_wrapper_path" { value = local.boundary_wrapper_path } +resource "coder_env" "boundary_config" { + agent_id = var.agent_id + name = "BOUNDARY_CONFIG" + value = local.effective_boundary_config_path +} + output "boundary_wrapper_path" { description = "Path to the boundary wrapper script." value = local.boundary_wrapper_path } +output "boundary_config_path" { + description = "Effective path to the boundary config file." + value = local.effective_boundary_config_path +} + output "scripts" { description = "List of script names for coder exp sync coordination." value = module.coder_utils.scripts diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 60702a5e3..90f56943c 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -9,6 +9,9 @@ COMPILE_BOUNDARY_FROM_SOURCE='${COMPILE_BOUNDARY_FROM_SOURCE}' USE_BOUNDARY_DIRECTLY='${USE_BOUNDARY_DIRECTLY}' MODULE_DIR="${MODULE_DIR}" BOUNDARY_WRAPPER_PATH="${BOUNDARY_WRAPPER_PATH}" +WRITE_BOUNDARY_CONFIG='${WRITE_BOUNDARY_CONFIG}' +BOUNDARY_CONFIG_DIR="${BOUNDARY_CONFIG_DIR}" +BOUNDARY_CONFIG_FILE="${BOUNDARY_CONFIG_FILE}" validate_boundary_subcommand() { if command -v coder > /dev/null 2>&1; then @@ -57,13 +60,30 @@ install_boundary() { fi } -# Set up boundary: install, create wrapper script. +# Write boundary config file if the module is responsible for it. +write_boundary_config() { + if [[ "$${WRITE_BOUNDARY_CONFIG}" != "true" ]]; then + echo "Using external boundary config, skipping config write." + return 0 + fi + + mkdir -p "$${BOUNDARY_CONFIG_DIR}" + cat > "$${BOUNDARY_CONFIG_FILE}" << '__BOUNDARY_CONFIG_EOF__' +${BOUNDARY_CONFIG_CONTENT} +__BOUNDARY_CONFIG_EOF__ + echo "Boundary config written to $${BOUNDARY_CONFIG_FILE}" +} + +# Set up boundary: install, write config, create wrapper script. setup_boundary() { echo "Setting up coder boundary..." # Install boundary binary if needed install_boundary + # Write boundary config + write_boundary_config + # Ensure the wrapper script directory exists. mkdir -p "$(dirname "$${BOUNDARY_WRAPPER_PATH}")" From cd71b2103e800aec83f468ab2800afc558c8ad2a Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 03:44:13 +0000 Subject: [PATCH 40/53] fix(boundary): base64 encode config content for template safety --- registry/coder/modules/boundary/main.tf | 2 +- registry/coder/modules/boundary/scripts/install.sh.tftpl | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index bda84756d..81bd010f8 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -86,7 +86,7 @@ locals { MODULE_DIR = var.module_directory BOUNDARY_WRAPPER_PATH = local.boundary_wrapper_path WRITE_BOUNDARY_CONFIG = tostring(local.write_boundary_config) - BOUNDARY_CONFIG_CONTENT = local.write_boundary_config ? local.boundary_config_content : "" + BOUNDARY_CONFIG_CONTENT_B64 = local.write_boundary_config ? base64encode(local.boundary_config_content) : "" BOUNDARY_CONFIG_DIR = local.boundary_config_dir BOUNDARY_CONFIG_FILE = local.boundary_config_file_path }) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 90f56943c..ce058908b 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -10,6 +10,7 @@ USE_BOUNDARY_DIRECTLY='${USE_BOUNDARY_DIRECTLY}' MODULE_DIR="${MODULE_DIR}" BOUNDARY_WRAPPER_PATH="${BOUNDARY_WRAPPER_PATH}" WRITE_BOUNDARY_CONFIG='${WRITE_BOUNDARY_CONFIG}' +BOUNDARY_CONFIG_CONTENT_B64='${BOUNDARY_CONFIG_CONTENT_B64}' BOUNDARY_CONFIG_DIR="${BOUNDARY_CONFIG_DIR}" BOUNDARY_CONFIG_FILE="${BOUNDARY_CONFIG_FILE}" @@ -68,9 +69,7 @@ write_boundary_config() { fi mkdir -p "$${BOUNDARY_CONFIG_DIR}" - cat > "$${BOUNDARY_CONFIG_FILE}" << '__BOUNDARY_CONFIG_EOF__' -${BOUNDARY_CONFIG_CONTENT} -__BOUNDARY_CONFIG_EOF__ + echo "$${BOUNDARY_CONFIG_CONTENT_B64}" | base64 -d > "$${BOUNDARY_CONFIG_FILE}" echo "Boundary config written to $${BOUNDARY_CONFIG_FILE}" } From c33ae2f40f4afb079c5ee186d8ac886aa20b2751 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 03:51:07 +0000 Subject: [PATCH 41/53] fix(boundary): decode b64 at variable init, add printf debug lines --- .../coder/modules/boundary/scripts/install.sh.tftpl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index ce058908b..3323d53da 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -10,10 +10,19 @@ USE_BOUNDARY_DIRECTLY='${USE_BOUNDARY_DIRECTLY}' MODULE_DIR="${MODULE_DIR}" BOUNDARY_WRAPPER_PATH="${BOUNDARY_WRAPPER_PATH}" WRITE_BOUNDARY_CONFIG='${WRITE_BOUNDARY_CONFIG}' -BOUNDARY_CONFIG_CONTENT_B64='${BOUNDARY_CONFIG_CONTENT_B64}' +BOUNDARY_CONFIG_CONTENT=$(echo -n '${BOUNDARY_CONFIG_CONTENT_B64}' | base64 -d) BOUNDARY_CONFIG_DIR="${BOUNDARY_CONFIG_DIR}" BOUNDARY_CONFIG_FILE="${BOUNDARY_CONFIG_FILE}" +printf "BOUNDARY_VERSION: %s\n" "$${BOUNDARY_VERSION}" +printf "COMPILE_BOUNDARY_FROM_SOURCE: %s\n" "$${COMPILE_BOUNDARY_FROM_SOURCE}" +printf "USE_BOUNDARY_DIRECTLY: %s\n" "$${USE_BOUNDARY_DIRECTLY}" +printf "MODULE_DIR: %s\n" "$${MODULE_DIR}" +printf "BOUNDARY_WRAPPER_PATH: %s\n" "$${BOUNDARY_WRAPPER_PATH}" +printf "WRITE_BOUNDARY_CONFIG: %s\n" "$${WRITE_BOUNDARY_CONFIG}" +printf "BOUNDARY_CONFIG_DIR: %s\n" "$${BOUNDARY_CONFIG_DIR}" +printf "BOUNDARY_CONFIG_FILE: %s\n" "$${BOUNDARY_CONFIG_FILE}" + validate_boundary_subcommand() { if command -v coder > /dev/null 2>&1; then if coder boundary --help > /dev/null 2>&1; then @@ -69,7 +78,7 @@ write_boundary_config() { fi mkdir -p "$${BOUNDARY_CONFIG_DIR}" - echo "$${BOUNDARY_CONFIG_CONTENT_B64}" | base64 -d > "$${BOUNDARY_CONFIG_FILE}" + echo "$${BOUNDARY_CONFIG_CONTENT}" > "$${BOUNDARY_CONFIG_FILE}" echo "Boundary config written to $${BOUNDARY_CONFIG_FILE}" } From f70ac78e27d971708061ee003f3818d693094e14 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 09:51:39 +0000 Subject: [PATCH 42/53] refactor(boundary): address review feedback from matifali - Remove BOUNDARY_WRAPPER_PATH env var, keep output only - Move config path into module_directory (config/config.yaml) - Auto-fill Coder deployment domain via data.coder_workspace.me - Add OpenAI endpoints to default config allowlist --- registry/coder/modules/boundary/README.md | 38 ++++---- .../modules/boundary/boundary.tftest.hcl | 50 +++-------- registry/coder/modules/boundary/config.yaml | 11 ++- registry/coder/modules/boundary/main.test.ts | 89 ++++++++----------- registry/coder/modules/boundary/main.tf | 17 ++-- 5 files changed, 83 insertions(+), 122 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index c8acaaca4..9a52128b6 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -14,9 +14,10 @@ This module: - Installs boundary (via coder subcommand, direct installation, or compilation from source) - Creates a wrapper script at `$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh` -- Writes a default boundary config to `~/.config/coder_boundary/config.yaml` (customizable) -- Exports `BOUNDARY_WRAPPER_PATH` and `BOUNDARY_CONFIG` as workspace environment variables -- Provides the wrapper path and config path via outputs +- Writes a default boundary config to `$HOME/.coder-modules/coder/boundary/config/config.yaml` (customizable) +- Automatically adds your Coder deployment domain to the config allowlist +- Exports `BOUNDARY_CONFIG` as a workspace environment variable +- Provides the wrapper path, config path, and script names via outputs ```tf module "boundary" { @@ -31,12 +32,15 @@ module "boundary" { The module ships with a comprehensive default config based on the [Coder dogfood allowlist](./config.yaml). It covers Anthropic services, -version control, package managers, container registries, cloud platforms, -and common development tools. +OpenAI services, version control, package managers, container registries, +cloud platforms, and common development tools. -By default the config is written to `~/.config/coder_boundary/config.yaml` -and the `BOUNDARY_CONFIG` env var points there. You can override it in two -ways: +The Coder deployment domain is automatically added to the allowlist using +`data.coder_workspace.me.access_url`. + +By default the config is written to +`$HOME/.coder-modules/coder/boundary/config/config.yaml` and the +`BOUNDARY_CONFIG` env var points there. You can override it in two ways: ### Inline config @@ -53,6 +57,7 @@ module "boundary" { allowlist: - domain=your-deployment.coder.com - domain=api.anthropic.com + - domain=api.openai.com log_dir: /tmp/boundary_logs proxy_port: 8087 log_level: warn @@ -84,18 +89,8 @@ for the full config reference. ## Usage -The `BOUNDARY_WRAPPER_PATH` environment variable is automatically available to all -workspace processes. Start scripts should check for this variable and use it to prefix -commands that should run in network isolation: - -```bash -if [ -n "${BOUNDARY_WRAPPER_PATH:-}" ]; then - # Run command with boundary wrapper - "${BOUNDARY_WRAPPER_PATH}" -- my-command --args -fi -``` - -Alternatively, you can use the module output to access the wrapper path in Terraform: +Use the `boundary_wrapper_path` output to access the wrapper path in Terraform +and pass it to scripts that should run commands in network isolation: ```tf module "boundary" { @@ -108,7 +103,6 @@ module "boundary" { resource "coder_script" "my_app" { agent_id = coder_agent.main.id script = <<-EOT - # Access the boundary wrapper path WRAPPER="${module.boundary[0].boundary_wrapper_path}" "$WRAPPER" -- my-command --args EOT @@ -163,7 +157,7 @@ resource "coder_script" "claude_with_boundary" { coder exp sync start claude-boundary # Run Claude inside the boundary wrapper. - "$BOUNDARY_WRAPPER_PATH" -- claude + "${module.boundary[0].boundary_wrapper_path}" -- claude EOT } ``` diff --git a/registry/coder/modules/boundary/boundary.tftest.hcl b/registry/coder/modules/boundary/boundary.tftest.hcl index a43ef7b4e..8fc8bef6a 100644 --- a/registry/coder/modules/boundary/boundary.tftest.hcl +++ b/registry/coder/modules/boundary/boundary.tftest.hcl @@ -7,22 +7,6 @@ run "plan_with_required_vars" { agent_id = "test-agent-id" } - # Verify the coder_env resource is created with correct agent_id - assert { - condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" - error_message = "boundary_wrapper_path agent_id should match the input variable" - } - - assert { - condition = coder_env.boundary_wrapper_path.name == "BOUNDARY_WRAPPER_PATH" - error_message = "Environment variable name should be 'BOUNDARY_WRAPPER_PATH'" - } - - assert { - condition = coder_env.boundary_wrapper_path.value == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" - error_message = "Environment variable value should be the boundary wrapper path" - } - # Verify BOUNDARY_CONFIG env var with default config path assert { condition = coder_env.boundary_config.name == "BOUNDARY_CONFIG" @@ -30,8 +14,8 @@ run "plan_with_required_vars" { } assert { - condition = coder_env.boundary_config.value == "$HOME/.config/coder_boundary/config.yaml" - error_message = "BOUNDARY_CONFIG should default to ~/.config/coder_boundary/config.yaml" + condition = coder_env.boundary_config.value == "$HOME/.coder-modules/coder/boundary/config/config.yaml" + error_message = "BOUNDARY_CONFIG should default to module_directory/config/config.yaml" } # Verify the boundary_wrapper_path output @@ -42,7 +26,7 @@ run "plan_with_required_vars" { # Verify boundary_config_path output defaults to the managed path assert { - condition = output.boundary_config_path == "$HOME/.config/coder_boundary/config.yaml" + condition = output.boundary_config_path == "$HOME/.coder-modules/coder/boundary/config/config.yaml" error_message = "boundary_config_path output should default to managed config path" } @@ -62,11 +46,6 @@ run "plan_with_compile_from_source" { boundary_version = "main" } - assert { - condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" - error_message = "boundary_wrapper_path agent_id should match the input variable" - } - assert { condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should be correct" @@ -87,11 +66,6 @@ run "plan_with_use_directly" { boundary_version = "latest" } - assert { - condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" - error_message = "boundary_wrapper_path agent_id should match the input variable" - } - assert { condition = output.boundary_wrapper_path == "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh" error_message = "boundary_wrapper_path output should be correct" @@ -112,11 +86,6 @@ run "plan_with_custom_hooks" { post_install_script = "echo 'After install'" } - assert { - condition = coder_env.boundary_wrapper_path.agent_id == "test-agent-id" - error_message = "boundary_wrapper_path agent_id should match the input variable" - } - assert { condition = contains(output.scripts, "coder-boundary-install_script") error_message = "scripts should contain the install script name" @@ -143,13 +112,14 @@ run "plan_with_custom_module_directory" { } assert { - condition = coder_env.boundary_wrapper_path.value == "$HOME/.coder-modules/custom/boundary/scripts/boundary-wrapper.sh" - error_message = "Environment variable should use custom module directory" + condition = output.boundary_wrapper_path == "$HOME/.coder-modules/custom/boundary/scripts/boundary-wrapper.sh" + error_message = "boundary_wrapper_path output should use custom module directory" } + # Config path should also follow the module directory assert { - condition = output.boundary_wrapper_path == "$HOME/.coder-modules/custom/boundary/scripts/boundary-wrapper.sh" - error_message = "boundary_wrapper_path output should use custom module directory" + condition = output.boundary_config_path == "$HOME/.coder-modules/custom/boundary/config/config.yaml" + error_message = "boundary_config_path output should use custom module directory" } } @@ -164,12 +134,12 @@ run "plan_with_inline_boundary_config" { # BOUNDARY_CONFIG should still point to the managed path since we write # the inline content there. assert { - condition = coder_env.boundary_config.value == "$HOME/.config/coder_boundary/config.yaml" + condition = coder_env.boundary_config.value == "$HOME/.coder-modules/coder/boundary/config/config.yaml" error_message = "BOUNDARY_CONFIG should point to managed config path when using inline config" } assert { - condition = output.boundary_config_path == "$HOME/.config/coder_boundary/config.yaml" + condition = output.boundary_config_path == "$HOME/.coder-modules/coder/boundary/config/config.yaml" error_message = "boundary_config_path output should point to managed config path" } } diff --git a/registry/coder/modules/boundary/config.yaml b/registry/coder/modules/boundary/config.yaml index 0dde4452f..b40690245 100644 --- a/registry/coder/modules/boundary/config.yaml +++ b/registry/coder/modules/boundary/config.yaml @@ -1,5 +1,6 @@ allowlist: - # Your Coder deployment domain (required — replace with your own). + # Your Coder deployment domain (auto-filled from access URL when + # using the default config; replace if customising manually). - domain=your-deployment.coder.com # Anthropic Services @@ -7,6 +8,14 @@ allowlist: - domain=statsig.anthropic.com - domain=claude.ai + # OpenAI Services + - domain=api.openai.com + - domain=platform.openai.com + - domain=openai.com + - domain=chatgpt.com + - domain=*.oaiusercontent.com + - domain=*.oaistatic.com + # Version Control - domain=github.com - domain=www.github.com diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index 8c18d5c26..ccb9e5811 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -43,6 +43,10 @@ interface SetupProps { skipCoderMock?: boolean; } +const MODULE_DIR = "/home/coder/.coder-modules/coder/boundary"; +const CONFIG_PATH = `${MODULE_DIR}/config/config.yaml`; +const WRAPPER_PATH = `${MODULE_DIR}/scripts/boundary-wrapper.sh`; + const setup = async ( props?: SetupProps, ): Promise<{ id: string; coderEnvVars: Record }> => { @@ -132,17 +136,11 @@ describe("boundary", async () => { const resources = state.resources; - // Verify coder_env resource for BOUNDARY_WRAPPER_PATH - const boundaryEnv = resources.find( + // BOUNDARY_WRAPPER_PATH env should NOT exist (only output) + const wrapperEnv = resources.find( (r) => r.type === "coder_env" && r.name === "boundary_wrapper_path", ); - expect(boundaryEnv).toBeDefined(); - expect(boundaryEnv?.instances[0]?.attributes.name).toBe( - "BOUNDARY_WRAPPER_PATH", - ); - expect(boundaryEnv?.instances[0]?.attributes.value).toBe( - "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", - ); + expect(wrapperEnv).toBeUndefined(); // Verify coder_env resource for BOUNDARY_CONFIG const configEnv = resources.find( @@ -151,16 +149,14 @@ describe("boundary", async () => { expect(configEnv).toBeDefined(); expect(configEnv?.instances[0]?.attributes.name).toBe("BOUNDARY_CONFIG"); expect(configEnv?.instances[0]?.attributes.value).toBe( - "$HOME/.config/coder_boundary/config.yaml", + "$HOME/.coder-modules/coder/boundary/config/config.yaml", ); // Verify the outputs are set correctly const coderEnvVars = extractCoderEnvVars(state); - expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( - "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", - ); + expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBeUndefined(); expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( - "$HOME/.config/coder_boundary/config.yaml", + "$HOME/.coder-modules/coder/boundary/config/config.yaml", ); }); @@ -171,10 +167,15 @@ describe("boundary", async () => { module_directory: customDir, }); - const coderEnvVars = extractCoderEnvVars(state); - expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( + // Verify output uses custom dir + const outputs = state.outputs; + expect(outputs["boundary_wrapper_path"]?.value).toBe( `${customDir}/scripts/boundary-wrapper.sh`, ); + // Config path follows module directory + expect(outputs["boundary_config_path"]?.value).toBe( + `${customDir}/config/config.yaml`, + ); }); test("terraform-state-inline-config", async () => { @@ -188,7 +189,7 @@ describe("boundary", async () => { const coderEnvVars = extractCoderEnvVars(state); // Inline config still writes to the managed path. expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( - "$HOME/.config/coder_boundary/config.yaml", + "$HOME/.coder-modules/coder/boundary/config/config.yaml", ); }); @@ -208,10 +209,7 @@ describe("boundary", async () => { await execModuleScript(id); // Verify the wrapper script was created - const wrapperContent = await readFileContainer( - id, - "/home/coder/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", - ); + const wrapperContent = await readFileContainer(id, WRAPPER_PATH); expect(wrapperContent).toContain("#!/usr/bin/env bash"); expect(wrapperContent).toContain("coder-no-caps"); expect(wrapperContent).toContain("boundary"); @@ -221,31 +219,29 @@ describe("boundary", async () => { "stat", "-c", "%a", - "/home/coder/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", + WRAPPER_PATH, ]); - expect(statResult.stdout.trim()).toMatch(/7[0-9][0-9]/); // Should be executable (7xx) + expect(statResult.stdout.trim()).toMatch(/7[0-9][0-9]/); // Verify coder-no-caps binary was created const coderNoCapsResult = await execContainer(id, [ "test", "-f", - "/home/coder/.coder-modules/coder/boundary/scripts/coder-no-caps", + `${MODULE_DIR}/scripts/coder-no-caps`, ]); expect(coderNoCapsResult.exitCode).toBe(0); - // Verify default boundary config was written - const configContent = await readFileContainer( - id, - "/home/coder/.config/coder_boundary/config.yaml", - ); + // Verify default boundary config was written inside module directory + const configContent = await readFileContainer(id, CONFIG_PATH); expect(configContent).toContain("allowlist:"); expect(configContent).toContain("domain=api.anthropic.com"); + expect(configContent).toContain("domain=api.openai.com"); expect(configContent).toContain("proxy_port: 8087"); // Check install log const installLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/logs/install.log", + `${MODULE_DIR}/logs/install.log`, ); expect(installLog).toContain("Using coder boundary subcommand"); expect(installLog).toContain("Boundary config written to"); @@ -263,10 +259,7 @@ describe("boundary", async () => { await execModuleScript(id); // Verify the inline config was written - const configContent = await readFileContainer( - id, - "/home/coder/.config/coder_boundary/config.yaml", - ); + const configContent = await readFileContainer(id, CONFIG_PATH); expect(configContent).toContain("domain=custom.example.com"); expect(configContent).toContain("log_level: info"); }); @@ -280,17 +273,13 @@ describe("boundary", async () => { await execModuleScript(id); // Verify NO config was written to the default path - const checkResult = await execContainer(id, [ - "test", - "-f", - "/home/coder/.config/coder_boundary/config.yaml", - ]); + const checkResult = await execContainer(id, ["test", "-f", CONFIG_PATH]); expect(checkResult.exitCode).not.toBe(0); // Check install log confirms skip const installLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/logs/install.log", + `${MODULE_DIR}/logs/install.log`, ); expect(installLog).toContain( "Using external boundary config, skipping config write", @@ -316,36 +305,34 @@ describe("boundary", async () => { // Verify pre-install script ran const preInstallLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/logs/pre_install.log", + `${MODULE_DIR}/logs/pre_install.log`, ); expect(preInstallLog).toContain(preInstallMarker); // Verify post-install script ran const postInstallLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/logs/post_install.log", + `${MODULE_DIR}/logs/post_install.log`, ); expect(postInstallLog).toContain(postInstallMarker); // Verify main install still ran const installLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/logs/install.log", + `${MODULE_DIR}/logs/install.log`, ); expect(installLog).toContain("boundary wrapper configured"); }); test("env-var-set-correctly", async () => { - const { id, coderEnvVars } = await setup(); + const { coderEnvVars } = await setup(); - // Verify BOUNDARY_WRAPPER_PATH is in the coder env vars - expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBe( - "$HOME/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh", - ); + // BOUNDARY_WRAPPER_PATH env var should NOT exist + expect(coderEnvVars["BOUNDARY_WRAPPER_PATH"]).toBeUndefined(); // Verify BOUNDARY_CONFIG is in the coder env vars expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( - "$HOME/.config/coder_boundary/config.yaml", + "$HOME/.coder-modules/coder/boundary/config/config.yaml", ); }); @@ -357,7 +344,7 @@ describe("boundary", async () => { const wrapperResult = await execContainer(id, [ "bash", "-c", - "/home/coder/.coder-modules/coder/boundary/scripts/boundary-wrapper.sh echo boundary-test", + `${WRAPPER_PATH} echo boundary-test`, ]); // The wrapper passes the command directly to the boundary command @@ -371,7 +358,7 @@ describe("boundary", async () => { await execModuleScript(id); const firstInstallLog = await readFileContainer( id, - "/home/coder/.coder-modules/coder/boundary/logs/install.log", + `${MODULE_DIR}/logs/install.log`, ); // Run again diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 81bd010f8..e5f7149a8 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -9,6 +9,8 @@ terraform { } } +data "coder_workspace" "me" {} + variable "agent_id" { type = string description = "The ID of a Coder agent." @@ -70,11 +72,16 @@ variable "module_directory" { locals { boundary_wrapper_path = "${var.module_directory}/scripts/boundary-wrapper.sh" + # Extract domain from the Coder access URL for the default config + # allowlist (e.g., "https://dev.coder.com/" -> "dev.coder.com"). + coder_domain = try(regex("^https?://([^/:]+)", data.coder_workspace.me.access_url)[0], "") + # Config handling: resolve which config content to write and where # BOUNDARY_CONFIG points to. - default_boundary_config = file("${path.module}/config.yaml") + raw_default_config = file("${path.module}/config.yaml") + default_boundary_config = local.coder_domain != "" ? replace(local.raw_default_config, "domain=your-deployment.coder.com", "domain=${local.coder_domain}") : local.raw_default_config boundary_config_content = var.boundary_config != null ? var.boundary_config : local.default_boundary_config - boundary_config_dir = "$HOME/.config/coder_boundary" + boundary_config_dir = "${var.module_directory}/config" boundary_config_file_path = "${local.boundary_config_dir}/config.yaml" effective_boundary_config_path = var.boundary_config_path != null ? var.boundary_config_path : local.boundary_config_file_path write_boundary_config = var.boundary_config_path == null @@ -103,12 +110,6 @@ module "coder_utils" { install_script = local.install_script } -resource "coder_env" "boundary_wrapper_path" { - agent_id = var.agent_id - name = "BOUNDARY_WRAPPER_PATH" - value = local.boundary_wrapper_path -} - resource "coder_env" "boundary_config" { agent_id = var.agent_id name = "BOUNDARY_CONFIG" From 559f4eaba5c958e60deb6068d078dba497e1249b Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 10:23:44 +0000 Subject: [PATCH 43/53] refactor(boundary): convert config.yaml to tftpl, inject coder_domain directly --- .../modules/boundary/{config.yaml => config.yaml.tftpl} | 2 +- registry/coder/modules/boundary/main.tf | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) rename registry/coder/modules/boundary/{config.yaml => config.yaml.tftpl} (99%) diff --git a/registry/coder/modules/boundary/config.yaml b/registry/coder/modules/boundary/config.yaml.tftpl similarity index 99% rename from registry/coder/modules/boundary/config.yaml rename to registry/coder/modules/boundary/config.yaml.tftpl index b40690245..2bc598bdc 100644 --- a/registry/coder/modules/boundary/config.yaml +++ b/registry/coder/modules/boundary/config.yaml.tftpl @@ -1,7 +1,7 @@ allowlist: # Your Coder deployment domain (auto-filled from access URL when # using the default config; replace if customising manually). - - domain=your-deployment.coder.com + - domain=${CODER_DOMAIN} # Anthropic Services - domain=api.anthropic.com diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index e5f7149a8..58c7c7c4c 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -78,8 +78,9 @@ locals { # Config handling: resolve which config content to write and where # BOUNDARY_CONFIG points to. - raw_default_config = file("${path.module}/config.yaml") - default_boundary_config = local.coder_domain != "" ? replace(local.raw_default_config, "domain=your-deployment.coder.com", "domain=${local.coder_domain}") : local.raw_default_config + default_boundary_config = templatefile("${path.module}/config.yaml.tftpl", { + CODER_DOMAIN = local.coder_domain + }) boundary_config_content = var.boundary_config != null ? var.boundary_config : local.default_boundary_config boundary_config_dir = "${var.module_directory}/config" boundary_config_file_path = "${local.boundary_config_dir}/config.yaml" From 01d1800d2734200fabf5e6afa0d54ce143db821a Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Apr 2026 16:11:08 +0530 Subject: [PATCH 44/53] bun fmt --- registry/coder/modules/boundary/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder/modules/boundary/main.tf b/registry/coder/modules/boundary/main.tf index 58c7c7c4c..d5b5495ab 100644 --- a/registry/coder/modules/boundary/main.tf +++ b/registry/coder/modules/boundary/main.tf @@ -78,7 +78,7 @@ locals { # Config handling: resolve which config content to write and where # BOUNDARY_CONFIG points to. - default_boundary_config = templatefile("${path.module}/config.yaml.tftpl", { + default_boundary_config = templatefile("${path.module}/config.yaml.tftpl", { CODER_DOMAIN = local.coder_domain }) boundary_config_content = var.boundary_config != null ? var.boundary_config : local.default_boundary_config From 8c91560874de50630c605366d9cf320fda805190 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 10:44:37 +0000 Subject: [PATCH 45/53] test(boundary): add coverage for coder_domain auto-fill, scripts and config_path outputs --- registry/coder/modules/boundary/main.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/registry/coder/modules/boundary/main.test.ts b/registry/coder/modules/boundary/main.test.ts index ccb9e5811..01a37ab1a 100644 --- a/registry/coder/modules/boundary/main.test.ts +++ b/registry/coder/modules/boundary/main.test.ts @@ -158,6 +158,15 @@ describe("boundary", async () => { expect(coderEnvVars["BOUNDARY_CONFIG"]).toBe( "$HOME/.coder-modules/coder/boundary/config/config.yaml", ); + + // Verify boundary_config_path output + expect(state.outputs["boundary_config_path"]?.value).toBe( + "$HOME/.coder-modules/coder/boundary/config/config.yaml", + ); + + // Verify scripts output contains install script + const scripts = state.outputs["scripts"]?.value as string[]; + expect(scripts).toContain("coder-boundary-install_script"); }); test("terraform-state-custom-module-directory", async () => { @@ -238,6 +247,10 @@ describe("boundary", async () => { expect(configContent).toContain("domain=api.openai.com"); expect(configContent).toContain("proxy_port: 8087"); + // Verify Coder domain was auto-filled from data.coder_workspace.me + // (the placeholder should be replaced with the actual deployment domain). + expect(configContent).not.toContain("domain=your-deployment.coder.com"); + // Check install log const installLog = await readFileContainer( id, From 123c48bbd2abb72a2bb3078529b1fe64f5a4eed2 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 13:14:30 +0000 Subject: [PATCH 46/53] fix(boundary): validate coder boundary with a real invocation, not --help 'coder boundary --help' succeeds even on unlicensed deployments. Use 'coder boundary -- true' instead to catch license entitlement errors and surface an actionable message. --- .../modules/boundary/scripts/install.sh.tftpl | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 3323d53da..d82a84ad7 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -24,17 +24,25 @@ printf "BOUNDARY_CONFIG_DIR: %s\n" "$${BOUNDARY_CONFIG_DIR}" printf "BOUNDARY_CONFIG_FILE: %s\n" "$${BOUNDARY_CONFIG_FILE}" validate_boundary_subcommand() { - if command -v coder > /dev/null 2>&1; then - if coder boundary --help > /dev/null 2>&1; then - return 0 - else - echo "Error: 'coder' command found but does not support 'boundary' subcommand. Set use_boundary_directly=true or compile_boundary_from_source=true." >&2 - exit 1 - fi - else + if ! command -v coder > /dev/null 2>&1; then echo "Error: 'coder' command not found. boundary cannot be enabled." >&2 exit 1 fi + + # Run a no-op command through coder boundary to verify the subcommand + # exists AND the deployment license includes the boundary feature. + # 'coder boundary --help' always succeeds, so we use 'true' as a + # harmless command to surface license or capability errors. + local output + if ! output=$(coder boundary -- true 2>&1); then + echo "Error: 'coder boundary' is not available." >&2 + echo "$${output}" >&2 + echo "" >&2 + echo "If your Coder deployment is not licensed for boundary, set" >&2 + echo "use_boundary_directly=true or compile_boundary_from_source=true" >&2 + echo "to use the standalone boundary binary instead." >&2 + exit 1 + fi } # Install boundary binary if needed. From e2b69a1cfbded8110132cc489712217669c4ccc7 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 13:26:14 +0000 Subject: [PATCH 47/53] fix(boundary): only fail on license entitlement error, ignore other coder boundary failures --- .../modules/boundary/scripts/install.sh.tftpl | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index d82a84ad7..131df5d92 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -29,19 +29,20 @@ validate_boundary_subcommand() { exit 1 fi - # Run a no-op command through coder boundary to verify the subcommand - # exists AND the deployment license includes the boundary feature. - # 'coder boundary --help' always succeeds, so we use 'true' as a - # harmless command to surface license or capability errors. + # Run a no-op command through coder boundary to verify the deployment + # license includes the boundary feature. Only a license entitlement + # error is fatal here; other failures (missing nsjail, etc.) are + # expected at validation time and will be reported at runtime. local output if ! output=$(coder boundary -- true 2>&1); then - echo "Error: 'coder boundary' is not available." >&2 - echo "$${output}" >&2 - echo "" >&2 - echo "If your Coder deployment is not licensed for boundary, set" >&2 - echo "use_boundary_directly=true or compile_boundary_from_source=true" >&2 - echo "to use the standalone boundary binary instead." >&2 - exit 1 + if echo "$${output}" | grep -qi "license is not entitled"; then + echo "Error: your Coder deployment is not licensed for the boundary feature." >&2 + echo "$${output}" >&2 + echo "" >&2 + echo "Set use_boundary_directly=true or compile_boundary_from_source=true" >&2 + echo "to use the standalone boundary binary instead." >&2 + exit 1 + fi fi } From b918896ec3ba00ee0ec04347ce41617525480ca9 Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 13:27:01 +0000 Subject: [PATCH 48/53] chore(boundary): trim verbose comment --- registry/coder/modules/boundary/scripts/install.sh.tftpl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 131df5d92..ac495c394 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -29,10 +29,7 @@ validate_boundary_subcommand() { exit 1 fi - # Run a no-op command through coder boundary to verify the deployment - # license includes the boundary feature. Only a license entitlement - # error is fatal here; other failures (missing nsjail, etc.) are - # expected at validation time and will be reported at runtime. + # Only a license entitlement error is fatal here. local output if ! output=$(coder boundary -- true 2>&1); then if echo "$${output}" | grep -qi "license is not entitled"; then From 4fdad04e29287d26349689b2f2208571ef2d7e5e Mon Sep 17 00:00:00 2001 From: Jay Kumar Date: Tue, 28 Apr 2026 15:57:54 +0000 Subject: [PATCH 49/53] docs(boundary): update Claude Code example to coder_app, suppress sync output --- registry/coder/modules/boundary/README.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/registry/coder/modules/boundary/README.md b/registry/coder/modules/boundary/README.md index 9a52128b6..934eec791 100644 --- a/registry/coder/modules/boundary/README.md +++ b/registry/coder/modules/boundary/README.md @@ -124,40 +124,37 @@ The list may contain the following script names: ### With Claude Code Use boundary alongside the `claude-code` module to run Claude in a -network-isolated environment. The `coder_script` below waits for both +network-isolated environment. The `coder_app` below waits for both modules to finish installing before launching Claude behind the boundary wrapper. ```tf module "boundary" { - count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/boundary/coder" version = "0.0.1" agent_id = coder_agent.main.id } module "claude_code" { - count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/claude-code/coder" version = "5.3.0" agent_id = coder_agent.main.id } -# Launch Claude behind the boundary wrapper after both modules -# have finished installing. -resource "coder_script" "claude_with_boundary" { +resource "coder_app" "claude_with_boundary" { agent_id = coder_agent.main.id + slug = "claude-cli" display_name = "Claude (Boundary)" - run_on_start = true - script = <<-EOT + command = <<-EOT # Wait for boundary and claude-code install scripts to complete. coder exp sync want claude-boundary \ - ${join(" ", module.boundary[0].scripts)} \ - ${join(" ", module.claude_code[0].scripts)} - coder exp sync start claude-boundary + ${join(" ", module.boundary.scripts)} \ + ${join(" ", module.claude_code.scripts)} > /dev/null 2>&1 + coder exp sync start claude-boundary > /dev/null 2>&1 # Run Claude inside the boundary wrapper. - "${module.boundary[0].boundary_wrapper_path}" -- claude + "${module.boundary.boundary_wrapper_path}" \ + --config="${module.boundary.boundary_config_path}" -- claude EOT } ``` From 39f0a5a369edc59c23597e2b08e40bf61d39d8a3 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Apr 2026 22:48:14 +0530 Subject: [PATCH 50/53] debug --- registry/coder/modules/boundary/scripts/install.sh.tftpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index ac495c394..4122feed0 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -31,13 +31,13 @@ validate_boundary_subcommand() { # Only a license entitlement error is fatal here. local output - if ! output=$(coder boundary -- true 2>&1); then + echo "Checking for license" + coder boundary + if ! output=$(coder boundary 2>&1); then if echo "$${output}" | grep -qi "license is not entitled"; then echo "Error: your Coder deployment is not licensed for the boundary feature." >&2 echo "$${output}" >&2 echo "" >&2 - echo "Set use_boundary_directly=true or compile_boundary_from_source=true" >&2 - echo "to use the standalone boundary binary instead." >&2 exit 1 fi fi From 50db5207fec809c4721e3c05f7fac825a6ada285 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Apr 2026 22:58:51 +0530 Subject: [PATCH 51/53] debug --- registry/coder/modules/boundary/scripts/install.sh.tftpl | 1 - 1 file changed, 1 deletion(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 4122feed0..16e22f3d7 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -32,7 +32,6 @@ validate_boundary_subcommand() { # Only a license entitlement error is fatal here. local output echo "Checking for license" - coder boundary if ! output=$(coder boundary 2>&1); then if echo "$${output}" | grep -qi "license is not entitled"; then echo "Error: your Coder deployment is not licensed for the boundary feature." >&2 From f0a469b4e4e83308db78d34349a8d1e9ba526305 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Apr 2026 22:59:30 +0530 Subject: [PATCH 52/53] debug --- registry/coder/modules/boundary/scripts/install.sh.tftpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 16e22f3d7..7d7c6e7de 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -38,6 +38,9 @@ validate_boundary_subcommand() { echo "$${output}" >&2 echo "" >&2 exit 1 + else + echo "Warning: 'coder boundary' command failed with unexpected error. boundary may not work properly. Error details:" >&2 + echo "$${output}" >&2 fi fi } From b15c1973b70820636f7e1de9b9b462caf4fbb3e3 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Apr 2026 23:11:59 +0530 Subject: [PATCH 53/53] debug --- registry/coder/modules/boundary/scripts/install.sh.tftpl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/registry/coder/modules/boundary/scripts/install.sh.tftpl b/registry/coder/modules/boundary/scripts/install.sh.tftpl index 7d7c6e7de..6523d85aa 100644 --- a/registry/coder/modules/boundary/scripts/install.sh.tftpl +++ b/registry/coder/modules/boundary/scripts/install.sh.tftpl @@ -29,7 +29,6 @@ validate_boundary_subcommand() { exit 1 fi - # Only a license entitlement error is fatal here. local output echo "Checking for license" if ! output=$(coder boundary 2>&1); then @@ -38,9 +37,6 @@ validate_boundary_subcommand() { echo "$${output}" >&2 echo "" >&2 exit 1 - else - echo "Warning: 'coder boundary' command failed with unexpected error. boundary may not work properly. Error details:" >&2 - echo "$${output}" >&2 fi fi }