Compare commits

7 Commits

Author SHA1 Message Date
UGA Innovation Factory
d39e9ee253 chore: Run nix fmt
All checks were successful
CI / Format Check (push) Successful in 10s
CI / Flake Check (push) Successful in 1m32s
CI / Evaluate Key Configurations (nix-builder) (push) Successful in 13s
CI / Evaluate Key Configurations (nix-desktop1) (push) Successful in 12s
CI / Evaluate Key Configurations (nix-laptop1) (push) Successful in 19s
CI / Evaluate Artifacts (installer-iso-nix-laptop1) (push) Successful in 23s
CI / Evaluate Artifacts (lxc-nix-builder) (push) Successful in 13s
2026-01-13 18:28:00 -05:00
UGA Innovation Factory
6bf939a305 chore: Update hdh20267 user to use new shell selection 2026-01-13 18:24:41 -05:00
UGA Innovation Factory
97358a6aee feat: Refactor to use flake-parts and import inventory and users thru the flake parts 2026-01-13 18:20:24 -05:00
UGA Innovation Factory
854882cbb9 fix: Refactor flake structure to properly use flake-parts
- Remove incorrect parts/fleet-data.nix import from flake.nix
- Create flake-parts wrappers for fleet-option.nix and users.nix
- Import inventory.nix through fleet-option wrapper
- Fix module argument passing (remove pkgs from mkFleet call)
- Move NixOS-specific modules out of flake-parts imports

This addresses the 'path does not exist' error but introduces infinite recursion that needs to be resolved.
2026-01-13 16:28:31 -05:00
UGA Innovation Factory
acbc7518e8 fix: Remove incorrect parts/fleet-data.nix import from flake.nix
fleet-data.nix is a NixOS module imported by fleet/common.nix, not a flake-parts module. It should not be imported at the flake level.
2026-01-13 16:24:24 -05:00
UGA Innovation Factory
005207d3e4 flake.lock: Update
Flake lock file updates:

• Updated input 'home-manager':
    'github:nix-community/home-manager/6bd04da47cfb48dfd15eabf08364b78ad894f5b2?narHash=sha256-KpoCBPvwHz3gAQtIUkohE2InRBFK3r0/FM6z5SPWfvM%3D' (2026-01-05)
  → 'github:nix-community/home-manager/82fb7dedaad83e5e279127a38ef410bcfac6d77c?narHash=sha256-MOU5YdVu4DVwuT5ztXgQpPuRRBjSjUGIdUzOQr9iQOY%3D' (2026-01-08)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/30a3c519afcf3f99e2c6df3b359aec5692054d92?narHash=sha256-8IQQUorUGiSmFaPnLSo2%2BT%2BrjHtiNWc%2BOAzeHck7N48%3D' (2026-01-03)
  → 'github:NixOS/nixpkgs/1327e798cb055f96f92685df444e9a2c326ab5ed?narHash=sha256-F4IIxa5xDHjtrmMcayM8lHctUq1oGltfBQu2%2BoqDWP4%3D' (2026-01-12)
• Updated input 'nixpkgs-old-kernel':
    'github:NixOS/nixpkgs/40ee5e1944bebdd128f9fbada44faefddfde29bd?narHash=sha256-0MnuWoN%2Bn1UYaGBIpqpPs9I9ZHW4kynits4mrnh1Pk4%3D' (2025-12-29)
  → 'github:NixOS/nixpkgs/ac62194c3917d5f474c1a844b6fd6da2db95077d?narHash=sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w%3D' (2026-01-02)
2026-01-13 16:21:42 -05:00
UGA Innovation Factory
d34325de53 fix: Remove incorrect ./parts/fleet-data.nix import from flake.nix and use correct flake-parts structure 2026-01-13 16:21:20 -05:00
17 changed files with 349 additions and 299 deletions

BIN
core Normal file

Binary file not shown.

41
flake.lock generated
View File

