commit e23814f29689228c313b4b88e68bc29dad7e8c95
parent f4fbedbb786ee1854bb8a1f2e0d12da129a0b06e
Author: maydayv7 <maydayv7@gmail.com>
Date: Tue, 30 Jun 2026 22:13:34 +0530
feat: `nixos` -> `os` + `nh`, `micro`
Diffstat:
11 files changed, 534 insertions(+), 545 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
@@ -2,6 +2,8 @@
### June
+- Rename `nixos` script to `os` and adopt [`nh`](https://github.com/nix-community/nh)
+- Use `micro` as default editor
- Use [`disko`](https://github.com/nix-community/disko) for declarative disk partitioning
- Disable keyless SSH Access
- Declaratively configure a Windows 11 VM
diff --git a/README.md b/README.md
@@ -196,7 +196,7 @@ github:maydayv7/dotfiles
│ └── map.nix
├── scripts
│ ├── install.nix
-│ └── nixos.nix
+│ └── os.nix
├── packages
│ ├── overlays
│ └── patches
@@ -266,7 +266,7 @@ To use my configuration as-is for a fresh NixOS installation, you can try the fo
4. Import all required GPG Keys into a convenient location (like `/etc/gpg`) using <code>gpg --homedir <i>DIR</i> import</code> and specify it at `config.sops.gnupg.home` (Required for decryption of `secrets` on boot, can also be on an external drive)
-5. Make new `secrets` and `passwords` in the desired directories by appending the paths to `secrets.yaml` and then using the following command (The [`nixos`](./scripts/README.md) script can be used to simplify the process):
+5. Make new `secrets` and `passwords` in the desired directories by appending the paths to `secrets.yaml` and then using the following command (The [`os`](./scripts/README.md) script can be used to simplify the process):
_Replace_ **_PATH_** _with the path to the `secret`_
<pre><code>sops --config <i>/path/to/<b>secrets.yaml</b></i> -i <b><i>PATH</i></b></code></pre>
@@ -328,7 +328,7 @@ _Replace_ **_DEVICE_** _with the name of Device to build_
To install the OS, just boot the Live USB and run `sudo os-install`
_If the image doesn't boot, try disabling the `secure boot` and `RAID` options from `BIOS`_
-After the reboot, run `nixos setup` to finish the install
+After the reboot, run `os setup` to finish the install
_In case you are using the `advanced` filesystem scheme, you may need to set the boot flag `zfs_force=1` on first boot_
</details>
diff --git a/modules/shell/shell-utils.nix b/modules/shell/shell-utils.nix
@@ -15,7 +15,6 @@ in {
fd
hstr
lolcat
- micro
tree
yazi
zellij
@@ -58,10 +57,7 @@ in {
homeManager.shell-utils = _: {
home.persist = {
files = [".hstr_favorites"];
- directories = [
- ".config/micro"
- ".local/share/direnv"
- ];
+ directories = [".local/share/direnv"];
};
programs = {
@@ -87,30 +83,6 @@ in {
git = true;
extraOptions = ["--group-directories-first"];
};
-
- # Text Editor
- micro = {
- enable = true;
- settings = {
- autoindent = true;
- backup = true;
- clipboard = "external";
- cursorline = true;
- eofnewline = false;
- helpsplit = "vsplit";
- hltrailingws = true;
- infobar = true;
- matchbrace = true;
- keymenu = true;
- mouse = true;
- reload = "prompt";
- ruler = true;
- saveundo = true;
- smartpaste = true;
- statusline = true;
- syntax = true;
- };
- };
};
};
};
diff --git a/modules/shell/shell.nix b/modules/shell/shell.nix
@@ -1,12 +1,45 @@
## Shell Configuration ##
{config, ...}: let
inherit (config.flake) files;
+
+ editor = {
+ autoindent = true;
+ backup = true;
+ clipboard = "external";
+ cursorline = true;
+ eofnewline = false;
+ helpsplit = "vsplit";
+ hltrailingws = true;
+ infobar = true;
+ matchbrace = true;
+ keymenu = true;
+ mouse = true;
+ reload = "prompt";
+ ruler = true;
+ saveundo = true;
+ smartpaste = true;
+ statusline = true;
+ syntax = true;
+ };
in {
flake.modules = {
nixos.shell = {pkgs, ...}: {
config = {
# Text Editor
- environment.variables."EDITOR" = "nano";
+ environment.variables."EDITOR" = "micro";
+ environment.systemPackages = [pkgs.micro];
+ environment.interactiveShellInit = ''
+ e() { "''${EDITOR:-nano}" "$@"; }
+ '';
+
+ systemd.tmpfiles.rules = let
+ settings = pkgs.writeText "micro-settings.json" (builtins.toJSON editor);
+ in [
+ "d /root/.config 0700 root root -"
+ "d /root/.config/micro 0700 root root -"
+ "L+ /root/.config/micro/settings.json - - - - ${settings}"
+ ];
+
programs = {
nano = {
enable = true;
@@ -81,10 +114,17 @@ in {
".zsh_history"
];
directories = [
+ ".config/micro"
".local/share/bash"
".cache/zsh"
];
};
+
+ # Text Editor
+ programs.micro = {
+ enable = true;
+ settings = editor;
+ };
};
};
}
diff --git a/modules/system/base.nix b/modules/system/base.nix
@@ -60,12 +60,13 @@ _: {
};
environment = {
- variables."NIXOS_SPECIALISATION" = with config.system.nixos;
- mkIf (hasPrefix "special." label) (removePrefix "special." label);
+ etc."specialisation" =
+ mkIf (hasPrefix "special." cfg.nixos.label)
+ {text = removePrefix "special." cfg.nixos.label;};
# Essential Utilities
systemPackages = with pkgs; [
- custom.nixos
+ custom.os
cryptsetup
file
inxi
diff --git a/packages/_module.nix b/packages/_module.nix
@@ -70,7 +70,7 @@ in {
}
)
// {
- default = self'.apps.nixos;
+ default = self'.apps.os;
};
}
);
diff --git a/scripts/README.md b/scripts/README.md
@@ -2,6 +2,6 @@
The `scripts` directory contains a combination of custom Bash Scripts (with `nix` shebangs, and can be run using <code><i>./path/to/script</i></code>) as well as ones written in conjunction with the Nix Syntax (which can be accessed by `github:maydayv7/dotfiles#apps.${system}`)
-A system management script is present, invoked via the [`nixos`](./nixos.nix) command, which can be used to apply user and device configuration changes, setup the device on first boot, and perform various other useful functions (If you have a working NixOS install, you can check it out using `nix run github:maydayv7/dotfiles`)
+A system management script is present, invoked via the [`os`](./os.nix) command, which can be used to apply user and device configuration changes, setup the device on first boot, and perform various other useful functions (If you have a working NixOS install, you can check it out using `nix run github:maydayv7/dotfiles`)
There is also a system install script, invoked via the [`os-install`](./install.nix) command, that painlessly installs the OS
diff --git a/scripts/install.nix b/scripts/install.nix
@@ -124,13 +124,13 @@ in
read -rp "Installation failed after $TRIES attempts. Try again? (Y/*): " choice
case $choice in
[Yy]*) newline; info "Retrying installation...";;
- *) cleanup; error "Installation cancelled by user";;
+ *) cleanup; error "Installation cancelled";;
esac
done
newline
cleanup
- info "Run 'nixos setup' after rebooting to finish the install"
+ info "Run 'os setup' after rebooting to finish the install"
info "Select the (recovery) boot menu option and run the above script as the 'recovery' user"
restart
'';
diff --git a/scripts/nixos.nix b/scripts/nixos.nix
@@ -1,503 +0,0 @@
-{
- lib,
- inputs,
- pkgs,
- files,
- ...
-}:
-with files; let
- inherit (inputs) self;
- inherit (lib) licenses recursiveUpdate;
-
- # Joins an attrset's names into a space-separated string (for shell `grep -wq`)
- list = attrs: builtins.foldl' (x: y: x + y + " ") "" (builtins.attrNames attrs);
-
- devShells = list self.devShells."${pkgs.stdenv.system}";
- nixosConfigurations = list self.nixosConfigurations;
-
- # Usage Description
- usage = {
- script = ''
- # Legend #
- xxx - Command
- [ ] - Optional - Command Description
- ' ' - Variable
-
- # Usage #
- apply [ --'option' ] - Applies Device and User Configuration
- cache 'command' - Pushes Binary Cache Output to Cachix
- check [ --trace ] - Checks System Configuration [ Displays Error to Trace ]
- clean [ --all ] - Garbage Collects and Optimises Nix Store
- explore - Opens Interactive Shell to explore Syntax and Configuration
- iso 'variant' [ --burn ] - Builds Image for Specified Device [ Burns '.iso' to USB ]
- list [ 'pattern' ] - Lists all Installed Packages [ Returns Matches ]
- locate 'package' - Locates Installed Package
- run [ 'path' ] 'command' - Runs Specified Command [ from 'path' ] (Wraps 'nix run')
- search 'term' [ 'source' ] - Searches for Packages [ Providing 'term' ] or Configuration Options
- secret 'choice' [ 'path' ] - Manages 'sops' Encrypted Secrets
- setup - Sets up NixOS System (on First Boot)
- shell [ 'name' ] - Opens desired Nix Developer Shell
- update [ 'repo' / --'option' ] - Manages System Package Updates
- '';
-
- apply = ''
- # Usage #
- 'specialisation' - Activates Specified System Specialisation
- --activate [ home ] - Activates Current [ Home ] Configuration
- --boot - Applies Configuration on boot
- --delta - Shows Package Delta for Build
- --rollback [ 'generation' ] - Reverts to Last [ or Specified ] Build Generation
- --test - Tests Configuration Build
- '';
-
- search = ''
- # Usage #
- cmd.'command' - Searches for Package providing 'command'
- pkgs.'package' [ 'repo' ] - Searches for Package 'package' [ In Repository ]
- 'term' - Searches for Packages and Configuration Options and matching 'term'
- '';
-
- secret = ''
- # Usage #
- create 'path' - Creates desired Secret
- edit 'name' - Edits desired Secret
- list - Lists all 'sops' Encrypted Secrets
- show 'name' - Shows desired Secret
- update - Updates Secrets to defined Keys
- '';
-
- update = ''
- # Usage #
- --pkgs - Automatically updates manually packaged apps
- --commit - Updates 'inputs' and commits changes
- 'repo' [ 'source' ] - Updates 'repo' input [ To specified 'source' ]
- '';
- };
-in
- recursiveUpdate
- {
- meta = {
- mainProgram = "nixos";
- description = "System Management Script";
- homepage = path.repo;
- license = licenses.gpl3Only;
- maintainers = ["maydayv7"];
- };
- }
- (
- pkgs.writeShellApplication {
- name = "nixos";
- runtimeInputs = with pkgs; [
- coreutils
- gnugrep
- gnused
- git
- jq
- tree
- gnupg
- sops
-
- nixFlakes
- cachix
- manix
- dix
- nix-output-monitor
- ];
-
- text = ''
- set +eu
- ${scripts.commands}
-
- installed() { nix-store -q -R /run/current-system | sed -n -e 's/\/nix\/store\/[0-9a-z]\{32\}-//p' | sort | uniq; }
-
- missing() {
- if nix search nixpkgs#"$1" &> /dev/null
- then error "Package '$1' is not installed"
- else error "$2"
- fi
- }
-
- secret_exists() { find ${path.system} -name "$1".secret | grep "secret" &> /dev/null; }
-
- if [[ -n $IN_NIX_SHELL ]]
- then
- warn "You are in a Nix Developer Shell" "This script may not work here properly\n"
- fi
-
- case $1 in
- "") error "Expected an Option" "${usage.script}";;
- help|--help|-h) echo -e "## Tool for NixOS System Management ##\n${usage.script}";;
- "apply")
- case $2 in
- help|--help|-h) echo "${usage.apply}";;
- "")
- if [ -z "$NIXOS_SPECIALISATION" ]
- then
- echo "Applying Configuration..."
- sudo nixos-rebuild switch --flake ${path.system}#
- else
- echo "Applying Configuration ($NIXOS_SPECIALISATION)..."
- sudo nixos-rebuild switch --specialisation "$NIXOS_SPECIALISATION"
- fi
- ;;
- "--activate")
- case $3 in
- "")
- if [ -z "$NIXOS_SPECIALISATION" ]
- then
- echo "Activating Configuration..."
- sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
- else
- echo "Activating Configuration ($NIXOS_SPECIALISATION)..."
- sudo /nix/var/nix/profiles/system/specialisation/"$NIXOS_SPECIALISATION"/bin/switch-to-configuration switch
- fi
- ;;
- "home")
- echo "Applying Home Configuration..."
- sudo systemctl restart home-manager-"$USER"
- ;;
- *) error "Unknown Option '$3'";;
- esac
- ;;
- "--boot")
- echo "Applying Configuration..."
- if sudo nixos-rebuild boot --flake ${path.system}#
- then
- restart
- else
- error "Couldn't build generation successfully"
- fi
- ;;
- "--delta")
- echo "Building Configuration..."
- temp nixos_build 2
- HOSTNAME=$(cat /etc/hostname)
- if nom build ${path.system}#nixosConfigurations."$HOSTNAME".config.system.build.toplevel --out-link "$TEMP"
- then
- echo "Processing Delta..."
- dix /run/current-system "$TEMP"
- read -rp "Do you want to apply the configuration? (Y/*): " choice
- case $choice in
- [Yy]*)
- echo "Applying Configuration..."
- sudo "$TEMP"/bin/switch-to-configuration switch
- ;;
- *) exit;;
- esac
- else
- error "Couldn't build generation successfully"
- fi
- ;;
- "--test")
- echo "Testing Configuration..."
- sudo nixos-rebuild test --no-build-nix --show-trace --flake ${path.system}#
- ;;
- "--rollback")
- case $3 in
- "")
- echo "Applying Rollback..."
- sudo nixos-rebuild switch --rollback
- ;;
- "list")
- echo "# System Generations #"
- nixos-rebuild list-generations
- ;;
- *)
- echo "Rolling Back to Generation '$3'..."
- sudo nix-env --switch-generation "$3" -p "/nix/var/nix/profiles/system" && nixos apply --activate
- ;;
- esac
- ;;
- *)
- SPECIALISATIONS=$(ls -1 /nix/var/nix/profiles/system/specialisation)
- if grep -wq "$2" <<<"$SPECIALISATIONS" &> /dev/null
- then
- echo "Applying Configuration ($2)..."
- sudo nixos-rebuild switch --specialisation "$2"
- else
- error "Unknown Option '$2'\n${usage.apply}" "# Available Specialisations #\n$SPECIALISATIONS"
- fi
- ;;
- esac
- ;;
- "cache")
- if [ -z "$2" ]
- then
- error "Expected a Build Command"
- else
- echo "Executing Command '" "''${@:2}" "'..."
- cachix authtoken "$(find ${path.system} -name cachix-token.secret -exec sops --config ${path.sops} -d {} \+)"
- cachix watch-exec ${path.cache} "''${@:2}"
- fi
- ;;
- "check")
- echo "Formatting Code..."
- pushd ${path.system} &> /dev/null; nix fmt; popd &> /dev/null
- case $2 in
- "") nix flake check ${path.system} --keep-going;;
- "--trace") nix flake check ${path.system} --keep-going --show-trace;;
- *) nix flake check "$2" --keep-going;;
- esac
- ;;
- "clean")
- echo "Running Garbage Collection..."
- nix-collect-garbage -d
- rm -rf /nix/var/nix/profiles/per-user/"$USER"/profile
- if [ "$EUID" -ne 0 ] && [ "$2" != "--all" ]
- then
- warn "Run as 'root' or use Option '--all' to Clean System Generations"
- else
- sudo nix-collect-garbage -d
- sudo rm -rf /run/secrets/*
- sudo nix-env --delete-generations old --profile /nix/var/nix/profiles/system
- nixos apply --activate
- fi
- newline
- echo "Running De-Duplication..."
- nix store optimise
- ;;
- "explore")
- case $2 in
- "") nix repl --arg host true --arg path ${path.system} --file ${repl};;
- *) nix repl --arg path "$(readlink -f "$2" | sed 's|/flake.nix||')" --file ${repl};;
- esac
- ;;
- "iso")
- case $2 in
- "") error "Expected a Device name";;
- *)
- if grep -wq "$2" <<<"${nixosConfigurations}" &> /dev/null
- then
- echo "Building '$2' Image..."
- nom build ${path.system}#nixosConfigurations."$2".config.system.build.images.iso
- else
- error "Unknown Device '$2'" "# Available Devices #\n ${nixosConfigurations}"
- fi
- ;;
- esac
- case $3 in
- "") echo "The '--burn' Option can be used to Flash the Image onto a USB";;
- "--burn")
- case $4 in
- "") error "Expected a 'path' to USB Drive";;
- *)
- IMAGE=$(find ./result/iso -type f -name "*.iso")
- sudo dd if="$IMAGE" of="$4" status=progress bs=1M
- ;;
- esac
- ;;
- *) error "Unknown Option '$3'";;
- esac
- ;;
- "list")
- case $2 in
- "") installed;;
- *) find=$(installed | grep "$2")
- if [ -z "$find" ]
- then
- missing "$2" "Package '$2' not found"
- else
- echo "$find"
- fi
- ;;
- esac
- ;;
- "locate")
- case $2 in
- "") error "Expected Package Name";;
- *)
- package=$(installed | grep "$2")
- if [ -z "$package" ]
- then
- location=$(find /nix/store -maxdepth 1 -type d -name "*$2*")
- if [ -n "$location" ]
- then
- if (( $(grep -c . <<<"$location") > 1 ))
- then
- echo -e "Locations:\n$location"
- else
- echo -e "Location: $location"
- fi
- else
- missing "$2" "Package '$2' is invalid"
- fi
- else
- if (( $(grep -c . <<<"$package") > 1 ))
- then
- locations=$(find /nix/store -maxdepth 1 -type d -name "*$2*")
- echo -e "Locations:\n$locations"
- else
- echo "Package $package found"
- nix search nixpkgs#"$2" &> /dev/null && location=$(nix eval nixpkgs#"$2".outPath 2> /dev/null | sed 's/"//g') || location=$(find /nix/store -maxdepth 1 -type d -name "*$package")
- echo "Location: $location"
- fi
- fi
- ;;
- esac
- ;;
- "run")
- export NIXPKGS_ALLOW_UNFREE=1
- if [[ "$2" == *[:/]* ]] || grep -wq "$2" <<<"${list inputs}"
- then
- nix run "$2"#"$3" --impure -- "''${@:4}"
- else
- nix run ${path.system}#"$2" --impure -- "''${@:3}"
- fi
- ;;
- "search")
- case $2 in
- "") error "Expected an Option" "${usage.search}";;
- help|--help|-h) echo "${usage.search}";;
- cmd.*)
- command="''${2//cmd\./}"
- echo "Searching for Package providing Command '$command'..."
- output=$(nix-locate --whole-name --type x --type s --no-group --top-level --at-root "/bin/$command")
- if [ -z "$output" ]
- then
- error "Command '$command' not found"
- else
- echo "$output"
- fi
- ;;
- pkgs.*)
- package="''${2//pkgs\./}"
- echo "Searching for Package '$package'..."
- if [ -z "$3" ]
- then
- nix search nixpkgs#"$package"
- else
- nix search "$3"#"$package"
- fi
- ;;
- *)
- echo "Searching for Term '$2'..."
- manix "$2"
- ;;
- esac
- ;;
- "secret")
- case $2 in
- "") error "Expected an Option" "${usage.secret}";;
- help|--help|-h) echo "${usage.secret}";;
- "create")
- case $3 in
- "") error "Expected 'name' of Secret";;
- *)
- echo "Creating Secret '$3'..."
- sops --config ${path.sops} -i ${path.system}/"$3".secret
- ;;
- esac
- ;;
- "edit")
- case $3 in
- "") error "Expected 'name' of Secret";;
- *)
- if secret_exists "$3"
- then
- echo "Editing Secret '$3'..."
- find ${path.system} -name "$3".secret -exec sops --config ${path.sops} -i {} \+
- else
- error "Unknown Secret '$3'"
- fi
- ;;
- esac
- ;;
- "list")
- echo "## Secrets in ${path.system} ##"
- grep / ${path.sops} | sed -e 's|- path_regex:||' -e 's/\/\.\*\$//' -e 's| |${path.system}/|' | xargs tree -C --noreport -P '*.secret' -I '_*' | sed 's/\.secret//'
- ;;
- "show")
- if secret_exists "$3"
- then
- echo "Showing Secret '$3'..."
- find ${path.system} -name "$3".secret -exec sops --config ${path.sops} -d {} \+
- else
- error "Unknown Secret '$3'"
- fi
- ;;
- "update")
- echo "Updating Secrets..."
- find ${path.system} -name '*.secret' ! -name '_*' -exec sops --config ${path.sops} updatekeys {} \;
- ;;
- *) error "Unknown Option '$2'" "${usage.secret}";;
- esac
- ;;
- "setup")
- if [ -d ${path.persist} ]; then
- DIR=${path.persist}${path.system}
- else
- DIR=${path.system}
- fi
-
- echo "Cloning Repository..."
- sudo git clone --recurse-submodules ${path.repo} "$DIR"
- pushd "$DIR" &> /dev/null; sudo git config core.fileMode false; popd &> /dev/null
- sudo chgrp -R keys "$DIR"
- newline
-
- read -rp "Enter Path to GPG Keys (path/.git): " KEY
- LINK='(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'
- if [ -z "$KEY" ]
- then
- error "Path to GPG Keys cannot be empty"
- elif [[ $KEY =~ $LINK ]]
- then
- echo "Cloning Keys..."
- git clone "$KEY" keys --progress
- else
- cp -r "$KEY"/. ./keys
- fi
- echo "Importing Keys..."
- find ./keys -name '*.gpg' -exec sudo gpg --homedir ${path.gpg} --import {} \+
- rm -rf ./keys
- newline
-
- nixos apply --activate
- ;;
- "shell")
- case $2 in
- "") nix develop ${path.system} --command "$SHELL";;
- *)
- if grep -wq "$2" <<<"${devShells}" &> /dev/null
- then
- nix develop ${path.system}#"$2" --command "$SHELL"
- else
- error "Unknown Shell '$2'" "# Available Shells #\n ${devShells}"
- fi
- ;;
- esac
- ;;
- "update")
- case $2 in
- help|--help|-h) echo "${usage.update}";;
- "--pkgs")
- echo "Updating Packages..."
- pushd ${path.system}/packages &> /dev/null
- bash ${./packages.sh}
- popd &> /dev/null
- ;;
- "--commit")
- echo "Updating Flake Inputs..."
- nix flake update --flake ${path.system} --commit-lock-file
- ;;
- "")
- echo "Updating Flake Inputs..."
- nix flake update --flake ${path.system}
- ;;
- *)
- echo "Updating Flake Input '$2'..."
- if [ -z "$3" ]
- then
- nix flake update --flake ${path.system} "$2"
- else
-
- nix flake update --flake ${path.system} "$2" --override-input "$2" "$3"
- fi
- ;;
- esac
- ;;
- *) error "Unknown Option '$1'" "${usage.script}";;
- esac
- '';
- }
- )
diff --git a/scripts/os.nix b/scripts/os.nix
@@ -0,0 +1,477 @@
+{
+ lib,
+ inputs,
+ pkgs,
+ files,
+ ...
+}:
+with files; let
+ inherit (inputs) self;
+ inherit (lib) licenses recursiveUpdate;
+
+ list = attrs: builtins.foldl' (x: y: x + y + " ") "" (builtins.attrNames attrs);
+ devShells = list self.devShells."${pkgs.stdenv.system}";
+ nixosConfigurations = list self.nixosConfigurations;
+
+ # Usage Description
+ usage = {
+ script = ''
+ # Legend #
+ xxx - Command
+ [ ] - Optional - Description
+ ' ' - Variable
+
+ # Usage #
+ apply [ --'option' ] - Applies device and user config
+ cache 'command' - Pushes binary output to Cachix
+ check [ --trace ] - Checks system configuration [ Displays error trace ]
+ clean [ --all ] - Cleans and optimises Nix Store
+ explore - Opens interactive shell to explore syntax and config
+ iso 'variant' [ --burn ] - Builds image for specified device [ Burns '.iso' to USB ]
+ list [ 'pattern' ] - Lists all installed packages [ Returns matches ]
+ locate 'package' - Locates installed package
+ run [ 'path' ] 'command' - Runs specified command [ from 'path' ] (Wraps 'nix run')
+ search 'term' [ 'source' ] - Searches for packages [ providing 'term' ] or config options
+ secret 'choice' [ 'path' ] - Manages 'sops' encrypted secrets
+ setup - Sets up system (on first boot)
+ shell [ 'name' ] - Opens desired Nix Developer Shell
+ update [ 'repo' / --'option' ] - Manages system package updates
+ '';
+
+ apply = ''
+ # Usage #
+ 'specialisation' - Activates specified system specialisation
+ --activate [ home ] - Activates current [ home ] config
+ --boot - Applies config on boot
+ --delta - Shows config build delta
+ --rollback [ 'generation' ] - Reverts to last [ or specified ] build
+ --test - Tests config build
+ '';
+
+ search = ''
+ # Usage #
+ cmd.'command' - Searches for package providing 'command'
+ pkgs.'package' [ 'repo' ] - Searches for 'package' [ In Repository ]
+ 'term' - Searches for packages and config option (matching 'term')
+ '';
+
+ secret = ''
+ # Usage #
+ create 'path' - Creates desired secret
+ edit 'name' - Edits desired secret
+ list - Lists all 'sops' encrypted secrets
+ show 'name' - Shows desired secret
+ update - Updates secrets to defined keys
+ '';
+
+ update = ''
+ # Usage #
+ --pkgs - Automatically updates custom packages
+ --commit - Updates 'inputs' and commits changes
+ 'repo' [ 'source' ] - Updates 'repo' input [ To specified 'source' ]
+ '';
+ };
+in
+ recursiveUpdate
+ {
+ meta = {
+ mainProgram = "os";
+ description = "System Management Script";
+ homepage = path.repo;
+ license = licenses.gpl3Only;
+ maintainers = ["maydayv7"];
+ };
+ }
+ (
+ pkgs.writeShellApplication {
+ name = "os";
+ runtimeInputs = with pkgs; [
+ coreutils
+ gnugrep
+ gnused
+ git
+ jq
+ tree
+ gnupg
+ sops
+
+ nixFlakes
+ cachix
+ manix
+ nh
+ nix-output-monitor
+ ];
+
+ text = ''
+ set +eu
+ ${scripts.commands}
+
+ installed() { nix-store -q -R /run/current-system | sed -n -e 's/\/nix\/store\/[0-9a-z]\{32\}-//p' | sort | uniq; }
+
+ missing() {
+ if nix search nixpkgs#"$1" &> /dev/null
+ then error "Package '$1' is not installed"
+ else error "$2"
+ fi
+ }
+
+ secret_exists() { find ${path.system} -name "$1".secret | grep "secret" &> /dev/null; }
+
+ if [[ -n $IN_NIX_SHELL ]]
+ then
+ warn "You are in a Nix Developer Shell" "This script may not work here properly\n"
+ fi
+
+ case $1 in
+ "") error "Expected an option" "${usage.script}";;
+ help|--help|-h) echo -e "## Tool for NixOS System Management ##\n${usage.script}";;
+ "apply")
+ case $2 in
+ help|--help|-h) echo "${usage.apply}";;
+ "")
+ echo "Applying Configuration..."
+ nh os switch ${path.system}
+ ;;
+ "--activate")
+ case $3 in
+ "")
+ SPEC=$(cat /etc/specialisation 2> /dev/null || true)
+ if [ -z "$SPEC" ]
+ then
+ echo "Activating Configuration..."
+ sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch
+ else
+ echo "Activating Configuration ($SPEC)..."
+ sudo /nix/var/nix/profiles/system/specialisation/"$SPEC"/bin/switch-to-configuration switch
+ fi
+ ;;
+ "home")
+ echo "Applying Home Configuration..."
+ sudo systemctl restart home-manager-"$USER"
+ ;;
+ *) error "Unknown option '$3'";;
+ esac
+ ;;
+ "--boot")
+ echo "Applying Configuration..."
+ if nh os boot ${path.system}
+ then
+ restart
+ else
+ error "Couldn't build generation successfully"
+ fi
+ ;;
+ "--delta")
+ echo "Building Configuration..."
+ nh os switch -a ${path.system}
+ ;;
+ "--test")
+ echo "Testing Configuration..."
+ nh os test ${path.system}
+ ;;
+ "--rollback")
+ case $3 in
+ "")
+ echo "Applying Rollback..."
+ sudo nixos-rebuild switch --rollback
+ ;;
+ "list")
+ echo "# System Generations #"
+ nixos-rebuild list-generations
+ ;;
+ *)
+ echo "Rolling Back to Generation '$3'..."
+ sudo nix-env --switch-generation "$3" -p "/nix/var/nix/profiles/system" && os apply --activate
+ ;;
+ esac
+ ;;
+ *)
+ SPECIALISATIONS=$(ls -1 /nix/var/nix/profiles/system/specialisation)
+ if grep -wq "$2" <<<"$SPECIALISATIONS" &> /dev/null
+ then
+ echo "Applying Configuration ($2)..."
+ nh os switch ${path.system} -s "$2"
+ else
+ error "Unknown option '$2'\n${usage.apply}" "# Available Specialisations #\n$SPECIALISATIONS"
+ fi
+ ;;
+ esac
+ ;;
+ "cache")
+ if [ -z "$2" ]
+ then
+ error "Expected a build command"
+ else
+ echo "Executing command '" "''${@:2}" "'..."
+ cachix authtoken "$(find ${path.system} -name cachix-token.secret -exec sops --config ${path.sops} -d {} \+)"
+ cachix watch-exec ${path.cache} "''${@:2}"
+ fi
+ ;;
+ "check")
+ echo "Formatting Code..."
+ pushd ${path.system} &> /dev/null; nix fmt; popd &> /dev/null
+ case $2 in
+ "") nix flake check ${path.system} --keep-going;;
+ "--trace") nix flake check ${path.system} --keep-going --show-trace;;
+ *) nix flake check "$2" --keep-going;;
+ esac
+ ;;
+ "clean")
+ if [ "$EUID" -ne 0 ] && [ "$2" != "--all" ]
+ then
+ echo "Running Garbage Collection..."
+ nh clean user --optimise
+ warn "Run as 'root' or use '--all' to clean system generations"
+ else
+ echo "Running Garbage Collection..."
+ sudo nh clean all --optimise
+ sudo rm -rf /run/secrets/*
+ os apply --activate
+ fi
+ ;;
+ "explore")
+ case $2 in
+ "") nix repl --arg host true --arg path ${path.system} --file ${repl};;
+ *) nix repl --arg path "$(readlink -f "$2" | sed 's|/flake.nix||')" --file ${repl};;
+ esac
+ ;;
+ "iso")
+ case $2 in
+ "") error "Expected a device name";;
+ *)
+ if grep -wq "$2" <<<"${nixosConfigurations}" &> /dev/null
+ then
+ echo "Building '$2' Image..."
+ nom build ${path.system}#nixosConfigurations."$2".config.system.build.images.iso
+ else
+ error "Unknown device '$2'" "# Available devices #\n ${nixosConfigurations}"
+ fi
+ ;;
+ esac
+ case $3 in
+ "") echo "The '--burn' option can be used to flash the image to a USB";;
+ "--burn")
+ case $4 in
+ "") error "Expected 'path' to USB";;
+ *)
+ IMAGE=$(find ./result/iso -type f -name "*.iso")
+ sudo dd if="$IMAGE" of="$4" status=progress bs=1M
+ ;;
+ esac
+ ;;
+ *) error "Unknown option '$3'";;
+ esac
+ ;;
+ "list")
+ case $2 in
+ "") installed;;
+ *) find=$(installed | grep "$2")
+ if [ -z "$find" ]
+ then
+ missing "$2" "Package '$2' not found"
+ else
+ echo "$find"
+ fi
+ ;;
+ esac
+ ;;
+ "locate")
+ case $2 in
+ "") error "Expected package name";;
+ *)
+ package=$(installed | grep "$2")
+ if [ -z "$package" ]
+ then
+ location=$(find /nix/store -maxdepth 1 -type d -name "*$2*")
+ if [ -n "$location" ]
+ then
+ if (( $(grep -c . <<<"$location") > 1 ))
+ then
+ echo -e "Locations:\n$location"
+ else
+ echo -e "Location: $location"
+ fi
+ else
+ missing "$2" "Package '$2' is invalid"
+ fi
+ else
+ if (( $(grep -c . <<<"$package") > 1 ))
+ then
+ locations=$(find /nix/store -maxdepth 1 -type d -name "*$2*")
+ echo -e "Locations:\n$locations"
+ else
+ echo "Package $package found"
+ nix search nixpkgs#"$2" &> /dev/null && location=$(nix eval nixpkgs#"$2".outPath 2> /dev/null | sed 's/"//g') || location=$(find /nix/store -maxdepth 1 -type d -name "*$package")
+ echo "Location: $location"
+ fi
+ fi
+ ;;
+ esac
+ ;;
+ "run")
+ export NIXPKGS_ALLOW_UNFREE=1
+ if [[ "$2" == *[:/]* ]] || grep -wq "$2" <<<"${list inputs}"
+ then
+ nix run "$2"#"$3" --impure -- "''${@:4}"
+ else
+ nix run ${path.system}#"$2" --impure -- "''${@:3}"
+ fi
+ ;;
+ "search")
+ case $2 in
+ "") error "Expected an option" "${usage.search}";;
+ help|--help|-h) echo "${usage.search}";;
+ cmd.*)
+ command="''${2//cmd\./}"
+ echo "Searching for Package providing command '$command'..."
+ output=$(nix-locate --whole-name --type x --type s --no-group --top-level --at-root "/bin/$command")
+ if [ -z "$output" ]
+ then
+ error "Command '$command' not found"
+ else
+ echo "$output"
+ fi
+ ;;
+ pkgs.*)
+ package="''${2//pkgs\./}"
+ echo "Searching for package '$package'..."
+ if [ -z "$3" ]
+ then
+ nix search nixpkgs#"$package"
+ else
+ nix search "$3"#"$package"
+ fi
+ ;;
+ *)
+ echo "Searching for term '$2'..."
+ manix "$2"
+ ;;
+ esac
+ ;;
+ "secret")
+ case $2 in
+ "") error "Expected an option" "${usage.secret}";;
+ help|--help|-h) echo "${usage.secret}";;
+ "create")
+ case $3 in
+ "") error "Expected 'name' of secret";;
+ *)
+ echo "Creating secret '$3'..."
+ sops --config ${path.sops} -i ${path.system}/"$3".secret
+ ;;
+ esac
+ ;;
+ "edit")
+ case $3 in
+ "") error "Expected 'name' of secret";;
+ *)
+ if secret_exists "$3"
+ then
+ echo "Editing secret '$3'..."
+ find ${path.system} -name "$3".secret -exec sops --config ${path.sops} -i {} \+
+ else
+ error "Unknown secret '$3'"
+ fi
+ ;;
+ esac
+ ;;
+ "list")
+ echo "## Secrets in ${path.system} ##"
+ grep / ${path.sops} | sed -e 's|- path_regex:||' -e 's/\/\.\*\$//' -e 's| |${path.system}/|' | xargs tree -C --noreport -P '*.secret' -I '_*' | sed 's/\.secret//'
+ ;;
+ "show")
+ if secret_exists "$3"
+ then
+ echo "Showing secret '$3'..."
+ find ${path.system} -name "$3".secret -exec sops --config ${path.sops} -d {} \+
+ else
+ error "Unknown secret '$3'"
+ fi
+ ;;
+ "update")
+ echo "Updating secrets..."
+ find ${path.system} -name '*.secret' ! -name '_*' -exec sops --config ${path.sops} updatekeys {} \;
+ ;;
+ *) error "Unknown option '$2'" "${usage.secret}";;
+ esac
+ ;;
+ "setup")
+ if [ -d ${path.persist} ]
+ then
+ DIR=${path.persist}${path.system}
+ else
+ DIR=${path.system}
+ fi
+
+ echo "Cloning Repository..."
+ sudo git clone --recurse-submodules ${path.repo} "$DIR"
+ pushd "$DIR" &> /dev/null; sudo git config core.fileMode false; popd &> /dev/null
+ sudo chgrp -R keys "$DIR"
+ newline
+
+ read -rp "Enter path to GPG Keys (path/.git): " KEY
+ LINK='(https?|ftp|file)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'
+ if [ -z "$KEY" ]
+ then
+ error "Path cannot be empty"
+ elif [[ $KEY =~ $LINK ]]
+ then
+ echo "Cloning Keys..."
+ git clone "$KEY" keys --progress
+ else
+ cp -r "$KEY"/. ./keys
+ fi
+ echo "Importing Keys..."
+ find ./keys -name '*.gpg' -exec sudo gpg --homedir ${path.gpg} --import {} \+
+ rm -rf ./keys
+ newline
+
+ os apply --activate
+ ;;
+ "shell")
+ case $2 in
+ "") nix develop ${path.system} --command "$SHELL";;
+ *)
+ if grep -wq "$2" <<<"${devShells}" &> /dev/null
+ then
+ nix develop ${path.system}#"$2" --command "$SHELL"
+ else
+ error "Unknown Shell '$2'" "# Available Shells #\n ${devShells}"
+ fi
+ ;;
+ esac
+ ;;
+ "update")
+ case $2 in
+ help|--help|-h) echo "${usage.update}";;
+ "--pkgs")
+ echo "Updating Packages..."
+ pushd ${path.system}/packages &> /dev/null
+ bash ${./packages.sh}
+ popd &> /dev/null
+ ;;
+ "--commit")
+ echo "Updating Flake inputs..."
+ nix flake update --flake ${path.system} --commit-lock-file
+ ;;
+ "")
+ echo "Updating Flake inputs..."
+ nix flake update --flake ${path.system}
+ ;;
+ *)
+ echo "Updating Flake Input '$2'..."
+ if [ -z "$3" ]
+ then
+ nix flake update --flake ${path.system} "$2"
+ else
+
+ nix flake update --flake ${path.system} "$2" --override-input "$2" "$3"
+ fi
+ ;;
+ esac
+ ;;
+ *) error "Unknown option '$1'" "${usage.script}";;
+ esac
+ '';
+ }
+ )
diff --git a/secrets/README.md b/secrets/README.md
@@ -6,11 +6,11 @@ User passwords are generated using `mkpasswd -m sha-512` and specified using the
The `sops` encrypted secrets are of `binary` format (and have the extension `.secret`) and can be conveniently managed using the [`nixos`](../scripts/README.md) `secret` command.
The `keys` directory contains the _public_ User GPG Keys which are automatically imported
-To create a secret, use the `nixos secret create` command, and append the directory along with requisite access permissions to the `secrets.yaml` file.
+To create a secret, use the `os secret create` command, and append the directory along with requisite access permissions to the `secrets.yaml` file.
Device-specific secrets are automatically imported, if a directory (with the same name as the device `HOSTNAME`) containing them is present in this directory
> [!NOTE]
-> Any update to a `creation_rule` in [`secrets.yaml`](./secrets.yaml) must be accompanied by a `nixos secret update` to re-encrypt for the new key set
+> Any update to a `creation_rule` in [`secrets.yaml`](./secrets.yaml) must be accompanied by an `os secret update` to re-encrypt for the new key set
#### Per-User Secrets