{ 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; hostSourceControlUsers = host.sourceControl.users; hostUserSourceControl = if lib.hasAttr user.name hostSourceControlUsers then hostSourceControlUsers.${user.name} else { }; profileNames = builtins.attrNames sourceControl.profiles; parsedProfiles = map ( name: let matches = builtins.match "(github|gitlab)-(personal|work)" name; in { inherit matches name; isValid = matches != null; scope = if matches == null then null else builtins.elemAt matches 1; } ) profileNames; validProfiles = builtins.filter (profile: profile.isValid) parsedProfiles; invalidProfileNames = map (profile: profile.name) ( builtins.filter (profile: !profile.isValid) parsedProfiles ); emailNamesForScope = { personal = [ "personal" "main" ]; work = [ "work" ]; }; scopeEmails = scope: map (name: user.emails.${name}) ( builtins.filter (name: lib.hasAttr name user.emails) emailNamesForScope.${scope} ); emailForScope = scope: let emails = scopeEmails scope; in if builtins.length emails == 1 then (builtins.head emails).address else null; scopeConfig = scope: if lib.hasAttr scope hostUserSourceControl then hostUserSourceControl.${scope} else null; privateKeyPathForScope = scope: let keyConfig = scopeConfig scope; in if keyConfig == null || keyConfig.privateKeyPath == null then "~/.ssh/id_${scope}" else keyConfig.privateKeyPath; scopePublicKey = scope: let keyConfig = scopeConfig scope; in if keyConfig == null then null else keyConfig.publicKey; scopesInUse = lib.unique ( [ "personal" sourceControl.projectScope ] ++ map (profile: profile.scope) validProfiles ); missingKeyScopes = builtins.filter (scope: scopePublicKey scope == null) scopesInUse; invalidEmailScopes = builtins.filter (scope: emailForScope scope == null) scopesInUse; allowedSignersLines = map (scope: "${emailForScope scope} ${scopePublicKey scope}") ( builtins.filter (scope: emailForScope scope != null && scopePublicKey scope != null) scopesInUse ); gitConfigForScope = scope: { gpg.ssh.allowedSignersFile = "${config.xdg.configHome}/git/allowed_signers"; user = { name = user.realName; email = emailForScope scope; signingKey = "${privateKeyPathForScope scope}.pub"; }; }; gitRoots = [ { root = user.nixosConfigurationPath; scope = "personal"; } { root = config.xdg.userDirs.projects; scope = sourceControl.projectScope; } ]; in { imports = [ homeModules.git ]; assertions = [ { assertion = invalidProfileNames == [ ]; message = "Invalid source control profiles for `${user.name}`: ${lib.concatStringsSep ", " invalidProfileNames}. Expected `-` using github/gitlab and personal/work."; } { assertion = missingKeyScopes == [ ]; message = "Missing source control keys for `${user.name}` scopes: ${lib.concatStringsSep ", " missingKeyScopes}."; } { assertion = invalidEmailScopes == [ ]; message = "Expected exactly one email selected by name for `${user.name}` scopes: ${lib.concatStringsSep ", " invalidEmailScopes}. Personal uses `personal` or `main`; work uses `work`."; } ]; xdg.configFile."git/allowed_signers".text = lib.concatStringsSep "\n" ( allowedSignersLines ++ [ "" ] ); programs.git.includes = map (gitRoot: { condition = "gitdir:${gitRoot.root}/"; contents = gitConfigForScope gitRoot.scope; }) gitRoots; }; }