feat: enhance boundary configuration options in Claude Code module
- Added new variables `boundary_config` and `boundary_config_path` for inline YAML and file path configurations, respectively. - Implemented validation rules to ensure proper configuration when `enable_boundary` is true. - Updated README with usage examples for both configuration methods. - Enhanced test cases to cover various boundary configuration scenarios, including validation failures.
This commit is contained in:
parent
5ee68d04d1
commit
eb2da40cf7
@ -55,7 +55,14 @@ module "claude-code" {
|
||||
|
||||
This example shows how to configure the Claude Code module to run the agent behind a process-level boundary that restricts its network access.
|
||||
|
||||
By default, when `enable_boundary = true`, the module uses `coder boundary` subcommand (provided by Coder) without requiring any installation.
|
||||
When `enable_boundary = true`, you must provide network filtering rules via one of two options:
|
||||
|
||||
- `boundary_config` — inline YAML string (config lives in the template)
|
||||
- `boundary_config_path` — path to a config file already on disk
|
||||
|
||||
The module writes the config to `~/.config/coder_boundary/config.yaml` automatically.
|
||||
|
||||
#### Inline boundary config
|
||||
|
||||
```tf
|
||||
module "claude-code" {
|
||||
@ -64,6 +71,27 @@ module "claude-code" {
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
enable_boundary = true
|
||||
|
||||
boundary_config = <<-EOT
|
||||
allow:
|
||||
- "*.anthropic.com"
|
||||
- "*.github.com"
|
||||
EOT
|
||||
}
|
||||
```
|
||||
|
||||
#### Boundary config from file path
|
||||
|
||||
Use this when the config file is provisioned separately or managed outside the template:
|
||||
|
||||
```tf
|
||||
module "claude-code" {
|
||||
source = "registry.coder.com/coder/claude-code/coder"
|
||||
version = "4.8.0"
|
||||
agent_id = coder_agent.main.id
|
||||
workdir = "/home/coder/project"
|
||||
enable_boundary = true
|
||||
boundary_config_path = "/home/coder/.config/coder_boundary/config.yaml"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -231,6 +231,33 @@ variable "enable_boundary" {
|
||||
type = bool
|
||||
description = "Whether to enable coder boundary for network filtering"
|
||||
default = false
|
||||
|
||||
validation {
|
||||
condition = !var.enable_boundary || var.boundary_config != null || var.boundary_config_path != null
|
||||
error_message = "When enable_boundary is true, at least one of boundary_config or boundary_config_path must be provided."
|
||||
}
|
||||
|
||||
validation {
|
||||
condition = !var.enable_boundary || var.boundary_config == null || var.boundary_config_path == null
|
||||
error_message = "Only one of boundary_config or boundary_config_path can be provided, not both."
|
||||
}
|
||||
|
||||
validation {
|
||||
condition = (var.boundary_config == null && var.boundary_config_path == null) || var.enable_boundary
|
||||
error_message = "boundary_config and boundary_config_path can only be set when enable_boundary is true."
|
||||
}
|
||||
}
|
||||
|
||||
variable "boundary_config" {
|
||||
type = string
|
||||
description = "Inline YAML config for coder boundary network filtering rules. Written to ~/.config/coder_boundary/config.yaml before boundary starts. Mutually exclusive with boundary_config_path."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "boundary_config_path" {
|
||||
type = string
|
||||
description = "Path to an existing boundary config file on disk. Symlinked to ~/.config/coder_boundary/config.yaml before boundary starts. Mutually exclusive with boundary_config."
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "boundary_version" {
|
||||
@ -407,6 +434,8 @@ module "agentapi" {
|
||||
ARG_COMPILE_FROM_SOURCE='${var.compile_boundary_from_source}' \
|
||||
ARG_USE_BOUNDARY_DIRECTLY='${var.use_boundary_directly}' \
|
||||
ARG_CODER_HOST='${local.coder_host}' \
|
||||
ARG_BOUNDARY_CONFIG='${var.boundary_config != null ? base64encode(var.boundary_config) : ""}' \
|
||||
ARG_BOUNDARY_CONFIG_PATH='${var.boundary_config_path != null ? var.boundary_config_path : ""}' \
|
||||
ARG_CLAUDE_BINARY_PATH='${var.claude_binary_path}' \
|
||||
/tmp/start.sh
|
||||
EOT
|
||||
|
||||
@ -188,13 +188,18 @@ run "test_claude_code_permission_mode_validation" {
|
||||
}
|
||||
}
|
||||
|
||||
run "test_claude_code_with_boundary" {
|
||||
run "test_claude_code_with_boundary_inline_config" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-boundary"
|
||||
workdir = "/home/coder/boundary-test"
|
||||
enable_boundary = true
|
||||
boundary_config = <<-EOT
|
||||
allow:
|
||||
- "*.anthropic.com"
|
||||
- "*.github.com"
|
||||
EOT
|
||||
}
|
||||
|
||||
assert {
|
||||
@ -202,12 +207,98 @@ run "test_claude_code_with_boundary" {
|
||||
error_message = "Boundary should be enabled"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = var.boundary_config != null
|
||||
error_message = "Boundary config should be set"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = local.coder_host != ""
|
||||
error_message = "Coder host should be extracted from access URL"
|
||||
}
|
||||
}
|
||||
|
||||
run "test_claude_code_with_boundary_config_path" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-boundary-path"
|
||||
workdir = "/home/coder/boundary-test"
|
||||
enable_boundary = true
|
||||
boundary_config_path = "/home/coder/.config/coder_boundary/config.yaml"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = var.enable_boundary == true
|
||||
error_message = "Boundary should be enabled"
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = var.boundary_config_path == "/home/coder/.config/coder_boundary/config.yaml"
|
||||
error_message = "Boundary config path should be set correctly"
|
||||
}
|
||||
}
|
||||
|
||||
run "test_boundary_without_config_fails" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-boundary-fail"
|
||||
workdir = "/home/coder/boundary-test"
|
||||
enable_boundary = true
|
||||
}
|
||||
|
||||
expect_failures = [
|
||||
var.enable_boundary,
|
||||
]
|
||||
}
|
||||
|
||||
run "test_boundary_both_configs_fails" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-boundary-both"
|
||||
workdir = "/home/coder/boundary-test"
|
||||
enable_boundary = true
|
||||
boundary_config = "allow:\n - '*.example.com'"
|
||||
boundary_config_path = "/home/coder/.config/coder_boundary/config.yaml"
|
||||
}
|
||||
|
||||
expect_failures = [
|
||||
var.enable_boundary,
|
||||
]
|
||||
}
|
||||
|
||||
run "test_boundary_config_without_boundary_fails" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-no-boundary"
|
||||
workdir = "/home/coder/boundary-test"
|
||||
enable_boundary = false
|
||||
boundary_config = "allow:\n - '*.example.com'"
|
||||
}
|
||||
|
||||
expect_failures = [
|
||||
var.enable_boundary,
|
||||
]
|
||||
}
|
||||
|
||||
run "test_boundary_config_path_without_boundary_fails" {
|
||||
command = plan
|
||||
|
||||
variables {
|
||||
agent_id = "test-agent-no-boundary-path"
|
||||
workdir = "/home/coder/boundary-test"
|
||||
enable_boundary = false
|
||||
boundary_config_path = "/home/coder/.config/coder_boundary/config.yaml"
|
||||
}
|
||||
|
||||
expect_failures = [
|
||||
var.enable_boundary,
|
||||
]
|
||||
}
|
||||
|
||||
run "test_claude_code_system_prompt" {
|
||||
command = plan
|
||||
|
||||
|
||||
@ -24,6 +24,8 @@ ARG_BOUNDARY_VERSION=${ARG_BOUNDARY_VERSION:-"latest"}
|
||||
ARG_COMPILE_FROM_SOURCE=${ARG_COMPILE_FROM_SOURCE:-false}
|
||||
ARG_USE_BOUNDARY_DIRECTLY=${ARG_USE_BOUNDARY_DIRECTLY:-false}
|
||||
ARG_CODER_HOST=${ARG_CODER_HOST:-}
|
||||
ARG_BOUNDARY_CONFIG=${ARG_BOUNDARY_CONFIG:-}
|
||||
ARG_BOUNDARY_CONFIG_PATH=${ARG_BOUNDARY_CONFIG_PATH:-}
|
||||
|
||||
echo "--------------------------------"
|
||||
|
||||
@ -223,6 +225,21 @@ function start_agentapi() {
|
||||
printf "Running claude code with args: %s\n" "$(printf '%q ' "${ARGS[@]}")"
|
||||
|
||||
if [ "$ARG_ENABLE_BOUNDARY" = "true" ]; then
|
||||
BOUNDARY_CONFIG_DIR="$HOME/.config/coder_boundary"
|
||||
BOUNDARY_CONFIG_FILE="$BOUNDARY_CONFIG_DIR/config.yaml"
|
||||
|
||||
if [ -n "$ARG_BOUNDARY_CONFIG" ]; then
|
||||
printf "Writing inline boundary config to %s\n" "$BOUNDARY_CONFIG_FILE"
|
||||
mkdir -p "$BOUNDARY_CONFIG_DIR"
|
||||
echo -n "$ARG_BOUNDARY_CONFIG" | base64 -d > "$BOUNDARY_CONFIG_FILE"
|
||||
elif [ -n "$ARG_BOUNDARY_CONFIG_PATH" ]; then
|
||||
printf "Linking boundary config from %s to %s\n" "$ARG_BOUNDARY_CONFIG_PATH" "$BOUNDARY_CONFIG_FILE"
|
||||
if [ "$ARG_BOUNDARY_CONFIG_PATH" != "$BOUNDARY_CONFIG_FILE" ]; then
|
||||
mkdir -p "$BOUNDARY_CONFIG_DIR"
|
||||
ln -sf "$ARG_BOUNDARY_CONFIG_PATH" "$BOUNDARY_CONFIG_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
install_boundary
|
||||
|
||||
printf "Starting with coder boundary enabled\n"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user