Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
pull-requests: write
packages: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: "Publish Features"
uses: devcontainers/action@v1
Expand Down
15 changes: 8 additions & 7 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ jobs:
strategy:
matrix:
features:
- color
- hello
- doppler-cli
baseImage:
- debian:latest
- ubuntu:latest
- alpine:latest
- fedora:latest
- mcr.microsoft.com/devcontainers/base:ubuntu
- mcr.microsoft.com/devcontainers/base:debian
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: "Install latest devcontainer CLI"
run: npm install -g @devcontainers/cli
Expand All @@ -34,10 +36,9 @@ jobs:
strategy:
matrix:
features:
- color
- hello
- doppler-cli
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: "Install latest devcontainer CLI"
run: npm install -g @devcontainers/cli
Expand All @@ -49,7 +50,7 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: "Install latest devcontainer CLI"
run: npm install -g @devcontainers/cli
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: "Validate devcontainer-feature.json files"
on:
workflow_dispatch:
pull_request:
workflow_dispatch:

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: "Validate devcontainer-feature.json files"
uses: devcontainers/action@v1
Expand Down
24 changes: 15 additions & 9 deletions src/doppler-cli/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
{
"name": "Doppler CLI",
"id": "doppler-cli",
"version": "1.0.0",
"description": "A feature that installs the Doppler CLI",
"documentationURL": "https://github.com/dopplerhq/devcontainer-features/tree/main/src/doppler-cli",
"name": "Doppler CLI",
"description": "Installs the Doppler CLI for secrets management.",
"options": {
"version": {
"type": "string",
"default": "latest",
"description": "Version of the Doppler CLI to install (e.g., '3.67.0' or 'latest')"
}
},
"containerEnv": {
"DOPPLER_CONFIG_DIR": "/doppler"
},
"mounts": [
{
"source": "doppler-cli-user-config",
"target": "/doppler",
"type": "volume"
}
{
"source": "doppler-cli-user-config",
"target": "/doppler",
"type": "volume"
}
Comment on lines +17 to +21

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check: Is it safe/valid to have a volume shared between all containers that might use this feature?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good question and I struggled with where to go for this. The volume gets shared across devcontainers, but the devcontainers stay in 1 location. Meaning if someone has multiple devcontainers running, those containers should be contained to their local machines and not be shared with other engineers. Where this could become an issue is if a team is working on a shared Docker host, but that seems very atypical of devcontainer usage. Having a volume means users don't have to reauthenticate across every dev container if they're running multiple or on every single devcontainer build. I could be talked into either direction on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been a long time since I looked at this, but as I recall, the volumes get a persistent, unique ID appended to the name when the container is started, so I don't think this should be a problem unless they're literally using the exact same devcontainer, which seems unlikely. Most ways I've seen this used, each developer has their own devcontainer running.

],
"installsAfter": [
"ghcr.io/devcontainers/features/common-utils"
"ghcr.io/devcontainers/features/common-utils"
]
}
164 changes: 149 additions & 15 deletions src/doppler-cli/install.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,158 @@
#!/usr/bin/env bash

set -e

