feat: pre-auth sudo once before brew bundle install with keepalive

Homebrew cask installers call sudo internally for each package that needs
admin privileges. Without pre-authentication, macOS prompts for a password
on every such package across a long brew bundle run.

_ssr_sudo_keepalive_start:
  Calls 'sudo -v' once (prompts user if not already cached), then spawns a
  background loop that calls 'sudo -n true' every 60s to prevent the
  default 5-minute credential cache from expiring mid-run.

_ssr_sudo_keepalive_stop:
  Kills the keepalive loop after brew bundle completes.

If sudo is unavailable (non-admin user), a warning is shown and the run
continues — individual cask installers that need sudo will prompt as before.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-12 09:49:34 +02:00
parent 698cbe145a
commit 488a9a2140
+45 -3
View File
@@ -62,19 +62,61 @@ ssr::brew::dump() {
ssr::ok "Brewfile written ($(wc -l < "$brewfile" | tr -d ' ') lines)" ssr::ok "Brewfile written ($(wc -l < "$brewfile" | tr -d ' ') lines)"
} }
# Pre-authenticate sudo once and keep credentials alive in the background.
# macOS caches sudo credentials for 5 minutes (300s); the keepalive loop
# refreshes every 60s so Homebrew cask installers never hit a timeout mid-run.
#
# Usage:
# _ssr_sudo_keepalive_start # prompts once, starts background loop
# … long-running commands …
# _ssr_sudo_keepalive_stop # kills the loop
_SSR_SUDO_KEEPALIVE_PID=""
_ssr_sudo_keepalive_start() {
# Check whether sudo is available at all (may already be cached).
if ! sudo -v 2>/dev/null; then
ssr::warn "sudo authentication failed — cask installs may prompt per-package."
return 0
fi
ssr::ok "sudo credentials cached — Homebrew casks will not prompt during install."
# Background loop: re-validate every 60s to prevent 5-minute timeout.
(
while true; do
sleep 60
sudo -n true 2>/dev/null || break
done
) &
_SSR_SUDO_KEEPALIVE_PID=$!
}
_ssr_sudo_keepalive_stop() {
if [[ -n "$_SSR_SUDO_KEEPALIVE_PID" ]]; then
kill "$_SSR_SUDO_KEEPALIVE_PID" 2>/dev/null || true
wait "$_SSR_SUDO_KEEPALIVE_PID" 2>/dev/null || true
_SSR_SUDO_KEEPALIVE_PID=""
fi
}
ssr::brew::restore() { ssr::brew::restore() {
local brewfile="$1" local brewfile="$1"
[[ -f "$brewfile" ]] || ssr::die "Brewfile not found: $brewfile" [[ -f "$brewfile" ]] || ssr::die "Brewfile not found: $brewfile"
ssr::log "brew bundle install ← $brewfile" ssr::log "brew bundle install ← $brewfile"
# Authenticate sudo once up front so Homebrew cask installers don't
# prompt individually for each package that needs admin privileges.
_ssr_sudo_keepalive_start
# Suppress per-app Spotlight indexing: mas would otherwise run mdimport # Suppress per-app Spotlight indexing: mas would otherwise run mdimport
# after every single App Store installation, which adds minutes of latency # after every App Store installation. One batch pass runs below instead.
# spread across the run. We do one batch mdimport after bundle completes.
local rc=0 local rc=0
MAS_NO_AUTO_INDEX=1 brew bundle install --file="$brewfile" --verbose || rc=$? MAS_NO_AUTO_INDEX=1 brew bundle install --file="$brewfile" --verbose || rc=$?
_ssr_sudo_keepalive_stop
# Single batch Spotlight index of /Applications after all installs. # Single batch Spotlight index of /Applications after all installs.
ssr::log "Indexing /Applications in Spotlight (one-time batch after all installs)" ssr::log "Indexing /Applications in Spotlight (one-time batch)"
mdimport /Applications 2>/dev/null || true mdimport /Applications 2>/dev/null || true
[[ -d "$HOME/Applications" ]] && mdimport "$HOME/Applications" 2>/dev/null || true [[ -d "$HOME/Applications" ]] && mdimport "$HOME/Applications" 2>/dev/null || true