From 5bc668aa4d140603237e6f49c6d063ba2b501f5c Mon Sep 17 00:00:00 2001 From: Ben Potter Date: Wed, 1 Apr 2026 13:38:27 -0500 Subject: [PATCH] feat: add 1password module under bpmct namespace (#824) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a 1Password module under the `bpmct` namespace. ## What it does Installs the [1Password CLI](https://developer.1password.com/docs/cli/) (`op`) into Coder workspaces at startup. Two auth paths: - **Service account token** — set `service_account_token` and `OP_SERVICE_ACCOUNT_TOKEN` is injected automatically. Fully headless. - **Personal account** — set `account_address`, `account_email`, `account_secret_key` to pre-register the account. User runs `op signin` in their terminal. Optionally installs the [1Password VS Code extension](https://marketplace.visualstudio.com/items?itemName=1Password.op-vscode) (`1Password.op-vscode`) for code-server and VS Code with `install_vscode_extension = true`. Supports `pre_install_script` and `post_install_script` for custom orchestration. ## What's included - `registry/bpmct/` — new namespace (Ben Potter, community) - `registry/bpmct/modules/1password/` — the module (`main.tf`, `run.sh`, `README.md`) - `.icons/1password.svg` — 1Password logo from Simple Icons ## Tested Spun up a dev Coder instance, pushed the template with a real 1Password service account token, created a workspace, and confirmed: - `op` CLI installs and authenticates - `op vault list` returns vaults - `1Password.op-vscode` extension installs in code-server --------- Co-authored-by: DevCats --- .icons/1password.svg | 1 + registry/bpmct/.images/avatar.png | Bin 0 -> 32700 bytes registry/bpmct/README.md | 11 ++ registry/bpmct/modules/onepassword/README.md | 95 ++++++++++ registry/bpmct/modules/onepassword/main.tf | 112 ++++++++++++ registry/bpmct/modules/onepassword/run.sh | 176 +++++++++++++++++++ 6 files changed, 395 insertions(+) create mode 100644 .icons/1password.svg create mode 100644 registry/bpmct/.images/avatar.png create mode 100644 registry/bpmct/README.md create mode 100644 registry/bpmct/modules/onepassword/README.md create mode 100644 registry/bpmct/modules/onepassword/main.tf create mode 100644 registry/bpmct/modules/onepassword/run.sh diff --git a/.icons/1password.svg b/.icons/1password.svg new file mode 100644 index 00000000..c81c316f --- /dev/null +++ b/.icons/1password.svg @@ -0,0 +1 @@ +1Password \ No newline at end of file diff --git a/registry/bpmct/.images/avatar.png b/registry/bpmct/.images/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..57fb2ef8ccad2c3302bed2562b656c895d1e7d00 GIT binary patch literal 32700 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 g=V=v{t2WE#P!B;<_$-#RIqgi ~/.secret + EOT +} +``` diff --git a/registry/bpmct/modules/onepassword/main.tf b/registry/bpmct/modules/onepassword/main.tf new file mode 100644 index 00000000..9f313c43 --- /dev/null +++ b/registry/bpmct/modules/onepassword/main.tf @@ -0,0 +1,112 @@ +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 "service_account_token" { + type = string + description = "A 1Password service account token. If set, account-based sign-in is skipped." + default = "" + sensitive = true +} + +variable "account_address" { + type = string + description = "The 1Password account sign-in address (e.g. myteam.1password.com)." + default = "" +} + +variable "account_email" { + type = string + description = "The email address for the 1Password account." + default = "" +} + +variable "account_secret_key" { + type = string + description = "The Secret Key for the 1Password account." + default = "" + sensitive = true +} + +variable "install_dir" { + type = string + description = "The directory to install the 1Password CLI to." + default = "/usr/local/bin" +} + +variable "op_cli_version" { + type = string + description = "The version of the 1Password CLI to install." + default = "latest" + validation { + condition = var.op_cli_version == "latest" || can(regex("^[0-9]+\\.[0-9]+\\.[0-9]+$", var.op_cli_version)) + error_message = "op_cli_version must be either 'latest' or a semantic version (e.g., '2.30.0')." + } +} + +variable "install_vscode_extension" { + type = bool + description = "Install the 1Password VS Code extension for both VS Code and code-server." + default = false +} + +variable "pre_install_script" { + type = string + description = "Custom script to run before installing the 1Password CLI." + default = null +} + +variable "post_install_script" { + type = string + description = "Custom script to run after installing the 1Password CLI." + default = null +} + +data "coder_parameter" "account_password" { + count = var.account_address != "" && var.service_account_token == "" ? 1 : 0 + type = "string" + name = "op_account_password" + display_name = "1Password Account Password" + description = "Your 1Password account password. Used to sign in to the CLI." + mutable = true + default = "" +} + +resource "coder_script" "1password" { + agent_id = var.agent_id + display_name = "1Password CLI" + icon = "/icon/1password.svg" + script = templatefile("${path.module}/run.sh", { + SERVICE_ACCOUNT_TOKEN = var.service_account_token + ACCOUNT_ADDRESS = var.account_address + ACCOUNT_EMAIL = var.account_email + ACCOUNT_SECRET_KEY = var.account_secret_key + ACCOUNT_PASSWORD = var.account_address != "" && var.service_account_token == "" ? data.coder_parameter.account_password[0].value : "" + INSTALL_DIR = var.install_dir + OP_CLI_VERSION = var.op_cli_version + INSTALL_VSCODE_EXTENSION = var.install_vscode_extension + PRE_INSTALL_SCRIPT = var.pre_install_script != null ? base64encode(var.pre_install_script) : "" + POST_INSTALL_SCRIPT = var.post_install_script != null ? base64encode(var.post_install_script) : "" + }) + run_on_start = true + start_blocks_login = true +} + +resource "coder_env" "op_service_account_token" { + count = var.service_account_token != "" ? 1 : 0 + agent_id = var.agent_id + name = "OP_SERVICE_ACCOUNT_TOKEN" + value = var.service_account_token +} diff --git a/registry/bpmct/modules/onepassword/run.sh b/registry/bpmct/modules/onepassword/run.sh new file mode 100644 index 00000000..bbad7493 --- /dev/null +++ b/registry/bpmct/modules/onepassword/run.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash + +SERVICE_ACCOUNT_TOKEN="${SERVICE_ACCOUNT_TOKEN}" +ACCOUNT_ADDRESS="${ACCOUNT_ADDRESS}" +ACCOUNT_EMAIL="${ACCOUNT_EMAIL}" +ACCOUNT_SECRET_KEY="${ACCOUNT_SECRET_KEY}" +ACCOUNT_PASSWORD="${ACCOUNT_PASSWORD}" +INSTALL_DIR="${INSTALL_DIR}" +OP_CLI_VERSION="${OP_CLI_VERSION}" +INSTALL_VSCODE_EXTENSION="${INSTALL_VSCODE_EXTENSION}" +PRE_INSTALL_SCRIPT="${PRE_INSTALL_SCRIPT}" +POST_INSTALL_SCRIPT="${POST_INSTALL_SCRIPT}" + +fetch() { + if command -v curl > /dev/null 2>&1; then + curl -sSL --fail "$1" + elif command -v wget > /dev/null 2>&1; then + wget -qO- "$1" + else + printf "curl or wget is not installed.\n" && return 1 + fi +} + +fetch_to_file() { + if command -v curl > /dev/null 2>&1; then + curl -sSL --fail "$2" -o "$1" + elif command -v wget > /dev/null 2>&1; then + wget -O "$1" "$2" + else + printf "curl or wget is not installed.\n" && return 1 + fi +} + +run_script() { + local ENCODED="$1" LABEL="$2" + if [ -n "$${ENCODED}" ]; then + printf "Running %s script...\n" "$${LABEL}" + SCRIPT_PATH=$(mktemp /tmp/op-"$${LABEL}"-XXXXXX.sh) + printf '%s' "$${ENCODED}" | base64 -d > "$${SCRIPT_PATH}" + chmod +x "$${SCRIPT_PATH}" + # shellcheck disable=SC2288 + "$${SCRIPT_PATH}" || printf "WARNING: %s script failed.\n" "$${LABEL}" + rm -f "$${SCRIPT_PATH}" + fi +} + +install() { + 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 + + OS=$(uname -s | tr '[:upper:]' '[:lower:]') + if [ "$${OS}" != "linux" ] && [ "$${OS}" != "darwin" ]; then + printf "Unsupported OS: %s\n" "$${OS}" && return 1 + fi + + if [ "$${OP_CLI_VERSION}" = "latest" ]; then + OP_CLI_VERSION=$(fetch "https://app-updates.agilebits.com/check/1/0/CLI2/en/2.0.0/N" \ + | grep -oE '"version":"[^"]+"' | head -1 | cut -d'"' -f4) || true + if [ -z "$${OP_CLI_VERSION}" ]; then + printf "Failed to resolve latest version, falling back to 2.30.3.\n" + OP_CLI_VERSION="2.30.3" + fi + fi + + printf "1Password CLI version: %s\n" "$${OP_CLI_VERSION}" + + if command -v op > /dev/null 2>&1; then + CURRENT_VERSION=$(op --version 2> /dev/null || true) + if [ "$${CURRENT_VERSION}" = "$${OP_CLI_VERSION}" ]; then + printf "Already installed.\n" + return 0 + fi + fi + + DOWNLOAD_URL="https://cache.agilebits.com/dist/1P/op2/pkg/v$${OP_CLI_VERSION}/op_$${OS}_$${ARCH}_v$${OP_CLI_VERSION}.zip" + + TEMP_DIR=$(mktemp -d) + cd "$${TEMP_DIR}" || return 1 + + if ! fetch_to_file op.zip "$${DOWNLOAD_URL}"; then + rm -rf "$${TEMP_DIR}" && return 1 + fi + + if command -v unzip > /dev/null 2>&1; then + unzip -o op.zip -d . > /dev/null + elif command -v busybox > /dev/null 2>&1; then + busybox unzip op.zip -d . + else + printf "unzip is not installed.\n" + rm -rf "$${TEMP_DIR}" && return 1 + fi + + chmod +x op + + if [ -n "$${INSTALL_DIR}" ] && [ -w "$${INSTALL_DIR}" ]; then + mv op "$${INSTALL_DIR}/op" + elif [ -n "$${INSTALL_DIR}" ] && sudo mv op "$${INSTALL_DIR}/op" 2> /dev/null; then + true + else + mkdir -p ~/.local/bin && mv op ~/.local/bin/op + INSTALL_DIR=~/.local/bin + fi + printf "Installed to %s.\n" "$${INSTALL_DIR}" + + rm -rf "$${TEMP_DIR}" +} + +run_script "$${PRE_INSTALL_SCRIPT}" "pre-install" + +if ! install; then + printf "Failed to install 1Password CLI.\n" + exit 1 +fi + +if [ -n "$${SERVICE_ACCOUNT_TOKEN}" ]; then + printf "Service account token configured.\n" +elif [ -n "$${ACCOUNT_ADDRESS}" ] && [ -n "$${ACCOUNT_EMAIL}" ]; then + ADD_ARGS="--address $${ACCOUNT_ADDRESS} --email $${ACCOUNT_EMAIL}" + if [ -n "$${ACCOUNT_SECRET_KEY}" ]; then + ADD_ARGS="$${ADD_ARGS} --secret-key $${ACCOUNT_SECRET_KEY}" + fi + + if [ -n "$${ACCOUNT_PASSWORD}" ] && command -v expect > /dev/null 2>&1; then + OP_SESSION=$(expect -c " + log_user 0 + spawn op account add $${ADD_ARGS} --raw + expect \"Enter the password*\" + send \"$${ACCOUNT_PASSWORD}\r\" + expect eof + catch wait result + set output \$expect_out(buffer) + puts -nonewline \$output + " 2>&1) + if op account list 2> /dev/null | grep -q "$${ACCOUNT_ADDRESS}"; then + printf "Signed in to %s.\n" "$${ACCOUNT_ADDRESS}" + if [ -n "$${OP_SESSION}" ]; then + mkdir -p "$${HOME}/.op" + SESSION_VAR="OP_SESSION_$(printf '%s' "$${ACCOUNT_ADDRESS}" | tr '.' '_' | tr '-' '_')" + printf 'export %s="%s"\n' "$${SESSION_VAR}" "$${OP_SESSION}" > "$${HOME}/.op/session" + chmod 600 "$${HOME}/.op/session" + for rc in "$${HOME}/.bashrc" "$${HOME}/.zshrc"; do + if [ -f "$${rc}" ] && ! grep -q ".op/session" "$${rc}" 2> /dev/null; then + printf '\n[ -f ~/.op/session ] && . ~/.op/session\n' >> "$${rc}" + fi + done + fi + else + printf "Sign-in failed. Run manually: op signin --account %s\n" "$${ACCOUNT_ADDRESS}" + fi + else + printf "To sign in, run in your terminal:\n" + printf " op account add %s\n" "$${ADD_ARGS}" + fi +fi + +if [ "$${INSTALL_VSCODE_EXTENSION}" = "true" ]; then + EXTENSION_ID="1Password.op-vscode" + for _ in 1 2 3 4 5 6; do + command -v code-server > /dev/null 2>&1 || command -v code > /dev/null 2>&1 && break + sleep 5 + done + if command -v code-server > /dev/null 2>&1; then + cd /tmp && code-server --install-extension "$${EXTENSION_ID}" --force 2>&1 || true + fi + if command -v code > /dev/null 2>&1; then + cd /tmp && code --install-extension "$${EXTENSION_ID}" --force 2>&1 || true + fi +fi + +run_script "$${POST_INSTALL_SCRIPT}" "post-install"