@@ -159,6 +159,26 @@
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1768135262,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"lazyvim-nixvim",
@@ -318,11 +338,11 @@
]
},
"locked": {
"lastModified": 1767619900,
"narHash": "sha256-KpoCBPvwHz3gAQtIUkohE2InRBFK3r0/FM6z5SPWfvM=",
"lastModified": 1767910483,
"narHash": "sha256-MOU5YdVu4DVwuT5ztXgQpPuRRBjSjUGIdUzOQr9iQOY=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "6bd04da47cfb48dfd15eabf08364b78ad894f5b2",
"rev": "82fb7dedaad83e5e279127a38ef410bcfac6d77c",
"type": "github"
},
"original": {
@@ -386,7 +406,7 @@
},
"lazyvim-nixvim": {
"inputs": {
"flake-parts": "flake-parts",
"flake-parts": "flake-parts_2",
"nixpkgs": "nixpkgs",
"nixvim": "nixvim"
},
@@ -518,11 +538,11 @@
},
"nixpkgs-old-kernel": {
"locked": {
"lastModified": 1767051569,
"narHash": "sha256-0MnuWoN+n1UYaGBIpqpPs9I9ZHW4kynits4mrnh1Pk4=",
"lastModified": 1767313136,
"narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "40ee5e1944bebdd128f9fbada44faefddfde29bd",
"rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d",
"type": "github"
},
"original": {
@@ -534,11 +554,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1767480499,
"narHash": "sha256-8IQQUorUGiSmFaPnLSo2+T+rjHtiNWc+OAzeHck7N48=",
"lastModified": 1768242861,
"narHash": "sha256-F4IIxa5xDHjtrmMcayM8lHctUq1oGltfBQu2+oqDWP4=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "30a3c519afcf3f99e2c6df3b359aec5692054d92",
"rev": "1327e798cb055f96f92685df444e9a2c326ab5ed",
"type": "github"
},
"original": {
@@ -608,6 +628,7 @@
"inputs": {
"agenix": "agenix",
"disko": "disko",
"flake-parts": "flake-parts",
"home-manager": "home-manager_2",
"lazyvim-nixvim": "lazyvim-nixvim",
"nixos-generators": "nixos-generators",

View File

@@ -4,7 +4,7 @@
# ============================================================================
# This file defines the inputs (dependencies) and outputs (configurations)
# for Athenix. It ties together the hardware, software, and user
# configurations into deployable systems.
# configurations into deployable systems using flake-parts.
inputs = {
# Core NixOS package repository (Release 25.11)
@@ -13,6 +13,12 @@
# Older kernel packages for Surface compatibility if needed
nixpkgs-old-kernel.url = "github:NixOS/nixpkgs/nixos-25.05";
# Flake-parts for modular flake organization
flake-parts = {
url = "github:hercules-ci/flake-parts";
inputs.nixpkgs-lib.follows = "nixpkgs";
};
# Home Manager for user environment management
home-manager = {
url = "github:nix-community/home-manager/release-25.11";
@@ -54,51 +60,28 @@
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
inputs@{
self,
nixpkgs,
nixpkgs-old-kernel,
home-manager,
disko,
agenix,
lazyvim-nixvim,
nixos-hardware,
vscode-server,
nixos-generators,
...
}:
let
fleet = self.lib.mkFleet { inherit inputs; };
linuxSystem = "x86_64-linux";
artifacts = import ./installer/artifacts.nix {
inherit inputs fleet self;
system = linuxSystem;
};
forAllSystems = nixpkgs.lib.genAttrs [
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
# Support all common systems
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
in
{
# Formatter for 'nix fmt'
formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt-rfc-style);
# Generate NixOS configurations from fleet generator
nixosConfigurations = fleet.nixosConfigurations;
# Expose artifacts to all systems, but they are always built for x86_64-linux
packages.${linuxSystem} = artifacts;
# Expose host type modules and installer modules for external use
nixosModules = import ./installer/modules.nix { inherit inputs; };
# Library functions
lib = import ./lib { inherit inputs; };
# Templates for external configurations
templates = import ./templates;
# Import flake-parts modules
imports = [
./parts/formatter.nix
./parts/lib.nix
./parts/nixos-configurations.nix
./parts/nixos-modules.nix
./parts/packages.nix
./parts/templates.nix
./inventory.nix
./users.nix
];
};
}

View File

@@ -15,8 +15,8 @@
./fs.nix
./boot.nix
./user-config.nix
./fleet-option.nix
../sw
../users.nix
];
options.athenix = {

View File

@@ -1,7 +1,7 @@
{
inputs,
fleet ? null,
hwTypes ? null,
lib,
config,
...
}:
@@ -13,26 +13,12 @@
# configurations with flexible type associations.
let
nixpkgs = inputs.nixpkgs;
lib = nixpkgs.lib;
# Evaluate inventory to get fleet data
# Import fleet-option.nix (defines athenix.fleet) and inventory.nix (sets values)
# We use a minimal module here to avoid circular dependencies from common.nix's imports
inventoryModule = lib.evalModules {
modules = [
(import ./fleet-option.nix { inherit inputs; })
{
_module.args = {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
};
}
(lib.mkIf (fleet != null) { athenix.fleet = lib.mkForce fleet; })
(lib.mkIf (hwTypes != null) { athenix.hwTypes = lib.mkForce hwTypes; })
];
};
hostTypes = inventoryModule.config.athenix.hwTypes;
hostTypes = config.athenix.hwTypes;
# Helper to create a single NixOS system configuration
mkHost =
@@ -64,9 +50,7 @@ let
null;
# Load users.nix to find external user modules
pkgs = nixpkgs.legacyPackages.${system};
usersData = import ../users.nix { inherit pkgs; };
accounts = usersData.athenix.users or { };
accounts = config.athenix.users or { };
# Build a map of user names to their nixos module paths (if they exist)
# We'll use this to conditionally import modules based on user.enable
@@ -285,7 +269,7 @@ let
lib.recursiveUpdate deviceHosts countHosts
);
fleetData = inventoryModule.config.athenix.fleet;
fleetData = config.athenix.fleet;
# Flatten the nested structure
allHosts = lib.foldl' lib.recursiveUpdate { } (lib.attrValues (processInventory fleetData));

View File

@@ -3,8 +3,7 @@
# ============================================================================
# This module only defines the athenix.fleet option without any dependencies.
# Used by fleet/default.nix to evaluate inventory data without circular dependencies.
{ inputs, ... }:
{ lib, ... }:
{ inputs, lib, ... }:
let
fleetDefinition = lib.mkOption {
description = "Hardware types definitions for the fleet.";
@@ -60,6 +59,109 @@ let
)
);
};
# Submodule defining the structure of a user account
userSubmodule = lib.types.submodule {
options = {
isNormalUser = lib.mkOption {
type = lib.types.bool;
default = true;
};
description = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
extraGroups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
hashedPassword = lib.mkOption {
type = lib.types.str;
default = "!";
};
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
excludePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
homePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
extraImports = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
};
external = lib.mkOption {
type = lib.types.nullOr (
lib.types.oneOf [
lib.types.path
lib.types.package
lib.types.attrs
]
);
default = null;
description = ''
External user configuration module. Can be:
- A path to a local module directory
- A fetchGit/fetchTarball result pointing to a repository
The external module can contain:
- user.nix (optional): Sets athenix.users.<name> options AND home-manager config
- nixos.nix (optional): System-level NixOS configuration
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
'';
};
opensshKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of SSH public keys for the user.";
};
shell = lib.mkOption {
type = lib.types.nullOr (
lib.types.enum [
"bash"
"zsh"
"fish"
"tcsh"
]
);
default = "bash";
description = "The shell for this user.";
};
editor = lib.mkOption {
type = lib.types.nullOr (
lib.types.enum [
"vim"
"neovim"
"emacs"
"nano"
"code"
]
);
default = "neovim";
description = "The default editor for this user.";
};
useZshTheme = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Zsh theme.";
};
useNvimPlugins = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Neovim configuration.";
};
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether this user account is enabled on this system.";
};
};
};
in
{
options.athenix = {
@@ -68,8 +170,12 @@ in
description = "Hardware types definitions for the fleet.";
type = lib.types.attrs;
};
users = lib.mkOption {
type = lib.types.attrsOf userSubmodule;
default = { };
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
};
};
config.athenix.fleet = lib.mkDefault (import ../inventory.nix);
config.athenix.hwTypes = lib.mkDefault (import ../hw { inherit inputs; });
}

