{ lib, pkgs, config, ... }: let cfg = config.sandboxing.boxxy; boxxyRuleModule = { name, lib, ... }: { options = { source = lib.mkOption { type = lib.types.str; description = '' The path of the file to be remounted. ''; example = "~/.tmux.conf"; }; destination = lib.mkOption { type = lib.types.str; default = name; description = '' The path where the source will be remounted to. ''; example = "~/.config/tmux/tmux.conf"; }; mode = lib.mkOption { type = with lib.types; nullOr (enum [ "file" "dir" ]); description = '' Mode indicating the behavior for remounting. ''; default = null; example = "dir"; }; }; }; boxxyModuleFactory = { isGlobal ? false }: { package = lib.mkPackageOption pkgs "boxxy" { } // lib.optionalAttrs (!isGlobal) { default = cfg.package; }; # TODO: Perhaps, consider creating a PR to upstream repo to pass a config file? # Boxxy doesn't have a way to pass a custom configuration file so we're # settling with this. Besides, Boxxy-launched programs can inherit the # environment anyways so a custom config file is not needed for now. rules = lib.mkOption { type = with lib.types; attrsOf (submodule boxxyRuleModule); default = { }; description = if isGlobal then '' Global set of rules to be applied per-wrapper. '' else '' Set of rules to be applied to the wrapper. ''; example = lib.literalExpression '' { "~/.config/tmux/tmux.conf".source = "~/.tmux.conf"; "~/.config/bash/bashrc".source = "~/.bashrc"; "~/.config/vscode" = { source = "~/.vscode"; mode = "dir"; }; } ''; }; extraArgs = lib.mkOption { type = with lib.types; listOf str; description = if isGlobal then '' Global list of arguments to be appended to each Boxxy-enabled wrappers. '' else '' List of arguments to the {command}`boxxy` executable. ''; default = [ ]; example = [ "--immutable" "--daemon" ]; }; }; in { options.sandboxing.boxxy = boxxyModuleFactory { isGlobal = true; }; options.wrappers = let boxxySandboxModule = { name, lib, config, pkgs, ... }: let submoduleCfg = config.sandboxing.boxxy; in { options.sandboxing.variant = lib.mkOption { type = with lib.types; nullOr (enum [ "boxxy" ]); }; options.sandboxing.boxxy = boxxyModuleFactory { isGlobal = false; }; config = lib.mkIf (config.sandboxing.variant == "boxxy") { sandboxing.boxxy.rules = cfg.rules; sandboxing.boxxy.extraArgs = cfg.extraArgs ++ (lib.mapAttrsToList (_: metadata: let inherit (metadata) source destination mode; ruleArg = if mode != null then "${source}:${destination}:${mode}" else "${source}:${destination}"; in "--rule ${lib.escapeShellArg ruleArg}") submoduleCfg.rules); arg0 = lib.getExe submoduleCfg.package; prependArgs = lib.mkBefore (submoduleCfg.extraArgs ++ [ "--" config.sandboxing.wraparound.arg0 ] ++ config.sandboxing.wraparound.extraArgs); }; }; in lib.mkOption { type = with lib.types; attrsOf (submodule boxxySandboxModule); }; }