{ config, lib, ... }: let homeModules = config.flake.modules.homeManager; in { flake.modules.homeManager.source-control = { config, lib, ... }: let host = config.meta.host; user = config.meta.user; sourceControl = user.sourceControl; sourceControlScopes = sourceControl.scopes; hostSourceControlUsers = host.sourceControl.users; hostUserSourceControl = hostSourceControlUsers.${user.name} or { }; scopeConfig = scope: hostUserSourceControl.${scope} or null; scopeIdentity = scope: sourceControlScopes.${scope} or null; emailForScope = scope: let identity = scopeIdentity scope; in if identity == null then null else identity.email; scopeHasSigningKey = scope: let keyConfig = scopeConfig scope; in keyConfig != null && keyConfig.publicKey != null; privateKeyPathForScope = scope: let keyConfig = scopeConfig scope; in if keyConfig == null || keyConfig.privateKeyPath == null then "~/.ssh/id_${scope}" else keyConfig.privateKeyPath; publicKeyForScope = scope: let keyConfig = scopeConfig scope; in if keyConfig == null then null else keyConfig.publicKey; scopesInUse = builtins.attrNames sourceControlScopes; allowedSignersLines = map (scope: "${emailForScope scope} ${publicKeyForScope scope}") ( builtins.filter (scope: emailForScope scope != null && scopeHasSigningKey scope) scopesInUse ); gitConfigForScope = scope: lib.recursiveUpdate { user = { name = user.realName; email = emailForScope scope; }; } ( lib.optionalAttrs (scopeHasSigningKey scope) { gpg.ssh.allowedSignersFile = "${config.xdg.configHome}/git/allowed_signers"; user.signingKey = "${privateKeyPathForScope scope}.pub"; } ); gitRoots = [ { root = user.nixosConfigurationPath; scope = "personal"; } { root = config.xdg.userDirs.projects; scope = sourceControl.projectScope; } ]; in { imports = [ homeModules.git ]; xdg.configFile."git/allowed_signers".text = lib.concatStringsSep "\n" ( allowedSignersLines ++ [ "" ] ); programs.git.includes = map (gitRoot: { condition = "gitdir:${gitRoot.root}/"; contents = gitConfigForScope gitRoot.scope; }) gitRoots; }; }