Start gnome-keyring, so the session has an ssh-agent

PAM starts the daemon at login but brings up only its `control` socket.
Nothing else brought up the rest, so a HyprCosmic session had no agent at
all: SSH_AUTH_SOCK unset, every SSH operation asking for the passphrase
again, and callers of the secrets API finding nothing listening. Under the
stock COSMIC session the same machine works, which makes it look like a
key problem rather than a session-script omission.

`--start` attaches to the daemon that is already running and brings up the
missing components; on this machine that created `pkcs11` and `ssh`
alongside the existing `control`.

Where the socket path comes from is the part worth writing down.
start-cosmic evals the daemon's stdout, but the eval is
`eval "$(... > /dev/null 2>&1)"` -- the redirect is inside the
substitution, so it always evaluates the empty string, and the block works
only because of the socket checks after it. Rather than repair that by
evaluating whatever a daemon writes to stdout, this reads out the single
variable we want and keeps the fixed paths as the fallback. The daemon
also writes chatter to stderr, so the 2>/dev/null is load-bearing for the
parse rather than tidiness.

start-cosmic's rule is kept intact: set the correct socket or set none at
all, never a wrong one. A plain file sitting where the socket belongs is
rejected by the `-S` test, and a machine with no keyring directory skips
the block entirely.

SSH_AUTH_SOCK then joins the systemd and D-Bus activation environments for
the same reason XDG_CURRENT_DESKTOP did: a user unit or an activated app
looks there, not in this script's environment. `import-environment` ignores
an unset name and exits 0, so a machine without a keyring still logs in.
This commit is contained in:
2026-08-10 15:09:07 +07:00
parent 22e894330e
commit bdff38edac
+53 -2
View File
@@ -68,6 +68,52 @@ export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:-COSMIC}"
export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-hyprcosmic}" export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-hyprcosmic}"
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:-wayland}" export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:-wayland}"
# gnome-keyring, and the SSH agent it provides.
#
# PAM starts the daemon at login but brings up only its `control` socket, so
# without this a HyprCosmic session has no ssh-agent at all: SSH_AUTH_SOCK is
# unset, anything over SSH asks for the passphrase every time, and callers of
# the secrets API find nothing listening. `--start` attaches to the daemon that
# is already running and brings up whichever components are missing.
#
# The daemon writes `NAME=value` to stdout and chatter like
# "discover_other_daemon: 1" to stderr, so the 2>/dev/null is load-bearing for
# the parse, not just for tidiness.
#
# start-cosmic evals that stdout, but its eval is
# `eval "$(... > /dev/null 2>&1)"` -- the redirect is *inside* the substitution,
# so the eval always runs on an empty string and the block works only because
# of the socket checks that follow it. Rather than repair that by evaluating
# whatever a daemon chooses to write to stdout, read out the one variable we
# actually want.
if [[ -d "/run/user/$(id -u)/keyring" ]]; then
keyring_ssh_sock=""
if command -v gnome-keyring-daemon >/dev/null 2>&1; then
keyring_ssh_sock="$(
gnome-keyring-daemon --start --components=pkcs11,secrets,ssh 2>/dev/null |
sed -n 's/^SSH_AUTH_SOCK=//p' | tail -n1
)"
else
echo "start-hyprcosmic: gnome-keyring-daemon not found in PATH" >&2
fi
# start-cosmic's rule, kept: set the correct socket or set none at all,
# never a wrong one. The daemon's own answer goes first because it is
# authoritative about where it just put the socket; the two fixed paths are
# the fallback for when it told us nothing.
for candidate in \
"${keyring_ssh_sock}" \
"/run/user/$(id -u)/gcr/ssh" \
"/run/user/$(id -u)/keyring/ssh"
do
if [[ -n "${candidate}" && -S "${candidate}" ]]; then
export SSH_AUTH_SOCK="${candidate}"
break
fi
done
unset keyring_ssh_sock candidate
fi
# Same hygiene as start-cosmic: a failed unit left by a previous graphical # Same hygiene as start-cosmic: a failed unit left by a previous graphical
# session will otherwise block this one from starting. # session will otherwise block this one from starting.
if command -v systemctl >/dev/null; then if command -v systemctl >/dev/null; then
@@ -102,9 +148,14 @@ if command -v systemctl >/dev/null; then
# `Requisite=graphical-session.target`, which cosmic-session brings up # `Requisite=graphical-session.target`, which cosmic-session brings up
# later, so the portal cannot start before this import. # later, so the portal cannot start before this import.
# #
# SSH_AUTH_SOCK rides along for the same reason: a user unit or a
# systemd-activated app that wants the agent has to find it in the manager's
# environment, not in this script's. It is skipped harmlessly when the
# keyring block above declined to set it.
#
# `||:` throughout -- losing a portal is bad, refusing to log in is worse. # `||:` throughout -- losing a portal is bad, refusing to log in is worse.
systemctl --user import-environment \ systemctl --user import-environment \
XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE ||: XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE SSH_AUTH_SOCK ||:
fi fi
# Same variables again for dbus-daemon's own activation environment, which # Same variables again for dbus-daemon's own activation environment, which
@@ -116,7 +167,7 @@ fi
# login arrives with DBUS_SESSION_BUS_ADDRESS already set. # login arrives with DBUS_SESSION_BUS_ADDRESS already set.
if [[ -n "${DBUS_SESSION_BUS_ADDRESS}" ]] && command -v dbus-update-activation-environment >/dev/null; then if [[ -n "${DBUS_SESSION_BUS_ADDRESS}" ]] && command -v dbus-update-activation-environment >/dev/null; then
dbus-update-activation-environment \ dbus-update-activation-environment \
XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE ||: XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE SSH_AUTH_SOCK ||:
fi fi
# cosmic-session takes the compositor to launch as its first argument # cosmic-session takes the compositor to launch as its first argument