1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
#!/bin/bash
# ssh client config. Dry run by default; pass `yes` to apply.
set -euo pipefail
# shellcheck source-path=SCRIPTDIR
# shellcheck source=lib.sh
source "$(dirname "$0")/lib.sh" "$@"
# ~/.ssh/config itself is the entry point: it reads ~/.config/ssh/config-fleet
# first, if another layer has linked one in, then this host's
# ~/.config/ssh/config-local -- see config/ssh/entry. Only the file is linked;
# ~/.ssh stays a real directory, because what else lives in it (keys,
# known_hosts, control and agent sockets) is this host's own.
#
# Each step below is skipped, loudly, rather than forced, because link() starts
# with `rm -rf`:
# - a symlinked ~/.ssh. On the Macs it once pointed into iCloud Drive, a
# single directory shared by two machines, so replacing a file in it on one
# deleted it on the other.
# - a real ~/.ssh/config holding anything but `Include ~/.config/ssh/config`,
# the one line each host was given by hand on 2026-09-07, before this file
# was linked. Anything else is host-specific and belongs in config-local;
# move it there first.
ssh_dir="$HOME/.ssh"
if [[ -L "$ssh_dir" ]]
then
red "$ssh_dir is a symlink to $(readlink "$ssh_dir"); skipping ssh links -- make it a real local directory first"
exit 0
fi
if [[ -z "${is_dry_run}" && ! -d "$ssh_dir" ]]
then
install -d -m 700 "$ssh_dir"
fi
ssh_config_extra=""
if [[ -f "$ssh_dir/config" && ! -L "$ssh_dir/config" ]]
then
ssh_config_extra="$(grep -vE '^[[:space:]]*(#|$)' "$ssh_dir/config" \
| grep -vxF 'Include ~/.config/ssh/config' || true)"
fi
if [[ -n "$ssh_config_extra" ]]
then
red "$ssh_dir/config has host-specific lines; move them to ~/.config/ssh/config-local, then re-run"
else
link "$config_dir/ssh/entry" "$ssh_dir/config"
fi
# Links this repo made while host blocks and their key pins were tracked here,
# now that another layer owns them: only a dangling link in ~/.config/ssh that
# points into this repo's config/ssh is removed -- never a real file, and never
# a link someone else made. Compared as real paths: the link holds whatever
# spelling this repo had when it was made, which on a machine whose checkout is
# reached through a symlink is not this run's.
ssh_repo_dir="$(realpath "$config_dir/ssh")"
for stale in "$xdg_config_dir"/ssh/*
do
if [[ -L "$stale" && ! -e "$stale" ]] \
&& [[ "$(realpath "$(dirname "$(readlink "$stale")")" 2>/dev/null)" == "$ssh_repo_dir" ]]
then
if [[ -n "${is_dry_run}" ]]
then
yellow "$stale is a dangling link into this repo and will be removed"
else
rm "$stale"
fi
fi
done
|