View File

@@ -14,10 +14,6 @@
# and Home Manager configuration.
let
# Load users.nix to get account definitions
usersData = import ../users.nix { inherit pkgs; };
accounts = usersData.athenix.users or { };
# Helper: Resolve external module path from fetchGit/fetchTarball/path
resolveExternalPath =
external:
@@ -34,149 +30,9 @@ let
path != null
&& (builtins.isPath path || (builtins.isString path && lib.hasPrefix "/" path))
&& builtins.pathExists path;
# Extract athenix.users options from external user.nix modules
# First, build a cache of options per user from their external user.nix (if any).
externalUserModuleOptions = lib.genAttrs (lib.attrNames accounts) (
name:
let
user = accounts.${name};
externalPath = resolveExternalPath (user.external or null);
userNixPath = if externalPath != null then externalPath + "/user.nix" else null;
in
if isValidPath userNixPath then
let
# Import and evaluate the module with minimal args
outerModule = import userNixPath { inherit inputs; };
evaluatedModule = outerModule {
config = { };
inherit lib pkgs;
osConfig = null;
};
# Extract just the athenix.users.<name> options
athenixUsers = evaluatedModule.athenix.users or { };
in
athenixUsers.${name} or { }
else
{ }
);
# externalUserOptions only contains users that actually have options defined
externalUserOptions = lib.filterAttrs (
_: moduleOptions: moduleOptions != { }
) externalUserModuleOptions;
# Submodule defining the structure of a user account
userSubmodule = lib.types.submodule {
options = {
isNormalUser = lib.mkOption {
type = lib.types.bool;
default = true;
};
description = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
extraGroups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
hashedPassword = lib.mkOption {
type = lib.types.str;
default = "!";
};
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
excludePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
homePackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
extraImports = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
};
external = lib.mkOption {
type = lib.types.nullOr (
lib.types.oneOf [
lib.types.path
lib.types.package
lib.types.attrs
]
);
default = null;
description = ''
External user configuration module. Can be:
- A path to a local module directory
- A fetchGit/fetchTarball result pointing to a repository
The external module can contain:
- user.nix (optional): Sets athenix.users.<name> options AND home-manager config
- nixos.nix (optional): System-level NixOS configuration
Example: builtins.fetchGit { url = "https://github.com/user/dotfiles"; rev = "..."; }
'';
};
opensshKeys = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of SSH public keys for the user.";
};
shell = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The shell for this user.";
};
editor = lib.mkOption {
type = lib.types.nullOr lib.types.package;
default = null;
description = "The default editor for this user.";
};
useZshTheme = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Zsh theme.";
};
useNvimPlugins = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to apply the system Neovim configuration.";
};
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether this user account is enabled on this system.";
};
};
};
in
{
options.athenix.users = lib.mkOption {
type = lib.types.attrsOf userSubmodule;
default = { };
description = "User accounts configuration. Set enable=true for users that should exist on this system.";
};
config = {
# Merge user definitions from users.nix with options from external user.nix modules
# External options take precedence over users.nix (which uses lib.mkDefault)
athenix.users = lib.mapAttrs (
name: user:
user
// {
description = lib.mkDefault (user.description or null);
shell = lib.mkDefault (user.shell or null);
extraGroups = lib.mkDefault (user.extraGroups or [ ]);
}
// (externalUserOptions.${name} or { })
) accounts;
# Generate NixOS users
users.users =
let
@@ -188,16 +44,31 @@ in
isPlasma6 = config.services.desktopManager.plasma6.enable;
defaultPackages = lib.optionals (isPlasma6 && name != "root") [ pkgs.kdePackages.kate ];
finalPackages = lib.subtractLists user.excludePackages (defaultPackages ++ user.extraPackages);
shells = {
bash = pkgs.bash;
zsh = pkgs.zsh;
fish = pkgs.fish;
tcsh = pkgs.tcsh;
};
in
{
rec {
inherit (user) isNormalUser extraGroups hashedPassword;
description = if user.description != null then user.description else lib.mkDefault "";
openssh.authorizedKeys.keys = user.opensshKeys;
packages = finalPackages;
shell = if user.shell != null then user.shell else pkgs.bash;
shell = if user.shell != null then shells.${user.shell} else pkgs.bash;
packages = finalPackages ++ [ shell ];
group = if user.isNormalUser then name else lib.mkDefault "root";
}
) enabledAccounts;
# Generate user groups for normal users
users.groups =
let
enabledAccounts = lib.filterAttrs (_: user: user.enable) config.athenix.users;
normalUsers = lib.filterAttrs (_: user: user.isNormalUser) enabledAccounts;
in
lib.mapAttrs (_: _: { }) normalUsers;
# Home Manager configs per user
home-manager = {
useGlobalPkgs = true;
@@ -264,6 +135,10 @@ in
home.username = name;
home.homeDirectory = if name == "root" then "/root" else "/home/${name}";
home.stateVersion = "25.11";
programs.${user.editor} = {
enable = true;
defaultEditor = true;
};
}
(lib.mkIf (!hasExternal) {
# For local users only, add their packages

View File

@@ -70,7 +70,9 @@
# rev = "e1ccd7cc3e709afe4f50b0627e1c4bde49165014";
# };
# };
{ ... }:
{
athenix.fleet = {
# ========== Lab Laptops ==========
# Creates: nix-laptop1, nix-laptop2
# Both get hdh20267 user via overrides
@@ -130,6 +132,7 @@
rev = "dab32f5884895cead0fae28cb7d88d17951d0c12";
submodules = true;
};
"usda-dash".athenix.users.engr-ugaif.enable = true;
};
overrides = {
athenix.host.useHostPrefix = false;
@@ -151,4 +154,5 @@
# ========== Ephemeral/Netboot System ==========
# Creates: nix-ephemeral1
nix-ephemeral.devices = 1;
};
}

View File

@@ -2,10 +2,9 @@
# Usage: nixosConfigurations = athenix.lib.mkFleet { fleet = { ... }; hwTypes = { ... }; }
{
inputs,
fleet ? null,
hwTypes ? null,
lib,
config,
}:
import ../fleet/default.nix {
inherit inputs;
inherit fleet hwTypes;
inherit inputs lib config;
}

9
parts/formatter.nix Normal file
View File

@@ -0,0 +1,9 @@
# Formatter configuration for flake-parts
{ ... }:
{
perSystem =
{ pkgs, ... }:
{
formatter = pkgs.nixfmt-rfc-style;
};
}

5
parts/lib.nix Normal file
View File

@@ -0,0 +1,5 @@
# Library functions for flake-parts
{ inputs, ... }:
{
flake.lib = import ../lib { inherit inputs; };
}

View File

@@ -0,0 +1,20 @@
# NixOS configurations generated from fleet
{
inputs,
self,
lib,
pkgs,
config,
...
}:
{
imports = [
../fleet/fleet-option.nix
];
flake.nixosConfigurations =
let
fleet = self.lib.mkFleet { inherit inputs lib config; };
in
fleet.nixosConfigurations;
}

5
parts/nixos-modules.nix Normal file
View File

@@ -0,0 +1,5 @@
# Expose host type modules and installer modules for external use
{ inputs, ... }:
{
flake.nixosModules = import ../installer/modules.nix { inherit inputs; };
}

27
parts/packages.nix Normal file
View File

@@ -0,0 +1,27 @@
# Build artifacts (ISOs, LXC containers, etc.)
{
inputs,
self,
lib,
config,
...
}:
{
perSystem =
{ system, ... }:
lib.mkIf (system == "x86_64-linux") {
packages =
let
fleet = self.lib.mkFleet { inherit inputs lib config; };
artifacts = import ../installer/artifacts.nix {
inherit
inputs
fleet
self
system
;
};
in
artifacts;
};
}

5
parts/templates.nix Normal file
View File

@@ -0,0 +1,5 @@
# Templates for external configurations
{ ... }:
{
flake.templates = import ../templates;
}

7
parts/users.nix Normal file
View File

@@ -0,0 +1,7 @@
# Flake-parts wrapper for users.nix
{ inputs, ... }:
let
# Minimal pkgs just for shell paths - will be overridden in actual NixOS configs
pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;
in
import ../users.nix { inherit pkgs; }

View File

@@ -1,4 +1,4 @@
{ pkgs, ... }:
{ ... }:
{
# ============================================================================
# User Definitions
@@ -49,7 +49,7 @@
hdh20267 = {
external = builtins.fetchGit {
url = "https://git.factory.uga.edu/hdh20267/hdh20267-nix";
rev = "c538e0c0510045b58264627bb897fc499dc7c490";
rev = "dbdf65c7bd59e646719f724a3acd2330e0c922ec";
};
};
sv22900 = {
@@ -58,7 +58,7 @@
"networkmanager"
"wheel"
];
shell = pkgs.zsh;
shell = "zsh";
# enable = false by default, set to true per-system
};
};