NixDaemon

NixOS pentest workstation as one flake — IceBreaker's successor
git clone https://git.daemon-sec.xyz/NixDaemon.git
Log | Files | Refs | README

options.nix (5755B)


      1 # modules/features/pentest/options.nix — the toolkit's master switch and the
      2 # options no single category owns.
      3 #
      4 #   daemon.pentest.enable                  the whole toolkit (default false)
      5 #   daemon.pentest.<category>.enable       declared by each category itself
      6 #                                          (_sets.nix), so adding a category
      7 #                                          touches one file, not two
      8 #   daemon.pentest.payloads.windowsArches  which .exe variants to cross-build
      9 #   daemon.pentest.htb.vpnDir              where .ovpn profiles are looked for
     10 #   daemon.pentest.htb.promptTarget        show $TARGET in the prompt
     11 #
     12 # Scope: authorised lab use (HackTheBox CPTS prep). Nothing here points at any
     13 # host; the operator supplies targets at runtime.
     14 { inputs, lib, self, ... }:
     15 {
     16   # `daemon.pentest.enable = false` must be a usable state, not an eval error.
     17   # The spec gives the master switch `default = false`, so "off" is the normal
     18   # case for any other machine built from this flake. This check evaluates the
     19   # whole toolkit with the master switch off and fails if any assertion fires.
     20   # Under `config` because this module also declares `options`.
     21   config.perSystem =
     22     { pkgs, system, ... }:
     23     let
     24       probe = enable:
     25         inputs.nixpkgs.lib.nixosSystem {
     26           inherit system;
     27           specialArgs = {
     28             inherit inputs;
     29             user = "probe";
     30           };
     31           modules = [
     32             self.nixosModules.pentest
     33             {
     34               daemon.pentest.enable = enable;
     35               # Enough to make a nixosSystem evaluate.
     36               boot.loader.grub.devices = [ "nodev" ];
     37               fileSystems."/" = { device = "/dev/null"; fsType = "ext4"; };
     38               system.stateVersion = "26.05";
     39               nixpkgs.config.allowUnfree = true;
     40               users.users.probe.isNormalUser = true;
     41             }
     42           ];
     43         };
     44       failures = enable:
     45         map (a: a.message) (builtins.filter (a: !a.assertion) (probe enable).config.assertions);
     46       offFailures = failures false;
     47     in
     48     {
     49       checks.pentest-options-off =
     50         if offFailures != [ ] then
     51           throw ''
     52             daemon.pentest.enable = false must evaluate cleanly, but these
     53             assertions fired:
     54             ${lib.concatMapStringsSep "\n" (m: "  - " + m) offFailures}
     55           ''
     56         else
     57           pkgs.runCommand "pentest-options-off-check" { } ''
     58             echo "daemon.pentest.enable = false evaluates with no failed assertions" > $out
     59           '';
     60     };
     61 
     62   # Each category file registers its package list here (_sets.nix), and
     63   # devshells.nix reads the merged result for the union shell and the
     64   # all-category collision check.
     65   #
     66   # It lives under `flake.lib` rather than a top-level `flake.pentestPackages`
     67   # for two reasons: the option has to be DECLARED as an attribute set, or
     68   # flake-parts treats the whole thing as one freeform value and the second
     69   # category to define it fails with "defined multiple times"; and `lib` is an
     70   # output Nix recognises, so `nix flake check` does not warn about an unknown
     71   # flake output.
     72   options.flake = inputs.flake-parts.lib.mkSubmoduleOptions {
     73     lib = lib.mkOption {
     74       # A submodule, not a bare attrset: `pentestPackages` has to merge across
     75       # the category files, so it needs its own attrsOf option. The freeform
     76       # type keeps `flake.lib` open for anything else.
     77       type = lib.types.submoduleWith {
     78         modules = [
     79           {
     80             freeformType = lib.types.lazyAttrsOf lib.types.raw;
     81             options.pentestPackages = lib.mkOption {
     82               type = lib.types.lazyAttrsOf lib.types.raw;
     83               default = { };
     84               description = "Per-category `pkgs -> [package]` functions, by category name.";
     85             };
     86           }
     87         ];
     88       };
     89       default = { };
     90       description = "Flake-level helpers, including pentestPackages.";
     91     };
     92   };
     93 
     94   # Under `config` because this module also declares `options` above.
     95   config.flake.nixosModules.pentest-options =
     96     { lib, config, user, ... }:
     97     let
     98       cfg = config.daemon.pentest;
     99       # Every category option declared by _sets.nix: an attrset carrying a
    100       # boolean `enable`. `htb` and `payloads.windowsArches` are not categories
    101       # and drop out of this filter on their own.
    102       categories = lib.filterAttrs (_: v: lib.isAttrs v && v ? enable && lib.isBool v.enable) cfg;
    103       enabledWhileOff = lib.attrNames (lib.filterAttrs (_: v: v.enable) categories);
    104     in
    105     {
    106       options.daemon.pentest = {
    107         enable = lib.mkEnableOption "the offensive security toolkit";
    108 
    109         payloads.windowsArches = lib.mkOption {
    110           type = lib.types.listOf (lib.types.enum [ "amd64" "x86" "arm64" ]);
    111           default = [ "amd64" "x86" ];
    112           description = "Windows architectures to cross-build payload binaries for.";
    113         };
    114 
    115         htb.vpnDir = lib.mkOption {
    116           type = lib.types.str;
    117           default = "/home/${user}/.config/htb/vpn";
    118           description = ''
    119             Directory scanned for OpenVPN profiles by `htbvpn list`. Deliberately
    120             not Nix-managed: HTB profiles are per-account and rotate.
    121           '';
    122         };
    123 
    124         htb.promptTarget = lib.mkOption {
    125           type = lib.types.bool;
    126           default = true;
    127           description = "Show the current $TARGET in the shell prompt.";
    128         };
    129       };
    130 
    131       config.assertions = [
    132         {
    133           assertion = cfg.enable || enabledWhileOff == [ ];
    134           message =
    135             "daemon.pentest: ${lib.concatStringsSep ", " enabledWhileOff} "
    136             + "enabled while daemon.pentest.enable is false. Set daemon.pentest.enable = true.";
    137         }
    138       ];
    139     };
    140 }