aboutsummaryrefslogtreecommitdiffhomepage
path: root/nixos.nix
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-09-04 17:03:21 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-09-04 17:03:21 +0900
commit945cce2f5e487492730e06e13e920e08c55d8084 (patch)
treebbc0147dd26df2c1e950d7b2b8242223ee869e68 /nixos.nix
parent5c3e7cf6640721fc2cb5006c879bf570cedf1902 (diff)
nix: implement nixos module
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'nixos.nix')
-rw-r--r--nixos.nix220
1 files changed, 220 insertions, 0 deletions
diff --git a/nixos.nix b/nixos.nix
new file mode 100644
index 00000000..0fe5b713
--- /dev/null
+++ b/nixos.nix
@@ -0,0 +1,220 @@
+{
+ lib,
+ pkgs,
+ config,
+ ...
+}:
+
+let
+ inherit (lib)
+ types
+ mkOption
+ mkEnableOption
+ mkIf
+ mapAttrs
+ mapAttrsToList
+ foldlAttrs
+ optional
+ ;
+
+ cfg = config.environment.fortify;
+in
+
+{
+ options = {
+ environment.fortify = {
+ enable = mkEnableOption "fortify";
+
+ target = mkOption {
+ default = { };
+ type =
+ let
+ inherit (types)
+ str
+ enum
+ bool
+ package
+ anything
+ submodule
+ listOf
+ attrsOf
+ nullOr
+ ;
+ in
+ attrsOf (submodule {
+ options = {
+ packages = mkOption {
+ type = listOf package;
+ default = [ ];
+ description = ''
+ List of extra packages to install via home-manager.
+ '';
+ };
+
+ launchers = mkOption {
+ type = attrsOf (submodule {
+ options = {
+ command = mkOption {
+ type = nullOr str;
+ default = null;
+ description = ''
+ Command to run as the target user.
+ Setting this to null will default command to wrapper name.
+ '';
+ };
+
+ pulse = mkOption {
+ type = bool;
+ default = true;
+ description = ''
+ Whether to share the PulseAudio socket and cookie.
+ '';
+ };
+
+ share = mkOption {
+ type = nullOr package;
+ default = null;
+ description = ''
+ Package containing share files.
+ Setting this to null will default package name to wrapper name.
+ '';
+ };
+
+ method = mkOption {
+ type = enum [
+ "fortify"
+ "fortify-sudo"
+ "sudo"
+ ];
+ default = "fortify";
+ description = ''
+ Launch method for the sandboxed program.
+ '';
+ };
+ };
+ });
+ default = { };
+ };
+
+ persistence = mkOption {
+ type = submodule {
+ options = {
+ directories = mkOption {
+ type = listOf anything;
+ default = [ ];
+ };
+
+ files = mkOption {
+ type = listOf anything;
+ default = [ ];
+ };
+ };
+ };
+ description = ''
+ Per-user state passed to github:nix-community/impermanence.
+ '';
+ };
+
+ extraConfig = mkOption {
+ type = anything;
+ default = { };
+ description = "Extra home-manager configuration.";
+ };
+ };
+ });
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.callPackage ./package.nix { };
+ description = "Package providing fortify.";
+ };
+
+ user = mkOption {
+ type = types.str;
+ description = "Privileged user account.";
+ };
+
+ shell = mkOption {
+ type = types.str;
+ description = ''
+ Shell set up to source home-manager for the privileged user.
+ Required for setting up the environment of sandboxed programs.
+ '';
+ };
+
+ stateDir = mkOption {
+ type = types.str;
+ description = ''
+ The path to persistent storage where per-user state should be stored.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment.persistence.${cfg.stateDir}.users = mapAttrs (_: target: target.persistence) cfg.target;
+
+ home-manager.users =
+ mapAttrs (_: target: target.extraConfig // { home.packages = target.packages; }) cfg.target
+ // {
+ ${cfg.user}.home.packages =
+ let
+ wrap =
+ user: launchers:
+ mapAttrsToList (
+ name: launcher:
+ let
+ command = if launcher.command == null then name else launcher.command;
+ in
+ pkgs.writeShellScriptBin name (
+ if launcher.method == "sudo" then
+ ''
+ exec sudo -u ${user} -i ${command} $@
+ ''
+ else
+ ''
+ exec fortify${if launcher.pulse then " -pulse" else ""} -u ${user}${
+ if launcher.method == "fortify-sudo" then " -sudo" else ""
+ } ${cfg.shell} -c "exec ${command} $@"
+ ''
+ )
+ ) launchers;
+ in
+ foldlAttrs (
+ acc: user: target:
+ acc
+ ++ (foldlAttrs (
+ shares: name: launcher:
+ let
+ pkg = if launcher.share != null then launcher.share else pkgs.${name};
+ link = source: "[ -d '${source}' ] && ln -sv '${source}' $out/share || true";
+ in
+ shares
+ ++ optional (launcher.method == "fortify") (
+ pkgs.runCommand "${name}-share" { } ''
+ mkdir -p $out/share
+ ${link "${pkg}/share/applications"}
+ ${link "${pkg}/share/icons"}
+ ${link "${pkg}/share/man"}
+ ''
+ )
+ ) (wrap user target.launchers) target.launchers)
+ ) [ cfg.package ] cfg.target;
+ };
+
+ security.polkit.extraConfig =
+ let
+ allowList = builtins.toJSON (mapAttrsToList (name: _: name) cfg.target);
+ in
+ ''
+ polkit.addRule(function(action, subject) {
+ if (action.id == "org.freedesktop.machine1.host-shell" &&
+ ${allowList}.indexOf(action.lookup("user")) > -1 &&
+ subject.user == "${cfg.user}") {
+ return polkit.Result.YES;
+ }
+ });
+ '';
+ };
+}