sshAuthSock: avoid cycles for socket providers

PR #9420 added set-SSH_AUTH_SOCK.service and ordered it before sshAuthSock.systemd.socketProviderUnit. When that provider is a socket unit, systemd default dependencies already order the socket before sockets.target while service defaults place set-SSH_AUTH_SOCK.service after basic.target. That creates a sockets.target -> basic.target -> set-SSH_AUTH_SOCK.service -> provider.socket -> sockets.target cycle.

For gpg-agent this makes systemd drop gpg-agent-ssh.socket, leaving SSH_AUTH_SOCK pointing at the expected S.gpg-agent.ssh path but with no socket listening there.

Only order and install the environment service against non-socket providers. Socket providers still get SSH_AUTH_SOCK imported through default.target.

Fixes #9432.
This commit is contained in:
Austin Horstman 2026-06-08 09:59:06 -05:00
parent 301871cd96
commit e9cbe69850
4 changed files with 33 additions and 6 deletions

View file

@ -7,6 +7,8 @@
let
cfg = config.sshAuthSock;
socketProviderIsSocket = lib.hasSuffix ".socket" cfg.systemd.socketProviderUnit;
orderedProviderUnits = lib.optional (!socketProviderIsSocket) cfg.systemd.socketProviderUnit;
in
{
meta.maintainers = [ lib.maintainers.bmrips ];
@ -102,7 +104,9 @@ in
systemd.user.services.set-SSH_AUTH_SOCK = {
Unit = {
Description = "Sets SSH_AUTH_SOCK in the D-BUS daemon and systemd";
Before = [ cfg.systemd.socketProviderUnit ];
# Socket units are ordered before sockets.target by systemd. Ordering
# this service before them creates a cycle through basic.target.
Before = orderedProviderUnits;
};
Service = {
Type = "oneshot";
@ -113,8 +117,8 @@ in
};
Install.WantedBy = [
"default.target"
cfg.systemd.socketProviderUnit
];
]
++ orderedProviderUnits;
};
};
}

View file

@ -1,4 +1,5 @@
{
sshAuthSock-disabled = ./disabled.nix;
sshAuthSock-enabled = ./enabled.nix;
sshAuthSock-socket-provider = ./socket-provider.nix;
}

View file

@ -13,7 +13,7 @@
fish = "echo fish";
nushell = "echo nushell";
};
systemd.socketProviderUnit = "foo.socket";
systemd.socketProviderUnit = "foo.service";
};
nmt.script = ''
@ -32,7 +32,7 @@
''
+ lib.optionalString config.systemd.user.enable ''
assertFileExists home-files/.config/systemd/user/set-SSH_AUTH_SOCK.service
assertFileContains home-files/.config/systemd/user/set-SSH_AUTH_SOCK.service 'Before=foo.socket'
assertFileContains home-files/.config/systemd/user/set-SSH_AUTH_SOCK.service 'WantedBy=foo.socket'
assertFileContains home-files/.config/systemd/user/set-SSH_AUTH_SOCK.service 'Before=foo.service'
assertFileContains home-files/.config/systemd/user/set-SSH_AUTH_SOCK.service 'WantedBy=foo.service'
'';
}

View file

@ -0,0 +1,22 @@
{ config, lib, ... }:
{
sshAuthSock = {
enable = true;
initialization = {
bash = "echo bash/zsh";
fish = "echo fish";
nushell = "echo nushell";
};
systemd.socketProviderUnit = "foo.socket";
};
nmt.script = lib.optionalString config.systemd.user.enable ''
serviceFile=home-files/.config/systemd/user/set-SSH_AUTH_SOCK.service
assertFileExists $serviceFile
assertFileContains $serviceFile 'WantedBy=default.target'
assertFileNotRegex $serviceFile 'Before=foo\.socket'
assertFileNotRegex $serviceFile 'WantedBy=foo\.socket'
'';
}