From 36ca3ed90eb41a630b9e675867a69f8efff514e1 Mon Sep 17 00:00:00 2001 From: mjallen18 Date: Fri, 22 Aug 2025 22:53:29 -0500 Subject: [PATCH] stuff --- flake.nix | 7 + .../mattjallen@macbook-pro/default.nix | 2 + lib/README.md | 130 ++++++++++++++++++ lib/default.nix | 16 +++ lib/examples/default.nix | 8 ++ lib/examples/file-utils.nix | 58 ++++++++ lib/examples/home-sops.nix | 31 +++++ lib/examples/sops.nix | 36 +++++ lib/examples/system-utils.nix | 111 +++++++++++++++ lib/file/default.nix | 127 +++++++++++++++++ lib/system/common.nix | 98 +++++++++++++ lib/system/default.nix | 5 + modules/nixos/sops/options.nix | 40 ++++++ .../settings/cline_mcp_settings.json | 14 ++ 14 files changed, 683 insertions(+) create mode 100644 lib/README.md create mode 100644 lib/default.nix create mode 100644 lib/examples/default.nix create mode 100644 lib/examples/file-utils.nix create mode 100644 lib/examples/home-sops.nix create mode 100644 lib/examples/sops.nix create mode 100644 lib/examples/system-utils.nix create mode 100644 lib/file/default.nix create mode 100644 lib/system/common.nix create mode 100644 lib/system/default.nix create mode 100644 modules/nixos/sops/options.nix create mode 100644 ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json diff --git a/flake.nix b/flake.nix index 4998f24..e4821bc 100644 --- a/flake.nix +++ b/flake.nix @@ -260,6 +260,13 @@ outputs-builder = channels: { formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix; + + # Add mjallen-lib to the flake outputs + overlays = { + mjallen-lib = final: prev: { + mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib; + }; + }; }; }; } diff --git a/homes/aarch64-darwin/mattjallen@macbook-pro/default.nix b/homes/aarch64-darwin/mattjallen@macbook-pro/default.nix index 034cd04..d33c535 100755 --- a/homes/aarch64-darwin/mattjallen@macbook-pro/default.nix +++ b/homes/aarch64-darwin/mattjallen@macbook-pro/default.nix @@ -16,6 +16,8 @@ let deadnix direnv nixfmt-rfc-style + nodePackages.nodejs + uv sops tree wget diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..c0be221 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,130 @@ +# mjallen-lib Utility Functions + +This directory contains utility functions that can be used to enhance your Nix configuration. These functions are inspired by the khanelinix repository and provide a more explicit and modular approach to building Nix configurations. + +## Directory Structure + +- `default.nix`: Main entry point that imports and exposes all utility functions +- `module/`: Utilities for module creation and option handling +- `file/`: Utilities for file handling and module discovery +- `system/`: Utilities for system configuration building + +## How to Use + +### 1. Import the Library + +The library is already imported in your flake.nix file through the outputs-builder: + +```nix +outputs-builder = channels: { + formatter = inputs.treefmt-nix.lib.mkWrapper channels.nixpkgs ./treefmt.nix; + + # Add mjallen-lib to the flake outputs + overlays = { + mjallen-lib = final: prev: { + mjallen-lib = (import ./lib { inherit inputs; }).mjallen-lib; + }; + }; +}; +``` + +This makes the mjallen-lib available to all your modules through the extended lib. + +### 2. Use the Module Utilities + +The module utilities provide functions for creating modules with consistent options: + +```nix +{ lib, ... }: +let + inherit (lib.mjallen.module) mkModule mkOpt mkBoolOpt; +in +mkModule { + name = "mymodule"; + description = "My awesome module"; + options = { + setting1 = mkOpt lib.types.str "default" "Description of setting1"; + setting2 = mkBoolOpt false "Description of setting2"; + }; + config = { + # Module implementation + }; +} +``` + +### 3. Use the File Utilities + +The file utilities provide functions for file handling and module discovery: + +```nix +{ lib, ... }: +let + inherit (lib.mjallen.file) safeImport importModulesRecursive; +in +{ + # Import a file with error handling + myConfig = safeImport ./my-config.nix {}; + + # Import all modules recursively + imports = importModulesRecursive ./modules; +} +``` + +### 4. Use the System Utilities + +The system utilities provide functions for building system configurations: + +```nix +{ lib, ... }: +let + inherit (lib.mjallen.system.common) mkHomeManagerConfig; +in +{ + # Build home-manager configurations + homeManagerConfig = mkHomeManagerConfig { + extendedLib = lib; + inputs = inputs; + system = "x86_64-linux"; + matchingHomes = { ... }; + }; +} +``` + +## Available Functions + +### Module Utilities + +- `mkModule`: Create a module with common options +- `mkOpt`: Create an option with a type, default value, and description +- `mkOpt'`: Create an option with a type and default value (no description) +- `mkBoolOpt`: Create a boolean option with a default value and description +- `mkBoolOpt'`: Create a boolean option with a default value (no description) +- `enabled`: Standard enable pattern +- `disabled`: Standard disable pattern +- `capitalize`: Capitalize a string +- `boolToNum`: Convert a boolean to a number +- `default-attrs`: Apply mkDefault to all attributes +- `force-attrs`: Apply mkForce to all attributes +- `nested-default-attrs`: Apply default-attrs to nested attributes +- `nested-force-attrs`: Apply force-attrs to nested attributes + +### File Utilities + +- `readFile`: Read a file and return its contents +- `pathExists`: Check if a file exists +- `safeImport`: Import a nix file with error handling +- `scanDir`: Scan a directory and return directory names +- `getFile`: Get a file path relative to the flake root +- `importModulesRecursive`: Recursively discover and import all Nix modules in a directory tree +- `scanSystems`: Recursively scan systems directory structure +- `filterNixOSSystems`: Filter systems for NixOS (Linux) +- `filterDarwinSystems`: Filter systems for Darwin (macOS) +- `scanHomes`: Scan homes directory structure for home configurations + +### System Utilities + +- `mkExtendedLib`: Extend the nixpkgs lib with mjallen-lib +- `mkNixpkgsConfig`: Create a nixpkgs configuration +- `mkHomeConfigs`: Create home configurations for a system and hostname +- `mkHomeManagerConfig`: Create a home-manager configuration +- `mkSpecialArgs`: Create special arguments for a system configuration diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..c50b4b0 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,16 @@ +{ inputs, ... }: +{ + mjallen-lib = { + # Import module utilities + module = import ./module { inherit inputs; }; + + # Import file utilities + file = import ./file { inherit inputs; }; + + # Import system utilities + system = import ./system { inherit inputs; }; + + # Import examples + examples = import ./examples { inherit inputs; }; + }; +} diff --git a/lib/examples/default.nix b/lib/examples/default.nix new file mode 100644 index 0000000..d9fc418 --- /dev/null +++ b/lib/examples/default.nix @@ -0,0 +1,8 @@ +{ inputs, ... }: +{ + # Import all examples + sops = import ./sops.nix; + homeSops = import ./home-sops.nix; + fileUtils = import ./file-utils.nix; + systemUtils = import ./system-utils.nix; +} diff --git a/lib/examples/file-utils.nix b/lib/examples/file-utils.nix new file mode 100644 index 0000000..e908c1f --- /dev/null +++ b/lib/examples/file-utils.nix @@ -0,0 +1,58 @@ +{ lib, ... }: +let + inherit (lib.mjallen.file) + readFile + pathExists + safeImport + scanDir + getFile + importModulesRecursive + scanSystems + filterNixOSSystems + filterDarwinSystems + scanHomes; +in +{ + # Example of reading a file + myFileContent = readFile ./example.txt; + + # Example of checking if a file exists + fileExists = pathExists ./example.txt; + + # Example of safely importing a file + myConfig = safeImport ./my-config.nix {}; + + # Example of scanning a directory + directoryContents = scanDir ./modules; + + # Example of getting a file path relative to the flake root + flakeFile = getFile "flake.nix"; + + # Example of importing modules recursively + modules = importModulesRecursive ./modules; + + # Example of scanning systems + allSystems = scanSystems ./systems; + + # Example of filtering systems + nixosSystems = filterNixOSSystems allSystems; + darwinSystems = filterDarwinSystems allSystems; + + # Example of scanning homes + allHomes = scanHomes ./homes; + + # Example of using these functions together + nixosConfigurations = lib.mapAttrs' ( + name: + { system, hostname, ... }: + { + name = hostname; + value = lib.nixosSystem { + inherit system; + modules = [ + { networking.hostName = hostname; } + ] ++ importModulesRecursive ./modules/nixos; + }; + } + ) nixosSystems; +} diff --git a/lib/examples/home-sops.nix b/lib/examples/home-sops.nix new file mode 100644 index 0000000..60152c2 --- /dev/null +++ b/lib/examples/home-sops.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib.mjallen.module) mkModule mkOpt mkBoolOpt; +in +mkModule { + name = "sops"; + description = "SOPS secret management for home-manager"; + options = { + defaultSopsFile = mkOpt lib.types.path null "Default sops file."; + + sshKeyPaths = mkOpt (lib.types.listOf lib.types.str) [] "SSH Key paths to use."; + }; + config = { + home.packages = with pkgs; [ + age + sops + ssh-to-age + ]; + + sops = { + inherit (config.mjallen.sops) defaultSopsFile; + defaultSopsFormat = "yaml"; + + age = { + generateKey = true; + keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; + sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/id_ed25519" ] ++ config.mjallen.sops.sshKeyPaths; + }; + }; + }; +} diff --git a/lib/examples/sops.nix b/lib/examples/sops.nix new file mode 100644 index 0000000..af655d4 --- /dev/null +++ b/lib/examples/sops.nix @@ -0,0 +1,36 @@ +{ config, lib, ... }: +let + inherit (lib.mjallen.module) mkModule mkOpt mkBoolOpt; +in +mkModule { + name = "sops"; + description = "SOPS secret management"; + options = { + defaultSopsFile = mkOpt lib.types.path null "Default sops file."; + + generateAgeKey = mkBoolOpt true "Whether to automatically generate an age key if one doesn't exist."; + + ageKeyPath = mkOpt (lib.types.nullOr lib.types.str) null "Custom path to the age key file. If null, will use the default path."; + + sshKeyPaths = mkOpt (lib.types.listOf lib.types.str) [ + "/etc/ssh/ssh_host_ed25519_key" + ] "SSH Key paths to use."; + + validateSopsFiles = mkBoolOpt false "Whether to validate that sops files exist."; + }; + config = { + sops = { + inherit (config.mjallen.sops) defaultSopsFile validateSopsFiles; + + age = { + inherit (config.mjallen.sops) generateAgeKey; + + keyFile = if config.mjallen.sops.ageKeyPath != null + then config.mjallen.sops.ageKeyPath + else "${config.users.users.${config.mjallen.user.name}.home}/.config/sops/age/keys.txt"; + + sshKeyPaths = config.mjallen.sops.sshKeyPaths; + }; + }; + }; +} diff --git a/lib/examples/system-utils.nix b/lib/examples/system-utils.nix new file mode 100644 index 0000000..65ae752 --- /dev/null +++ b/lib/examples/system-utils.nix @@ -0,0 +1,111 @@ +{ inputs, ... }: +let + inherit (inputs.self.mjallen-lib.system.common) + mkExtendedLib + mkNixpkgsConfig + mkHomeConfigs + mkHomeManagerConfig + mkSpecialArgs; +in +{ + # Example of creating NixOS configurations + nixosConfigurations = + let + # Get all systems + allSystems = inputs.self.mjallen-lib.file.scanSystems ../systems; + + # Filter for NixOS systems + nixosSystems = inputs.self.mjallen-lib.file.filterNixOSSystems allSystems; + in + inputs.nixpkgs.lib.mapAttrs' ( + name: + { system, hostname, ... }: + let + # Create extended lib with mjallen-lib + extendedLib = mkExtendedLib inputs.self inputs.nixpkgs; + + # Find matching home configurations for this system + matchingHomes = mkHomeConfigs { + flake = inputs.self; + inherit system hostname; + }; + + # Create home-manager configuration + homeManagerConfig = mkHomeManagerConfig { + inherit extendedLib inputs system matchingHomes; + isNixOS = true; + }; + in + { + name = hostname; + value = inputs.nixpkgs.lib.nixosSystem { + inherit system; + + # Pass special arguments to modules + specialArgs = mkSpecialArgs { + inherit inputs hostname extendedLib; + username = "mjallen"; + }; + + modules = [ + # Set lib to extended lib + { _module.args.lib = extendedLib; } + + # Configure nixpkgs + { + nixpkgs = { + inherit system; + } // mkNixpkgsConfig inputs.self; + } + + # Import home-manager module + inputs.home-manager.nixosModules.home-manager + + # Auto-inject home configurations + homeManagerConfig + + # Import all nixos modules recursively + ../${system}/${hostname} + ] ++ (extendedLib.mjallen.file.importModulesRecursive ../modules/nixos); + }; + } + ) nixosSystems; + + # Example of creating home-manager configurations + homeConfigurations = + let + # Get all homes + allHomes = inputs.self.mjallen-lib.file.scanHomes ../homes; + in + inputs.nixpkgs.lib.mapAttrs' ( + name: + { system, username, hostname, userAtHost, path, ... }: + let + # Create extended lib with mjallen-lib + extendedLib = mkExtendedLib inputs.self inputs.nixpkgs; + in + { + name = userAtHost; + value = inputs.home-manager.lib.homeManagerConfiguration { + pkgs = import inputs.nixpkgs { + inherit system; + inherit ((mkNixpkgsConfig inputs.self)) config overlays; + }; + + extraSpecialArgs = { + inherit inputs hostname username system; + inherit (inputs) self; + lib = extendedLib; + }; + + modules = [ + # Set lib to extended lib + { _module.args.lib = extendedLib; } + + # Import the home configuration + path + ] ++ (extendedLib.mjallen.file.importModulesRecursive ../modules/home); + }; + } + ) allHomes; +} diff --git a/lib/file/default.nix b/lib/file/default.nix new file mode 100644 index 0000000..a0f7129 --- /dev/null +++ b/lib/file/default.nix @@ -0,0 +1,127 @@ +{ inputs, ... }@args: +let + # Get self from args or default to ../.. (the flake root) + self = if args ? self then args.self else ../..; + + inherit (inputs.nixpkgs.lib) + genAttrs + filterAttrs + hasPrefix + foldl' + ; +in +{ + # Read a file and return its contents + readFile = path: builtins.readFile path; + + # Check if a file exists + pathExists = path: builtins.pathExists path; + + # Import a nix file with error handling + safeImport = path: default: if builtins.pathExists path then import path else default; + + # Scan a directory and return directory names + scanDir = path: builtins.attrNames (builtins.readDir path); + + # Get a file path relative to the flake root (similar to Snowfall's get-file) + getFile = relativePath: self + "/${relativePath}"; + + # Recursively discover and import all Nix modules in a directory tree + importModulesRecursive = + path: + let + # Helper function to recursively walk directories + walkDir = + currentPath: + let + currentEntries = builtins.readDir currentPath; + entryNames = builtins.attrNames currentEntries; + + # Get all directories that contain default.nix + directoriesWithDefault = builtins.filter ( + name: + currentEntries.${name} == "directory" && builtins.pathExists (currentPath + "/${name}/default.nix") + ) entryNames; + + # Get ALL directories (to recurse into) + allDirectories = builtins.filter (name: currentEntries.${name} == "directory") entryNames; + + # Import directories that have default.nix + directoryImports = map (name: currentPath + "/${name}") directoriesWithDefault; + + # Recursively walk ALL subdirectories + subDirImports = builtins.concatLists (map (dir: walkDir (currentPath + "/${dir}")) allDirectories); + + in + directoryImports ++ subDirImports; + + in + walkDir path; + + # Recursively scan systems directory structure + scanSystems = + systemsPath: + let + systemArchs = builtins.attrNames (builtins.readDir systemsPath); + + generateSystemConfigs = + system: + let + systemPath = systemsPath + "/${system}"; + hosts = builtins.attrNames (builtins.readDir systemPath); + in + genAttrs hosts (hostname: { + inherit system hostname; + path = systemPath + "/${hostname}"; + }); + in + foldl' (acc: system: acc // generateSystemConfigs system) { } systemArchs; + + # Filter systems for NixOS (Linux) + filterNixOSSystems = + systems: + filterAttrs ( + _name: { system, ... }: hasPrefix "x86_64-linux" system || hasPrefix "aarch64-linux" system + ) systems; + + # Filter systems for Darwin (macOS) + filterDarwinSystems = + systems: + filterAttrs ( + _name: { system, ... }: hasPrefix "aarch64-darwin" system || hasPrefix "x86_64-darwin" system + ) systems; + + # Scan homes directory structure for home configurations + scanHomes = + homesPath: + let + systemArchs = builtins.attrNames (builtins.readDir homesPath); + + generateHomeConfigs = + system: + let + systemPath = homesPath + "/${system}"; + userAtHosts = builtins.attrNames (builtins.readDir systemPath); + + parseUserAtHost = + userAtHost: + let + # Split "username@hostname" into parts + parts = builtins.split "@" userAtHost; + username = builtins.head parts; + hostname = builtins.elemAt parts 2; # After split: [username, "@", hostname] + in + { + inherit + system + username + hostname + userAtHost + ; + path = systemPath + "/${userAtHost}"; + }; + in + genAttrs userAtHosts parseUserAtHost; + in + foldl' (acc: system: acc // generateHomeConfigs system) { } systemArchs; +} diff --git a/lib/system/common.nix b/lib/system/common.nix new file mode 100644 index 0000000..8e485a9 --- /dev/null +++ b/lib/system/common.nix @@ -0,0 +1,98 @@ +{ inputs }: +let + inherit (inputs.nixpkgs.lib) filterAttrs mapAttrs'; +in +{ + mkExtendedLib = flake: nixpkgs: nixpkgs.lib.extend (final: prev: { + mjallen = flake.mjallen-lib; + }); + + mkNixpkgsConfig = flake: { + overlays = builtins.attrValues flake.overlays; + config = { + allowAliases = false; + allowUnfree = true; + permittedInsecurePackages = [ + # Add any permitted insecure packages here + ]; + }; + }; + + mkHomeConfigs = + { + flake, + system, + hostname, + }: + let + inherit (flake.mjallen-lib.file) scanHomes; + homesPath = ../../homes; + allHomes = scanHomes homesPath; + in + filterAttrs ( + _name: homeConfig: homeConfig.system == system && homeConfig.hostname == hostname + ) allHomes; + + mkHomeManagerConfig = + { + extendedLib, + inputs, + system, + matchingHomes, + isNixOS ? true, + }: + if matchingHomes != { } then + { + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + extraSpecialArgs = { + inherit inputs system; + inherit (inputs) self; + lib = extendedLib; + }; + sharedModules = [ + { _module.args.lib = extendedLib; } + ] + ++ (extendedLib.mjallen.file.importModulesRecursive ../../modules/home); + users = mapAttrs' (_name: homeConfig: { + name = homeConfig.username; + value = { + imports = [ homeConfig.path ]; + home = { + inherit (homeConfig) username; + homeDirectory = inputs.nixpkgs.lib.mkDefault ( + if isNixOS then "/home/${homeConfig.username}" else "/Users/${homeConfig.username}" + ); + }; + } + // ( + if isNixOS then + { + _module.args.username = homeConfig.username; + } + else + { } + ); + }) matchingHomes; + }; + } + else + { }; + + mkSpecialArgs = + { + inputs, + hostname, + username, + extendedLib, + }: + { + inherit inputs hostname username; + inherit (inputs) self; + lib = extendedLib; + namespace = "mjallen"; + format = "system"; + host = hostname; + }; +} diff --git a/lib/system/default.nix b/lib/system/default.nix new file mode 100644 index 0000000..193c703 --- /dev/null +++ b/lib/system/default.nix @@ -0,0 +1,5 @@ +{ inputs }: +{ + # Common utilities used by system builders + common = import ./common.nix { inherit inputs; }; +} diff --git a/modules/nixos/sops/options.nix b/modules/nixos/sops/options.nix new file mode 100644 index 0000000..e49ab17 --- /dev/null +++ b/modules/nixos/sops/options.nix @@ -0,0 +1,40 @@ +{ lib, ... }: +with lib; +{ + options.mjallen.sops = { + enable = mkEnableOption "enable sops"; + + defaultSopsFile = mkOption { + type = types.nullOr types.str; + default = null; + description = "Default sops file to use for secrets. If null, will use the system-wide default."; + example = "/etc/nixos/secrets/secrets.yaml"; + }; + + generateAgeKey = mkOption { + type = types.bool; + default = true; + description = "Whether to automatically generate an age key if one doesn't exist."; + }; + + ageKeyPath = mkOption { + type = types.nullOr types.str; + default = null; + description = "Custom path to the age key file. If null, will use the default path."; + example = "/var/lib/sops-nix/custom-key.txt"; + }; + + sshKeyPaths = mkOption { + type = types.listOf types.str; + default = [ "/etc/ssh/ssh_host_ed25519_key" ]; + description = "List of SSH key paths to use for age decryption."; + example = [ "/etc/ssh/ssh_host_ed25519_key" "/etc/ssh/ssh_host_rsa_key" ]; + }; + + validateSopsFiles = mkOption { + type = types.bool; + default = false; + description = "Whether to validate that sops files exist."; + }; + }; +} diff --git a/~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json b/~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json new file mode 100644 index 0000000..296f8cf --- /dev/null +++ b/~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json @@ -0,0 +1,14 @@ +{ + "mcpServers": { + "github.com/modelcontextprotocol/servers/tree/main/src/filesystem": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-filesystem", + "/Users/mattjallen/Documents/Cline/MCP/filesystem" + ], + "disabled": false, + "autoApprove": [] + } + } +}