Compare commits

..

11 Commits

Author SHA1 Message Date
Austen Bruhn a7a4ae4cdf Merge branch 'main' into aws-cli-module 2025-11-18 14:34:14 -07:00
Austen Bruhn be4dc937b5 Address PR review comments
- Add set -e for strict error handling
- Exit on version mismatch with clear error message
- Use >> for log appending (was overwriting with >)
- Add error checking after curl, unzip, and install commands
- Add macOS architecture-specific download URLs
- Move autocomplete config after successful installation verification
2025-11-15 18:33:05 -07:00
Austen Bruhn 7a70127f35 Add download_url parameter for airgapped environment support 2025-11-15 18:20:24 -07:00
Austen Bruhn 2039c3908b Update namespace profile with personal info and GitHub avatar 2025-11-15 18:12:47 -07:00
Austen Bruhn eef8697f52 Merge remote-tracking branch 'origin/main' into aws-cli-module 2025-11-15 17:54:32 -07:00
Austen Bruhn 3393a04272 Add AWS CLI autocomplete support for bash, zsh, and fish shells 2025-11-15 17:50:21 -07:00
Austen Bruhn 75fd523215 Add aws-cli module for ausbru87 namespace 2025-11-15 17:23:42 -07:00
Austen Bruhn 5564a552ba Remove trailing whitespace from README.md
Fix formatting issue on line 56 that was causing CI check to fail
2025-11-15 17:01:21 -07:00
Austen Bruhn fca4fdf2ef Fix formatting issues in AWS CLI module
- Format README.md tables with proper column alignment
- Add spaces around redirect operators in run.sh
- Remove trailing whitespace
- Update bun.lock with installed dependencies
2025-11-15 16:57:30 -07:00
Austen Bruhn c22fb8bcdc Restructure AWS CLI module to personal namespace
- Create ausbru87 namespace with avatar and README
- Move aws-cli module from registry/coder to registry/ausbru87
- Update all source paths to registry.coder.com/modules/ausbru87/aws-cli
- Follows contribution guidelines for community modules
2025-11-15 16:54:36 -07:00
Austen Bruhn fdaaba7378 Add AWS CLI module for Coder Registry
- Installs AWS CLI v2 in Coder workspaces
- Supports x86_64 and ARM64 architectures with auto-detection
- Allows version pinning or installs latest version
- Optional GPG signature verification for security
- Idempotent installation (skips if already installed)
- Supports custom installation directories
- Includes comprehensive tests (Terraform + TypeScript)
- Full documentation with multiple usage examples
2025-11-15 16:47:07 -07:00
19 changed files with 346 additions and 90 deletions
+12 -29
View File
@@ -70,38 +70,21 @@ update_readme_version() {
if grep -q "source.*${module_source}" "$readme_path"; then
echo "Updating version references for $namespace/$module_name in $readme_path"
awk -v module_source="$module_source" -v new_version="$new_version" '
/^[[:space:]]*module[[:space:]]/ {
in_module_block = 1
module_content = $0 "\n"
module_has_target_source = 0
next
}
in_module_block {
module_content = module_content $0 "\n"
if ($0 ~ /source.*=/ && $0 ~ module_source) {
module_has_target_source = 1
/source.*=.*/ {
if ($0 ~ module_source) {
in_target_module = 1
} else {
in_target_module = 0
}
if ($0 ~ /^[[:space:]]*}[[:space:]]*$/) {
in_module_block = 0
if (module_has_target_source) {
num_lines = split(module_content, lines, "\n")
for (i = 1; i <= num_lines; i++) {
line = lines[i]
if (line ~ /^[[:space:]]*version[[:space:]]*=/) {
match(line, /^[[:space:]]*/)
indent = substr(line, 1, RLENGTH)
printf "%sversion = \"%s\"\n", indent, new_version
} else {
print line
}
}
} else {
printf "%s", module_content
}
module_content = ""
}
/^[[:space:]]*version[[:space:]]*=/ {
if (in_target_module) {
match($0, /^[[:space]]*/
indent = substr($0, 1, RLENGTH)
print indent "version = \"" new_version "\""
in_target_module = 0
next
}
next
}
{ print }
' "$readme_path" > "${readme_path}.tmp" && mv "${readme_path}.tmp" "$readme_path"
+1
View File
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "registry",
Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

+32
View File
@@ -0,0 +1,32 @@
---
display_name: Austen Bruhn
bio: Solution Engineer at Coder, OSS enthusiast
github: ausbru87
avatar: ./.images/avatar.png
linkedin: https://www.linkedin.com/in/austen-bruhn-b0a646a1/
status: community
---
# ausbru87
Brief description of what this namespace provides. Include information about:
- What types of templates/modules you offer
- Your focus areas (e.g., specific cloud providers, technologies)
- Any special features or configurations
## Templates
List your available templates here:
- **template-name**: Brief description
## Modules
List your available modules here:
- **module-name**: Brief description
## Contributing
If you'd like to contribute to this namespace, please [open an issue](https://github.com/coder/registry/issues) or submit a pull request.
@@ -0,0 +1,78 @@
---
display_name: AWS CLI
description: Install AWS CLI v2 in your workspace
icon: ../../../../.icons/aws.svg
verified: false
tags: [helper, aws, cli]
---
# AWS CLI
Automatically install the [AWS CLI v2](https://aws.amazon.com/cli/) in your Coder workspace with command autocomplete support for bash, zsh, and fish shells.
```tf
module "aws-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/ausbru87/aws-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
}
```
## Features
- Installs AWS CLI v2 for Linux and macOS
- Supports x86_64 and ARM64 architectures
- Optional version pinning
- **Auto-configures command autocomplete** for bash, zsh, and fish shells
## Examples
### Basic Installation
```tf
module "aws-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/ausbru87/aws-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
}
```
### Pin to Specific Version
```tf
module "aws-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/ausbru87/aws-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
install_version = "2.15.0"
}
```
### Custom Log Path
```tf
module "aws-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/ausbru87/aws-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
log_path = "/var/log/aws-cli.log"
}
```
### Airgapped Environment
Use a custom download URL for environments without internet access to AWS:
```tf
module "aws-cli" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/ausbru87/aws-cli/coder"
version = "1.0.0"
agent_id = coder_agent.example.id
download_url = "https://internal-mirror.company.com/awscli-exe-linux-x86_64.zip"
}
```
@@ -0,0 +1,34 @@
run "required_vars" {
command = plan
variables {
agent_id = "test-agent-id"
}
}
run "with_custom_version" {
command = plan
variables {
agent_id = "test-agent-id"
install_version = "2.15.0"
}
}
run "with_custom_log_path" {
command = plan
variables {
agent_id = "test-agent-id"
log_path = "/var/log/aws-cli.log"
}
}
run "with_custom_download_url" {
command = plan
variables {
agent_id = "test-agent-id"
download_url = "https://internal-mirror.company.com/awscli-exe-linux-x86_64.zip"
}
}
+46
View File
@@ -0,0 +1,46 @@
terraform {
required_version = ">= 1.0"
required_providers {
coder = {
source = "coder/coder"
version = ">= 2.5"
}
}
}
variable "agent_id" {
type = string
description = "The ID of a Coder agent."
}
variable "install_version" {
type = string
description = "The version of AWS CLI to install."
default = ""
}
variable "download_url" {
type = string
description = "Custom download URL for AWS CLI. Useful for airgapped environments. If not set, uses the official AWS download URL."
default = ""
}
variable "log_path" {
type = string
description = "The path to the AWS CLI installation log file."
default = "/tmp/aws-cli-install.log"
}
resource "coder_script" "aws-cli" {
agent_id = var.agent_id
display_name = "AWS CLI"
icon = "/icon/aws.svg"
script = templatefile("${path.module}/run.sh", {
LOG_PATH : var.log_path,
VERSION : var.install_version,
DOWNLOAD_URL : var.download_url,
})
run_on_start = true
run_on_stop = false
}
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env sh
set -e
LOG_PATH=${LOG_PATH}
VERSION=${VERSION}
DOWNLOAD_URL=${DOWNLOAD_URL}
BOLD='\\033[0;1m'
RESET='\\033[0m'
printf "${BOLD}Installing AWS CLI...\\n${RESET}"
# Check if AWS CLI is already installed
if command -v aws > /dev/null 2>&1; then
INSTALLED_VERSION=$(aws --version 2>&1 | cut -d' ' -f1 | cut -d'/' -f2)
if [ -n "$VERSION" ] && [ "$INSTALLED_VERSION" != "$VERSION" ]; then
printf "❌ AWS CLI $INSTALLED_VERSION is installed, but version $VERSION was requested.\\n"
printf "Note: AWS CLI installer does not support version-specific installation.\\n"
exit 1
else
printf "AWS CLI is already installed ($INSTALLED_VERSION). Skipping installation.\\n"
exit 0
fi
fi
# Determine OS and architecture
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ARCH="x86_64" ;;
aarch64 | arm64) ARCH="aarch64" ;;
*)
printf "Unsupported architecture: $ARCH\\n" >> "${LOG_PATH}" 2>&1
exit 1
;;
esac
# Install AWS CLI
if [ "$OS" = "linux" ]; then
# Use custom download URL if provided, otherwise use default AWS URL
if [ -z "$DOWNLOAD_URL" ]; then
DOWNLOAD_URL="https://awscli.amazonaws.com/awscli-exe-linux-${ARCH}.zip"
fi
printf "Downloading AWS CLI from $DOWNLOAD_URL...\\n"
curl -fsSL "$DOWNLOAD_URL" -o /tmp/awscliv2.zip >> "${LOG_PATH}" 2>&1 || exit 1
unzip -q /tmp/awscliv2.zip -d /tmp >> "${LOG_PATH}" 2>&1 || exit 1
sudo /tmp/aws/install >> "${LOG_PATH}" 2>&1 || exit 1
rm -rf /tmp/awscliv2.zip /tmp/aws
elif [ "$OS" = "darwin" ]; then
# Use custom download URL if provided, otherwise use architecture-specific AWS URL
if [ -z "$DOWNLOAD_URL" ]; then
case "$ARCH" in
x86_64)
DOWNLOAD_URL="https://awscli.amazonaws.com/AWSCLIV2-x86_64.pkg"
;;
aarch64)
DOWNLOAD_URL="https://awscli.amazonaws.com/AWSCLIV2-arm64.pkg"
;;
*)
DOWNLOAD_URL="https://awscli.amazonaws.com/AWSCLIV2.pkg"
;;
esac
fi
printf "Downloading AWS CLI from $DOWNLOAD_URL...\\n"
curl -fsSL "$DOWNLOAD_URL" -o /tmp/AWSCLIV2.pkg >> "${LOG_PATH}" 2>&1 || exit 1
sudo installer -pkg /tmp/AWSCLIV2.pkg -target / >> "${LOG_PATH}" 2>&1 || exit 1
rm -f /tmp/AWSCLIV2.pkg
else
printf "Unsupported OS: $OS\\n" >> "${LOG_PATH}" 2>&1
exit 1
fi
# Verify installation was successful
if command -v aws > /dev/null 2>&1; then
printf "🥳 AWS CLI installed successfully!\\n"
aws --version
# Configure autocomplete for common shells
if command -v aws_completer > /dev/null 2>&1; then
AWS_COMPLETER_PATH=$(which aws_completer)
# Bash autocomplete
if [ -f ~/.bashrc ]; then
if ! grep -q "aws_completer.*aws" ~/.bashrc; then
echo "complete -C '$AWS_COMPLETER_PATH' aws" >> ~/.bashrc
printf "✓ Configured AWS CLI autocomplete for bash\\n"
fi
fi
# Zsh autocomplete
if [ -f ~/.zshrc ] || [ -d ~/.oh-my-zsh ]; then
if ! grep -q "aws_completer.*aws" ~/.zshrc 2> /dev/null; then
cat >> ~/.zshrc << ZSHEOF
# AWS CLI autocomplete
autoload bashcompinit && bashcompinit
autoload -Uz compinit && compinit
complete -C '$AWS_COMPLETER_PATH' aws
ZSHEOF
printf "✓ Configured AWS CLI autocomplete for zsh\\n"
fi
fi
# Fish autocomplete
if [ -d ~/.config/fish ] || command -v fish > /dev/null 2>&1; then
mkdir -p ~/.config/fish/completions
FISH_COMPLETION=~/.config/fish/completions/aws.fish
if [ ! -f "$FISH_COMPLETION" ]; then
cat > "$FISH_COMPLETION" << 'FISHEOF'
complete --command aws --no-files --arguments '(begin; set --local --export COMP_SHELL fish; set --local --export COMP_LINE (commandline); aws_completer | sed '"'"'s/ $//'"'"'; end)'
FISHEOF
printf "✓ Configured AWS CLI autocomplete for fish\\n"
fi
fi
fi
else
printf "❌ AWS CLI installation failed. Check logs at ${LOG_PATH}\\n"
exit 1
fi
@@ -14,7 +14,7 @@ This module lets you authenticate with [Hashicorp Vault](https://www.vaultprojec
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-github/coder"
version = "1.1.0"
version = "1.0.31"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
}
@@ -46,7 +46,7 @@ To configure the Vault module, you must set up a Vault GitHub auth method. See t
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-github/coder"
version = "1.1.0"
version = "1.0.31"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
coder_github_auth_id = "my-github-auth-id"
@@ -59,7 +59,7 @@ module "vault" {
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-github/coder"
version = "1.1.0"
version = "1.0.31"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
coder_github_auth_id = "my-github-auth-id"
@@ -73,7 +73,7 @@ module "vault" {
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-github/coder"
version = "1.1.0"
version = "1.0.31"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_cli_version = "1.15.0"
@@ -32,12 +32,6 @@ variable "vault_github_auth_path" {
default = "github"
}
variable "vault_namespace" {
type = string
description = "The Vault Enterprise namespace that contains the GitHub auth mount."
default = null
}
variable "vault_cli_version" {
type = string
description = "The version of Vault to install."
@@ -58,7 +52,6 @@ resource "coder_script" "vault" {
AUTH_PATH : var.vault_github_auth_path,
GITHUB_EXTERNAL_AUTH_ID : data.coder_external_auth.github.id,
INSTALL_VERSION : var.vault_cli_version,
VAULT_NAMESPACE : var.vault_namespace != null ? var.vault_namespace : "",
})
run_on_start = true
start_blocks_login = true
@@ -70,13 +63,6 @@ resource "coder_env" "vault_addr" {
value = var.vault_addr
}
resource "coder_env" "vault_namespace" {
count = var.vault_namespace == null ? 0 : 1
agent_id = var.agent_id
name = "VAULT_NAMESPACE"
value = var.vault_namespace
}
data "coder_external_auth" "github" {
id = var.coder_github_auth_id
}
@@ -4,7 +4,6 @@
INSTALL_VERSION=${INSTALL_VERSION}
GITHUB_EXTERNAL_AUTH_ID=${GITHUB_EXTERNAL_AUTH_ID}
AUTH_PATH=${AUTH_PATH}
VAULT_NAMESPACE=${VAULT_NAMESPACE}
fetch() {
dest="$1"
@@ -105,11 +104,6 @@ if ! (
fi
rm -rf "$TMP"
if [ -n "$${VAULT_NAMESPACE}" ]; then
export VAULT_NAMESPACE
printf "📁 Using Vault namespace: %s\n\n" "$${VAULT_NAMESPACE}"
fi
# Authenticate with Vault
printf "🔑 Authenticating with Vault ...\n\n"
GITHUB_TOKEN=$(coder external-auth access-token "$${GITHUB_EXTERNAL_AUTH_ID}")
+5 -5
View File
@@ -14,7 +14,7 @@ This module lets you authenticate with [Hashicorp Vault](https://www.vaultprojec
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-jwt/coder"
version = "1.2.0"
version = "1.1.1"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_jwt_role = "coder" # The Vault role to use for authentication
@@ -42,7 +42,7 @@ curl -H "X-Vault-Token: ${VAULT_TOKEN}" -X GET "${VAULT_ADDR}/v1/coder/secrets/d
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-jwt/coder"
version = "1.2.0"
version = "1.1.1"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_jwt_auth_path = "oidc"
@@ -58,7 +58,7 @@ data "coder_workspace_owner" "me" {}
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-jwt/coder"
version = "1.2.0"
version = "1.1.1"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_jwt_role = data.coder_workspace_owner.me.groups[0]
@@ -71,7 +71,7 @@ module "vault" {
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-jwt/coder"
version = "1.2.0"
version = "1.1.1"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_jwt_role = "coder" # The Vault role to use for authentication
@@ -132,7 +132,7 @@ resource "jwt_signed_token" "vault" {
module "vault" {
count = data.coder_workspace.me.start_count
source = "registry.coder.com/coder/vault-jwt/coder"
version = "1.2.0"
version = "1.1.1"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_jwt_role = "coder" # The Vault role to use for authentication
-14
View File
@@ -38,12 +38,6 @@ variable "vault_jwt_role" {
description = "The name of the Vault role to use for authentication."
}
variable "vault_namespace" {
type = string
description = "The Vault Enterprise namespace that contains the JWT auth mount."
default = null
}
variable "vault_cli_version" {
type = string
description = "The version of Vault to install."
@@ -63,7 +57,6 @@ resource "coder_script" "vault" {
VAULT_JWT_AUTH_PATH : var.vault_jwt_auth_path,
VAULT_JWT_ROLE : var.vault_jwt_role,
VAULT_CLI_VERSION : var.vault_cli_version,
VAULT_NAMESPACE : var.vault_namespace != null ? var.vault_namespace : "",
})
run_on_start = true
start_blocks_login = true
@@ -75,11 +68,4 @@ resource "coder_env" "vault_addr" {
value = var.vault_addr
}
resource "coder_env" "vault_namespace" {
count = var.vault_namespace == null ? 0 : 1
agent_id = var.agent_id
name = "VAULT_NAMESPACE"
value = var.vault_namespace
}
data "coder_workspace_owner" "me" {}
-6
View File
@@ -4,7 +4,6 @@
VAULT_CLI_VERSION=${VAULT_CLI_VERSION}
VAULT_JWT_AUTH_PATH=${VAULT_JWT_AUTH_PATH}
VAULT_JWT_ROLE=${VAULT_JWT_ROLE}
VAULT_NAMESPACE=${VAULT_NAMESPACE}
CODER_OIDC_ACCESS_TOKEN=${CODER_OIDC_ACCESS_TOKEN}
fetch() {
@@ -106,11 +105,6 @@ if ! (
fi
rm -rf "$TMP"
if [ -n "$${VAULT_NAMESPACE}" ]; then
export VAULT_NAMESPACE
printf "📁 Using Vault namespace: %s\n\n" "$${VAULT_NAMESPACE}"
fi
# Authenticate with Vault
printf "🔑 Authenticating with Vault ...\n\n"
echo "$${CODER_OIDC_ACCESS_TOKEN}" | vault write -field=token auth/"$${VAULT_JWT_AUTH_PATH}"/login role="$${VAULT_JWT_ROLE}" jwt=- | vault login -
+2 -2
View File
@@ -19,7 +19,7 @@ variable "vault_token" {
module "vault" {
source = "registry.coder.com/coder/vault-token/coder"
version = "1.3.0"
version = "1.2.2"
agent_id = coder_agent.example.id
vault_token = var.token # optional
vault_addr = "https://vault.example.com"
@@ -73,7 +73,7 @@ variable "vault_token" {
module "vault" {
source = "registry.coder.com/coder/vault-token/coder"
version = "1.3.0"
version = "1.2.2"
agent_id = coder_agent.example.id
vault_addr = "https://vault.example.com"
vault_token = var.token
+1 -2
View File
@@ -50,7 +50,6 @@ resource "coder_script" "vault" {
icon = "/icon/vault.svg"
script = templatefile("${path.module}/run.sh", {
INSTALL_VERSION : var.vault_cli_version,
VAULT_NAMESPACE : var.vault_namespace != null ? var.vault_namespace : "",
})
run_on_start = true
start_blocks_login = true
@@ -74,4 +73,4 @@ resource "coder_env" "vault_namespace" {
agent_id = var.agent_id
name = "VAULT_NAMESPACE"
value = var.vault_namespace
}
}
@@ -2,7 +2,6 @@
# Convert all templated variables to shell variables
INSTALL_VERSION=${INSTALL_VERSION}
VAULT_NAMESPACE=${VAULT_NAMESPACE}
fetch() {
dest="$1"
@@ -102,8 +101,3 @@ if ! (
exit 1
fi
rm -rf "$TMP"
if [ -n "$${VAULT_NAMESPACE}" ]; then
export VAULT_NAMESPACE
printf "📁 Using Vault namespace: %s\n\n" "$${VAULT_NAMESPACE}"
fi
@@ -3,7 +3,7 @@ display_name: airflow
description: A module that adds Apache Airflow in your Coder template
icon: ../../../../.icons/airflow.svg
maintainer_github: nataindata
verified: false
verified: true
tags: [airflow, ide, web]
---
@@ -2,7 +2,7 @@
display_name: DigitalOcean Region
description: A parameter with human region names and icons
icon: ../../../../.icons/digital-ocean.svg
verified: false
verified: true
tags: [helper, parameter, digitalocean, regions]
---