#!/usr/bin/env bash # The graphical askpass, and the machines that have no graphics. # # config/bash/shell used to export SSH_ASKPASS=ksshaskpass with # SSH_ASKPASS_REQUIRE=prefer unconditionally. `prefer` means ssh and git reach # for that dialog BEFORE the terminal prompt, so on a server the prompt that # would have worked was skipped in favour of a KDE window that cannot open: # # error: /usr/bin/ksshaskpass died of signal 6 # fatal: could not read Username for 'https://...' # # A `git push` from a headless box failed to ASK for a username rather than # failing to authenticate -- and the shell environment is the one half of # Panama a server does install, so nothing else was going to catch it. # # Pinned here: headless sessions never prefer a dialog, and a desktop with the # binary present still gets one. set -uo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" shell_file="$repo_dir/config/bash/shell" findings=() note() { findings+=("$1"); } work="$(mktemp -d)" trap 'rm -rf "$work"' EXIT mkdir -p "$work/home" # Sources the shell environment in a sandbox and reports one variable from it. # HOME is empty so the personal env file is not read, and the session is # non-interactive with no SSH_CONNECTION so the tmux hand-off cannot fire. askpass_state() { env -u DISPLAY -u WAYLAND_DISPLAY -u SSH_CONNECTION -u SSH_ASKPASS \ -u SSH_ASKPASS_REQUIRE "$@" \ HOME="$work/home" PANAMA_PATH="$repo_dir" \ bash -c 'source "$1" >/dev/null 2>&1 printf "%s|%s" "${SSH_ASKPASS:-}" "${SSH_ASKPASS_REQUIRE:-}"' \ _ "$shell_file" } # ── Headless is the case that broke ────────────────────────────────────────── got="$(askpass_state)" [[ "$got" == "|" ]] \ || note "a headless session still prefers a graphical askpass (got '$got')" got="$(askpass_state SSH_CONNECTION='10.0.0.1 22 10.0.0.2 22')" [[ "$got" == "|" ]] \ || note "an SSH session still prefers a graphical askpass (got '$got')" # The case the first version of this contract missed: declining to SET the # variables does nothing about ones already in the environment, inherited from # a parent that had a display or from a login predating the guard. A fresh # login shell on the repaired server still reported prefer until the headless # branch cleared them outright, so the clearing is what gets pinned. got="$(askpass_state SSH_ASKPASS=/usr/bin/ksshaskpass SSH_ASKPASS_REQUIRE=prefer)" [[ "$got" == "|" ]] \ || note "an inherited askpass survived a headless session (got '$got')" # ── A desktop still gets its dialog ────────────────────────────────────────── # Only assertable where the binary exists; saying so beats asserting that a # machine without KDE installed fails to configure KDE's dialog. if [[ -x /usr/bin/ksshaskpass ]]; then got="$(askpass_state WAYLAND_DISPLAY=wayland-0)" [[ "$got" == "/usr/bin/ksshaskpass|prefer" ]] \ || note "a Wayland session does not prefer the graphical askpass (got '$got')" got="$(askpass_state DISPLAY=:0)" [[ "$got" == "/usr/bin/ksshaskpass|prefer" ]] \ || note "an X session does not prefer the graphical askpass (got '$got')" else printf 'headless askpass contract: ksshaskpass is not installed, so the desktop half was not verified\n' >&2 fi # ── Report ─────────────────────────────────────────────────────────────────── if (( ${#findings[@]} > 0 )); then printf 'headless askpass contract FAILED:\n' >&2 printf ' - %s\n' "${findings[@]}" >&2 exit 1 fi printf 'headless askpass contract passed\n'