{ config, lib, ... }: let homeModules = config.flake.modules.homeManager; in { flake.modules.homeManager.source-control = { config, lib, ... }: let machine = config.meta.machine; user = config.meta.user; account = user.account; sourceControl = account.sourceControl; scopeConfig = scope: user.sourceControl.${scope} or null; emailForScope = scope: let scopedEmails = lib.filter (email: email.scope == scope) (builtins.attrValues account.emails); in if builtins.length scopedEmails == 1 then (builtins.head scopedEmails).address else null; 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 = lib.unique [ "personal" sourceControl.projectScope ]; missingEmailScopes = builtins.filter (scope: emailForScope scope == null) scopesInUse; allowedSignersLines = map (scope: "${emailForScope scope} ${publicKeyForScope scope}") ( builtins.filter (scope: emailForScope scope != null && scopeHasSigningKey scope) scopesInUse ); gitConfigForScope = scope: lib.recursiveUpdate { user = { name = account.realName; email = emailForScope scope; }; } ( lib.optionalAttrs (scopeHasSigningKey scope) { gpg.ssh.allowedSignersFile = "${config.xdg.configHome}/git/allowed_signers"; user.signingKey = "${privateKeyPathForScope scope}.pub"; } ); gitRoots = [ { root = account.nixosConfigurationPath; scope = "personal"; } { root = config.xdg.userDirs.projects; scope = sourceControl.projectScope; } ]; in { imports = [ homeModules.git ]; assertions = [ { assertion = missingEmailScopes == [ ]; message = "Missing source-control email scope for `${account.name}`: ${lib.concatStringsSep ", " missingEmailScopes}."; } ]; xdg.configFile."git/allowed_signers".text = lib.concatStringsSep "\n" ( allowedSignersLines ++ [ "" ] ); programs.git.includes = map (gitRoot: { condition = "gitdir:${gitRoot.root}/"; contents = gitConfigForScope gitRoot.scope; }) gitRoots; }; }