ensure_curl() {
if ! type curl >/dev/null 2>&1; then
apt-get update -y && apt-get -y install --no-install-recommends curl
fi
echo "=== Doppler CLI Feature Install ==="
echo "VERSION: ${VERSION:-latest}"
echo "_REMOTE_USER: ${_REMOTE_USER:-not set}"

VERSION="${VERSION:-latest}"

# Detect package manager
detect_package_manager() {
if type apt-get >/dev/null 2>&1; then
echo "apt"
elif type apk >/dev/null 2>&1; then
echo "apk"
elif type dnf >/dev/null 2>&1; then
echo "dnf"
elif type yum >/dev/null 2>&1; then
echo "yum"
else
echo "unknown"
fi
}

ensure_gpg() {
if ! type gpg >/dev/null 2>&1; then
apt-get update -y && apt-get -y install --no-install-recommends gnupg2
fi
# Install a package using the detected package manager
install_package() {
local pkg_manager="$1"
shift
local packages="$@"

case "$pkg_manager" in
apt)
apt-get update -y && apt-get install -y --no-install-recommends $packages
rm -rf /var/lib/apt/lists/*
;;
apk)
apk add --no-cache $packages
;;
dnf)
dnf install -y $packages && dnf clean all
rm -rf /var/cache/dnf
;;
yum)
yum install -y $packages && yum clean all
rm -rf /var/cache/yum
;;
*)
echo "ERROR: Unsupported package manager. Please install manually: $packages"
exit 1
;;
esac
}

ensure_curl
ensure_gpg
PKG_MANAGER=$(detect_package_manager)
echo "Detected package manager: $PKG_MANAGER"

# Install dependencies if missing
echo "Checking for curl..."
if ! type curl >/dev/null 2>&1; then
echo "Installing curl..."
case "$PKG_MANAGER" in
apt) install_package "$PKG_MANAGER" curl ca-certificates ;;
apk) install_package "$PKG_MANAGER" curl ca-certificates ;;
dnf|yum) install_package "$PKG_MANAGER" curl ;;
*) echo "ERROR: Cannot install curl"; exit 1 ;;
esac
fi

echo "Checking for gpg..."
if ! type gpg >/dev/null 2>&1; then
echo "Installing gnupg..."
case "$PKG_MANAGER" in
apt) install_package "$PKG_MANAGER" gnupg ;;
apk) install_package "$PKG_MANAGER" gnupg ;;
dnf|yum) install_package "$PKG_MANAGER" gnupg2 ;;
*) echo "ERROR: Cannot install gnupg"; exit 1 ;;
esac
fi

# Strip 'v' prefix from version if present (e.g., "v3.69.0" -> "3.69.0")
VERSION="${VERSION#v}"

# Install Doppler CLI
echo "Installing Doppler CLI (version: $VERSION)..."
if [ "$VERSION" = "latest" ]; then
# Use official install script for latest
echo "Fetching Doppler install script..."
curl -Ls --tlsv1.2 --proto "=https" --retry 3 https://cli.doppler.com/install.sh | bash
else
# Download specific version directly from GitHub releases
echo "Downloading Doppler CLI v$VERSION from GitHub releases..."

# Detect OS
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$OS" in
darwin) OS="macos" ;;
linux) OS="linux" ;;
*) echo "ERROR: Unsupported OS: $OS"; exit 1 ;;
esac

# Detect architecture
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64) ARCH="amd64" ;;
aarch64|arm64) ARCH="arm64" ;;
armv7l) ARCH="armv7" ;;
armv6l) ARCH="armv6" ;;
i386|i686) ARCH="i386" ;;
*) echo "ERROR: Unsupported architecture: $ARCH"; exit 1 ;;
esac

# Download and extract
DOWNLOAD_URL="https://github.com/DopplerHQ/cli/releases/download/${VERSION}/doppler_${VERSION}_${OS}_${ARCH}.tar.gz"
echo "Downloading from: $DOWNLOAD_URL"

TEMP_DIR=$(mktemp -d)
curl -Ls --tlsv1.2 --proto "=https" --retry 3 -o "$TEMP_DIR/doppler.tar.gz" "$DOWNLOAD_URL"

tar -xzf "$TEMP_DIR/doppler.tar.gz" -C "$TEMP_DIR"
mv "$TEMP_DIR/doppler" /usr/local/bin/doppler
chmod +x /usr/local/bin/doppler

rm -rf "$TEMP_DIR"
fi

# Ensure config directory is writable by the container user
# Use smart detection if _REMOTE_USER is not set
echo "Creating config directory /doppler..."
mkdir -p /doppler

# Determine user for config directory ownership
if [ -z "${_REMOTE_USER}" ] || [ "${_REMOTE_USER}" = "root" ]; then
# Try common dev container users first
for user in vscode node codespace; do
if id -u "$user" > /dev/null 2>&1; then
_REMOTE_USER="$user"
echo "Detected dev container user: $user"
break
fi
done
fi

# If still not found, try UID 1000 (common default for container users)
if [ -z "${_REMOTE_USER}" ] || [ "${_REMOTE_USER}" = "root" ]; then
_REMOTE_USER="$(awk -v val=1000 -F ':' '$3==val{print $1}' /etc/passwd)"
if [ -n "${_REMOTE_USER}" ]; then
echo "Detected user with UID 1000: $_REMOTE_USER"
fi
fi

# Finally, fallback to root
_REMOTE_USER="${_REMOTE_USER:-root}"

# download and execute the latest installer.
curl -Ls --tlsv1.2 --proto "=https" --retry 3 https://cli.doppler.com/install.sh | sh
echo "Setting ownership to ${_REMOTE_USER}..."
chown -R "${_REMOTE_USER}:${_REMOTE_USER}" /doppler

# ensure /doppler is writable to store CLI config data
mkdir -p /doppler && chown -R ${_REMOTE_USER}:${_REMOTE_USER} /doppler
echo "=== Installation complete ==="
echo "Doppler CLI installed: $(doppler --version)"
27 changes: 27 additions & 0 deletions test/doppler-cli/_common_latest_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Shared test logic for verifying latest version is installed

set -e

source dev-container-features-test-lib

# Install jq if needed for JSON parsing
if ! type jq >/dev/null 2>&1; then
if type apt-get >/dev/null 2>&1; then
apt-get update -y && apt-get -y install --no-install-recommends jq
elif type apk >/dev/null 2>&1; then
apk add --no-cache jq
elif type dnf >/dev/null 2>&1; then
dnf install -y jq
elif type yum >/dev/null 2>&1; then
yum install -y jq
fi
fi

# Get latest version from GitHub API
latest_version=$(curl -s https://api.github.com/repos/dopplerhq/cli/releases/latest | jq -r '.tag_name')

# Verify installed version matches latest
check "latest version installed" bash -c "doppler -v | grep '${latest_version}'"

reportResults
3 changes: 3 additions & 0 deletions test/doppler-cli/latest_on_alpine.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Test latest version on Alpine
source "$(dirname "$0")/_common_latest_version.sh"
3 changes: 3 additions & 0 deletions test/doppler-cli/latest_on_debian.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Test latest version on Debian
source "$(dirname "$0")/_common_latest_version.sh"
3 changes: 3 additions & 0 deletions test/doppler-cli/latest_on_devcontainer_base.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Test latest version on Microsoft devcontainer base
source "$(dirname "$0")/_common_latest_version.sh"
3 changes: 3 additions & 0 deletions test/doppler-cli/latest_on_fedora.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Test latest version on Fedora
source "$(dirname "$0")/_common_latest_version.sh"
3 changes: 3 additions & 0 deletions test/doppler-cli/latest_on_ubuntu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
# Test latest version on Ubuntu
source "$(dirname "$0")/_common_latest_version.sh"
10 changes: 10 additions & 0 deletions test/doppler-cli/pinned_version_on_ubuntu.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash

set -e

source dev-container-features-test-lib

# Verify the specific pinned version is installed
check "pinned version 3.69.0 installed" bash -c "doppler -v | grep 'v3.69.0'"

reportResults
32 changes: 29 additions & 3 deletions test/doppler-cli/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
{
"doppler_cli_installed": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"latest_on_ubuntu": {
"image": "ubuntu:latest",
"features": {
"doppler-cli": {}
}
},
"latest_on_debian": {
"image": "debian:latest",
"features": {
"doppler-cli": {}
}
},
"latest_on_alpine": {
"image": "alpine:latest",
"features": {
"doppler-cli": {}
}
},
"latest_on_fedora": {
"image": "fedora:latest",
"features": {
"doppler-cli": {}
}
},
"doppler_cli_version": {
"latest_on_devcontainer_base": {
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"doppler-cli": {}
}
},
"pinned_version_on_ubuntu": {
"image": "ubuntu:latest",
"features": {
"doppler-cli": {
"version": "3.69.0"
}
}
}
}
Loading
Loading