config/bash/shell exported SSH_ASKPASS=ksshaskpass with SSH_ASKPASS_REQUIRE=prefer on every machine. `prefer` means ssh and git reach for that dialog BEFORE the terminal prompt, so on a headless 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://git.gbrown.org' A push from a server failed to ASK for a username rather than failing to authenticate. The shell environment is the one half of Panama a server does install, so nothing downstream was going to catch this. The export is now conditional on a session existing to draw in, and on the binary being there to run. The headless branch also CLEARS both variables rather than merely declining to set them: an askpass inherited from a parent that had a display, or from a login predating this guard, is exactly as unusable and a guard that only withholds leaves it in place. A fresh login shell on the repaired server still reported prefer until it cleared them. A desktop is unchanged; a server, a serial console and a plain SSH session fall back to the terminal prompt, which works. tests/setup/headless-askpass-contract pins every branch, the inherited case included, and fails against the previous code and against a guard that only withholds. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
95 lines
4.3 KiB
Bash
95 lines
4.3 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Personal environment -- API keys, tokens -- lives OUTSIDE the checkout,
|
|
# where agents, backup tools and `panama update` walk, and is kept owner-only
|
|
# every time it is read: a secrets file that drifts to 644 is quietly
|
|
# re-tightened rather than trusted. Sourced first, because settings below
|
|
# (PANAMA_SSH_TMUX) read it. (config/bash/env, its old home inside the repo,
|
|
# is still sourced by .bashrc's glob if a machine has not been migrated yet.)
|
|
PANAMA_ENV="${XDG_CONFIG_HOME:-$HOME/.config}/panama/env"
|
|
if [ -f "$PANAMA_ENV" ]; then
|
|
[ "$(stat -c %a "$PANAMA_ENV" 2>/dev/null)" = "600" ] || chmod 600 "$PANAMA_ENV"
|
|
. "$PANAMA_ENV"
|
|
fi
|
|
unset PANAMA_ENV
|
|
|
|
# Editor used by CLI
|
|
export EDITOR="nvim"
|
|
export SUDO_EDITOR="$EDITOR"
|
|
# A graphical askpass, and only where there is a session to draw it in.
|
|
# SSH_ASKPASS_REQUIRE=prefer means ssh and git reach for the dialog BEFORE the
|
|
# terminal prompt, so on a headless machine the prompt that would have worked
|
|
# is skipped in favour of one that cannot open: `git push` then fails reading
|
|
# a username rather than asking for it. The desktop keeps the dialog; a
|
|
# server, a serial console and a plain SSH session fall back to the terminal.
|
|
if [ -n "${WAYLAND_DISPLAY:-}${DISPLAY:-}" ] && [ -x /usr/bin/ksshaskpass ]; then
|
|
export SSH_ASKPASS=/usr/bin/ksshaskpass
|
|
export SSH_ASKPASS_REQUIRE=prefer
|
|
else
|
|
# Cleared, not merely left unset. An askpass inherited from a parent that
|
|
# did have a display -- an agent's shell, a forwarded environment, a login
|
|
# that predates this guard -- is exactly as unusable here as one this file
|
|
# set itself, and declining to add it does nothing about a value already in
|
|
# the environment.
|
|
unset SSH_ASKPASS SSH_ASKPASS_REQUIRE
|
|
fi
|
|
|
|
# Define Paths
|
|
export CARGO_PATH="$HOME/.cargo"
|
|
export BUN_INSTALL="$HOME/.bun"
|
|
export PYENV_ROOT="$HOME/.pyenv"
|
|
export PNPM_HOME="$HOME/.local/share/pnpm"
|
|
export NVM_DIR="$HOME/.nvm"
|
|
export ANDROID_SDK_HOME="$HOME/.local/share/Android"
|
|
export GOPATH="$HOME/.local/share/go"
|
|
export DOTNETPATH="$HOME/.dotnet/tools"
|
|
|
|
# Podman
|
|
# export DOCKER_HOST=unix:///run/user/1000/podman/podman.sock
|
|
|
|
# Set complete path
|
|
export PATH="$HOME/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PANAMA_PATH/bin:$BUN_INSTALL/bin:$CARGO_PATH/bin:$PNPM_HOME/bin:$PYENV_ROOT/bin:$HOME/.rbenv/bin:/usr/lib/ccache/bin/:$GOPATH/bin:$DOTNETPATH"
|
|
|
|
# rustup writes this file, and initial-packages installs rustup rather than
|
|
# running rustup-init -- so on a fresh machine it does not exist yet and an
|
|
# unguarded source made every single shell start with an error.
|
|
[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env"
|
|
|
|
# Nvm. Guarded because the file belongs to the nvm package: before that is
|
|
# installed it does not exist, and an unconditional source means every shell on
|
|
# a fresh machine opens with an error.
|
|
[ -f /etc/profile.d/nvm.sh ] && source /etc/profile.d/nvm.sh
|
|
# Auto-switch Node version when entering a directory with .nvmrc
|
|
_nvm_auto_use() {
|
|
# Guarded on nvm actually being loaded: without this, a machine where the
|
|
# nvm profile script is absent printed "command not found" on every single
|
|
# prompt in any directory carrying a .nvmrc.
|
|
if [[ -f .nvmrc ]] && type -t nvm >/dev/null 2>&1; then
|
|
nvm use --silent
|
|
fi
|
|
}
|
|
export PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND; }_nvm_auto_use"
|
|
|
|
# Auto-start or attach tmux for SSH interactive shells. A deliberate Panama
|
|
# behavior (tmux is in initial-packages, and a dropped SSH session keeping its
|
|
# work is the point), but guarded: it must not replace the shell of someone
|
|
# whose machine lacks tmux, and PANAMA_SSH_TMUX=off turns it off for people
|
|
# who want a plain shell -- set it in ~/.config/panama/env.
|
|
if [[ -n "$SSH_CONNECTION" && -z "$TMUX" && $- == *i* &&
|
|
"${PANAMA_SSH_TMUX:-on}" != "off" ]] && command -v tmux >/dev/null 2>&1; then
|
|
exec tmux new-session -A -s main
|
|
fi
|
|
|
|
# Zoxide
|
|
eval "$(zoxide init bash)"
|
|
|
|
# Oh My Posh
|
|
# Guarded for the same reason the nvm source above is: oh-my-posh is a package,
|
|
# and a shell opened before it is installed -- a stage re-run by hand, an
|
|
# install that failed partway -- would otherwise print command-not-found on
|
|
# every prompt. An unthemed prompt is a worse shell; an erroring one is a
|
|
# broken-looking machine.
|
|
if command -v oh-my-posh >/dev/null 2>&1; then
|
|
eval "$(oh-my-posh init bash --config "$PANAMA_PATH/config/dot/ohmyposh/gib.omp.json")"
|
|
fi
|