diff options
| author | 2026-05-22 10:41:23 +0100 | |
|---|---|---|
| committer | 2026-05-22 10:41:23 +0100 | |
| commit | 159d69ddd122cfdb55d087d754d7472d42fa73ae (patch) | |
| tree | 83335fa7491a84e78d296218638bdc63fd1a5dd3 | |
| parent | 4c25f9b12269fcb4ea49f076b8d9f79e672c8072 (diff) | |
| download | dotfiles-159d69ddd122cfdb55d087d754d7472d42fa73ae.tar.gz dotfiles-159d69ddd122cfdb55d087d754d7472d42fa73ae.tar.bz2 dotfiles-159d69ddd122cfdb55d087d754d7472d42fa73ae.zip | |
fix(ssh): stabilise forwarded ssh-agent socket across reconnects
Forwarded SSH_AUTH_SOCK lives at /tmp/ssh-XXX/agent.NNN — a
per-connection path that disappears on disconnect, leaving every
long-running zellij pane (and its children: claude-code, nvim, …)
pointing at a dead socket. Reattaching after reconnect doesn't help:
the env was captured when zellij first started.
Fix: maintain ~/.ssh/agent.sock as a symlink, re-aimed at the live
forwarded socket on every login (zprofile). Export the stable path so
processes inherit a value that survives reconnects — git fetch /
commit signing keep working in re-attached zellij panes with zero
per-pane re-export.
Adds 'ssh-agent-refresh' helper for transitional panes still holding
the dead per-connection path: re-exports SSH_AUTH_SOCK to the stable
symlink and validates with ssh-add -l. Already-running children
(claude-code) must still be restarted since env is inherited, not
observed.
| -rw-r--r-- | dot_config/zsh/dot_zprofile | 20 | ||||
| -rw-r--r-- | dot_config/zsh/dot_zshrc | 23 |
2 files changed, 40 insertions, 3 deletions
diff --git a/dot_config/zsh/dot_zprofile b/dot_config/zsh/dot_zprofile index 9783e8e..66e97cd 100644 --- a/dot_config/zsh/dot_zprofile +++ b/dot_config/zsh/dot_zprofile @@ -45,9 +45,23 @@ export LESS="-F --RAW-CONTROL-CHARS" # ── GPG / SSH ───────────────────────────────────────────────────────────────── unset SSH_AGENT_PID -# If we're inside an SSH session with a forwarded agent socket, keep it. -# Otherwise route SSH auth through the local gpg-agent. -if [[ -z "$SSH_CONNECTION" || -z "$SSH_AUTH_SOCK" ]]; then +# Forwarded ssh-agent sockets live at /tmp/ssh-XXX/agent.NNN — a path +# that disappears the moment the originating ssh connection drops, +# leaving any long-running zellij pane (and its children: claude, +# nvim, etc.) pointing at a dead socket. Keep a stable +# ~/.ssh/agent.sock symlink that we re-aim on every login, and export +# the stable path so processes inherit a value that survives +# reconnects. Reattaching a zellij session after `ssh` → signing / +# git-fetch keep working without any per-pane re-export. +if [[ -n "$SSH_CONNECTION" && -S "$SSH_AUTH_SOCK" ]]; then + stable_sock="$HOME/.ssh/agent.sock" + if [[ "$SSH_AUTH_SOCK" != "$stable_sock" ]]; then + ln -sfn "$SSH_AUTH_SOCK" "$stable_sock" + fi + export SSH_AUTH_SOCK="$stable_sock" + unset stable_sock +else + # Local login: route ssh auth through gpg-agent. SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" export SSH_AUTH_SOCK fi diff --git a/dot_config/zsh/dot_zshrc b/dot_config/zsh/dot_zshrc index 2eea559..961a5b4 100644 --- a/dot_config/zsh/dot_zshrc +++ b/dot_config/zsh/dot_zshrc @@ -389,6 +389,29 @@ reload-env() { done < "/proc/$pid/environ" } +# Refresh the ssh-agent socket inside a zellij pane that has outlived +# its originating SSH connection. zprofile keeps ~/.ssh/agent.sock +# aimed at the live forwarded socket on every reconnect, so the stable +# path is current — this just re-exports it for shells whose own +# SSH_AUTH_SOCK still holds the dead per-connection path captured +# when zellij was first started. Already-running children +# (claude-code, etc.) must still be restarted: env is inherited, not +# observed. +ssh-agent-refresh() { + local sock="$HOME/.ssh/agent.sock" + if [[ ! -e $sock ]]; then + echo "ssh-agent-refresh: $sock missing; reconnect over ssh first to seed it" >&2 + return 1 + fi + export SSH_AUTH_SOCK="$sock" + if ssh-add -l >/dev/null 2>&1; then + print -r -- "ssh-agent: live → $(readlink -f -- "$sock")" + else + echo "ssh-agent-refresh: stable socket exists but ssh-add -l failed; agent forwarding off?" >&2 + return 1 + fi +} + # Just alias j='just' alias dj='just --justfile ~/dotfiles/justfile --working-directory ~/dotfiles' |
