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
134 changes: 134 additions & 0 deletions mdm-scripts/linux/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
# 1. Always installs the latest CLI to /usr/local/bin/sonar.
# 2. For every local user that has a standalone install, replaces it with a
# symlink to the MDM binary so PATH order cannot override it.
# Self-contained: no external scripts are downloaded or executed.
# SONARQUBE_CLI_APPROVED_VERSION -- optional JumpCloud variable; pins the install version instead of
# using stable.version.
set -euo pipefail

MDM_BINARY="/usr/local/bin/sonar"
STANDALONE_REL=".local/share/sonarqube-cli/bin/sonar"
readonly ARTIFACT_BASE_URL="https://binaries.sonarsource.com/Distribution/sonarqube-cli"
# JumpCloud-specific: {{SONARQUBE_CLI_APPROVED_VERSION}} is replaced with the Custom Variable's
# value (quoted) at runtime -- not a real environment variable. Other MDM systems may inject this
# differently.
APPROVED_VERSION_OVERRIDE={{SONARQUBE_CLI_APPROVED_VERSION}}
[[ "$APPROVED_VERSION_OVERRIDE" == \{\{*\}\} ]] && APPROVED_VERSION_OVERRIDE="" # defensive: unattached JumpCloud var may leave the literal placeholder
readonly HTTPS_ONLY="=https"
export PATH="/usr/local/bin:$PATH"

# ── Platform helpers ──────────────────────────────────────────────────────────

cdn_os() { echo "linux"; }

cdn_platform() {
case "$(uname -m)" in
aarch64|arm64) echo "linux-arm64" ;;
x86_64|amd64) echo "linux-x86-64" ;;
*) echo "" ;;
esac
}

# ── SHA256 helpers ────────────────────────────────────────────────────────────

sha256_of() {
local file="$1"
sha256sum "$file" | awk '{print $1}'
}

verify_sha256() {
local binary="$1" version="$2"
local platform os base url expected actual
platform="$(cdn_platform)"
os="$(cdn_os)"
if [[ -z "$platform" || -z "$os" ]]; then
echo "Warning: unsupported platform — skipping SHA256 check." >&2
return
fi
base="sonarqube-cli-${version}-${platform}"
url="${ARTIFACT_BASE_URL}/${version}/${os}/${base}.bin.sha256"
expected="$(curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "$url" 2>/dev/null | awk '{print $1}')"
if [[ -z "$expected" ]]; then
echo "Error: could not fetch SHA256 from $url — aborting." >&2
exit 1
Comment on lines +40 to +54

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Security: SHA256 fetched from same origin as binary gives no supply-chain protection

verify_sha256 / Test-BinarySha256 download the .sha256 file from the same artifact host as the binary itself over the same channel. This only guards against transport corruption; an attacker who can tamper with (or MITM) the artifact server can replace both the binary and its published hash, so the check provides no integrity guarantee against a compromised source. Consider verifying a detached signature against a pinned public key, or pinning the expected hash out-of-band, rather than trusting a hash served alongside the artifact.

Was this helpful? React with 👍 / 👎

fi
actual="$(sha256_of "$binary")"
if [[ "$actual" != "$expected" ]]; then
echo "Error: SHA256 mismatch for $binary" >&2
echo " expected: $expected" >&2
echo " actual: $actual" >&2
exit 1
fi
echo "SHA256 verified: $binary ($version)"
}

# ── Binary download ───────────────────────────────────────────────────────────

download_binary() {
local version="$1" dest="$2"
local platform os base url_bin url_exe tmp_bin
platform="$(cdn_platform)"
os="$(cdn_os)"
if [[ -z "$platform" || -z "$os" ]]; then
echo "Error: unsupported platform." >&2; exit 1
fi
base="sonarqube-cli-${version}-${platform}"
url_bin="${ARTIFACT_BASE_URL}/${version}/${os}/${base}.bin"
url_exe="${ARTIFACT_BASE_URL}/${version}/${os}/${base}.exe"
tmp_bin="$(mktemp /tmp/sonar-bin.XXXXXX)"
trap 'rm -f "$tmp_bin"' EXIT
echo "Downloading sonarqube-cli from:"
if curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "$url_bin" -o "$tmp_bin" 2>/dev/null; then
echo " $url_bin"
elif curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "$url_exe" -o "$tmp_bin" 2>/dev/null; then
echo " $url_exe"
else
echo "Error: could not download sonarqube-cli." >&2; rm -f "$tmp_bin"; exit 1
fi
chmod +x "$tmp_bin"
verify_sha256 "$tmp_bin" "$version"
trap - EXIT
mv "$tmp_bin" "$dest"
}

