From e1f4a9a3551d6ad1f519e4c5653d83f8a2a3766b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Tue, 2 Dec 2025 19:41:10 +0000 Subject: [PATCH 1/7] feat: add vault-cli module with optional token and namespace configuration Closes #50 This adds a new vault-cli module that: - Installs the Vault CLI using the official HashiCorp releases API - Uses jq to parse API response when available, falls back to sed - Fetches download URL directly from API (with fallback to constructed URL) - Optionally configures token authentication if provided - Optionally configures Vault Enterprise namespace if provided - Sets up VAULT_ADDR environment variable - Conditionally sets VAULT_TOKEN environment variable when token is provided - Conditionally sets VAULT_NAMESPACE environment variable when namespace is provided - Validates vault_cli_version must be 'latest' or a semantic version without v prefix The module can be used standalone for just CLI installation, or with a token and/or namespace for authentication scenarios. --- registry/coder/modules/vault-cli/README.md | 99 ++++++++++ registry/coder/modules/vault-cli/main.tf | 90 +++++++++ .../coder/modules/vault-cli/main.tftest.hcl | 165 +++++++++++++++++ registry/coder/modules/vault-cli/run.sh | 172 ++++++++++++++++++ 4 files changed, 526 insertions(+) create mode 100644 registry/coder/modules/vault-cli/README.md create mode 100644 registry/coder/modules/vault-cli/main.tf create mode 100644 registry/coder/modules/vault-cli/main.tftest.hcl create mode 100644 registry/coder/modules/vault-cli/run.sh diff --git a/registry/coder/modules/vault-cli/README.md b/registry/coder/modules/vault-cli/README.md new file mode 100644 index 000000000..16f826509 --- /dev/null +++ b/registry/coder/modules/vault-cli/README.md @@ -0,0 +1,99 @@ +--- +display_name: Vault CLI +description: Installs the Hashicorp Vault CLI and optionally configures token authentication +icon: ../../../../.icons/vault.svg +verified: true +tags: [helper, integration, vault, cli] +--- + +# Vault CLI + +Installs the [Vault](https://www.vaultproject.io/) CLI and optionally configures token authentication. This module focuses on CLI installation and can be used standalone or as a base for other authentication methods. + +```tf +module "vault_cli" { + source = "registry.coder.com/coder/vault-cli/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + vault_addr = "https://vault.example.com" +} +``` + +## With Token Authentication + +If you have a Vault token, you can provide it to automatically configure authentication: + +```tf +module "vault_cli" { + source = "registry.coder.com/coder/vault-cli/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + vault_addr = "https://vault.example.com" + vault_token = var.vault_token # Optional +} +``` + +## Examples + +### Basic Installation (CLI Only) + +Install the Vault CLI without any authentication: + +```tf +module "vault_cli" { + source = "registry.coder.com/coder/vault-cli/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + vault_addr = "https://vault.example.com" +} +``` + +### With Specific Version + +```tf +module "vault_cli" { + source = "registry.coder.com/coder/vault-cli/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + vault_addr = "https://vault.example.com" + vault_cli_version = "1.15.0" +} +``` + +### Custom Installation Directory + +```tf +module "vault_cli" { + source = "registry.coder.com/coder/vault-cli/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + vault_addr = "https://vault.example.com" + install_dir = "/home/coder/bin" +} +``` + +### With Vault Enterprise Namespace + +For Vault Enterprise users who need to specify a namespace: + +```tf +module "vault_cli" { + source = "registry.coder.com/coder/vault-cli/coder" + version = "1.0.0" + agent_id = coder_agent.example.id + vault_addr = "https://vault.example.com" + vault_token = var.vault_token + vault_namespace = "admin/my-namespace" +} +``` + +## Related Modules + +For more advanced authentication methods, see: + +- [vault-github](https://registry.coder.com/modules/coder/vault-github) - Authenticate with Vault using GitHub tokens +- [vault-jwt](https://registry.coder.com/modules/coder/vault-jwt) - Authenticate with Vault using OIDC/JWT + +For simple token-based authentication, see: + +- [vault-token](https://registry.coder.com/modules/coder/vault-token) - Authenticate with Vault using a token diff --git a/registry/coder/modules/vault-cli/main.tf b/registry/coder/modules/vault-cli/main.tf new file mode 100644 index 000000000..eaacb66b0 --- /dev/null +++ b/registry/coder/modules/vault-cli/main.tf @@ -0,0 +1,90 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.17" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "vault_addr" { + type = string + description = "The address of the Vault server." +} + +variable "vault_token" { + type = string + description = "The Vault token to use for authentication. If not provided, only the CLI will be installed." + default = "" + sensitive = true +} + +variable "install_dir" { + type = string + description = "The directory to install the Vault CLI to." + default = "/usr/local/bin" +} + +variable "vault_cli_version" { + type = string + description = "The version of the Vault CLI to install." + default = "latest" + validation { + condition = var.vault_cli_version == "latest" || can(regex("^[0-9]+\\.[0-9]+\\.[0-9]+$", var.vault_cli_version)) + error_message = "vault_cli_version must be either 'latest' or a semantic version (e.g., '1.15.0')." + } +} + +variable "vault_namespace" { + type = string + description = "The Vault Enterprise namespace to use. If not provided, no namespace will be configured." + default = null +} + +data "coder_workspace" "me" {} + +resource "coder_script" "vault_cli" { + agent_id = var.agent_id + display_name = "Vault CLI" + icon = "/icon/vault.svg" + script = templatefile("${path.module}/run.sh", { + VAULT_ADDR = var.vault_addr + VAULT_TOKEN = var.vault_token + INSTALL_DIR = var.install_dir + VAULT_CLI_VERSION = var.vault_cli_version + }) + run_on_start = true + start_blocks_login = true +} + +resource "coder_env" "vault_addr" { + agent_id = var.agent_id + name = "VAULT_ADDR" + value = var.vault_addr +} + +resource "coder_env" "vault_token" { + count = var.vault_token != "" ? 1 : 0 + agent_id = var.agent_id + name = "VAULT_TOKEN" + value = var.vault_token +} + +resource "coder_env" "vault_namespace" { + count = var.vault_namespace != null ? 1 : 0 + agent_id = var.agent_id + name = "VAULT_NAMESPACE" + value = var.vault_namespace +} + +output "vault_cli_version" { + description = "The version of the Vault CLI that was installed." + value = var.vault_cli_version +} diff --git a/registry/coder/modules/vault-cli/main.tftest.hcl b/registry/coder/modules/vault-cli/main.tftest.hcl new file mode 100644 index 000000000..94a9b7aca --- /dev/null +++ b/registry/coder/modules/vault-cli/main.tftest.hcl @@ -0,0 +1,165 @@ +mock_provider "coder" {} + +variables { + agent_id = "test-agent-id" + vault_addr = "https://vault.example.com" +} + +run "test_vault_cli_without_token" { + assert { + condition = resource.coder_script.vault_cli.display_name == "Vault CLI" + error_message = "Display name should be 'Vault CLI'" + } + + assert { + condition = resource.coder_env.vault_addr.name == "VAULT_ADDR" + error_message = "VAULT_ADDR environment variable should be set" + } + + assert { + condition = resource.coder_env.vault_addr.value == "https://vault.example.com" + error_message = "VAULT_ADDR should match the provided vault_addr" + } + + assert { + condition = length(resource.coder_env.vault_token) == 0 + error_message = "VAULT_TOKEN should not be set when vault_token is not provided" + } + + assert { + condition = length(resource.coder_env.vault_namespace) == 0 + error_message = "VAULT_NAMESPACE should not be set when vault_namespace is not provided" + } +} + +run "test_vault_cli_with_token" { + variables { + vault_token = "test-vault-token" + } + + assert { + condition = resource.coder_script.vault_cli.display_name == "Vault CLI" + error_message = "Display name should be 'Vault CLI'" + } + + assert { + condition = resource.coder_env.vault_addr.name == "VAULT_ADDR" + error_message = "VAULT_ADDR environment variable should be set" + } + + assert { + condition = length(resource.coder_env.vault_token) == 1 + error_message = "VAULT_TOKEN should be set when vault_token is provided" + } + + assert { + condition = resource.coder_env.vault_token[0].name == "VAULT_TOKEN" + error_message = "VAULT_TOKEN environment variable name should be correct" + } + + assert { + condition = resource.coder_env.vault_token[0].value == "test-vault-token" + error_message = "VAULT_TOKEN should match the provided vault_token" + } +} + +run "test_vault_cli_custom_version" { + variables { + vault_cli_version = "1.15.0" + } + + assert { + condition = output.vault_cli_version == "1.15.0" + error_message = "Vault CLI version output should match the provided version" + } +} + +run "test_vault_cli_custom_install_dir" { + variables { + install_dir = "/custom/install/dir" + } + + assert { + condition = resource.coder_script.vault_cli.display_name == "Vault CLI" + error_message = "Display name should be 'Vault CLI'" + } +} + +run "test_vault_cli_invalid_version" { + command = plan + + variables { + vault_cli_version = "invalid-version" + } + + expect_failures = [var.vault_cli_version] +} + +run "test_vault_cli_valid_semver" { + variables { + vault_cli_version = "1.18.3" + } + + assert { + condition = output.vault_cli_version == "1.18.3" + error_message = "Vault CLI version output should match the provided version" + } +} + +run "test_vault_cli_rejects_v_prefix" { + command = plan + + variables { + vault_cli_version = "v1.18.3" + } + + expect_failures = [var.vault_cli_version] +} + +run "test_vault_cli_with_namespace" { + variables { + vault_namespace = "admin/my-namespace" + } + + assert { + condition = length(resource.coder_env.vault_namespace) == 1 + error_message = "VAULT_NAMESPACE should be set when vault_namespace is provided" + } + + assert { + condition = resource.coder_env.vault_namespace[0].name == "VAULT_NAMESPACE" + error_message = "VAULT_NAMESPACE environment variable name should be correct" + } + + assert { + condition = resource.coder_env.vault_namespace[0].value == "admin/my-namespace" + error_message = "VAULT_NAMESPACE should match the provided vault_namespace" + } +} + +run "test_vault_cli_with_token_and_namespace" { + variables { + vault_token = "test-vault-token" + vault_namespace = "admin/my-namespace" + } + + assert { + condition = length(resource.coder_env.vault_token) == 1 + error_message = "VAULT_TOKEN should be set when vault_token is provided" + } + + assert { + condition = length(resource.coder_env.vault_namespace) == 1 + error_message = "VAULT_NAMESPACE should be set when vault_namespace is provided" + } + + assert { + condition = resource.coder_env.vault_token[0].value == "test-vault-token" + error_message = "VAULT_TOKEN should match the provided vault_token" + } + + assert { + condition = resource.coder_env.vault_namespace[0].value == "admin/my-namespace" + error_message = "VAULT_NAMESPACE should match the provided vault_namespace" + } +} diff --git a/registry/coder/modules/vault-cli/run.sh b/registry/coder/modules/vault-cli/run.sh new file mode 100644 index 000000000..a80eff09e --- /dev/null +++ b/registry/coder/modules/vault-cli/run.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash + +# Convert all templated variables to shell variables +VAULT_ADDR=${VAULT_ADDR} +VAULT_TOKEN=${VAULT_TOKEN} +INSTALL_DIR=${INSTALL_DIR} +VAULT_CLI_VERSION=${VAULT_CLI_VERSION} + +fetch() { + dest="$1" + url="$2" + if command -v curl > /dev/null 2>&1; then + curl -sSL --fail "$${url}" -o "$${dest}" + elif command -v wget > /dev/null 2>&1; then + wget -O "$${dest}" "$${url}" + elif command -v busybox > /dev/null 2>&1; then + busybox wget -O "$${dest}" "$${url}" + else + printf "curl, wget, or busybox is not installed. Please install curl or wget in your image.\n" + return 1 + fi +} + +unzip_safe() { + if command -v unzip > /dev/null 2>&1; then + command unzip "$@" + elif command -v busybox > /dev/null 2>&1; then + busybox unzip "$@" + else + printf "unzip or busybox is not installed. Please install unzip in your image.\n" + return 1 + fi +} + +install() { + # Get the architecture of the system + ARCH=$(uname -m) + if [ "$${ARCH}" = "x86_64" ]; then + ARCH="amd64" + elif [ "$${ARCH}" = "aarch64" ]; then + ARCH="arm64" + else + printf "Unsupported architecture: %s\n" "$${ARCH}" + return 1 + fi + + # Determine OS and validate + OS=$(uname -s | tr '[:upper:]' '[:lower:]') + if [ "$${OS}" != "linux" ] && [ "$${OS}" != "darwin" ]; then + printf "Unsupported OS: %s. Only linux and darwin are supported.\n" "$${OS}" + return 1 + fi + + # Fetch release information from HashiCorp API + if [ "$${VAULT_CLI_VERSION}" = "latest" ]; then + API_URL="https://api.releases.hashicorp.com/v1/releases/vault/latest" + else + API_URL="https://api.releases.hashicorp.com/v1/releases/vault/$${VAULT_CLI_VERSION}" + fi + + API_RESPONSE=$(curl -s "$${API_URL}") + if [ -z "$${API_RESPONSE}" ]; then + printf "Failed to fetch release information from HashiCorp API.\n" + return 1 + fi + + # Parse version and download URL from API response + if command -v jq > /dev/null 2>&1; then + VAULT_CLI_VERSION=$(printf '%s' "$${API_RESPONSE}" | jq -r '.version') + DOWNLOAD_URL=$(printf '%s' "$${API_RESPONSE}" | jq -r --arg os "$${OS}" --arg arch "$${ARCH}" '.builds[] | select(.os == $os and .arch == $arch) | .url') + else + VAULT_CLI_VERSION=$(printf '%s' "$${API_RESPONSE}" | sed -n 's/.*"version":"\([^"]*\)".*/\1/p') + # Fallback: construct URL manually if jq not available + DOWNLOAD_URL="https://releases.hashicorp.com/vault/$${VAULT_CLI_VERSION}/vault_$${VAULT_CLI_VERSION}_$${OS}_$${ARCH}.zip" + fi + + if [ -z "$${VAULT_CLI_VERSION}" ]; then + printf "Failed to determine Vault version.\n" + return 1 + fi + + if [ -z "$${DOWNLOAD_URL}" ]; then + printf "Failed to determine download URL for Vault %s (%s/%s).\n" "$${VAULT_CLI_VERSION}" "$${OS}" "$${ARCH}" + return 1 + fi + + printf "Vault version: %s\n" "$${VAULT_CLI_VERSION}" + + # Check if the vault CLI is installed and has the correct version + installation_needed=1 + if command -v vault > /dev/null 2>&1; then + CURRENT_VERSION=$(vault version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+') + if [ "$${CURRENT_VERSION}" = "$${VAULT_CLI_VERSION}" ]; then + printf "Vault version %s is already installed and up-to-date.\n\n" "$${CURRENT_VERSION}" + installation_needed=0 + fi + fi + + if [ "$${installation_needed}" = "1" ]; then + # Download and install Vault + if [ -z "$${CURRENT_VERSION}" ]; then + printf "Installing Vault CLI ...\n\n" + else + printf "Upgrading Vault CLI from version %s to %s ...\n\n" "$${CURRENT_VERSION}" "$${VAULT_CLI_VERSION}" + fi + + # Create temporary directory for download + TEMP_DIR=$(mktemp -d) + cd "$${TEMP_DIR}" || return 1 + + printf "Downloading from %s\n" "$${DOWNLOAD_URL}" + if ! fetch vault.zip "$${DOWNLOAD_URL}"; then + printf "Failed to download Vault.\n" + rm -rf "$${TEMP_DIR}" + return 1 + fi + if ! unzip_safe vault.zip; then + printf "Failed to unzip Vault.\n" + rm -rf "$${TEMP_DIR}" + return 1 + fi + + # Install to the specified directory + if [ -n "$${INSTALL_DIR}" ] && [ -w "$${INSTALL_DIR}" ]; then + mv vault "$${INSTALL_DIR}/vault" + printf "Vault installed to %s successfully!\n\n" "$${INSTALL_DIR}" + elif [ -n "$${INSTALL_DIR}" ] && [ ! -w "$${INSTALL_DIR}" ]; then + # Try with sudo if install dir specified but not writable + if sudo mv vault "$${INSTALL_DIR}/vault" 2> /dev/null; then + printf "Vault installed to %s successfully!\n\n" "$${INSTALL_DIR}" + else + printf "Warning: Cannot write to %s. " "$${INSTALL_DIR}" + mkdir -p ~/.local/bin + if mv vault ~/.local/bin/vault; then + printf "Installed to ~/.local/bin instead.\n" + printf "Please add ~/.local/bin to your PATH to use vault CLI.\n" + else + printf "Failed to install Vault.\n" + rm -rf "$${TEMP_DIR}" + return 1 + fi + fi + elif sudo mv vault /usr/local/bin/vault 2> /dev/null; then + printf "Vault installed successfully!\n\n" + else + mkdir -p ~/.local/bin + if ! mv vault ~/.local/bin/vault; then + printf "Failed to move Vault to local bin.\n" + rm -rf "$${TEMP_DIR}" + return 1 + fi + printf "Please add ~/.local/bin to your PATH to use vault CLI.\n" + fi + + # Clean up temp directory + rm -rf "$${TEMP_DIR}" + fi + return 0 +} + +# Run installation +if ! install; then + printf "Failed to install Vault CLI.\n" + exit 1 +fi + +# Indicate token configuration status +if [ -n "$${VAULT_TOKEN}" ]; then + printf "Vault token has been configured via VAULT_TOKEN environment variable.\n" +else + printf "No Vault token provided. Use 'vault login' or set VAULT_TOKEN to authenticate.\n" +fi From 9115d27ca7c591cef19a153b21c3dc151f57c884 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 3 Dec 2025 12:26:42 +0000 Subject: [PATCH 2/7] Merge fetch functions into single function with optional dest parameter Address review feedback: - Combine fetch_stdout() and fetch() into single fetch() function - fetch outputs to stdout, fetch writes to file - HTTP client detection is cached and reused for both cases - Fixes issue where curl was used explicitly for API calls but fetch() function supported wget/busybox --- registry/coder/modules/vault-cli/run.sh | 44 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/registry/coder/modules/vault-cli/run.sh b/registry/coder/modules/vault-cli/run.sh index a80eff09e..022c29fea 100644 --- a/registry/coder/modules/vault-cli/run.sh +++ b/registry/coder/modules/vault-cli/run.sh @@ -6,18 +6,38 @@ VAULT_TOKEN=${VAULT_TOKEN} INSTALL_DIR=${INSTALL_DIR} VAULT_CLI_VERSION=${VAULT_CLI_VERSION} +# Fetch URL content. If dest is provided, write to file; otherwise output to stdout. +# Usage: fetch [dest] fetch() { - dest="$1" - url="$2" - if command -v curl > /dev/null 2>&1; then - curl -sSL --fail "$${url}" -o "$${dest}" - elif command -v wget > /dev/null 2>&1; then - wget -O "$${dest}" "$${url}" - elif command -v busybox > /dev/null 2>&1; then - busybox wget -O "$${dest}" "$${url}" + url="$1" + dest="$${2:-}" + + # Detect HTTP client on first run + if [ -z "$${HTTP_CLIENT:-}" ]; then + if command -v curl > /dev/null 2>&1; then + HTTP_CLIENT="curl" + elif command -v wget > /dev/null 2>&1; then + HTTP_CLIENT="wget" + elif command -v busybox > /dev/null 2>&1; then + HTTP_CLIENT="busybox" + else + printf "curl, wget, or busybox is not installed. Please install curl or wget in your image.\n" + return 1 + fi + fi + + if [ -n "$${dest}" ]; then + case "$${HTTP_CLIENT}" in + curl) curl -sSL --fail "$${url}" -o "$${dest}" ;; + wget) wget -O "$${dest}" "$${url}" ;; + busybox) busybox wget -O "$${dest}" "$${url}" ;; + esac else - printf "curl, wget, or busybox is not installed. Please install curl or wget in your image.\n" - return 1 + case "$${HTTP_CLIENT}" in + curl) curl -sSL --fail "$${url}" ;; + wget) wget -qO- "$${url}" ;; + busybox) busybox wget -qO- "$${url}" ;; + esac fi } @@ -58,7 +78,7 @@ install() { API_URL="https://api.releases.hashicorp.com/v1/releases/vault/$${VAULT_CLI_VERSION}" fi - API_RESPONSE=$(curl -s "$${API_URL}") + API_RESPONSE=$(fetch "$${API_URL}") if [ -z "$${API_RESPONSE}" ]; then printf "Failed to fetch release information from HashiCorp API.\n" return 1 @@ -109,7 +129,7 @@ install() { cd "$${TEMP_DIR}" || return 1 printf "Downloading from %s\n" "$${DOWNLOAD_URL}" - if ! fetch vault.zip "$${DOWNLOAD_URL}"; then + if ! fetch "$${DOWNLOAD_URL}" vault.zip; then printf "Failed to download Vault.\n" rm -rf "$${TEMP_DIR}" return 1 From 7bd41fc92b13c630e849d9dceb1ddda2c997566b Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 3 Dec 2025 13:04:00 +0000 Subject: [PATCH 3/7] Add prerequisites section to README documenting required tools --- registry/coder/modules/vault-cli/README.md | 7 +++++++ registry/coder/modules/vault-cli/run.sh | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/registry/coder/modules/vault-cli/README.md b/registry/coder/modules/vault-cli/README.md index 16f826509..1da562b70 100644 --- a/registry/coder/modules/vault-cli/README.md +++ b/registry/coder/modules/vault-cli/README.md @@ -10,6 +10,13 @@ tags: [helper, integration, vault, cli] Installs the [Vault](https://www.vaultproject.io/) CLI and optionally configures token authentication. This module focuses on CLI installation and can be used standalone or as a base for other authentication methods. +## Prerequisites + +The following tools are required in the workspace image: + +- **HTTP client**: `curl`, `wget`, or `busybox` (at least one) +- **Archive utility**: `unzip` or `busybox` (at least one) + ```tf module "vault_cli" { source = "registry.coder.com/coder/vault-cli/coder" diff --git a/registry/coder/modules/vault-cli/run.sh b/registry/coder/modules/vault-cli/run.sh index 022c29fea..9012bc7c9 100644 --- a/registry/coder/modules/vault-cli/run.sh +++ b/registry/coder/modules/vault-cli/run.sh @@ -28,14 +28,14 @@ fetch() { if [ -n "$${dest}" ]; then case "$${HTTP_CLIENT}" in - curl) curl -sSL --fail "$${url}" -o "$${dest}" ;; - wget) wget -O "$${dest}" "$${url}" ;; + curl) curl -sSL --fail "$${url}" -o "$${dest}" ;; + wget) wget -O "$${dest}" "$${url}" ;; busybox) busybox wget -O "$${dest}" "$${url}" ;; esac else case "$${HTTP_CLIENT}" in - curl) curl -sSL --fail "$${url}" ;; - wget) wget -qO- "$${url}" ;; + curl) curl -sSL --fail "$${url}" ;; + wget) wget -qO- "$${url}" ;; busybox) busybox wget -qO- "$${url}" ;; esac fi From b10036516a6ff37de82d50587177c9539e77426f Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 3 Dec 2025 13:04:17 +0000 Subject: [PATCH 4/7] Add jq as recommended tool in prerequisites --- registry/coder/modules/vault-cli/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/registry/coder/modules/vault-cli/README.md b/registry/coder/modules/vault-cli/README.md index 1da562b70..feba11381 100644 --- a/registry/coder/modules/vault-cli/README.md +++ b/registry/coder/modules/vault-cli/README.md @@ -17,6 +17,10 @@ The following tools are required in the workspace image: - **HTTP client**: `curl`, `wget`, or `busybox` (at least one) - **Archive utility**: `unzip` or `busybox` (at least one) +**Recommended:** + +- **jq**: For reliable JSON parsing of the HashiCorp releases API (falls back to sed if not available) + ```tf module "vault_cli" { source = "registry.coder.com/coder/vault-cli/coder" From daba3438b5412a50f58305cd0f5950ac5a205350 Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 3 Dec 2025 13:05:35 +0000 Subject: [PATCH 5/7] Simplify prerequisites formatting --- registry/coder/modules/vault-cli/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/registry/coder/modules/vault-cli/README.md b/registry/coder/modules/vault-cli/README.md index feba11381..35e817281 100644 --- a/registry/coder/modules/vault-cli/README.md +++ b/registry/coder/modules/vault-cli/README.md @@ -16,10 +16,7 @@ The following tools are required in the workspace image: - **HTTP client**: `curl`, `wget`, or `busybox` (at least one) - **Archive utility**: `unzip` or `busybox` (at least one) - -**Recommended:** - -- **jq**: For reliable JSON parsing of the HashiCorp releases API (falls back to sed if not available) +- **jq**: Optional but recommended for reliable JSON parsing (falls back to sed if not available) ```tf module "vault_cli" { From ed935218f2281b4b86e61810d8585d83a66d39bf Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 3 Dec 2025 13:18:44 +0000 Subject: [PATCH 6/7] Move Prerequisites section after first code block README validation requires Terraform code block in h1 section --- registry/coder/modules/vault-cli/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/registry/coder/modules/vault-cli/README.md b/registry/coder/modules/vault-cli/README.md index 35e817281..776ec6bee 100644 --- a/registry/coder/modules/vault-cli/README.md +++ b/registry/coder/modules/vault-cli/README.md @@ -10,14 +10,6 @@ tags: [helper, integration, vault, cli] Installs the [Vault](https://www.vaultproject.io/) CLI and optionally configures token authentication. This module focuses on CLI installation and can be used standalone or as a base for other authentication methods. -## Prerequisites - -The following tools are required in the workspace image: - -- **HTTP client**: `curl`, `wget`, or `busybox` (at least one) -- **Archive utility**: `unzip` or `busybox` (at least one) -- **jq**: Optional but recommended for reliable JSON parsing (falls back to sed if not available) - ```tf module "vault_cli" { source = "registry.coder.com/coder/vault-cli/coder" @@ -27,6 +19,14 @@ module "vault_cli" { } ``` +## Prerequisites + +The following tools are required in the workspace image: + +- **HTTP client**: `curl`, `wget`, or `busybox` (at least one) +- **Archive utility**: `unzip` or `busybox` (at least one) +- **jq**: Optional but recommended for reliable JSON parsing (falls back to sed if not available) + ## With Token Authentication If you have a Vault token, you can provide it to automatically configure authentication: From f295070544da60a04046dd590f373ff21810db7d Mon Sep 17 00:00:00 2001 From: Atif Ali Date: Wed, 3 Dec 2025 14:06:31 +0000 Subject: [PATCH 7/7] fix: add shellcheck disable SC2195 for Terraform-templated case statements The $${} syntax is Terraform template escaping which shellcheck doesn't understand. Added disable directive for both case statements in the fetch() function. --- registry/coder/modules/vault-cli/run.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/registry/coder/modules/vault-cli/run.sh b/registry/coder/modules/vault-cli/run.sh index 9012bc7c9..a1917f994 100644 --- a/registry/coder/modules/vault-cli/run.sh +++ b/registry/coder/modules/vault-cli/run.sh @@ -27,12 +27,14 @@ fetch() { fi if [ -n "$${dest}" ]; then + # shellcheck disable=SC2195 case "$${HTTP_CLIENT}" in curl) curl -sSL --fail "$${url}" -o "$${dest}" ;; wget) wget -O "$${dest}" "$${url}" ;; busybox) busybox wget -O "$${dest}" "$${url}" ;; esac else + # shellcheck disable=SC2195 case "$${HTTP_CLIENT}" in curl) curl -sSL --fail "$${url}" ;; wget) wget -qO- "$${url}" ;;