{ pkgs, lib, config, ... }: let cfg = config.services.tvix-binary-cache; systemdHardening = { PrivateDevices = true; PrivateTmp = true; ProtectControlGroups = true; ProtectKernelTunables = true; RestrictSUIDSGID = true; ProtectSystem = "strict"; ProtectKernelLogs = true; ProtectProc = "invisible"; PrivateUsers = true; ProtectHome = true; UMask = "0077"; RuntimeDirectoryMode = "0750"; StateDirectoryMode = "0750"; }; in { imports = [ ./nginx.nix ]; options = { services.tvix-binary-cache = { enable = lib.mkEnableOption "BinaryCache using tvix ca-store"; blob-service-addr = lib.mkOption { type = lib.types.str; default = "objectstore+file://%S/tvix-castore/blobs.object-store"; description = '' `blob-service-addr` option for the mutualized content addressed storage. ''; }; directory-service-addr = lib.mkOption { type = lib.types.str; default = "sled://%S/tvix-castore/directories.sled"; description = '' `directory-service-addr` option for the mutualized content addressed storage. ''; }; caches = lib.mkOption { type = lib.types.attrsOf ( lib.types.submodule ( { name, ... }: { options = { port = lib.mkOption { type = lib.types.port; default = 9000; }; name = lib.mkOption { type = lib.types.str; description = "Name of the cache"; default = name; defaultText = lib.literalMD "Defaults to attribute name in services.tvix-binary-cache.caches"; }; path-info-service-addr = lib.mkOption { type = with lib.types; str; description = "Path info service path"; default = "sled://%S/%N/pathinfo.sled"; }; remote-path-info-service-addr = lib.mkOption { type = with lib.types; nullOr str; description = "Upstream cache to substitute from if nothing in "; example = "nix+https://cache.nixos.org?trusted-public-keys=cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="; default = null; }; blob-service-addr = lib.mkOption { type = with lib.types; nullOr str; default = null; description = '' Use a specific blob service and do not use the mutualized one. ''; }; directory-service-addr = lib.mkOption { type = with lib.types; nullOr str; default = null; description = '' Use a specific directory address and do not use the mutualized one. ''; }; }; } ) ); }; }; }; config = lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.tvix-store ]; systemd.services = lib.mkMerge ( (lib.singleton { tvix-castore = { environment = { BLOB_SERVICE_ADDR = cfg.blob-service-addr; DIRECTORY_SERVICE_ADDR = cfg.directory-service-addr; PATH_INFO_SERVICE_ADDR = "sled://%S/tvix-castore/pathinfo.sled"; # Unused but probably needed }; serviceConfig = { ExecStart = "${pkgs.tvix-store}/bin/tvix-store --otlp=false daemon --listen-address=\"%t/tvix-castore/socket\""; DynamicUser = true; User = "tvix-binary-cache"; StateDirectory = "tvix-castore"; RuntimeDirectory = "tvix-castore"; } // systemdHardening; }; }) ++ (lib.mapAttrsToList ( name: cfg: let unitName = "tvix-store-${cfg.name}"; in { ${unitName} = { wantedBy = [ "multi-user.target" ]; wants = [ "tvix-castore.service" ]; after = [ "tvix-castore.service" ]; environment = { BLOB_SERVICE_ADDR = if cfg.blob-service-addr != null then cfg.blob-service-addr else "grpc+unix://%t/tvix-castore/socket"; DIRECTORY_SERVICE_ADDR = if cfg.directory-service-addr != null then cfg.directory-service-addr else "grpc+unix://%t/tvix-castore/socket"; PATH_INFO_SERVICE_ADDR = cfg.path-info-service-addr; REMOTE_PATH_INFO_SERVICE_ADDR = lib.mkIf ( cfg.remote-path-info-service-addr != null ) cfg.remote-path-info-service-addr; }; serviceConfig = { ExecStart = "${pkgs.nar-bridge}/bin/nar-bridge --otlp=false --listen-address=\"[::1]:${builtins.toString cfg.port}\""; DynamicUser = true; User = "tvix-binary-cache"; StateDirectory = unitName; RuntimeDirectory = unitName; } // systemdHardening; }; } ) cfg.caches) ); }; }