# ── Step 1: install MDM binary ───────────────────────────────────────────────

echo "Installing SonarQube CLI to $MDM_BINARY..."

if [[ -n "$APPROVED_VERSION_OVERRIDE" ]]; then
version="$APPROVED_VERSION_OVERRIDE"
else
version="$(curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "${ARTIFACT_BASE_URL}/stable.version" | tr -d '[:space:]')"
fi
echo "Target version: $version"

mkdir -p "$(dirname "$MDM_BINARY")"
download_binary "$version" "$MDM_BINARY"

# ── Step 2: enumerate local user home directories ────────────────────────────

get_user_homes() {
getent passwd | awk -F: '$6 ~ /^\/home\// { print $6 }'
}

# ── Step 3: symlink standalone path → MDM binary for each user ───────────────

while IFS= read -r home; do
standalone="$home/$STANDALONE_REL"
[[ -e "$standalone" || -L "$standalone" ]] || continue

if [[ -L "$standalone" && "$(readlink "$standalone")" == "$MDM_BINARY" ]]; then
echo " $standalone — already symlinked, skipping"
continue
fi

echo " $standalone — replacing with symlink to $MDM_BINARY"
ln -sf "$MDM_BINARY" "$standalone"
done < <(get_user_homes)

# ── Verify ───────────────────────────────────────────────────────────────────

echo "MDM sonar: $MDM_BINARY — $("$MDM_BINARY" --version)"
echo "which sonar: $(which sonar)"
echo "sonar -v: $(sonar --version)"
61 changes: 61 additions & 0 deletions mdm-scripts/linux/remove.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# 1. Removes the MDM-managed binary.
# 2. Keeps removing wherever sonar resolves in system PATH until nothing is found.
# 3. Removes standalone installs from every local user's home directory.
set -euo pipefail

MDM_BINARY="/usr/local/bin/sonar"
STANDALONE_REL=".local/share/sonarqube-cli/bin/sonar"
export PATH="/usr/local/bin:$PATH"

# -- Remove MDM binary ---------------------------------------------------------

rm -f "$MDM_BINARY"

if [[ -f "$MDM_BINARY" ]]; then
echo "Error: failed to remove $MDM_BINARY" >&2
exit 1
fi
echo "MDM binary removed from $MDM_BINARY."

# -- Remove any remaining resolvable copies (system PATH) ----------------------
# Catches binaries in Homebrew, manually added PATH entries, etc.

while true; do
sonar_path="$(command -v sonar 2>/dev/null || true)"
[[ -z "$sonar_path" ]] && break
if ! "$sonar_path" --version 2>/dev/null | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
echo "Error: $sonar_path does not look like the SonarQube CLI (unexpected --version output) -- refusing to remove it." >&2
exit 1
fi
echo "sonar still resolves to: $sonar_path -- removing..."
rm -f "$sonar_path"
if [[ -e "$sonar_path" ]]; then
echo "Error: failed to remove $sonar_path" >&2
exit 1
fi
done
Comment thread
gitar-bot[bot] marked this conversation as resolved.

# -- Remove standalone installs from all local user home directories -----------
# These are not in SYSTEM's PATH so command -v cannot find them.

get_user_homes() {
case "$(uname -s)" in
Darwin)
dscl . list /Users NFSHomeDirectory \
| awk '$1 !~ /^_/ && $2 ~ /^\/Users\// { print $2 }'
;;
Linux)
getent passwd | awk -F: '$6 ~ /^\/home\// { print $6 }'
;;
esac
}

while IFS= read -r home; do
standalone="$home/$STANDALONE_REL"
[[ -e "$standalone" || -L "$standalone" ]] || continue
echo " $standalone -- removing..."
rm -f "$standalone"
done < <(get_user_homes)

echo "which sonar: not found"
101 changes: 101 additions & 0 deletions mdm-scripts/linux/rollback.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env bash
# Ensures the MDM binary is present, then rolls back to SONARQUBE_CLI_ROLLBACK_VERSION.
# SONARQUBE_CLI_ROLLBACK_VERSION — required JumpCloud variable (e.g. 1.1.0.3122).
set -euo pipefail

