forked from tangled.org/core
this repo has no description
1{self}: { 2 config, 3 pkgs, 4 lib, 5 ... 6}: let 7 cfg = config.services.tangled-knot; 8in 9 with lib; { 10 options = { 11 services.tangled-knot = { 12 enable = mkOption { 13 type = types.bool; 14 default = false; 15 description = "Enable a tangled knot"; 16 }; 17 18 appviewEndpoint = mkOption { 19 type = types.str; 20 default = "https://tangled.sh"; 21 description = "Appview endpoint"; 22 }; 23 24 gitUser = mkOption { 25 type = types.str; 26 default = "git"; 27 description = "User that hosts git repos and performs git operations"; 28 }; 29 30 openFirewall = mkOption { 31 type = types.bool; 32 default = true; 33 description = "Open port 22 in the firewall for ssh"; 34 }; 35 36 stateDir = mkOption { 37 type = types.path; 38 default = "/home/${cfg.gitUser}"; 39 description = "Tangled knot data directory"; 40 }; 41 42 repo = { 43 scanPath = mkOption { 44 type = types.path; 45 default = cfg.stateDir; 46 description = "Path where repositories are scanned from"; 47 }; 48 49 mainBranch = mkOption { 50 type = types.str; 51 default = "main"; 52 description = "Default branch name for repositories"; 53 }; 54 }; 55 56 server = { 57 listenAddr = mkOption { 58 type = types.str; 59 default = "0.0.0.0:5555"; 60 description = "Address to listen on"; 61 }; 62 63 internalListenAddr = mkOption { 64 type = types.str; 65 default = "127.0.0.1:5444"; 66 description = "Internal address for inter-service communication"; 67 }; 68 69 secretFile = mkOption { 70 type = lib.types.path; 71 example = "KNOT_SERVER_SECRET=<hash>"; 72 description = "File containing secret key provided by appview (required)"; 73 }; 74 75 dbPath = mkOption { 76 type = types.path; 77 default = "${cfg.stateDir}/knotserver.db"; 78 description = "Path to the database file"; 79 }; 80 81 hostname = mkOption { 82 type = types.str; 83 example = "knot.tangled.sh"; 84 description = "Hostname for the server (required)"; 85 }; 86 87 dev = mkOption { 88 type = types.bool; 89 default = false; 90 description = "Enable development mode (disables signature verification)"; 91 }; 92 }; 93 }; 94 }; 95 96 config = mkIf cfg.enable { 97 environment.systemPackages = with pkgs; [ 98 git 99 self.packages."${pkgs.system}".knot 100 ]; 101 102 system.activationScripts.gitConfig = '' 103 mkdir -p "${cfg.repo.scanPath}" 104 chown -R ${cfg.gitUser}:${cfg.gitUser} \ 105 "${cfg.repo.scanPath}" 106 107 mkdir -p "${cfg.stateDir}/.config/git" 108 cat > "${cfg.stateDir}/.config/git/config" << EOF 109 [user] 110 name = Git User 111 email = git@example.com 112 EOF 113 chown -R ${cfg.gitUser}:${cfg.gitUser} \ 114 "${cfg.stateDir}" 115 ''; 116 117 users.users.${cfg.gitUser} = { 118 isSystemUser = true; 119 useDefaultShell = true; 120 home = cfg.stateDir; 121 createHome = true; 122 group = cfg.gitUser; 123 }; 124 125 users.groups.${cfg.gitUser} = {}; 126 127 services.openssh = { 128 enable = true; 129 extraConfig = '' 130 Match User ${cfg.gitUser} 131 AuthorizedKeysCommand /etc/ssh/keyfetch_wrapper 132 AuthorizedKeysCommandUser nobody 133 ''; 134 }; 135 136 environment.etc."ssh/keyfetch_wrapper" = { 137 mode = "0555"; 138 text = '' 139 #!${pkgs.stdenv.shell} 140 ${self.packages.${pkgs.system}.knot}/bin/knot keys \ 141 -output authorized-keys \ 142 -internal-api "http://${cfg.server.internalListenAddr}" \ 143 -git-dir "${cfg.repo.scanPath}" \ 144 -log-path /tmp/knotguard.log 145 ''; 146 }; 147 148 systemd.services.knot = { 149 description = "knot service"; 150 after = ["network.target" "sshd.service"]; 151 wantedBy = ["multi-user.target"]; 152 serviceConfig = { 153 User = cfg.gitUser; 154 WorkingDirectory = cfg.stateDir; 155 Environment = [ 156 "KNOT_REPO_SCAN_PATH=${cfg.repo.scanPath}" 157 "KNOT_REPO_MAIN_BRANCH=${cfg.repo.mainBranch}" 158 "APPVIEW_ENDPOINT=${cfg.appviewEndpoint}" 159 "KNOT_SERVER_INTERNAL_LISTEN_ADDR=${cfg.server.internalListenAddr}" 160 "KNOT_SERVER_LISTEN_ADDR=${cfg.server.listenAddr}" 161 "KNOT_SERVER_DB_PATH=${cfg.server.dbPath}" 162 "KNOT_SERVER_HOSTNAME=${cfg.server.hostname}" 163 ]; 164 EnvironmentFile = cfg.server.secretFile; 165 ExecStart = "${self.packages.${pkgs.system}.knot}/bin/knot server"; 166 Restart = "always"; 167 }; 168 }; 169 170 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [22]; 171 }; 172 }