{ config, pkgs, lib, ... }: let inherit (lib) mkOption types; in { config = { resources.login-shell = { description = "The operator needs to be able to log into the shell"; request = { ... }: { _class = "fediversity-resource-request"; options = { wheel = mkOption { description = "Whether the login user needs root permissions"; type = types.bool; default = false; }; packages = mkOption { description = "Packages that need to be available in the user environment"; type = with types; attrsOf package; }; }; }; policy = { config, ... }: { _class = "fediversity-resource-policy"; options = { username = mkOption { description = "Username for the operator"; type = types.str; # TODO: use the proper constraints from NixOS }; wheel = mkOption { description = "Whether to allow login with root permissions"; type = types.bool; default = false; }; }; config = { resource-type = types.raw; # TODO: splice out the user type from NixOS apply = requests: let # Filter out requests that need wheel if policy doesn't allow it validRequests = lib.filterAttrs ( _name: req: !req.login-shell.wheel || config.wheel ) requests.resources; in lib.optionalAttrs (validRequests != { }) { ${config.username} = { isNormalUser = true; packages = with lib; attrValues (concatMapAttrs (_name: request: request.login-shell.packages) validRequests); extraGroups = lib.optional config.wheel "wheel"; }; }; }; }; }; applications.hello = { ... }: { description = ''Command-line tool that will print "Hello, world!" on the terminal''; module = { ... }: { options.enable = lib.mkEnableOption "Hello in the shell"; }; implementation = cfg: { resources = lib.optionalAttrs cfg.enable { hello.login-shell.packages.hello = pkgs.hello; }; }; }; }; options."example-configuration" = mkOption { type = config.configuration; default = { enable = true; applications.hello.enable = true; }; }; }