MDM_BINARY="/usr/local/bin/sonar"
readonly ARTIFACT_BASE_URL="https://binaries.sonarsource.com/Distribution/sonarqube-cli"
readonly HTTPS_ONLY="=https"
export PATH="/usr/local/bin:$PATH"
# JumpCloud-specific: {{SONARQUBE_CLI_ROLLBACK_VERSION}} is replaced with the Custom Variable's
# value (quoted) at runtime -- not a real environment variable. Other MDM systems may inject this
# differently.
ROLLBACK_VERSION={{SONARQUBE_CLI_ROLLBACK_VERSION}}
[[ "$ROLLBACK_VERSION" == \{\{*\}\} ]] && ROLLBACK_VERSION="" # defensive: unattached JumpCloud var may leave the literal placeholder
: "${ROLLBACK_VERSION:?SONARQUBE_CLI_ROLLBACK_VERSION must be set via JumpCloud variable injection}"

# ── SHA256 helpers ────────────────────────────────────────────────────────────

sha256_of() {
local file="$1"
sha256sum "$file" | awk '{print $1}'
}

cdn_os() { echo "linux"; }

cdn_platform() {
case "$(uname -m)" in
aarch64|arm64) echo "linux-arm64" ;;
x86_64|amd64) echo "linux-x86-64" ;;
*) echo "" ;;
esac
}

verify_sha256() {
local binary="$1" version="$2"
local platform os base url expected actual
platform="$(cdn_platform)"
os="$(cdn_os)"
if [[ -z "$platform" || -z "$os" ]]; then
echo "Warning: unsupported platform — skipping SHA256 check." >&2
return
fi
base="sonarqube-cli-${version}-${platform}"
url="${ARTIFACT_BASE_URL}/${version}/${os}/${base}.bin.sha256"
expected="$(curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "$url" 2>/dev/null | awk '{print $1}')"
if [[ -z "$expected" ]]; then
echo "Error: could not fetch SHA256 from $url — aborting." >&2
exit 1
fi
actual="$(sha256_of "$binary")"
if [[ "$actual" != "$expected" ]]; then
echo "Error: SHA256 mismatch for $binary" >&2
echo " expected: $expected" >&2
echo " actual: $actual" >&2
exit 1
fi
echo "SHA256 verified: $binary ($version)"
}

# ── Binary download ───────────────────────────────────────────────────────────

download_binary() {
local version="$1" dest="$2"
local platform os base url_bin url_exe tmp_bin
platform="$(cdn_platform)"
os="$(cdn_os)"
if [[ -z "$platform" || -z "$os" ]]; then
echo "Error: unsupported platform." >&2; exit 1
fi
base="sonarqube-cli-${version}-${platform}"
url_bin="${ARTIFACT_BASE_URL}/${version}/${os}/${base}.bin"
url_exe="${ARTIFACT_BASE_URL}/${version}/${os}/${base}.exe"
tmp_bin="$(mktemp /tmp/sonar-bin.XXXXXX)"
trap 'rm -f "$tmp_bin"' EXIT
echo "Downloading sonarqube-cli from:"
if curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "$url_bin" -o "$tmp_bin" 2>/dev/null; then
echo " $url_bin"
elif curl -fsSL --proto "$HTTPS_ONLY" --proto-redir "$HTTPS_ONLY" "$url_exe" -o "$tmp_bin" 2>/dev/null; then
echo " $url_exe"
else
echo "Error: could not download sonarqube-cli." >&2; rm -f "$tmp_bin"; exit 1
fi
chmod +x "$tmp_bin"
verify_sha256 "$tmp_bin" "$version"
trap - EXIT
mv "$tmp_bin" "$dest"
}

# ─────────────────────────────────────────────────────────────────────────────

if [[ ! -f "$MDM_BINARY" ]]; then
echo "MDM binary not found — installing target version directly..."
mkdir -p "$(dirname "$MDM_BINARY")"
download_binary "$ROLLBACK_VERSION" "$MDM_BINARY"
else
download_binary "$ROLLBACK_VERSION" "$MDM_BINARY"
fi

echo "MDM sonar: $MDM_BINARY — $("$MDM_BINARY" --version)"
echo "which sonar: $(which sonar)"
echo "sonar -v: $(sonar --version)"
Loading