service.proton-pass-agent: init module
This commit is contained in:
parent
7213f7ee3e
commit
85e3ee7e59
12 changed files with 358 additions and 0 deletions
143
modules/services/proton-pass-agent.nix
Normal file
143
modules/services/proton-pass-agent.nix
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.services.proton-pass-agent;
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.delafthi ];
|
||||
|
||||
options.services.proton-pass-agent = {
|
||||
enable = lib.mkEnableOption "Proton Pass as a SSH agent";
|
||||
|
||||
package = lib.mkPackageOption pkgs "proton-pass-cli" { };
|
||||
|
||||
socket = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "proton-pass-agent";
|
||||
example = "proton-pass-agent/socket";
|
||||
description = ''
|
||||
The agent's socket; interpreted as a suffix to {env}`$XDG_RUNTIME_DIR`
|
||||
on Linux and `$(getconf DARWIN_USER_TEMP_DIR)` on macOS. This option
|
||||
adds the `--socket-path` argument to the command.
|
||||
'';
|
||||
};
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"--share-id"
|
||||
"--vault-name"
|
||||
"MySshKeyVault"
|
||||
"--refresh-interval"
|
||||
"7200"
|
||||
];
|
||||
description = ''
|
||||
Options given to `pass-cli ssh-agent shart` when the service is run.
|
||||
|
||||
See <https://protonpass.github.io/pass-cli/commands/ssh-agent/#passphrase-protected-ssh-keys>
|
||||
for more information.
|
||||
'';
|
||||
};
|
||||
|
||||
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };
|
||||
|
||||
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };
|
||||
|
||||
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
|
||||
|
||||
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
socketPath =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
"$(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"
|
||||
else
|
||||
"$XDG_RUNTIME_DIR/${cfg.socket}";
|
||||
cmd = [
|
||||
"${lib.getExe' cfg.package "pass-cli"}"
|
||||
"ssh-agent"
|
||||
"start"
|
||||
"--socket-path"
|
||||
"${if pkgs.stdenv.isDarwin then socketPath else "%t/${cfg.socket}"}"
|
||||
]
|
||||
++ cfg.extraArgs;
|
||||
in
|
||||
lib.mkIf cfg.enable {
|
||||
home.packages = [ cfg.package ];
|
||||
|
||||
programs =
|
||||
let
|
||||
# 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
|
||||
export SSH_AUTH_SOCK=${socketPath}
|
||||
fi
|
||||
'';
|
||||
fishIntegration = ''
|
||||
if test -z "$SSH_AUTH_SOCK"; or test -z "$SSH_CONNECTION"
|
||||
set -x SSH_AUTH_SOCK ${socketPath}
|
||||
end
|
||||
'';
|
||||
nushellIntegration =
|
||||
let
|
||||
unsetOrEmpty = var: ''("${var}" not-in $env) or ($env.${var} | is-empty)'';
|
||||
socketPath =
|
||||
if pkgs.stdenv.isDarwin then
|
||||
''$"(${lib.getExe pkgs.getconf} DARWIN_USER_TEMP_DIR)/${cfg.socket}"''
|
||||
else
|
||||
''$"($env.XDG_RUNTIME_DIR)/${cfg.socket}"'';
|
||||
in
|
||||
''
|
||||
if ${unsetOrEmpty "SSH_AUTH_SOCK"} or ${unsetOrEmpty "SSH_CONNECTION"} {
|
||||
$env.SSH_AUTH_SOCK = ${socketPath}
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
# $SSH_AUTH_SOCK has to be set early since other tools rely on it
|
||||
bash.profileExtra = lib.mkIf cfg.enableBashIntegration (lib.mkOrder 900 bashIntegration);
|
||||
fish.shellInit = lib.mkIf cfg.enableFishIntegration (lib.mkOrder 900 fishIntegration);
|
||||
nushell.extraConfig = lib.mkIf cfg.enableNushellIntegration (lib.mkOrder 900 nushellIntegration);
|
||||
zsh.envExtra = lib.mkIf cfg.enableZshIntegration (lib.mkOrder 900 bashIntegration);
|
||||
};
|
||||
|
||||
systemd.user.services.proton-pass-agent = {
|
||||
Install.WantedBy = [ "default.target" ];
|
||||
Unit = {
|
||||
Description = "Proton Pass SSH agent";
|
||||
Documentation = "https://protonpass.github.io/pass-cli/commands/ssh-agent/#ssh-agent-integration";
|
||||
};
|
||||
Service = {
|
||||
ExecStart = lib.concatStringsSep " " cmd;
|
||||
KeyringMode = "shared";
|
||||
};
|
||||
};
|
||||
|
||||
launchd.agents.proton-pass-agent = {
|
||||
enable = true;
|
||||
config = {
|
||||
ProgramArguments = [
|
||||
(lib.getExe pkgs.bash)
|
||||
"-c"
|
||||
(lib.concatStringsSep " " cmd)
|
||||
];
|
||||
KeepAlive = {
|
||||
Crashed = true;
|
||||
SuccessfulExit = false;
|
||||
};
|
||||
ProcessType = "Background";
|
||||
RunAtLoad = true;
|
||||
StandardOutPath = "${config.home.homeDirectory}/Library/Logs/Proton Pass CLI/ssh-agent-stdout.log";
|
||||
StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/Proton Pass CLI/ssh-agent-stderr.log";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -140,6 +140,7 @@ let
|
|||
"pls"
|
||||
"poetry"
|
||||
"powerline-go"
|
||||
"proton-pass-cli"
|
||||
"pubs"
|
||||
"pyenv"
|
||||
"qcal"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
{ pkgs, ... }:
|
||||
{
|
||||
services.proton-pass-agent = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
};
|
||||
|
||||
programs.bash.enable = true;
|
||||
|
||||
nmt.script = ''
|
||||
bash_profile=home-files/.profile
|
||||
|
||||
assertFileContains $bash_profile \
|
||||
'if [ -z "$SSH_AUTH_SOCK" -o -z "$SSH_CONNECTION" ]; then'
|
||||
assertFileContains $bash_profile \
|
||||
'export SSH_AUTH_SOCK=${
|
||||
if pkgs.stdenv.hostPlatform.isDarwin then
|
||||
"$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)"
|
||||
else
|
||||
"$XDG_RUNTIME_DIR"
|
||||
}/proton-pass-agent'
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>KeepAlive</key>
|
||||
<dict>
|
||||
<key>Crashed</key>
|
||||
<true/>
|
||||
<key>SuccessfulExit</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Label</key>
|
||||
<string>org.nix-community.home.proton-pass-agent</string>
|
||||
<key>ProcessType</key>
|
||||
<string>Background</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>@bash-interactive@/bin/bash</string>
|
||||
<string>-c</string>
|
||||
<string>@proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path $(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/proton-pass-agent/socket</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/home/hm-user/Library/Logs/Proton Pass CLI/ssh-agent-stderr.log</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/home/hm-user/Library/Logs/Proton Pass CLI/ssh-agent-stdout.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path %t/proton-pass-agent/socket
|
||||
KeyringMode=shared
|
||||
|
||||
[Unit]
|
||||
Description=Proton Pass SSH agent
|
||||
Documentation=https://protonpass.github.io/pass-cli/commands/ssh-agent/#ssh-agent-integration
|
||||
23
tests/modules/services/proton-pass-agent/basic-service.nix
Normal file
23
tests/modules/services/proton-pass-agent/basic-service.nix
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.proton-pass-agent = {
|
||||
enable = true;
|
||||
socket = "proton-pass-agent/socket";
|
||||
};
|
||||
|
||||
nmt.script =
|
||||
if pkgs.stdenv.hostPlatform.isDarwin then
|
||||
''
|
||||
plistFile=LaunchAgents/org.nix-community.home.proton-pass-agent.plist
|
||||
|
||||
assertFileExists $plistFile
|
||||
assertFileContent $plistFile ${./basic-service-expected.plist}
|
||||
''
|
||||
else
|
||||
''
|
||||
serviceFile=home-files/.config/systemd/user/proton-pass-agent.service
|
||||
|
||||
assertFileExists $serviceFile
|
||||
assertFileContent $serviceFile ${./basic-service-expected.service}
|
||||
'';
|
||||
}
|
||||
7
tests/modules/services/proton-pass-agent/default.nix
Normal file
7
tests/modules/services/proton-pass-agent/default.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
proton-pass-agent-basic-service = ./basic-service.nix;
|
||||
proton-pass-agent-full-service = ./full-service.nix;
|
||||
proton-pass-agent-bash-integration = ./bash-integration.nix;
|
||||
proton-pass-agent-fish-integration = ./fish-integration.nix;
|
||||
proton-pass-agent-nushell-integration = ./nushell-integration.nix;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{ pkgs, ... }:
|
||||
{
|
||||
services.proton-pass-agent = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
};
|
||||
|
||||
programs.fish.enable = true;
|
||||
|
||||
nmt.script = ''
|
||||
fish_config=home-files/.config/fish/config.fish
|
||||
|
||||
assertFileContains $fish_config \
|
||||
'if test -z "$SSH_AUTH_SOCK"; or test -z "$SSH_CONNECTION'
|
||||
assertFileContains $fish_config \
|
||||
'set -x SSH_AUTH_SOCK ${
|
||||
if pkgs.stdenv.hostPlatform.isDarwin then
|
||||
"$(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)"
|
||||
else
|
||||
"$XDG_RUNTIME_DIR"
|
||||
}/proton-pass-agent'
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>KeepAlive</key>
|
||||
<dict>
|
||||
<key>Crashed</key>
|
||||
<true/>
|
||||
<key>SuccessfulExit</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Label</key>
|
||||
<string>org.nix-community.home.proton-pass-agent</string>
|
||||
<key>ProcessType</key>
|
||||
<string>Background</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>@bash-interactive@/bin/bash</string>
|
||||
<string>-c</string>
|
||||
<string>@proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path $(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)/proton-pass-agent/socket --share-id 123456789 --vault-name MySshKeyVault --refresh-interval 7200 --create-new-identities MySshKeyVault</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/home/hm-user/Library/Logs/Proton Pass CLI/ssh-agent-stderr.log</string>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/home/hm-user/Library/Logs/Proton Pass CLI/ssh-agent-stdout.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@proton-pass-cli@/bin/pass-cli ssh-agent start --socket-path %t/proton-pass-agent/socket --share-id 123456789 --vault-name MySshKeyVault --refresh-interval 7200 --create-new-identities MySshKeyVault
|
||||
KeyringMode=shared
|
||||
|
||||
[Unit]
|
||||
Description=Proton Pass SSH agent
|
||||
Documentation=https://protonpass.github.io/pass-cli/commands/ssh-agent/#ssh-agent-integration
|
||||
33
tests/modules/services/proton-pass-agent/full-service.nix
Normal file
33
tests/modules/services/proton-pass-agent/full-service.nix
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.proton-pass-agent = {
|
||||
enable = true;
|
||||
socket = "proton-pass-agent/socket";
|
||||
extraArgs = [
|
||||
"--share-id"
|
||||
"123456789"
|
||||
"--vault-name"
|
||||
"MySshKeyVault"
|
||||
"--refresh-interval"
|
||||
"7200"
|
||||
"--create-new-identities"
|
||||
"MySshKeyVault"
|
||||
];
|
||||
};
|
||||
|
||||
nmt.script =
|
||||
if pkgs.stdenv.hostPlatform.isDarwin then
|
||||
''
|
||||
plistFile=LaunchAgents/org.nix-community.home.proton-pass-agent.plist
|
||||
|
||||
assertFileExists $plistFile
|
||||
assertFileContent $plistFile ${./full-service-expected.plist}
|
||||
''
|
||||
else
|
||||
''
|
||||
serviceFile=home-files/.config/systemd/user/proton-pass-agent.service
|
||||
|
||||
assertFileExists $serviceFile
|
||||
assertFileContent $serviceFile ${./full-service-expected.service}
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{ pkgs, ... }:
|
||||
{
|
||||
services.proton-pass-agent = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
};
|
||||
|
||||
programs.nushell.enable = true;
|
||||
|
||||
nmt.script =
|
||||
let
|
||||
unsetOrEmpty = var: ''("${var}" not-in $env) or ($env.${var} | is-empty)'';
|
||||
in
|
||||
''
|
||||
nu_config=home-files/.config/nushell/config.nu
|
||||
|
||||
assertFileContains $nu_config \
|
||||
'if ${unsetOrEmpty "SSH_AUTH_SOCK"} or ${unsetOrEmpty "SSH_CONNECTION"} {'
|
||||
assertFileContains $nu_config \
|
||||
'$env.SSH_AUTH_SOCK = $"${
|
||||
if pkgs.stdenv.hostPlatform.isDarwin then
|
||||
"(@getconf-system_cmds@/bin/getconf DARWIN_USER_TEMP_DIR)"
|
||||
else
|
||||
"($env.XDG_RUNTIME_DIR)"
|
||||
}/proton-pass-agent"'
|
||||
'';
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue