feat(sandbox): port-in-use consent gate + uniform sudo capture

GUI launch (docker/podman) now pre-flights the noVNC port (6080): if it's
already bound, a modal names the holding pid and asks before killing it and
proceeding — never a blind `bind: address already in use` collision.

Sudo capture is now uniform across every backend installer. Previously only
Docker fed the masked-modal password through `--stdin-pass`/`sudo -S`; the
captured password was silently dropped for Podman/Multipass and never wired
for VirtualBox, and those scripts used bare `sudo` (which hangs/corrupts a
raw-mode tty). Now:
- shared `run_ensure()` feeds the password to any ensure-*.sh via stdin
- podman/multipass/vbox scripts gain the docker sudo ladder
  (interactive `sudo` / `--yes` `sudo -n` / `--stdin-pass` `sudo -S -p ''`)
- podman's apt path wrapped in `sh -c` so one sudo covers update+install
- vbox GUI path preflights `sudo_ready()` with actionable guidance, falling
  back to fail-fast `sudo -n` instead of a tty hang

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-06-08 11:00:09 -07:00
parent ad13ec14ba
commit c6eeb9b897
5 changed files with 318 additions and 47 deletions
+15 -1
View File
@@ -14,21 +14,35 @@
# ./ensure-multipass.sh --yes # install without prompting
# ./ensure-multipass.sh --check # test only; exit 0 if present, 1 if missing
# ./ensure-multipass.sh --plan # show the install plan; change nothing
# ./ensure-multipass.sh --stdin-pass # read a sudo password from stdin (sudo -S)
set -uo pipefail
ASSUME_YES=0
CHECK_ONLY=0
PLAN_ONLY=0
STDIN_PASS=0
for arg in "$@"; do
case "$arg" in
-y|--yes) ASSUME_YES=1 ;;
--check) CHECK_ONLY=1 ;;
--plan|--dry-run) PLAN_ONLY=1 ;;
# A sudo password is waiting on stdin (the hack-house TUI feeds it). Use
# `sudo -S` so escalation reads that, never the controlling tty.
--stdin-pass) STDIN_PASS=1 ;;
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "✖ unknown arg: $arg" >&2; exit 2 ;;
esac
done
# How to escalate (mirrors ensure-docker.sh):
# * --stdin-pass: a password is on stdin → `sudo -S -p ''` (reads stdin, never
# the tty; a raw-mode TUI would corrupt a tty prompt). First sudo caches it.
# * --yes alone: `sudo -n` — fails fast if creds aren't cached, never hangs.
# * interactive shell: plain `sudo` (a real terminal can prompt normally).
SUDO="sudo"
[[ $ASSUME_YES -eq 1 ]] && SUDO="sudo -n"
[[ $STDIN_PASS -eq 1 ]] && SUDO="sudo -S -p ''"
installed() { command -v multipass >/dev/null 2>&1 && multipass version >/dev/null 2>&1; }
mp_version() { multipass version 2>/dev/null | head -1; }
@@ -78,7 +92,7 @@ if [[ -z "$install_cmd" ]]; then
echo "✖ don't know how to install Multipass here — get it from https://multipass.run/install" >&2
exit 1
fi
[[ $need_sudo -eq 1 ]] && install_cmd="sudo $install_cmd"
[[ $need_sudo -eq 1 ]] && install_cmd="$SUDO $install_cmd"
[[ -n "$manual_note" ]] && echo "$manual_note" >&2
# --plan: show the real plan and change nothing.
+18 -2
View File
@@ -17,21 +17,35 @@
# ./ensure-podman.sh --yes # install without prompting
# ./ensure-podman.sh --check # test only; exit 0 if present, 1 if missing
# ./ensure-podman.sh --plan # show the install plan; change nothing
# ./ensure-podman.sh --stdin-pass # read a sudo password from stdin (sudo -S)
set -uo pipefail
ASSUME_YES=0
CHECK_ONLY=0
PLAN_ONLY=0
STDIN_PASS=0
for arg in "$@"; do
case "$arg" in
-y|--yes) ASSUME_YES=1 ;;
--check) CHECK_ONLY=1 ;;
--plan|--dry-run) PLAN_ONLY=1 ;;
# A sudo password is waiting on stdin (the hack-house TUI feeds it). Use
# `sudo -S` so escalation reads that, never the controlling tty.
--stdin-pass) STDIN_PASS=1 ;;
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "✖ unknown arg: $arg" >&2; exit 2 ;;
esac
done
# How to escalate (mirrors ensure-docker.sh):
# * --stdin-pass: a password is on stdin → `sudo -S -p ''` (reads stdin, never
# the tty; a raw-mode TUI would corrupt a tty prompt). First sudo caches it.
# * --yes alone: `sudo -n` — fails fast if creds aren't cached, never hangs.
# * interactive shell: plain `sudo` (a real terminal can prompt normally).
SUDO="sudo"
[[ $ASSUME_YES -eq 1 ]] && SUDO="sudo -n"
[[ $STDIN_PASS -eq 1 ]] && SUDO="sudo -S -p ''"
installed() { command -v podman >/dev/null 2>&1 && podman --version >/dev/null 2>&1; }
pm_version() { podman --version 2>/dev/null | head -1; }
@@ -67,7 +81,9 @@ manual_note=""
case "$(uname -s)" in
Linux)
if command -v apt-get >/dev/null 2>&1; then
install_cmd="apt-get update && apt-get install -y podman"
# Wrapped in `sh -c` so a single `$SUDO …` escalation covers BOTH the
# update and the install (a bare `$SUDO a && b` would only sudo `a`).
install_cmd="sh -c 'apt-get update && apt-get install -y podman'"
plan_cmd="apt-cache policy podman"
need_sudo=1
elif command -v dnf >/dev/null 2>&1; then
@@ -99,7 +115,7 @@ if [[ -z "$install_cmd" ]]; then
echo "✖ don't know how to install Podman here — get it from https://podman.io/docs/installation" >&2
exit 1
fi
[[ $need_sudo -eq 1 ]] && install_cmd="sudo $install_cmd"
[[ $need_sudo -eq 1 ]] && install_cmd="$SUDO $install_cmd"
[[ -n "$manual_note" ]] && echo "$manual_note" >&2
# --plan: show the real plan and change nothing.
+17 -1
View File
@@ -12,21 +12,35 @@
# ./ensure-vbox.sh --yes # install without prompting (used by --install)
# ./ensure-vbox.sh --check # test only; exit 0 if present, 1 if missing
# ./ensure-vbox.sh --plan # show the install/download plan; change nothing
# ./ensure-vbox.sh --stdin-pass # read a sudo password from stdin (sudo -S)
set -uo pipefail
ASSUME_YES=0
CHECK_ONLY=0
PLAN_ONLY=0
STDIN_PASS=0
for arg in "$@"; do
case "$arg" in
-y|--yes) ASSUME_YES=1 ;;
--check) CHECK_ONLY=1 ;;
--plan|--dry-run) PLAN_ONLY=1 ;;
# A sudo password is waiting on stdin (the hack-house TUI feeds it). Use
# `sudo -S` so escalation reads that, never the controlling tty.
--stdin-pass) STDIN_PASS=1 ;;
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "✖ unknown arg: $arg" >&2; exit 2 ;;
esac
done
# How to escalate (mirrors ensure-docker.sh):
# * --stdin-pass: a password is on stdin → `sudo -S -p ''` (reads stdin, never
# the tty; a raw-mode TUI would corrupt a tty prompt). First sudo caches it.
# * --yes alone: `sudo -n` — fails fast if creds aren't cached, never hangs.
# * interactive shell: plain `sudo` (a real terminal can prompt normally).
SUDO="sudo"
[[ $ASSUME_YES -eq 1 ]] && SUDO="sudo -n"
[[ $STDIN_PASS -eq 1 ]] && SUDO="sudo -S -p ''"
# HH_VBOX_FORCE_MISSING=1 lets a demo exercise the missing→install path without
# actually uninstalling anything (the probe is the single source of truth).
installed() {
@@ -88,7 +102,9 @@ if [[ -z "$install_cmd" ]]; then
echo "✖ don't know how to install VirtualBox here — get it from https://www.virtualbox.org/wiki/Downloads" >&2
exit 1
fi
[[ $need_sudo -eq 1 ]] && install_cmd="sudo $install_cmd"
[[ $need_sudo -eq 1 ]] && install_cmd="$SUDO $install_cmd"
# The plan path is only ever run interactively (the TUI never asks for --plan), so
# a plain `sudo` tty prompt is fine there.
[[ $plan_sudo -eq 1 ]] && plan_cmd="sudo $plan_cmd"
# Secure Boot needs the vboxdrv kernel module signed/enrolled (MOK) or it won't