mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
fix: MacOS MDM based Deployment (#277)
* fix: MacOS MDM deployment script * fix: Handle shell alias for bash on macos * fix: Code review fixes * fix: Code review fixes * feat: Add support for global config file * feat: Add support for global config file * fix: Code review fixes * fix: Avoid blocking CLI for analytics flush
This commit is contained in:
Executable
+113
@@ -0,0 +1,113 @@
|
||||
#!/bin/bash
|
||||
# pmg_setup_install_macos.sh — Install and configure PMG on a Mac.
|
||||
#
|
||||
# Deploy via Jamf or any MDM, alongside lib_macos.sh in the same directory.
|
||||
# Run as root, it installs the machine-wide binary and configures every local
|
||||
# user (config, aliases, shims). Cloud credentials are stored in the logged-in
|
||||
# user's Keychain when SAFEDEP_API_KEY and SAFEDEP_TENANT_ID are set. Run as a
|
||||
# user, it configures just that user. See lib_macos.sh for the model.
|
||||
#
|
||||
# Environment variables:
|
||||
# SAFEDEP_API_KEY — SafeDep Cloud API key (with tenant ID, enables cloud sync)
|
||||
# SAFEDEP_TENANT_ID — SafeDep Cloud tenant ID
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=lib_macos.sh
|
||||
source "${SCRIPT_DIR}/lib_macos.sh"
|
||||
|
||||
require_macos
|
||||
|
||||
REPO="safedep/pmg"
|
||||
CLOUD_API_KEY="${SAFEDEP_API_KEY:-}"
|
||||
CLOUD_TENANT_ID="${SAFEDEP_TENANT_ID:-}"
|
||||
|
||||
install_via_brew() {
|
||||
local brew_bin="$1"
|
||||
log "Installing/updating pmg via Homebrew"
|
||||
if run_brew "$brew_bin" ls --versions safedep/tap/pmg &>/dev/null; then
|
||||
run_brew "$brew_bin" upgrade safedep/tap/pmg || true
|
||||
else
|
||||
run_brew "$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" tag asset url checksums_url tmpdir expected actual
|
||||
|
||||
tag=$(curl -fsSI -o /dev/null -w '%{redirect_url}' "https://github.com/${REPO}/releases/latest" | sed 's|.*/||')
|
||||
[[ -n "$tag" ]] || { echo "Error: could not determine latest release" >&2; exit 1; }
|
||||
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)
|
||||
[[ -n "$expected" ]] || { echo "Error: no checksum entry found for ${asset}" >&2; exit 1; }
|
||||
actual=$(shasum -a 256 "${tmpdir}/${asset}" | cut -d' ' -f1)
|
||||
if [[ "$actual" != "$expected" ]]; then
|
||||
echo "Error: checksum mismatch for ${asset} (expected $expected, got $actual)" >&2
|
||||
exit 1
|
||||
fi
|
||||
log "Checksum verified"
|
||||
|
||||
tar -xzf "${tmpdir}/${asset}" -C "${tmpdir}" pmg
|
||||
run_as_root install -m 755 "${tmpdir}/pmg" "${install_dir}/pmg"
|
||||
log "Installed pmg $tag to ${install_dir}/pmg"
|
||||
}
|
||||
|
||||
if brew_bin=$(find_brew); then
|
||||
install_via_brew "$brew_bin"
|
||||
else
|
||||
install_via_release
|
||||
fi
|
||||
|
||||
PMG_BIN=$(resolve_pmg) || { echo "Error: pmg not found after install" >&2; exit 1; }
|
||||
log "pmg installed: $("$PMG_BIN" version 2>/dev/null || echo unknown)"
|
||||
|
||||
# Install the globally managed config if the package ships one. Done before the
|
||||
# per-user loop so each user's `setup install` sees managed mode and skips
|
||||
# writing a per-user config.
|
||||
if [[ -f "${SCRIPT_DIR}/config.yml" ]]; then
|
||||
install_global_config "${SCRIPT_DIR}/config.yml"
|
||||
fi
|
||||
|
||||
if [[ -f "$GLOBAL_CONFIG_FILE" && -n "$CLOUD_API_KEY" && -n "$CLOUD_TENANT_ID" ]]; then
|
||||
log "Config is globally managed; set 'cloud.enabled: true' in the bundled config.yml to enable sync (per-user config is locked)"
|
||||
fi
|
||||
|
||||
configure_user() {
|
||||
local user="$1"
|
||||
log "Configuring pmg for $user"
|
||||
run_user_file "$user" "$PMG_BIN" setup install || { warn "setup failed for $user"; return; }
|
||||
|
||||
[[ -n "$CLOUD_API_KEY" && -n "$CLOUD_TENANT_ID" ]] || return
|
||||
if ! user_has_session "$user"; then
|
||||
log " $user is not logged in; run 'pmg cloud login' in their session to enable cloud sync"
|
||||
return
|
||||
fi
|
||||
# When config is globally managed, `cloud.enabled` comes from the global file;
|
||||
# per-user `config set` is refused. Per-user credentials still go to the Keychain.
|
||||
if [[ ! -f "$GLOBAL_CONFIG_FILE" ]]; then
|
||||
run_user_file "$user" "$PMG_BIN" config set cloud.enabled true || warn "could not enable cloud sync for $user"
|
||||
fi
|
||||
run_user_session "$user" \
|
||||
env SAFEDEP_API_KEY="$CLOUD_API_KEY" SAFEDEP_TENANT_ID="$CLOUD_TENANT_ID" "$PMG_BIN" cloud login --from-env \
|
||||
|| warn "cloud login failed for $user"
|
||||
}
|
||||
|
||||
while IFS=$'\t' read -r user _ _; do
|
||||
configure_user "$user"
|
||||
done < <(each_target_user)
|
||||
|
||||
log "pmg setup complete"
|
||||
Reference in New Issue
Block a user