aboutsummaryrefslogtreecommitdiff
path: root/home/modules/onepassword.nix
blob: d1851eaf6bf68e2e24c190331bbf259c8d17d947 (plain) (blame)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
{
  config,
  lib,
  pkgs,
  ...
}:

with lib;

let
  cfg = config.programs.onepassword;

  generateAgentConfig =
    keys:
    let
      keyToToml =
        key:
        let
          lines = [
            "[[ssh-keys]]"
          ]
          ++ optional (key.item != null) ''item = "${key.item}"''
          ++ optional (key.vault != null) ''vault = "${key.vault}"''
          ++ [ ''account = "${key.account}"'' ];
        in
        concatStringsSep "\n" lines;
    in
    concatStringsSep "\n\n" (map keyToToml keys);

  home = config.home.homeDirectory;
  darwinSockPath = "${home}/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock";
  defaultSockPath = ".1password/agent.sock";

in
{
  options.programs.onepassword = {
    enable = mkEnableOption "1Password CLI and SSH agent integration";

    package = mkOption {
      type = types.package;
      default = pkgs._1password-cli;
      description = "The 1Password CLI package to use.";
    };

    socketPath = mkOption {
      type = types.str;
      default = defaultSockPath;
      description = "Relative path from home directory for the SSH agent socket.";
      example = ".1password/agent.sock";
    };

    darwinSocketPath = mkOption {
      type = types.str;
      default = darwinSockPath;
      description = "Full path to the 1Password agent socket on macOS.";
    };

    setSshAuthSock = mkOption {
      type = types.bool;
      default = true;
      description = "Whether to set the SSH_AUTH_SOCK environment variable.";
    };

    configureSshClient = mkOption {
      type = types.bool;
      default = true;
      description = "Whether to configure the SSH client to use 1Password agent.";
    };

    fishIntegration = mkOption {
      type = types.bool;
      default = false;
      description = "Enable fish shell completion for 1Password CLI.";
    };

    sshKeys = mkOption {
      type =
        with types;
        listOf (submodule {
          options = {
            item = mkOption {
              type = nullOr str;
              default = null;
              description = "The name of the SSH key item in 1Password.";
              example = "Git Signing Key";
            };

            vault = mkOption {
              type = nullOr str;
              default = null;
              description = "The vault name where the SSH key is stored (optional).";
              example = "Private";
            };

            account = mkOption {
              type = str;
              default = "my.1password.com";
              description = "The 1Password account identifier.";
              example = "my.1password.com";
            };
          };
        });
      default = [ ];
      description = "SSH keys configuration for 1Password agent. Lists from multiple configurations will be merged.";
      example = [
        { account = "my.1password.com"; }
        {
          item = "Git Signing Key";
          vault = "Work";
          account = "ACME, Inc.";
        }
        {
          item = "Personal SSH Key";
          account = "my.1password.com";
        }
      ];
    };
  };

  config = mkIf cfg.enable {
    home.packages = [ cfg.package ];

    home.sessionVariables = mkIf cfg.setSshAuthSock {
      SSH_AUTH_SOCK = "${home}/${cfg.socketPath}";
    };

    # Create symlink to Darwin socket (macOS specific)
    home.file."${cfg.socketPath}" = mkIf pkgs.stdenv.isDarwin {
      source = config.lib.file.mkOutOfStoreSymlink cfg.darwinSocketPath;
    };

    # Configure SSH client
    programs.ssh = mkIf cfg.configureSshClient {
      extraConfig = "IdentityAgent ~/${cfg.socketPath}";
    };

    # Fish shell integration
    programs.fish = mkIf cfg.fishIntegration {
      interactiveShellInit = ''
        op completion fish | source
      '';
    };

    # Generate SSH agent configuration
    home.file.".config/1Password/ssh/agent.toml" = mkIf (cfg.sshKeys != [ ]) {
      text = generateAgentConfig cfg.sshKeys;
    };
  };
}