nix: implement nixos module

Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
Ophestra Umiker 2024-09-04 17:03:21 +09:00
parent 5c3e7cf664
commit 945cce2f5e
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
4 changed files with 271 additions and 41 deletions

View File

@ -2,16 +2,16 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1717179513, "lastModified": 1725361206,
"narHash": "sha256-vboIEwIQojofItm2xGCdZCzW96U85l9nDW3ifMuAIdM=", "narHash": "sha256-/HTUg+kMaqBPGrcQBYboAMsQHIWIkuKRDldss/035Hc=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "63dacb46bf939521bdc93981b4cbb7ecb58427a0", "rev": "2830c7c930311397d94c0b86a359c865c081c875",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "24.05", "ref": "nixos-unstable-small",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View File

@ -1,56 +1,41 @@
{ {
description = "fortify development environment"; description = "fortify sandbox tool and nixos module";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/24.05"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
}; };
outputs = outputs =
{ self, nixpkgs }: { self, nixpkgs }:
let let
supportedSystems = [ "x86_64-linux" ]; supportedSystems = [
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system); "aarch64-linux"
"i686-linux"
"x86_64-linux"
];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
in in
{ {
devShells = forAllSystems ( nixosModules.fortify = import ./nixos.nix;
packages = forAllSystems (
system: system:
let let
pkgs = import nixpkgs { inherit system; }; pkgs = nixpkgsFor.${system};
in in
{ {
default = default = self.packages.${system}.fortify;
let
inherit (pkgs)
mkShell
buildGoModule
acl
xorg
;
in
mkShell {
packages = [
(buildGoModule rec {
pname = "fortify";
version = "0.0.0-flake";
src = ./.; fortify = pkgs.callPackage ./package.nix { };
vendorHash = null; # we have no Go dependencies :3
ldflags = [
"-s"
"-w"
"-X"
"main.Version=v${version}"
];
buildInputs = [
acl
xorg.libxcb
];
})
];
};
} }
); );
devShells = forAllSystems (system: {
default = nixpkgsFor.${system}.mkShell {
buildInputs = with nixpkgsFor.${system}; [ self.packages.${system}.fortify ];
};
});
}; };
} }

220
nixos.nix Normal file
View File

@ -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;
}
});
'';
};
}

25
package.nix Normal file
View File

@ -0,0 +1,25 @@
{
acl,
xorg,
buildGoModule,
}:
buildGoModule rec {
pname = "fortify";
version = "1.0.3";
src = ./.;
vendorHash = null;
ldflags = [
"-s"
"-w"
"-X"
"main.Version=v${version}"
];
buildInputs = [
acl
xorg.libxcb
];
}