diff --git a/install.sh b/install.sh index 84c5be9742..dface28918 100755 --- a/install.sh +++ b/install.sh @@ -625,6 +625,36 @@ _is_pkg_installed() { esac } +# ── Helper: human-readable apt distro label for the sudo package prompt (#6207) ── +# Reads /etc/os-release so the Accept? prompt can say which distro we detected and +# that packages come from that distro's official apt repos (not a tarball). +_apt_distro_description() { + # Plain ( ... ) subshell — not $() — so case/;; stays bash-3.2-safe on macOS. + # Bash 3.2 misparses case arms inside command substitution and errors on `;;`. + ( + if [ ! -r /etc/os-release ]; then + printf 'a debian-like system' + exit 0 + fi + # shellcheck disable=SC1091 + . /etc/os-release 2>/dev/null || true + if [ -n "${NAME:-}" ] && [ -n "${VERSION_ID:-}" ]; then + _ad_label="$NAME $VERSION_ID" + elif [ -n "${PRETTY_NAME:-}" ]; then + _ad_label="$PRETTY_NAME" + elif [ -n "${NAME:-}" ]; then + _ad_label="$NAME" + else + printf 'a debian-like system' + exit 0 + fi + case " ${ID:-} ${ID_LIKE:-} " in + *" debian "*|*" ubuntu "*) _ad_label="${_ad_label} (debian-like)" ;; + esac + printf '%s' "$_ad_label" + ) +} + # ── Helper: install packages via apt, escalating to sudo only if needed ── # Usage: _smart_apt_install pkg1 pkg2 pkg3 ... _smart_apt_install() { @@ -655,11 +685,14 @@ _smart_apt_install() { # Step 3: Escalate -- need elevated permissions for remaining packages if command -v sudo >/dev/null 2>&1; then + _ad_desc="$(_apt_distro_description)" echo "" echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo " WARNING: We require sudo elevated permissions to install:" echo " $_STILL_MISSING" - echo " If you accept, we'll run sudo now, and it'll prompt your password." + echo " Detected ${_ad_desc}." + echo " If you accept, we'll run sudo apt-get to install these packages" + echo " from your distro's official repositories (not a third-party tarball)." echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" echo "" printf " Accept? [Y/n] " diff --git a/tests/sh/test_apt_distro_prompt.sh b/tests/sh/test_apt_distro_prompt.sh new file mode 100755 index 0000000000..19601b0065 --- /dev/null +++ b/tests/sh/test_apt_distro_prompt.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 +# Unit tests for install.sh's _apt_distro_description helper (#6207). +# The sudo Accept? prompt should name the detected distro and say packages come +# from official apt repos. Hermetic: extract the helper and rewrite +# /etc/os-release to per-test fixtures (same pattern as test_strixhalo_wsl_reroute.sh). +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INSTALL_SH="$SCRIPT_DIR/../../install.sh" +PASS=0 +FAIL=0 + +_TMP_ROOT=$(mktemp -d) +trap 'rm -rf "$_TMP_ROOT"' EXIT + +assert_eq() { + _label="$1"; _expected="$2"; _actual="$3" + if [ "$_actual" = "$_expected" ]; then + echo " PASS: $_label"; PASS=$((PASS + 1)) + else + echo " FAIL: $_label (expected '$_expected', got '$_actual')"; FAIL=$((FAIL + 1)) + fi +} + +assert_contains() { + _label="$1"; _hay="$2"; _needle="$3" + case "$_hay" in + *"$_needle"*) echo " PASS: $_label"; PASS=$((PASS + 1)) ;; + *) echo " FAIL: $_label (missing '$_needle' in: $_hay)"; FAIL=$((FAIL + 1)) ;; + esac +} + +# Extract helper with /etc/os-release rewritten to $1. +build_func() { + _fix="$1" + _f=$(mktemp -p "$_TMP_ROOT") + sed -n '/^_apt_distro_description()/,/^}/p' "$INSTALL_SH" \ + | sed -e "s#/etc/os-release#$_fix/os-release#g" \ + > "$_f" + echo "$_f" +} + +run_desc() { + _os="$1" + _d=$(mktemp -d -p "$_TMP_ROOT") + printf '%s\n' "$_os" > "$_d/os-release" + _f=$(build_func "$_d") + # shellcheck disable=SC1090 + . "$_f" + _apt_distro_description +} + +echo "=== _apt_distro_description ===" + +assert_eq "ubuntu name+version debian-like" \ + "Ubuntu 24.04 (debian-like)" \ + "$(run_desc "$(printf 'NAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nID=ubuntu\nID_LIKE=debian\n')")" + +assert_eq "debian name+version debian-like" \ + "Debian GNU/Linux 12 (debian-like)" \ + "$(run_desc "$(printf 'NAME=\"Debian GNU/Linux\"\nVERSION_ID=\"12\"\nID=debian\n')")" + +assert_eq "pretty_name fallback when name/version missing" \ + "Linux Mint 22 (debian-like)" \ + "$(run_desc "$(printf 'PRETTY_NAME=\"Linux Mint 22\"\nID=linuxmint\nID_LIKE=\"ubuntu debian\"\n')")" + +# NAME alone (no VERSION_ID) — still prefer NAME over PRETTY_NAME. +assert_eq "name only" \ + "Pop!_OS (debian-like)" \ + "$(run_desc "$(printf 'NAME=\"Pop!_OS\"\nID=pop\nID_LIKE=\"ubuntu debian\"\n')")" + +assert_eq "missing os-release file" \ + "a debian-like system" \ + "$( + _d=$(mktemp -d -p "$_TMP_ROOT") + _f=$(build_func "$_d") + # shellcheck disable=SC1090 + . "$_f" + _apt_distro_description + )" + +echo "=== _smart_apt_install prompt contract ===" +_smart=$(sed -n '/^_smart_apt_install()/,/^}/p' "$INSTALL_SH") +assert_contains "calls distro helper" "$_smart" '_apt_distro_description' +assert_contains "names detected distro" "$_smart" 'Detected ${_ad_desc}' +assert_contains "mentions apt-get" "$_smart" 'sudo apt-get' +assert_contains "mentions official repos" "$_smart" "official repositories" +assert_contains "rejects tarball worry" "$_smart" "not a third-party tarball" + +echo "" +echo "Results: $PASS passed, $FAIL failed" +[ "$FAIL" -eq 0 ]