forked from tangled.org/core
Monorepo for Tangled — https://tangled.org
1{ 2 description = "atproto github"; 3 4 inputs = { 5 nixpkgs.url = "github:nixos/nixpkgs"; 6 indigo = { 7 url = "github:oppiliappan/indigo"; 8 flake = false; 9 }; 10 htmx-src = { 11 url = "https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js"; 12 flake = false; 13 }; 14 lucide-src = { 15 url = "https://unpkg.com/lucide@0.482.0"; 16 flake = false; 17 }; 18 ia-fonts-src = { 19 url = "github:iaolo/iA-Fonts"; 20 flake = false; 21 }; 22 gitignore = { 23 url = "github:hercules-ci/gitignore.nix"; 24 inputs.nixpkgs.follows = "nixpkgs"; 25 }; 26 }; 27 28 outputs = { 29 self, 30 nixpkgs, 31 indigo, 32 htmx-src, 33 lucide-src, 34 gitignore, 35 ia-fonts-src, 36 }: let 37 supportedSystems = ["x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin"]; 38 forAllSystems = nixpkgs.lib.genAttrs supportedSystems; 39 nixpkgsFor = forAllSystems (system: 40 import nixpkgs { 41 inherit system; 42 overlays = [self.overlays.default]; 43 }); 44 inherit (gitignore.lib) gitignoreSource; 45 in { 46 overlays.default = final: prev: let 47 goModHash = "sha256-zJKjcxd+gr+9Kx2e1lUv+0hlXlxJm5YbWeIGUo0eIiE="; 48 buildCmdPackage = name: 49 final.buildGoModule { 50 pname = name; 51 version = "0.1.0"; 52 src = gitignoreSource ./.; 53 subPackages = ["cmd/${name}"]; 54 vendorHash = goModHash; 55 env.CGO_ENABLED = 0; 56 }; 57 in { 58 indigo-lexgen = final.buildGoModule { 59 pname = "indigo-lexgen"; 60 version = "0.1.0"; 61 src = indigo; 62 subPackages = ["cmd/lexgen"]; 63 vendorHash = "sha256-pGc29fgJFq8LP7n/pY1cv6ExZl88PAeFqIbFEhB3xXs="; 64 doCheck = false; 65 }; 66 67 appview = with final; 68 final.pkgsStatic.buildGoModule { 69 pname = "appview"; 70 version = "0.1.0"; 71 src = gitignoreSource ./.; 72 postUnpack = '' 73 pushd source 74 cp -f ${htmx-src} appview/pages/static/htmx.min.js 75 cp -f ${lucide-src} appview/pages/static/lucide.min.js 76 mkdir -p appview/pages/static/fonts 77 cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ 78 cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ 79 ${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o appview/pages/static/tw.css 80 popd 81 ''; 82 doCheck = false; 83 subPackages = ["cmd/appview"]; 84 vendorHash = goModHash; 85 env.CGO_ENABLED = 1; 86 stdenv = pkgsStatic.stdenv; 87 }; 88 89 knotserver = with final; 90 final.pkgsStatic.buildGoModule { 91 pname = "knotserver"; 92 version = "0.1.0"; 93 src = gitignoreSource ./.; 94 nativeBuildInputs = [final.makeWrapper]; 95 subPackages = ["cmd/knotserver"]; 96 vendorHash = goModHash; 97 installPhase = '' 98 runHook preInstall 99 100 mkdir -p $out/bin 101 cp $GOPATH/bin/knotserver $out/bin/knotserver 102 103 wrapProgram $out/bin/knotserver \ 104 --prefix PATH : ${pkgs.git}/bin 105 106 runHook postInstall 107 ''; 108 env.CGO_ENABLED = 1; 109 }; 110 knotserver-unwrapped = final.pkgsStatic.buildGoModule { 111 pname = "knotserver"; 112 version = "0.1.0"; 113 src = gitignoreSource ./.; 114 subPackages = ["cmd/knotserver"]; 115 vendorHash = goModHash; 116 env.CGO_ENABLED = 1; 117 }; 118 repoguard = buildCmdPackage "repoguard"; 119 keyfetch = buildCmdPackage "keyfetch"; 120 }; 121 packages = forAllSystems (system: { 122 inherit 123 (nixpkgsFor."${system}") 124 indigo-lexgen 125 appview 126 knotserver 127 knotserver-unwrapped 128 repoguard 129 keyfetch 130 ; 131 }); 132 defaultPackage = forAllSystems (system: nixpkgsFor.${system}.appview); 133 formatter = forAllSystems (system: nixpkgsFor."${system}".alejandra); 134 devShells = forAllSystems (system: let 135 pkgs = nixpkgsFor.${system}; 136 staticShell = pkgs.mkShell.override { 137 stdenv = pkgs.pkgsStatic.stdenv; 138 }; 139 in { 140 default = staticShell { 141 nativeBuildInputs = [ 142 pkgs.go 143 pkgs.air 144 pkgs.gopls 145 pkgs.httpie 146 pkgs.indigo-lexgen 147 pkgs.litecli 148 pkgs.websocat 149 pkgs.tailwindcss 150 pkgs.nixos-shell 151 ]; 152 shellHook = '' 153 cp -f ${htmx-src} appview/pages/static/htmx.min.js 154 cp -f ${lucide-src} appview/pages/static/lucide.min.js 155 cp -f ${ia-fonts-src}/"iA Writer Quattro"/Static/*.ttf appview/pages/static/fonts/ 156 cp -f ${ia-fonts-src}/"iA Writer Mono"/Static/*.ttf appview/pages/static/fonts/ 157 ''; 158 }; 159 }); 160 apps = forAllSystems (system: let 161 pkgs = nixpkgsFor."${system}"; 162 air-watcher = name: 163 pkgs.writeShellScriptBin "run" 164 '' 165 ${pkgs.air}/bin/air -c /dev/null \ 166 -build.cmd "${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o ./appview/pages/static/tw.css && ${pkgs.go}/bin/go build -o ./out/${name}.out ./cmd/${name}/main.go" \ 167 -build.bin "./out/${name}.out" \ 168 -build.include_ext "go,html,css" 169 ''; 170 in { 171 watch-appview = { 172 type = "app"; 173 program = ''${air-watcher "appview"}/bin/run''; 174 }; 175 watch-knotserver = { 176 type = "app"; 177 program = ''${air-watcher "knotserver"}/bin/run''; 178 }; 179 }); 180 181 nixosModules.appview = { 182 config, 183 pkgs, 184 lib, 185 ... 186 }: 187 with lib; { 188 options = { 189 services.tangled-appview = { 190 enable = mkOption { 191 type = types.bool; 192 default = false; 193 description = "Enable tangled appview"; 194 }; 195 port = mkOption { 196 type = types.int; 197 default = 3000; 198 description = "Port to run the appview on"; 199 }; 200 cookie_secret = mkOption { 201 type = types.str; 202 default = "00000000000000000000000000000000"; 203 description = "Cookie secret"; 204 }; 205 }; 206 }; 207 208 config = mkIf config.services.tangled-appview.enable { 209 systemd.services.tangled-appview = { 210 description = "tangled appview service"; 211 wantedBy = ["multi-user.target"]; 212 213 serviceConfig = { 214 ListenStream = "0.0.0.0:${toString config.services.tangled-appview.port}"; 215 ExecStart = "${self.packages.${pkgs.system}.appview}/bin/appview"; 216 Restart = "always"; 217 }; 218 219 environment = { 220 TANGLED_DB_PATH = "appview.db"; 221 TANGLED_COOKIE_SECRET = config.services.tangled-appview.cookie_secret; 222 }; 223 }; 224 }; 225 }; 226 227 nixosModules.knotserver = { 228 config, 229 pkgs, 230 lib, 231 ... 232 }: 233 with lib; { 234 options = { 235 services.tangled-knotserver = { 236 enable = mkOption { 237 type = types.bool; 238 default = false; 239 description = "Enable a tangled knotserver"; 240 }; 241 242 appviewEndpoint = mkOption { 243 type = types.str; 244 default = "https://tangled.sh"; 245 description = "Appview endpoint"; 246 }; 247 248 gitUser = mkOption { 249 type = types.str; 250 default = "git"; 251 description = "User that hosts git repos and performs git operations"; 252 }; 253 254 repo = { 255 scanPath = mkOption { 256 type = types.path; 257 default = "/home/git"; 258 description = "Path where repositories are scanned from"; 259 }; 260 261 mainBranch = mkOption { 262 type = types.str; 263 default = "main"; 264 description = "Default branch name for repositories"; 265 }; 266 }; 267 268 server = { 269 listenAddr = mkOption { 270 type = types.str; 271 default = "0.0.0.0:5555"; 272 description = "Address to listen on"; 273 }; 274 275 internalListenAddr = mkOption { 276 type = types.str; 277 default = "127.0.0.1:5444"; 278 description = "Internal address for inter-service communication"; 279 }; 280 281 secret = mkOption { 282 type = types.str; 283 example = "super-secret-key"; 284 description = "Secret key provided by appview (required)"; 285 }; 286 287 dbPath = mkOption { 288 type = types.path; 289 default = "knotserver.db"; 290 description = "Path to the database file"; 291 }; 292 293 hostname = mkOption { 294 type = types.str; 295 example = "knot.tangled.sh"; 296 description = "Hostname for the server (required)"; 297 }; 298 299 dev = mkOption { 300 type = types.bool; 301 default = false; 302 description = "Enable development mode (disables signature verification)"; 303 }; 304 }; 305 }; 306 }; 307 308 config = mkIf config.services.tangled-knotserver.enable { 309 environment.systemPackages = with pkgs; [git]; 310 311 system.activationScripts.gitConfig = '' 312 mkdir -p /home/git/.config/git 313 cat > /home/git/.config/git/config << EOF 314 [user] 315 name = Git User 316 email = git@example.com 317 EOF 318 chown -R git:git /home/git/.config 319 ''; 320 321 users.users.git = { 322 isNormalUser = true; 323 home = "/home/git"; 324 createHome = true; 325 uid = 1000; 326 group = "git"; 327 }; 328 329 users.groups.git = {}; 330 331 services.openssh = { 332 enable = true; 333 extraConfig = '' 334 Match User git 335 AuthorizedKeysCommand /etc/ssh/keyfetch_wrapper 336 AuthorizedKeysCommandUser nobody 337 ''; 338 }; 339 340 environment.etc."ssh/keyfetch_wrapper" = { 341 mode = "0555"; 342 text = '' 343 #!${pkgs.stdenv.shell} 344 ${self.packages.${pkgs.system}.keyfetch}/bin/keyfetch \ 345 -repoguard-path ${self.packages.${pkgs.system}.repoguard}/bin/repoguard \ 346 -log-path /tmp/repoguard.log 347 ''; 348 }; 349 350 systemd.services.knotserver = { 351 description = "knotserver service"; 352 after = ["network.target" "sshd.service"]; 353 wantedBy = ["multi-user.target"]; 354 serviceConfig = { 355 User = "git"; 356 WorkingDirectory = "/home/git"; 357 Environment = [ 358 "KNOT_REPO_SCAN_PATH=${config.services.tangled-knotserver.repo.scanPath}" 359 "APPVIEW_ENDPOINT=${config.services.tangled-knotserver.appviewEndpoint}" 360 "KNOT_SERVER_INTERNAL_LISTEN_ADDR=${config.services.tangled-knotserver.server.internalListenAddr}" 361 "KNOT_SERVER_LISTEN_ADDR=${config.services.tangled-knotserver.server.listenAddr}" 362 "KNOT_SERVER_SECRET=${config.services.tangled-knotserver.server.secret}" 363 "KNOT_SERVER_HOSTNAME=${config.services.tangled-knotserver.server.hostname}" 364 ]; 365 ExecStart = "${self.packages.${pkgs.system}.knotserver}/bin/knotserver"; 366 Restart = "always"; 367 }; 368 }; 369 370 networking.firewall.allowedTCPPorts = [22]; 371 }; 372 }; 373 374 nixosConfigurations.knotVM = nixpkgs.lib.nixosSystem { 375 system = "x86_64-linux"; 376 modules = [ 377 self.nixosModules.knotserver 378 ({ 379 config, 380 pkgs, 381 ... 382 }: { 383 virtualisation.memorySize = 2048; 384 virtualisation.cores = 2; 385 services.getty.autologinUser = "root"; 386 environment.systemPackages = with pkgs; [curl vim git]; 387 services.tangled-knotserver = { 388 enable = true; 389 server = { 390 secret = "6995e040e80e2d593b5e5e9ca611a70140b9ef8044add0a28b48b1ee34aa3e85"; 391 hostname = "localhost:6000"; 392 listenAddr = "0.0.0.0:6000"; 393 }; 394 }; 395 }) 396 ]; 397 }; 398 }; 399}