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/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 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/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 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 } ``` 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/mux/README.md b/registry/coder/modules/mux/README.md index 00a9de65..69073926 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.2.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.2.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.2.0" agent_id = coder_agent.main.id # Default is "latest"; set to a specific version to pin install_version = "0.4.0" @@ -63,19 +63,34 @@ 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.2.0" agent_id = coder_agent.main.id add-project = "/path/to/project" } ``` +### Pass Arbitrary `mux server` Arguments + +Use `additional_arguments` to append additional arguments to `mux server`. +The module parses quoted values, so grouped arguments remain intact. + +```tf +module "mux" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/mux/coder" + version = "1.2.0" + agent_id = coder_agent.main.id + additional_arguments = "--open-mode pinned --add-project '/workspaces/my repo'" +} +``` + ### Custom Port ```tf module "mux" { count = data.coder_workspace.me.start_count source = "registry.coder.com/coder/mux/coder" - version = "1.0.8" + version = "1.2.0" agent_id = coder_agent.main.id port = 8080 } @@ -89,7 +104,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.2.0" agent_id = coder_agent.main.id use_cached = true } @@ -103,7 +118,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.2.0" agent_id = coder_agent.main.id install = false } diff --git a/registry/coder/modules/mux/main.test.ts b/registry/coder/modules/mux/main.test.ts index 96fae5e4..c1b6e238 100644 --- a/registry/coder/modules/mux/main.test.ts +++ b/registry/coder/modules/mux/main.test.ts @@ -1,6 +1,11 @@ import { describe, expect, it } from "bun:test"; import { executeScriptInContainer, + execContainer, + findResourceInstance, + readFileContainer, + removeContainer, + runContainer, runTerraformApply, runTerraformInit, testRequiredVariables, @@ -40,6 +45,57 @@ describe("mux", async () => { } }, 60000); + it("parses custom additional_arguments", async () => { + const state = await runTerraformApply(import.meta.dir, { + agent_id: "foo", + install: false, + log_path: "/tmp/mux.log", + additional_arguments: + "--open-mode pinned --add-project '/workspaces/my repo'", + }); + + const instance = findResourceInstance(state, "coder_script"); + const id = await runContainer("alpine/curl"); + + try { + const setup = await execContainer(id, [ + "sh", + "-c", + `apk add --no-cache bash >/dev/null +mkdir -p /tmp/mux +cat <<'EOF' > /tmp/mux/mux +#!/usr/bin/env sh +i=1 +for arg in "$@"; do + echo "arg$i=$arg" + i=$((i + 1)) +done +EOF +chmod +x /tmp/mux/mux`, + ]); + expect(setup.exitCode).toBe(0); + + const output = await execContainer(id, ["sh", "-c", instance.script]); + if (output.exitCode !== 0) { + console.log("STDOUT:\n" + output.stdout); + console.log("STDERR:\n" + output.stderr); + } + expect(output.exitCode).toBe(0); + + await execContainer(id, ["sh", "-c", "sleep 1"]); + const log = await readFileContainer(id, "/tmp/mux.log"); + expect(log).toContain("arg1=server"); + expect(log).toContain("arg2=--port"); + expect(log).toContain("arg3=4000"); + expect(log).toContain("arg4=--open-mode"); + expect(log).toContain("arg5=pinned"); + expect(log).toContain("arg6=--add-project"); + expect(log).toContain("arg7=/workspaces/my repo"); + } finally { + await removeContainer(id); + } + }, 60000); + it("runs with npm present", async () => { const state = await runTerraformApply(import.meta.dir, { agent_id: "foo", diff --git a/registry/coder/modules/mux/main.tf b/registry/coder/modules/mux/main.tf index 870beae2..dbc585d8 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" + } } } @@ -51,6 +55,12 @@ variable "add-project" { default = null } +variable "additional_arguments" { + type = string + description = "Additional command-line arguments to pass to `mux server` (for example: `--add-project /path --open-mode pinned`)." + default = "" +} + variable "install_version" { type = string description = "The version or dist-tag of Mux to install." @@ -113,6 +123,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 @@ -122,9 +148,11 @@ resource "coder_script" "mux" { PORT : var.port, LOG_PATH : var.log_path, ADD_PROJECT : var.add-project == null ? "" : var.add-project, + ADDITIONAL_ARGUMENTS : var.additional_arguments, 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 +168,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 +182,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..688ddedb 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,65 @@ 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" + } +} + +run "custom_additional_arguments" { + command = plan + + variables { + agent_id = "foo" + additional_arguments = "--open-mode pinned --add-project '/workspaces/my repo'" + } + + assert { + condition = strcontains(resource.coder_script.mux.script, "--open-mode pinned --add-project '/workspaces/my repo'") + error_message = "mux launch script must include the configured additional arguments" } } @@ -62,5 +121,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..099448fb 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 @@ -18,9 +20,25 @@ function run_mux() { if [ -n "${ADD_PROJECT}" ]; then set -- "$@" --add-project "${ADD_PROJECT}" fi + + # Parse additional user-supplied server arguments while preserving quoted groups. + if [ -n "${ADDITIONAL_ARGUMENTS}" ]; then + local parsed_additional_arguments + if ! parsed_additional_arguments="$(printf "%s\n" "${ADDITIONAL_ARGUMENTS}" | xargs -n1 printf "%s\n" 2> /dev/null)"; then + echo "❌ Failed to parse additional_arguments. Ensure quotes are balanced." + exit 1 + fi + while IFS= read -r parsed_arg; do + [ -n "$parsed_arg" ] || continue + set -- "$@" "$parsed_arg" + done << EOF +$${parsed_additional_arguments} +EOF + 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 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, 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/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. 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 9365b444..1d391296 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" {} @@ -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