-
Notifications
You must be signed in to change notification settings - Fork 8
CLI-871 Add MDM deployment scripts as public reference #601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
kirill-knize-sonarsource
wants to merge
1
commit into
master
Choose a base branch
from
knize/CLI-871-mdm-scripts
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
| 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)" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
|
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" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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
.sha256file 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 👍 / 👎