From 682e3769f6927b08b15b646b96b38d9f6bc4ea1b Mon Sep 17 00:00:00 2001 From: The_miro Date: Thu, 9 Jul 2026 09:55:54 +0200 Subject: [PATCH] feat(setup/tools): add passwordless-sudo.sh toggle script For sessions that need to run a string of sudo commands with nothing around to answer a password prompt (unattended VM builds, agent-driven scripting). Drops a validated sudoers.d NOPASSWD entry for the current user on enable, removes it on disable. Off by default, not part of the regular install/update flow. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01TLz6HWsXCwzQ97LrLt2em6 --- setup/tools/passwordless-sudo.sh | 104 +++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100755 setup/tools/passwordless-sudo.sh diff --git a/setup/tools/passwordless-sudo.sh b/setup/tools/passwordless-sudo.sh new file mode 100755 index 0000000..34ec14a --- /dev/null +++ b/setup/tools/passwordless-sudo.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# ============================================================================= +# passwordless-sudo.sh — toggle temporary NOPASSWD sudo for the current user +# ============================================================================= +# Some workflows (unattended VM builds, agent-driven scripting sessions) need +# to run a string of `sudo` commands with nothing around to answer a password +# prompt. This drops a single sudoers.d file granting the invoking user full +# NOPASSWD sudo, and removes it again just as easily. +# +# This is a deliberate, temporary reduction in local security — anything +# running as your user can become root without a password while it's active. +# Turn it off (`disable`) as soon as whatever needed it is done. It does NOT +# persist across the dotfiles install/update flow — it's a manual toggle you +# reach for and put back, not a permanent config. +# +# Usage: +# passwordless-sudo.sh enable [--yes] Grant NOPASSWD sudo to $USER +# passwordless-sudo.sh disable Revoke it +# passwordless-sudo.sh status Report whether it's currently active +# +# The drop-in is validated with `visudo -c` before being installed, so a typo +# here can't corrupt sudo for the whole system. +# ============================================================================= + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# lib/logging.sh lives at setup/modules/lib/, two levels up from setup/tools/. +source "$SCRIPT_DIR/../modules/lib/logging.sh" + +TARGET_USER="$(id -un)" +SUDOERS_FILE="/etc/sudoers.d/90-${TARGET_USER}-temp-nopasswd" + +usage() { + printf 'Usage: %s {enable|disable|status} [--yes]\n' "$(basename "$0")" >&2 + exit 1 +} + +[[ $# -ge 1 ]] || usage +ACTION="$1"; shift || true +ASSUME_YES=0 +for arg in "$@"; do + case "$arg" in + -y|--yes) ASSUME_YES=1 ;; + *) usage ;; + esac +done + +is_enabled() { [[ -f "$SUDOERS_FILE" ]]; } + +cmd_status() { + if is_enabled; then + log "Passwordless sudo is ENABLED for $TARGET_USER ($SUDOERS_FILE)" + else + skip "Passwordless sudo is disabled for $TARGET_USER" + fi +} + +cmd_enable() { + if is_enabled; then + skip "Already enabled — nothing to do." + return 0 + fi + + warn "This grants $TARGET_USER full root access with NO password prompt," + warn "system-wide, until you run: $(basename "$0") disable" + if [[ $ASSUME_YES -ne 1 ]]; then + read -rp "Proceed? [y/N] " _ans + [[ "${_ans,,}" == "y" ]] || { skip "Aborted."; exit 0; } + fi + + local tmp + tmp="$(mktemp)" + printf '%s ALL=(ALL) NOPASSWD: ALL\n' "$TARGET_USER" > "$tmp" + + # Validate the drop-in in isolation before it ever touches /etc/sudoers.d — + # visudo -c checks syntax without requiring the file to be in place first. + if ! sudo visudo -c -f "$tmp" >/dev/null; then + err "Generated sudoers snippet failed validation — not installing it." + rm -f "$tmp" + exit 1 + fi + + sudo install -m 0440 -o root -g root "$tmp" "$SUDOERS_FILE" + rm -f "$tmp" + log "Passwordless sudo enabled for $TARGET_USER." + warn "Remember to run: $(basename "$0") disable" +} + +cmd_disable() { + if ! is_enabled; then + skip "Already disabled — nothing to do." + return 0 + fi + sudo rm -f "$SUDOERS_FILE" + log "Passwordless sudo disabled for $TARGET_USER." +} + +case "$ACTION" in + enable) cmd_enable ;; + disable) cmd_disable ;; + status) cmd_status ;; + *) usage ;; +esac