mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
feat: add macOS setup script for Jamf deployment (#258)
* feat: add macOS setup script for Jamf deployment Adds scripts/pmg_setup_install.sh that installs/updates pmg (via Homebrew or GitHub releases), runs pmg setup install, and optionally enables cloud sync with credentials stored in macOS Keychain. * feat: add --from-env flag to pmg cloud login Allows non-interactive credential import from SAFEDEP_API_KEY and SAFEDEP_TENANT_ID environment variables. Fails explicitly if either is missing. Used by the setup script for Jamf deployments. * refactor: use cloud.NewEnvCredentialResolver for --from-env Use the dry library's env credential resolver instead of reading env vars directly, keeping env var ownership in the shared library. * update DRY * update go to 1.25 back
This commit is contained in:
Executable
+138
@@ -0,0 +1,138 @@
|
||||
#!/bin/bash
|
||||
# pmg_setup_install.sh — Install/update PMG, configure it, and enable cloud sync.
|
||||
#
|
||||
# This script is intended to be packaged and deployed via Jamf or similar MDM tools.
|
||||
#
|
||||
# Usage:
|
||||
# ./pmg_setup_install.sh
|
||||
# SAFEDEP_API_KEY=... SAFEDEP_TENANT_ID=... ./pmg_setup_install.sh
|
||||
#
|
||||
# Environment variables:
|
||||
# SAFEDEP_API_KEY — SafeDep Cloud API key (enables cloud sync when set with tenant ID)
|
||||
# SAFEDEP_TENANT_ID — SafeDep Cloud tenant ID
|
||||
#
|
||||
# What it does:
|
||||
# 1. Installs or updates pmg (via Homebrew if available, otherwise from GitHub releases)
|
||||
# 2. Runs `pmg setup install` to create config, shell aliases, and PATH shims
|
||||
# 3. Enables cloud sync and stores credentials in macOS Keychain (if both env vars are set)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$(uname -s)" != "Darwin" ]]; then
|
||||
echo "Error: this script is for macOS only" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO="safedep/pmg"
|
||||
CLOUD_API_KEY="${SAFEDEP_API_KEY:-}"
|
||||
CLOUD_TENANT_ID="${SAFEDEP_TENANT_ID:-}"
|
||||
|
||||
log() { echo "==> $*"; }
|
||||
|
||||
# ── Install or update pmg ───────────────────────────────────────────────────
|
||||
install_via_brew() {
|
||||
local brew_bin="$1"
|
||||
log "Installing/updating pmg via Homebrew"
|
||||
if "$brew_bin" ls --versions safedep/tap/pmg &>/dev/null; then
|
||||
log "pmg is already installed, upgrading"
|
||||
"$brew_bin" upgrade safedep/tap/pmg || true
|
||||
else
|
||||
"$brew_bin" install safedep/tap/pmg
|
||||
fi
|
||||
}
|
||||
|
||||
install_via_release() {
|
||||
log "Homebrew not found, installing pmg from GitHub releases"
|
||||
|
||||
local install_dir="/usr/local/bin"
|
||||
|
||||
log "Fetching latest release..."
|
||||
tag=$(curl -fsSI -o /dev/null -w '%{redirect_url}' "https://github.com/${REPO}/releases/latest" | sed 's|.*/||')
|
||||
if [[ -z "$tag" ]]; then
|
||||
echo "Error: could not determine latest release" >&2
|
||||
exit 1
|
||||
fi
|
||||
log "Latest release: $tag"
|
||||
|
||||
asset="pmg_Darwin_all.tar.gz"
|
||||
url="https://github.com/${REPO}/releases/download/${tag}/${asset}"
|
||||
checksums_url="https://github.com/${REPO}/releases/download/${tag}/checksums.txt"
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
|
||||
log "Downloading $asset"
|
||||
curl -fsSL -o "${tmpdir}/${asset}" "$url"
|
||||
curl -fsSL -o "${tmpdir}/checksums.txt" "$checksums_url"
|
||||
|
||||
expected=$(grep " ${asset}$" "${tmpdir}/checksums.txt" | cut -d' ' -f1)
|
||||
if [[ -z "$expected" ]]; then
|
||||
echo "Error: no checksum entry found for ${asset}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
actual=$(shasum -a 256 "${tmpdir}/${asset}" | cut -d' ' -f1)
|
||||
if [[ "$actual" != "$expected" ]]; then
|
||||
echo "Error: checksum mismatch for ${asset}" >&2
|
||||
echo " expected: $expected" >&2
|
||||
echo " actual: $actual" >&2
|
||||
exit 1
|
||||
fi
|
||||
log "Checksum verified"
|
||||
|
||||
tar -xzf "${tmpdir}/${asset}" -C "${tmpdir}" pmg
|
||||
|
||||
if [[ -w "$install_dir" ]]; then
|
||||
install -m 755 "${tmpdir}/pmg" "${install_dir}/pmg"
|
||||
else
|
||||
sudo install -m 755 "${tmpdir}/pmg" "${install_dir}/pmg"
|
||||
fi
|
||||
log "Installed pmg $tag to ${install_dir}/pmg"
|
||||
}
|
||||
|
||||
BREW_BIN=""
|
||||
for candidate in "/opt/homebrew/bin/brew" "/usr/local/bin/brew"; do
|
||||
if [[ -x "$candidate" ]]; then
|
||||
BREW_BIN="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "$BREW_BIN" ]]; then
|
||||
install_via_brew "$BREW_BIN"
|
||||
else
|
||||
install_via_release
|
||||
fi
|
||||
|
||||
if ! command -v pmg &>/dev/null; then
|
||||
echo "Error: pmg not found in PATH after install" >&2
|
||||
exit 1
|
||||
fi
|
||||
log "pmg installed: $(pmg version 2>/dev/null || echo 'unknown')"
|
||||
|
||||
# ── Run pmg setup ────────────────────────────────────────────────────────────
|
||||
log "Running pmg setup install"
|
||||
pmg setup install
|
||||
|
||||
# ── Enable cloud sync ───────────────────────────────────────────────────────
|
||||
if [[ -n "$CLOUD_API_KEY" && -n "$CLOUD_TENANT_ID" ]]; then
|
||||
log "Enabling cloud sync"
|
||||
|
||||
CONFIG_FILE="${HOME}/Library/Application Support/safedep/pmg/config.yml"
|
||||
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
awk '
|
||||
/^cloud:/ { in_cloud=1 }
|
||||
in_cloud && /^ enabled: false/ { sub(/enabled: false/, "enabled: true"); in_cloud=0 }
|
||||
/^[a-z]/ && !/^cloud:/ { in_cloud=0 }
|
||||
{ print }
|
||||
' "$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
|
||||
log "Cloud sync enabled in config"
|
||||
fi
|
||||
|
||||
SAFEDEP_API_KEY="$CLOUD_API_KEY" SAFEDEP_TENANT_ID="$CLOUD_TENANT_ID" pmg cloud login --from-env
|
||||
log "Credentials stored securely"
|
||||
fi
|
||||
|
||||
# ── Done ─────────────────────────────────────────────────────────────────────
|
||||
log "pmg setup complete!"
|
||||
Reference in New Issue
Block a user