dotfiles

My PC Dotfiles & Website
commit e23814f29689228c313b4b88e68bc29dad7e8c95
parent f4fbedbb786ee1854bb8a1f2e0d12da129a0b06e
Author: maydayv7 <maydayv7@gmail.com>
Date:   Tue, 30 Jun 2026 22:13:34 +0530

feat: `nixos` -> `os` + `nh`, `micro`

Diffstat:
MCHANGELOG.md | 2++
MREADME.md | 6+++---
Mmodules/shell/shell-utils.nix | 30+-----------------------------
Mmodules/shell/shell.nix | 42+++++++++++++++++++++++++++++++++++++++++-
Mmodules/system/base.nix | 7++++---
Mpackages/_module.nix | 2+-
Mscripts/README.md | 2+-
Mscripts/install.nix | 4++--
Dscripts/nixos.nix | 503-------------------------------------------------------------------------------
Ascripts/os.nix | 477+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msecrets/README.md | 4++--
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