From efe95f113aac9923bbc9f0f9cf1174399c17ab8b Mon Sep 17 00:00:00 2001 From: Benedikt Rips Date: Tue, 2 Jun 2026 14:30:57 +0200 Subject: [PATCH] sshAuthSock: use enable flag instead of nullable submodule --- modules/misc/ssh-auth-sock.nix | 122 +++++++++--------- modules/services/gpg-agent.nix | 45 ++++--- modules/services/proton-pass-agent.nix | 21 +-- modules/services/ssh-agent.nix | 39 +++--- modules/services/ssh-tpm-agent.nix | 11 +- modules/services/yubikey-agent.nix | 39 +++--- tests/modules/misc/ssh-auth-sock/default.nix | 3 +- tests/modules/misc/ssh-auth-sock/disabled.nix | 23 ++++ .../{initialization.nix => enabled.nix} | 11 +- 9 files changed, 179 insertions(+), 135 deletions(-) create mode 100644 tests/modules/misc/ssh-auth-sock/disabled.nix rename tests/modules/misc/ssh-auth-sock/{initialization.nix => enabled.nix} (82%) diff --git a/modules/misc/ssh-auth-sock.nix b/modules/misc/ssh-auth-sock.nix index b9f7f7e81..5efae1b98 100644 --- a/modules/misc/ssh-auth-sock.nix +++ b/modules/misc/ssh-auth-sock.nix @@ -2,72 +2,74 @@ let cfg = config.sshAuthSock; - - mkShellInitOption = - shell: - lib.mkOption { - description = "Code that initializes {env}`SSH_AUTH_SOCK` in ${shell}."; - type = lib.types.str; - }; - - initSubmodule = { - options.bash = mkShellInitOption "bash"; - options.fish = mkShellInitOption "fish"; - options.nushell = mkShellInitOption "nushell"; - }; - - # Preserve $SSH_AUTH_SOCK only if it stems from a forwarded agent which - # is the case if both $SSH_AUTH_SOCK and $SSH_CONNECTION are set. - bashIntegration = '' - if [ -z "$SSH_AUTH_SOCK" -o -z "$SSH_CONNECTION" ]; then - ${cfg.initialization.bash} - fi - ''; - fishIntegration = '' - if test -z "$SSH_AUTH_SOCK"; or test -z "$SSH_CONNECTION" - ${cfg.initialization.fish} - end - ''; - nushellIntegration = - let - unsetOrEmpty = var: ''("${var}" not-in $env) or ($env.${var} | is-empty)''; - in - '' - if ${unsetOrEmpty "SSH_AUTH_SOCK"} or ${unsetOrEmpty "SSH_CONNECTION"} { - ${cfg.initialization.nushell} - } - ''; - in { meta.maintainers = [ lib.maintainers.bmrips ]; - options.sshAuthSock.initialization = lib.mkOption { - description = '' - Shell-specific code to initialize {env}`SSH_AUTH_SOCK`. + options.sshAuthSock = { - RATIONALE: {env}`SSH_AUTH_SOCK` must not be set unconditionally through - {option}`home.sessionVariables` since its value needs to be preserved if - it stems from a forwarded agent. Hence, this option establishes a - centralized interface for setting {env}`SSH_AUTH_SOCK`. It checks whether - its value has to be preserved and injects the initialization code into the - proper {option}`programs.(bash|fish|nushell|zsh).*` options. - ''; - example = { - bash = "export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock"; - fish = "set -x SSH_AUTH_SOCK $HOME/.ssh/agent.sock"; - nushell = "$env.SSH_AUTH_SOCK = $HOME/.ssh/agent.sock"; + enable = lib.mkEnableOption "" // { + description = '' + Whether to set {env}`SSH_AUTH_SOCK` in shells, systemd, and the D-BUS daemon + unless it was already defined through SSH agent forwarding. + + Typically, this module will be implicitly enabled and configured by SSH + agent modules. + ''; }; - default = null; - internal = true; - type = with lib.types; nullOr (submodule initSubmodule); + + initialization = + let + mkShellInitOption = + shell: + lib.mkOption { + description = "Code that initializes {env}`SSH_AUTH_SOCK` in ${shell}."; + type = lib.types.str; + }; + in + { + bash = mkShellInitOption "bash" // { + example = "export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock"; + }; + fish = mkShellInitOption "fish" // { + example = "set -x SSH_AUTH_SOCK $HOME/.ssh/agent.sock"; + }; + nushell = mkShellInitOption "nushell" // { + example = "$env.SSH_AUTH_SOCK = $HOME/.ssh/agent.sock"; + }; + }; + }; - config = lib.mkIf (cfg.initialization != null) { - # $SSH_AUTH_SOCK has to be set early since other tools rely on it - programs.bash.profileExtra = lib.mkOrder 900 bashIntegration; - programs.fish.shellInit = lib.mkOrder 900 fishIntegration; - programs.nushell.extraConfig = lib.mkOrder 900 nushellIntegration; - programs.zsh.envExtra = lib.mkOrder 900 bashIntegration; - }; + config = + let + # Preserve $SSH_AUTH_SOCK if it stems from a forwarded agent which is the + # case if both $SSH_AUTH_SOCK and $SSH_CONNECTION are set. + bashIntegration = '' + if [ -z "$SSH_AUTH_SOCK" -o -z "$SSH_CONNECTION" ]; then + ${cfg.initialization.bash} + fi + ''; + fishIntegration = '' + if test -z "$SSH_AUTH_SOCK"; or test -z "$SSH_CONNECTION" + ${cfg.initialization.fish} + end + ''; + nushellIntegration = + let + unsetOrEmpty = var: ''("${var}" not-in $env) or ($env.${var} | is-empty)''; + in + '' + if ${unsetOrEmpty "SSH_AUTH_SOCK"} or ${unsetOrEmpty "SSH_CONNECTION"} { + ${cfg.initialization.nushell} + } + ''; + in + lib.mkIf cfg.enable { + # $SSH_AUTH_SOCK has to be set early since other tools rely on it + programs.bash.profileExtra = lib.mkOrder 900 bashIntegration; + programs.fish.shellInit = lib.mkOrder 900 fishIntegration; + programs.nushell.extraConfig = lib.mkOrder 900 nushellIntegration; + programs.zsh.envExtra = lib.mkOrder 900 bashIntegration; + }; } diff --git a/modules/services/gpg-agent.nix b/modules/services/gpg-agent.nix index 74524a7f9..aa7f7673b 100644 --- a/modules/services/gpg-agent.nix +++ b/modules/services/gpg-agent.nix @@ -366,30 +366,33 @@ in ++ [ cfg.extraConfig ] ); - sshAuthSock.initialization = lib.mkIf cfg.enableSshSupport { - bash = '' - unset SSH_AGENT_PID - if [ "''${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then - export SSH_AUTH_SOCK="$(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)" - fi - ''; - fish = '' - set -e SSH_AGENT_PID + sshAuthSock = lib.mkIf cfg.enableSshSupport { + enable = true; + initialization = { + bash = '' + unset SSH_AGENT_PID + if [ "''${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then + export SSH_AUTH_SOCK="$(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)" + fi + ''; + fish = '' + set -e SSH_AGENT_PID - begin - set -l gnupg_val 0 - if set -q gnupg_SSH_AUTH_SOCK_by - set gnupg_val $gnupg_SSH_AUTH_SOCK_by - end + begin + set -l gnupg_val 0 + if set -q gnupg_SSH_AUTH_SOCK_by + set gnupg_val $gnupg_SSH_AUTH_SOCK_by + end - if test $gnupg_val -ne %self - set -x SSH_AUTH_SOCK (${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket) + if test $gnupg_val -ne %self + set -x SSH_AUTH_SOCK (${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket) + end end - end - ''; - nushell = '' - $env.SSH_AUTH_SOCK = $"(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)" - ''; + ''; + nushell = '' + $env.SSH_AUTH_SOCK = $"(${gpgPkg}/bin/gpgconf --list-dirs agent-ssh-socket)" + ''; + }; }; programs = { diff --git a/modules/services/proton-pass-agent.nix b/modules/services/proton-pass-agent.nix index f41f740ee..14bca6b56 100644 --- a/modules/services/proton-pass-agent.nix +++ b/modules/services/proton-pass-agent.nix @@ -74,15 +74,18 @@ in lib.mkIf cfg.enable { home.packages = [ cfg.package ]; - sshAuthSock.initialization = { - bash = ''export SSH_AUTH_SOCK="${socketPath}"''; - fish = ''set -x SSH_AUTH_SOCK "${socketPath}"''; - nushell = "$env.SSH_AUTH_SOCK = ${ - if pkgs.stdenv.isDarwin then - ''$"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"'' - else - ''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'' - }"; + sshAuthSock = { + enable = true; + initialization = { + bash = ''export SSH_AUTH_SOCK="${socketPath}"''; + fish = ''set -x SSH_AUTH_SOCK "${socketPath}"''; + nushell = "$env.SSH_AUTH_SOCK = ${ + if pkgs.stdenv.isDarwin then + ''$"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"'' + else + ''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'' + }"; + }; }; systemd.user.services.proton-pass-agent = { diff --git a/modules/services/ssh-agent.nix b/modules/services/ssh-agent.nix index 8b1d6ee22..34c0aa9ba 100644 --- a/modules/services/ssh-agent.nix +++ b/modules/services/ssh-agent.nix @@ -60,24 +60,27 @@ in config = lib.mkIf cfg.enable { - sshAuthSock.initialization = - let - socketPath = - if pkgs.stdenv.isDarwin then - "$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}" - else - "$XDG_RUNTIME_DIR/${cfg.socket}"; - in - { - bash = ''export SSH_AUTH_SOCK="${socketPath}"''; - fish = ''set -x SSH_AUTH_SOCK "${socketPath}"''; - nushell = "$env.SSH_AUTH_SOCK = ${ - if pkgs.stdenv.isDarwin then - ''$"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"'' - else - ''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'' - }"; - }; + sshAuthSock = { + enable = true; + initialization = + let + socketPath = + if pkgs.stdenv.isDarwin then + "$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}" + else + "$XDG_RUNTIME_DIR/${cfg.socket}"; + in + { + bash = ''export SSH_AUTH_SOCK="${socketPath}"''; + fish = ''set -x SSH_AUTH_SOCK "${socketPath}"''; + nushell = "$env.SSH_AUTH_SOCK = ${ + if pkgs.stdenv.isDarwin then + ''$"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"'' + else + ''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'' + }"; + }; + }; systemd.user.services.ssh-agent = { Install.WantedBy = [ "default.target" ]; diff --git a/modules/services/ssh-tpm-agent.nix b/modules/services/ssh-tpm-agent.nix index 9d3dd183d..937721469 100644 --- a/modules/services/ssh-tpm-agent.nix +++ b/modules/services/ssh-tpm-agent.nix @@ -73,10 +73,13 @@ in # Override ssh-agent's $SSH_AUTH_SOCK definition since ssh-tpm-agent is a # proxy to it. - sshAuthSock.initialization = lib.mkOverride 90 { - bash = ''export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-tpm-agent.sock"''; - fish = ''set -x SSH_AUTH_SOCK "$XDG_RUNTIME_DIR/ssh-tpm-agent.sock"''; - nushell = ''$env.SSH_AUTH_SOCK = $"($env.XDG_RUNTIME_DIR)/ssh-tpm-agent.sock"''; + sshAuthSock = { + enable = true; + initialization = lib.mkOverride 90 { + bash = ''export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-tpm-agent.sock"''; + fish = ''set -x SSH_AUTH_SOCK "$XDG_RUNTIME_DIR/ssh-tpm-agent.sock"''; + nushell = ''$env.SSH_AUTH_SOCK = $"($env.XDG_RUNTIME_DIR)/ssh-tpm-agent.sock"''; + }; }; systemd.user = { diff --git a/modules/services/yubikey-agent.nix b/modules/services/yubikey-agent.nix index ee439d32a..1fe0bdbb0 100644 --- a/modules/services/yubikey-agent.nix +++ b/modules/services/yubikey-agent.nix @@ -22,24 +22,27 @@ in config = mkIf cfg.enable { home.packages = [ cfg.package ]; - sshAuthSock.initialization = - let - socketPath = - if pkgs.stdenv.isDarwin then - "/tmp/yubikey-agent.sock" - else - "\${XDG_RUNTIME_DIR:-/run/user/$UID}/yubikey-agent/yubikey-agent.sock"; - in - { - bash = ''export SSH_AUTH_SOCK="${socketPath}"''; - fish = ''set -x SSH_AUTH_SOCK "${socketPath}"''; - nushell = "$env.SSH_AUTH_SOCK = ${ - if pkgs.stdenv.isDarwin then - "/tmp/yubikey-agent.sock" - else - ''$"($env.XDG_RUNTIME_DIR | default $"/run/user/(id -u)")/yubikey-agent/yubikey-agent.sock"'' - }"; - }; + sshAuthSock = { + enable = true; + initialization = + let + socketPath = + if pkgs.stdenv.isDarwin then + "/tmp/yubikey-agent.sock" + else + "\${XDG_RUNTIME_DIR:-/run/user/$UID}/yubikey-agent/yubikey-agent.sock"; + in + { + bash = ''export SSH_AUTH_SOCK="${socketPath}"''; + fish = ''set -x SSH_AUTH_SOCK "${socketPath}"''; + nushell = "$env.SSH_AUTH_SOCK = ${ + if pkgs.stdenv.isDarwin then + "/tmp/yubikey-agent.sock" + else + ''$"($env.XDG_RUNTIME_DIR | default $"/run/user/(id -u)")/yubikey-agent/yubikey-agent.sock"'' + }"; + }; + }; systemd.user.services.yubikey-agent = { Unit = { diff --git a/tests/modules/misc/ssh-auth-sock/default.nix b/tests/modules/misc/ssh-auth-sock/default.nix index 58d77c499..a50485c44 100644 --- a/tests/modules/misc/ssh-auth-sock/default.nix +++ b/tests/modules/misc/ssh-auth-sock/default.nix @@ -1,3 +1,4 @@ { - sshAuthSock-initialization = ./initialization.nix; + sshAuthSock-disabled = ./disabled.nix; + sshAuthSock-enabled = ./enabled.nix; } diff --git a/tests/modules/misc/ssh-auth-sock/disabled.nix b/tests/modules/misc/ssh-auth-sock/disabled.nix new file mode 100644 index 000000000..5748c00ac --- /dev/null +++ b/tests/modules/misc/ssh-auth-sock/disabled.nix @@ -0,0 +1,23 @@ +{ + programs.bash.enable = true; + programs.fish.enable = true; + programs.nushell.enable = true; + programs.zsh.enable = true; + + sshAuthSock.enable = false; + + nmt.script = '' + assertFileNotRegex \ + home-files/.profile \ + 'SSH_AUTH_SOCK' + assertFileNotRegex \ + home-files/.config/fish/config.fish \ + 'SSH_AUTH_SOCK' + assertFileNotRegex \ + home-files/.config/nushell/config.nu \ + 'SSH_AUTH_SOCK' + assertFileNotRegex \ + home-files/.zshenv \ + 'SSH_AUTH_SOCK' + ''; +} diff --git a/tests/modules/misc/ssh-auth-sock/initialization.nix b/tests/modules/misc/ssh-auth-sock/enabled.nix similarity index 82% rename from tests/modules/misc/ssh-auth-sock/initialization.nix rename to tests/modules/misc/ssh-auth-sock/enabled.nix index e2d958cac..ff1c14ce2 100644 --- a/tests/modules/misc/ssh-auth-sock/initialization.nix +++ b/tests/modules/misc/ssh-auth-sock/enabled.nix @@ -4,10 +4,13 @@ programs.nushell.enable = true; programs.zsh.enable = true; - sshAuthSock.initialization = { - bash = "echo bash/zsh"; - fish = "echo fish"; - nushell = "echo nushell"; + sshAuthSock = { + enable = true; + initialization = { + bash = "echo bash/zsh"; + fish = "echo fish"; + nushell = "echo nushell"; + }; }; nmt.script = ''