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} "${cfg.repo.scanPath}" 105 106 mkdir -p "${cfg.stateDir}/.config/git" 107 cat > "${cfg.stateDir}/.config/git/config" << EOF 108 [user] 109 name = Git User 110 email = git@example.com 111 EOF 112 chown -R ${cfg.gitUser}:${cfg.gitUser} "${cfg.stateDir}" 113 ''; 114 115 users.users.${cfg.gitUser} = { 116 isSystemUser = true; 117 useDefaultShell = true; 118 home = cfg.stateDir; 119 createHome = true; 120 group = cfg.gitUser; 121 }; 122 123 users.groups.${cfg.gitUser} = {}; 124 125 services.openssh = { 126 enable = true; 127 extraConfig = '' 128 Match User ${cfg.gitUser} 129 AuthorizedKeysCommand /etc/ssh/keyfetch_wrapper 130 AuthorizedKeysCommandUser nobody 131 ''; 132 }; 133 134 environment.etc."ssh/keyfetch_wrapper" = { 135 mode = "0555"; 136 text = '' 137 #!${pkgs.stdenv.shell} 138 ${self.packages.${pkgs.system}.knot}/bin/knot keys \ 139 -output authorized-keys \ 140 -internal-api "http://${cfg.server.internalListenAddr}" \ 141 -git-dir "${cfg.repo.scanPath}" \ 142 -log-path /tmp/knotguard.log 143 ''; 144 }; 145 146 systemd.services.knot = { 147 description = "knot service"; 148 after = ["network.target" "sshd.service"]; 149 wantedBy = ["multi-user.target"]; 150 serviceConfig = { 151 User = cfg.gitUser; 152 WorkingDirectory = cfg.stateDir; 153 Environment = [ 154 "KNOT_REPO_SCAN_PATH=${cfg.repo.scanPath}" 155 "KNOT_REPO_MAIN_BRANCH=${cfg.repo.mainBranch}" 156 "APPVIEW_ENDPOINT=${cfg.appviewEndpoint}" 157 "KNOT_SERVER_INTERNAL_LISTEN_ADDR=${cfg.server.internalListenAddr}" 158 "KNOT_SERVER_LISTEN_ADDR=${cfg.server.listenAddr}" 159 "KNOT_SERVER_DB_PATH=${cfg.server.dbPath}" 160 "KNOT_SERVER_HOSTNAME=${cfg.server.hostname}" 161 ]; 162 EnvironmentFile = cfg.server.secretFile; 163 ExecStart = "${self.packages.${pkgs.system}.knot}/bin/knot server"; 164 Restart = "always"; 165 }; 166 }; 167 168 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [22]; 169 }; 170 }