diff --git a/TODO.md b/TODO.md index c43e8c6..a12b8c3 100755 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,58 @@ -Allow `Cerulean.mkNexus` to be an alias for `flake-parts.lib.mkFlake` -also rename `Cerulean` to `cerulean` in Nix to maintain the naming convention. +- [ ] deploy port should default to the first port given to `services.openssh` -Using `flake-parts` ensures Cerulean is usable without restricting -yourself only to the Cerulean ecosystem. +- [ ] use the Nix module system instead of projectOnto for `cerulean.mkNexus` +- [ ] create an alternative to nixos-install called cerulean-install that + allows people to easily bootstrap new machines (and host it on dobutterfliescry.net) + +- [ ] find an alternative to `nix.settings.trusted-users` probably +- [ ] add the ceru-build user, +- [ ] add support for github:microvm-nix/microvm.nix +- [ ] add support for sops-nix + +- [ ] it would be cool to enable/disable groups and hosts +- [ ] find a standard for how nixpkgs.nix can have a different base per group + +- [ ] go through all flake inputs (recursively) and ENSURE we remove all duplicates by using follows!! + +- [X] rename nixos-modules/ to nixos/ +- [X] ensure all machines are in groups.all by default + +- [X] fix nixpkgs.nix not working (default not respected) +- [X] remove dependence on nixpkgs + +- [ ] allow multiple privesc methods, the standard is pam_ssh_agent_auth + +## Low Priority +- [ ] rename extraModules to modules? +- [ ] rename specialArgs to args? + +- [ ] make an extension to the nix module system (different to mix) + that allows transformations (ie a stop post config, ie outputs, which + it then returns instead of config) + + +- [ ] what if we automated the process of replacing windows with Nix?? + then push this to nixos-anywhere or nix-infect lmaooo + +- [ ] patch microvm so that acpi=off https://github.com/microvm-nix/microvm.nix/commit/b59a26962bb324cc0a134756a323f3e164409b72 + cause otherwise 2GB causes a failure + +- [ ] rewrite the ceru cli in rust +- [ ] make `ceru` do local and remote deployments + +```nix +# REF: foxora +vms = { + home-assistant = { + autostart = true; + # matches in vms/* + image = "home-assistant"; + options = { + mem = 2048; + }; + }; + equinox = { + image = "home-assistant"; + }; +}; +``` diff --git a/cerulean/default.nix b/cerulean/default.nix index 68846bf..f24bb5a 100644 --- a/cerulean/default.nix +++ b/cerulean/default.nix @@ -13,23 +13,24 @@ # limitations under the License. { mix, - deploy-rs, + inputs, ... -} @ inputs: -mix.newMixture inputs (mixture: { +} @ args: +mix.newMixture args (mixture: { includes.public = [ ./nexus ]; + version = "0.2.1"; + + nixosModules = rec { + default = cerulean; + cerulean = ./nixos; + }; + overlays = [ # build deploy-rs as a package not from the flake input, # hence we can rely on a nixpkg binary cache. - deploy-rs.overlays.default - # (self: super: { - # deploy-rs = { - # inherit (super) deploy-rs; - # lib = super.deploy-rs.lib; - # }; - # }) + inputs.deploy-rs.overlays.default ]; }) diff --git a/cerulean/nexus/default.nix b/cerulean/nexus/default.nix index d8e0f7c..65495bf 100644 --- a/cerulean/nexus/default.nix +++ b/cerulean/nexus/default.nix @@ -11,8 +11,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -{mix, ...} @ inputs: -mix.newMixture inputs (mixture: { +{mix, ...} @ args: +mix.newMixture args (mixture: { includes.public = [ ./nodes.nix ./nexus.nix diff --git a/cerulean/nexus/nexus.nix b/cerulean/nexus/nexus.nix index 8b65fdd..24a0b75 100644 --- a/cerulean/nexus/nexus.nix +++ b/cerulean/nexus/nexus.nix @@ -14,11 +14,8 @@ { self, this, - nixpkgs, - nixpkgs-unstable, nt, - lib, - deploy-rs, + inputs, ... }: let inherit @@ -42,20 +39,22 @@ mapNodes ; + inherit + (nt) + findImport + ; + templateNexus = let inherit (nt.naive.terminal) Terminal ; - - missing = msg: path: - Terminal (abort '' - Each Cerulean Nexus node is required to specify ${msg}! - Ensure `nexus.${path}` exists under your call to `cerulean.mkNexus`. - ''); in { + base = null; + extraModules = []; + specialArgs = Terminal {}; + groups = Terminal {}; - overlays = []; nodes = Terminal {}; }; @@ -66,7 +65,8 @@ isAttrs g || throw '' Cerulean Nexus groups must be provided as attribute sets, got "${typeOf g}" instead! - Ensure all the `groups` definitions are attribute sets under your call to `cerulean.mkNexus`. + Ensure all the group definitions are attribute sets under your call to `cerulean.mkNexus`. + NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP` ''; delegate = parent: gName: g: let result = @@ -90,7 +90,7 @@ assert isAttrs nexus || abort '' Cerulean Nexus config must be provided as an attribute set, got "${typeOf nexus}" instead! - Ensure all the `nexus` declaration is an attribute set under your call to `cerulean.mkNexus`. + Ensure the `nexus` declaration is an attribute set under your call to `cerulean.mkNexus`. ''; let base = nt.projectOnto templateNexus nexus; in @@ -121,11 +121,56 @@ in final; - # XXX: TODO: create a function in NixTypes that handles this instead - findImport = path: - if pathExists path - then path - else path + ".nix"; + getGroupModules = root: nodeName: node: + assert isList node.groups + || throw '' + Cerulean Nexus node "${nodeName}" does not declare group membership as a list, got "${typeOf node.groups}" instead! + Ensure `nexus.nodes.${nodeName}.groups` is a list under your call to `cerulean.mkNexus`. + ''; + # ensure root group is always added + (node.groups + ++ [ + { + _parent = null; + _name = ROOT_GROUP_NAME; + } + ]) + # ensure all members are actually groups + |> map (group: let + got = + if ! isAttrs group + then toString group + else + group + |> attrNames + |> map (name: "${name} = <${typeOf (getAttr name group)}>;") + |> concatStringsSep " " + |> (x: "{ ${x} }"); + in + if group ? _name + then group + else + throw '' + Cerulean Nexus node "${nodeName}" is a member of an incorrectly structured group. + Got "${got}" of primitive type "${typeOf group}". + NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP` + '') + # add all inherited groups via _parent + |> map (let + delegate = g: + if g._parent == null + then [g] + else [g] ++ delegate (g._parent); + in + delegate) + # flatten recursion result + |> concatLists + # find import location + |> map (group: findImport (root + "/groups/${group._name}")) + # filter by uniqueness + |> nt.prim.unique + # ignore missing groups + |> filter pathExists; in { mkNexus = root: outputsBuilder: let decl = parseDecl outputsBuilder; @@ -137,118 +182,47 @@ in { customOutputs = removeAttrs decl ["nexus"]; outputs = rec { - nixosConfigurations = mapNodes nexus.nodes ( - nodeName: node: - lib.nixosSystem { + nixosConfigurations = mapNodes nexus ( + { + lib, + nodeName, + node, + ... + }: let + nixosDecl = lib.nixosSystem { system = node.system; - modules = let - host = findImport (root + "/hosts/${nodeName}"); - # XXX: TODO: don't use a naive type for this (ie _name property) - # XXX: TODO: i really need NixTypes to be stable and use that instead - # groups = - # node.groups - # |> map (group: - # assert group ? _name - # || throw (let - # got = - # if ! isAttrs group - # then toString group - # else - # group - # |> attrNames - # |> map (name: "${name} = <${typeOf (getAttr name group)}>;") - # |> concatStringsSep " " - # |> (x: "{ ${x} }"); - # in '' - # Cerulean Nexus node "${nodeName}" is a member of a nonexistent group. - # Got "${got}" of primitive type "${typeOf group}". - # NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP` - # ''); - # findImport (root + "/groups/${group._name}")) - # |> nt.prim.unique; # filter by uniqueness - groups = assert isList node.groups - || throw '' - Cerulean Nexus node "${nodeName}" does not declare group membership as a list, got "${typeOf node.groups}" instead! - Ensure `nexus.nodes.${nodeName}.groups` is a list under your call to `cerulean.mkNexus`. - ''; - node.groups - # ensure all members are actually groups - |> map (group: let - got = - if ! isAttrs group - then toString group - else - group - |> attrNames - |> map (name: "${name} = <${typeOf (getAttr name group)}>;") - |> concatStringsSep " " - |> (x: "{ ${x} }"); - in - if group ? _name - then group - else - throw '' - Cerulean Nexus node "${nodeName}" is a member of an incorrectly structured group. - Got "${got}" of primitive type "${typeOf group}". - NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP` - '') - # add all inherited groups via _parent - |> map (let - delegate = g: let - got = - if ! isAttrs g - then toString g - else - g - |> attrNames - |> map (name: "${name} = <${typeOf (getAttr name g)}>;") - |> concatStringsSep " " - |> (x: "{ ${x} }"); - in - assert g ? _parent - || throw '' - Cerulean Nexus node "${nodeName}" is a member of an incorrectly structured group. - Got "${got}" of primitive type "${typeOf g}". - NOTE: Groups can be accessed via `self.groups.PATH.TO.YOUR.GROUP` - ''; - if g._parent == null - then [g] - else [g] ++ delegate (g._parent); - in - delegate) - # flatten recursion result - |> concatLists - # find import location - |> map (group: findImport (root + "/groups/${group._name}")) - # filter by uniqueness - |> nt.prim.unique - # ignore missing groups - |> filter pathExists; - in - [../nixos-module host] ++ groups ++ node.extraModules; - - # nix passes these to every single module specialArgs = let - pkgConfig = - { + specialArgs = + nexus.specialArgs + // node.specialArgs + // { + inherit root specialArgs; inherit (node) system; - # XXX: WARNING: TODO: i've stopped caring - # XXX: WARNING: TODO: just figure out a better solution to pkgConfig - config.allowUnfree = true; - overlays = self.overlays ++ nexus.overlays ++ node.overlays; - } - // node.extraPkgConfig; + _deploy-rs = inputs.deploy-rs; + }; in - node.specialArgs - // { - inherit root; - pkgs = import nixpkgs pkgConfig; - upkgs = import nixpkgs-unstable pkgConfig; - }; - } + specialArgs; + modules = + [ + self.nixosModules.default + (findImport (root + "/hosts/${nodeName}")) + + inputs.home-manager.nixosModules.default + # inputs.microvm.nixosModules.microvm + ] + ++ (getGroupModules root nodeName node) + ++ node.extraModules + ++ nexus.extraModules; + }; + in + nixosDecl ); - deploy.nodes = mapNodes nexus.nodes (nodeName: node: let + deploy.nodes = mapNodes nexus ({ + nodeName, + node, + ... + }: let inherit (node.deploy) activationTimeout @@ -262,7 +236,7 @@ in { user ; - nixosFor = system: deploy-rs.lib.${system}.activate.nixos; + nixosFor = system: inputs.deploy-rs.lib.${system}.activate.nixos; in { hostname = ssh.host; @@ -298,7 +272,7 @@ in { }; }); - checks = mapAttrs (system: deployLib: deployLib.deployChecks deploy) deploy-rs.lib; + checks = mapAttrs (system: deployLib: deployLib.deployChecks deploy) inputs.deploy-rs.lib; }; in outputs // customOutputs; diff --git a/cerulean/nexus/nodes.nix b/cerulean/nexus/nodes.nix index 25a1d02..ccb5c20 100644 --- a/cerulean/nexus/nodes.nix +++ b/cerulean/nexus/nodes.nix @@ -25,14 +25,20 @@ in rec { (nt.naive.terminal) Terminal ; + + missing = msg: path: + Terminal (abort '' + Each Cerulean Nexus node is required to specify ${msg}! + Ensure `nexus.${path}` exists under your call to `cerulean.mkNexus`. + ''); in { - system = "x86_64-linux"; # sane default (i hope...) + enabled = true; + system = missing "its system architecture" "system"; groups = []; extraModules = []; specialArgs = Terminal {}; - overlays = []; - # XXX: WARNING: extraPkgConfig is a terrible solution (but im lazy for now) - extraPkgConfig = Terminal {}; + + base = null; deploy = { user = "root"; @@ -69,7 +75,25 @@ in rec { in nt.projectOnto templateAttrs nodeAttrs; - mapNodes = nodes: f: - nodes - |> mapAttrs (nodeName: nodeAttrs: f nodeName (parseNode nodeName nodeAttrs)); + mapNodes = nexus: f: + nexus.nodes + |> mapAttrs (nodeName: nodeAttrs: let + node = parseNode nodeName nodeAttrs; + + # use per-node base or default to nexus base + base = + if node.base != null + then node.base + else if nexus.base != null + then nexus.base + else + abort '' + Cerulean cannot construct nexus node "${nodeName}" without a base package source. + Ensure `nexus.nodes.*.base` or `nexus.base` is a flake reference to the github:NixOS/nixpkgs repository. + ''; + in + f { + inherit nodeName node; + lib = base.lib; + }); } diff --git a/cerulean/nexus/snow.nix b/cerulean/nexus/snow.nix new file mode 100644 index 0000000..1316ee3 --- /dev/null +++ b/cerulean/nexus/snow.nix @@ -0,0 +1,108 @@ +# Copyright 2026 Emile Clark-Boman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +{ + inputs, + lib, + ... +}: { + # nexus + options = let + inherit + (lib) + mkOption + types + ; + in { + extraModules = mkOption { + type = types.listOf types.path; + }; + specialArgs = mkOption { + type = types.attrs; + }; + + groups = mkOption { + type = types.attrs; + }; + + nodes = mkOption { + type = types.attrsOf (types.submoduleWith ({...}: { + options = { + enabled = mkOption { + type = types.bool; + default = true; + }; + system = mkOption { + type = types.enum inputs.systems; + }; + groups = mkOption { + type = types.list; + }; + modules = mkOption { + type = types.list; + }; + args = mkOption { + type = types.attrs; + }; + + deploy = { + user = mkOption { + type = types.str; + }; + sudoCmd = mkOption { + type = types.str; + }; + interactiveSudo = mkOption { + type = types.bool; + }; + + remoteBuild = mkOption { + type = types.bool; + }; + autoRollback = mkOption { + type = types.bool; + }; + magicRollback = mkOption { + type = types.bool; + }; + + activationTimeout = mkOption { + type = types.int; + }; + confirmTimeout = mkOption { + type = types.int; + }; + + ssh = { + host = mkOption { + type = types.str; + }; + user = mkOption { + type = types.str; + }; + port = mkOption { + type = types.int; + }; + opts = mkOption { + type = types.listOf types.str; + }; + }; + }; + }; + })); + }; + }; + + config = { + }; +} diff --git a/cerulean/nixos-module/options.nix b/cerulean/nixos/default.nix similarity index 64% rename from cerulean/nixos-module/options.nix rename to cerulean/nixos/default.nix index 8fb6a46..f15b236 100644 --- a/cerulean/nixos-module/options.nix +++ b/cerulean/nixos/default.nix @@ -11,10 +11,22 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -{lib, ...}: { - cerulean.nexus.node = { - group = lib.mkOption { - type = lib.types.enum; - }; - }; +{ + root, + system, + _deploy-rs, + ... +} @ args: { + imports = [ + # user configuration + (import (root + "/nixpkgs.nix")) + # options declarations + (import ./nixpkgs.nix (args // {contextName = "hosts";})) + + ./home-manager.nix + ]; + + environment.systemPackages = [ + _deploy-rs.packages.${system}.default + ]; } diff --git a/cerulean/nixos/home-manager.nix b/cerulean/nixos/home-manager.nix new file mode 100644 index 0000000..21ee78c --- /dev/null +++ b/cerulean/nixos/home-manager.nix @@ -0,0 +1,50 @@ +# Copyright 2026 Emile Clark-Boman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +{ + root, + system, + config, + lib, + specialArgs, + ... +} @ args: let + inherit + (builtins) + attrNames + filter + pathExists + ; +in { + config = { + home-manager = { + users = + config.users.users + |> attrNames + |> filter (x: pathExists (root + "/homes/${x}")) + |> (x: lib.genAttrs x (y: import (root + "/homes/${y}"))); + + extraSpecialArgs = {inherit root system;} // (specialArgs.inputs or {}); + sharedModules = [ + # user configuration + (import (root + "/nixpkgs.nix")) + # options declarations + (import ./nixpkgs.nix (args // {contextName = "homes";})) + ]; + + # disable home-manager trying anything fancy + # we control the pkgs now!! + # useGlobalPkgs = true; + }; + }; +} diff --git a/cerulean/nixos-module/config.nix b/cerulean/nixos/microvm-child.nix similarity index 98% rename from cerulean/nixos-module/config.nix rename to cerulean/nixos/microvm-child.nix index 26d459c..2b6a12e 100644 --- a/cerulean/nixos-module/config.nix +++ b/cerulean/nixos/microvm-child.nix @@ -11,4 +11,3 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -{...}: {} diff --git a/cerulean/nixos-module/default.nix b/cerulean/nixos/microvm-parent.nix similarity index 85% rename from cerulean/nixos-module/default.nix rename to cerulean/nixos/microvm-parent.nix index cc92212..2b6a12e 100644 --- a/cerulean/nixos-module/default.nix +++ b/cerulean/nixos/microvm-parent.nix @@ -11,8 +11,3 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -{...} @ inputs: { - options = import ./options.nix inputs; - - config = import ./config.nix inputs; -} diff --git a/cerulean/nixos/nixpkgs.nix b/cerulean/nixos/nixpkgs.nix new file mode 100644 index 0000000..65db5a5 --- /dev/null +++ b/cerulean/nixos/nixpkgs.nix @@ -0,0 +1,101 @@ +# Copyright 2026 Emile Clark-Boman +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +{ + lib, + system, + config, + contextName, + ... +}: let + inherit + (builtins) + mapAttrs + ; + + cfg = config.nixpkgs.channels; +in { + options.nixpkgs.channels = lib.mkOption { + type = lib.types.attrsOf (lib.types.attrs); + default = {}; + description = "Declare package repositories per module context (nixos, home-manager, etc)"; + example = { + "homes" = { + "pkgs" = { + source = "inputs.nixpkgs"; + system = "x86-64-linux"; + config = { + allowUnfree = true; + allowBroken = false; + }; + }; + "upkgs" = { + source = "inputs.nixpkgs-unstable"; + system = "x86-64-linux"; + config = { + allowUnfree = true; + allowBroken = false; + }; + }; + }; + }; + }; + + config = let + # TODO: use lib.types.submodule to restrict what options + # TODO: can be given to `nixpkgs.channels.${moduleName}.${name}` + decl = + cfg.${contextName} or cfg.default; + + repos = + decl + |> mapAttrs ( + name: args: + lib.mkForce ( + assert args ? source + || abort '' + ${toString ./.} + `nixpkgs.channels.${contextName}.${name}` missing required attribute "source" + ''; + ((removeAttrs args ["source"]) + // {inherit system;}) + |> import args.source + ) + ); + in { + # NOTE: _module.args is a special option that allows us to + # NOTE: set extend specialArgs from inside the modules. + _module.args = repos; + + nixpkgs = let + defaultPkgs = + decl.default or (throw '' + Your `nixpkgs.nix` file does not declare a default package source. + Ensure you set `nixpkgs.channels.*.default = ...;` + ''); + in + if contextName == "hosts" + then { + flake.source = lib.mkOverride 200 defaultPkgs.source; + config = lib.mkOverride 200 defaultPkgs.config; + } + else if contextName == "homes" + then { + # XXX: XXX: XXX: OH OH OH OMG, its because aurora never defines pkgs + config = lib.mkOverride 200 (defaultPkgs.config or {}); + # XXX: WARNING: TODO: modify options so overlays must always be given as the correct type + overlays = lib.mkOverride 200 (defaultPkgs.overlays or []); + } + else {}; + }; +} diff --git a/flake.lock b/flake.lock index e9a0074..0dd06b1 100644 --- a/flake.lock +++ b/flake.lock @@ -36,43 +36,71 @@ "type": "github" } }, - "mix": { + "flake-parts": { "inputs": { - "nib": [ - "nib" + "nixpkgs-lib": [ + "nt", + "nix-unit", + "nixpkgs" ] }, "locked": { - "lastModified": 1768525804, - "narHash": "sha256-jlpNb7Utqfdq2HESAB1mtddWHOsxKlTjPiLFRLd35r8=", - "owner": "emilelcb", - "repo": "mix", - "rev": "617d8915a6518a3d4e375b87c50ae34d9daee6c6", + "lastModified": 1762440070, + "narHash": "sha256-xxdepIcb39UJ94+YydGP221rjnpkDZUlykKuF54PsqI=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "26d05891e14c88eb4a5d5bee659c0db5afb609d8", "type": "github" }, "original": { - "owner": "emilelcb", - "repo": "mix", + "owner": "hercules-ci", + "repo": "flake-parts", "type": "github" } }, - "nib": { + "nix-github-actions": { "inputs": { - "systems": [ - "systems" + "nixpkgs": [ + "nt", + "nix-unit", + "nixpkgs" ] }, "locked": { - "lastModified": 1768472076, - "narHash": "sha256-bdVRCDy6oJx/CZiyxkke783FgtBW//wDuOAITUsQcNc=", - "owner": "emilelcb", - "repo": "nib", - "rev": "42ac66dfc180a13af1cc8850397db66ec5556991", + "lastModified": 1737420293, + "narHash": "sha256-F1G5ifvqTpJq7fdkT34e/Jy9VCyzd5XfJ9TO8fHhJWE=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "f4158fa080ef4503c8f4c820967d946c2af31ec9", "type": "github" }, "original": { - "owner": "emilelcb", - "repo": "nib", + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, + "nix-unit": { + "inputs": { + "flake-parts": "flake-parts", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "nt", + "nixpkgs" + ], + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1762774186, + "narHash": "sha256-hRADkHjNt41+JUHw2EiSkMaL4owL83g5ZppjYUdF/Dc=", + "owner": "nix-community", + "repo": "nix-unit", + "rev": "1c9ab50554eed0b768f9e5b6f646d63c9673f0f7", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-unit", "type": "github" } }, @@ -124,14 +152,49 @@ "type": "github" } }, + "nixpkgs_3": { + "locked": { + "lastModified": 1767313136, + "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nt": { + "inputs": { + "nix-unit": "nix-unit", + "nixpkgs": "nixpkgs_3", + "systems": "systems_2" + }, + "locked": { + "lastModified": 1770975056, + "narHash": "sha256-ZXTz/P3zUbbM6lNXzt91u8EwfNqhXpYMu8+wvFZqQHE=", + "owner": "cry128", + "repo": "nt", + "rev": "f42dcdd49a7921a7f433512e83d5f93696632412", + "type": "github" + }, + "original": { + "owner": "cry128", + "repo": "nt", + "type": "github" + } + }, "root": { "inputs": { "deploy-rs": "deploy-rs", - "mix": "mix", - "nib": "nib", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", - "systems": "systems_2" + "nt": "nt", + "systems": "systems_3" } }, "systems": { @@ -164,6 +227,43 @@ "type": "github" } }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nt", + "nix-unit", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762410071, + "narHash": "sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g+mjR/p5TEg=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "97a30861b13c3731a84e09405414398fbf3e109f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, "utils": { "inputs": { "systems": "systems" diff --git a/flake.nix b/flake.nix index 94f4b33..89ce6b4 100644 --- a/flake.nix +++ b/flake.nix @@ -17,23 +17,36 @@ inputs = { systems.url = "github:nix-systems/default"; + # WARNING: nixpkgs is ONLY included so flakes using Cerulean can + # WARNING: force Cerulean's inputs to follow a specific revision. nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; - nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; - nt.url = "github:emilelcb/nt"; + nt.url = "github:cry128/nt"; - deploy-rs.url = "github:serokell/deploy-rs"; + home-manager = { + url = "github:nix-community/home-manager/release-25.11"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + deploy-rs = { + url = "github:serokell/deploy-rs"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + microvm = { + url = "github:microvm-nix/microvm.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { - nixpkgs, + self, nt, ... } @ inputs: import ./cerulean - (inputs - // { - inherit (nixpkgs) lib; - inherit (nt) mix; - }); + { + inherit inputs self nt; + inherit (nt) mix; + }; } diff --git a/lib/cdesktop.nix b/lib/cdesktop.nix deleted file mode 100644 index ef2b205..0000000 --- a/lib/cdesktop.nix +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2025 Emile Clark-Boman -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -{ - lib, - config, - pkgs, - pkgs-unstable, - ... -} @ args: let - getModule = name: "../modules/homemanager/${name}.nix"; - getModules = map (x: getModule x); -in { - imports = getModules [ - "term/foot" - "editor/vscode" - - "wm/hyprland" - "wm/hyprland/hyprlock" - - "dm/sddm" - "dm/sddm/themes/corners" - - "apps/firefox" - "apps/thunderbird" - "apps/obsidian" - "apps/rider" - "apps/winbox" - "apps/gitkraken" - "apps/thunar" - - "wm/kanshi" - "wm/mako" - ]; - - home = { - pointerCursor = { - gtk.enable = true; - # x11.enable = true # dont enable since im on hyprland - package = pkgs.bibata-cursors; - name = "Bibata-Modern-Ice"; - size = 16; - }; - - packages = with pkgs; [ - # for services.gnome-keyring - ( - if config.cerulean.isGraphical - then seahorse # gui - else null - ) - - fuzzel - ]; - }; - - gtk = { - enable = true; - font.name = "Victor Mono SemiBold 12"; - theme = { - name = "Dracula"; - package = pkgs.dracula-theme; - }; - iconTheme = { - name = "kora"; - package = pkgs.kora-icon-theme; - }; - # TODO: use a variable to mirror this cursor size - # with the `home.pointerCurser.size` - cursorTheme = { - package = pkgs.bibata-cursors; - name = "Bibata-Modern-Ice"; - size = 16; - }; - }; - - qt = { - enable = true; - platformTheme.name = "gtk2"; - style.name = "gtk2"; - }; - - services = { - # Set display manager (login screen) - displayManager = { - # sddm relies on pkgs.libsForQt5.qt5.qtgraphicaleffects - sddm = { - enable = true; - wayland.enable = true; # experimental - theme = "corners"; - }; - defaultSession = - "hyprland" - + ( - if config.programs.hyprland.withUWSM - then "-uwsm" - else null - ); - }; - - # Multimedia Framework - # With backwards compatability for alsa/pulseaudio/jack - pipewire = { - enable = true; - wireplumber.enable = true; - - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - jack.enable = true; - }; - }; - - # ---- ENVIRONMENT ---- - environment = { - sessionVariables = { - # Hint Electron apps to use support Wayland - NIXOS_OZONE_WL = "1"; - }; - }; - - # ---- SYSTEM PACKAGES ---- - environment.systemPackages = with pkgs; [ - # User Environment - swww - helvum - easyeffects - pavucontrol - hyprpicker # colour picking utility - hyprshot # screenshot utility - qbittorrent - signal-desktop # MAKE THIS ONLY FOR THE DESKTOP FOR END USERS, NOT SERVERS - kdePackages.gwenview # image viewer - libreoffice - wl-clipboard # clipboard for wayland - ]; - - security.rtkit.enable = true; # I *think* this is for pipewire -} diff --git a/lib/csystem.nix b/lib/csystem.nix deleted file mode 100644 index 64e3aa3..0000000 --- a/lib/csystem.nix +++ /dev/null @@ -1,330 +0,0 @@ -# Copyright 2025 Emile Clark-Boman -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -{ - inputs, - lib, - config, - pkgs, - pkgs-unstable, - homemanager, - cerulean, - ... -} @ args: let - getModule = name: "../modules/nixos/${name}.nix"; - getModules = map (x: getModule x); - - getHostModule = name: "TODO"; -in { - imports = getModules [ - (getHostModule "hardware-configuration") - (import "${homemanager}/nixos") - - "shell/bash" - "shell/bash/bashistrans.nix" - "shell/zsh" - "shell/fish" - - "cli/git" - "cli/bat" - "cli/btop" - "cli/tmux" - "cli/nvim" - - "lang/asm" - "lang/bash" # TODO: (YES THIS IS DIFFERENT TO shell/bash, this provides language support ie pkgs.shellcheck) - "lang/c-family" - "lang/dotnet" - # "lang/go" - # "lang/haskell" - # "lang/java" - # "lang/nim" - "lang/python" - # "lang/rust" - # "lang/sage" - - "editor/helix" - ]; - - nix.settings = { - # REF: https://nix.dev/manual/nix/2.24/development/experimental-features - experimental-features = [ - # Significant - "flakes" - "nix-command" - "pipe-operators" - - # Minor - "no-url-literals" - "parse-toml-timestamps" - "recursive-nix" - ]; - - download-buffer-size = 524288000; # 500 MiB - - # making wheel group members "trusted users" allows - # them to import packages not signed by a trusted key - # (aka super duper easier to remote deploy) - trusted-users = ["root" "@wheel"]; - }; - - nixpkgs = { - overlays = cerulean.lib.importOverlaysNixOS; - - config = if config.cerulean.allowUnfreeWhitelist != [] - then { - allowUnfreePredicate = - pkg: builtins.elem - (lib.getName pkg) - config.cerulean.allowUnfreeWhitelist; - } - else { - allowUnfree = config.cerulean.allowUnfree; - }; - }; - - # colmena deployment configuration - deployment = { - targetHost = config.cerulean.domain ?? config.cerulean.ip; - targetUser = "cerulean"; - targetPort = "22"; - sshOptions = [ - "-A" # forward ssh-agent - ]; - buildOnTarget = false; # build locally then deploy - }; - - - time.timeZone = config.cerulean.timeZone; - i18n.defaultLocale = "en_US.UTF-8"; - - # Enable initrd hook for virtual console customisation - # aka cool colours when booting yay!! - console = { - enable = true; - earlySetup = true; # initrd pre hook - keyMap = "us"; - font = "Lat2-Terminus16"; - # ANSI 24-bit color definitions (theme: dracula) - colors = [ - "21222c" - "ff5555" - "50fa7b" - "f1fa8c" - "bd93f9" - "ff79c6" - "8be9fd" - "f8f8f2" - "6272a4" - "ff6e6e" - "69ff94" - "ffffa5" - "d6acff" - "ff92df" - "a4ffff" - "ffffff" - ]; - }; - - # super duper minimum grub2 config - boot.loader = { - efi = { - canTouchEfiVariables = true; - efiSysMountPoint = "/boot/efi"; - }; - - grub = { - enable = true; - device = "nodev"; - }; - - # GitHub: vinceliuice/grub2-themes - grub2-theme = { - enable = true; - theme = "whitesur"; # stylish, vimix, or whitesur - footer = true; - # TODO: switch my cables to switch default grub display - customResolution = "3840x2160"; - }; - }; - - networking = { - hostName = config.cerulean.hostname; - networkmanager.enable = true; - - firewall = { - enable = true; - allowedTCPPorts = [ - 22 # sshd - 80 # nginx (http) - 443 # nginx (https) - # 5678 # MikroTik WinBox - ]; - }; - }; - - # ------- USERS ------- - security.sudo.wheelNeedsPassword = true; - users = { - defaultUserShell = pkgs.bash; - - users = cerulean.lib.importUsersNixOS; - }; - - home-manager = { - users = cerulean.lib.importUsersHomeManager; - - extraSpecialArgs = { inherit inputs pkgs pkgs-unstable; }; - sharedModules = []; - }; - - # ---- ENVIRONMENT ---- - environment = { - # always install "dev"/"man" derivation outputs - extraOutputsToInstall = ["dev" "man"]; - - systemPackages = with pkgs; [ - # User Environment - bluetui - - # Shell - bash - fish - shellcheck - grc # colorise command outputs - moreutils - - # Systems Programming & Compilation - qemu # Fellice Bellard's Quick Emulator - # GNU Utils - gnumake - # Binaries - binutils - strace - ltrace - perf-tools # ftrace + perf - radare2 - gdb - # ASM - nasm - (callPackage ../packages/x86-manpages {}) - # C Family - gcc - clang - clang-tools - - # Rust - cargo - rustc - # Go - go - # Nim - nim - nimble - # Haskell - ghc - ghcid - haskell-language-server - ormolu - - # Python - python312 # I use 3.12 since it's in a pretty stable state now - python314 # also 3.14 for latest features - poetry - - openvpn - inetutils - - # security tools - nmap - - httpie - curlie - zoxide - doggo - tldr - btop - eza - yazi - lazygit - ripgrep - viddy # modern `watch` command - thefuck - - # TODO: once upgraded past Nix-24.07 this line won't be necessary (I think) - # helix will support nixd by default - # SOURCE: https://github.com/nix-community/nixd/blob/main/nixd/docs/editor-setup.md#Helix - # nixd # lsp for nix # DEBUG - - # Pretty necessary - nix-prefetch-git - brightnessctl - acpi - powertop - imagemagick - - # "Standard" Unix Commands - vim - file - wget - tree - pstree - unzip - unrar-free - lz4 - man-pages - man-pages-posix - - # Cryptography - gnupg - openssl - libargon2 - ]; - }; - - programs = { - nix-ld.enable = true; - }; - - documentation = { - enable = true; - doc.enable = true; # install /share/doc packages - man.enable = true; # install manpages - info.enable = true; # install GNU info - dev.enable = true; # install docs intended for developers - nixos = { - enable = true; # install NixOS documentation (ie man -k nix, & nixos-help) - options.splitBuild = true; - # includeAllModules = true; - }; - }; - - virtualisation.docker.enable = true; - - - hardware = { - graphics = { - enable = true; - enable32Bit = true; - }; - - bluetooth = let - btSupported = config.cerulean.bluetoothSupported; - in { - enable = btSupported; - powerOnBoot = btSupported; - }; - }; - - system.stateVersion = config.cerulean.stateVersion; # DO NOT MODIFY -} diff --git a/lib/cuser.nix b/lib/cuser.nix deleted file mode 100644 index f602e03..0000000 --- a/lib/cuser.nix +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2025 Emile Clark-Boman -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -{ - lib, - config, - pkgs, - pkgs-unstable, - ... -} @ args: let - getModule = name: "../modules/homemanager/${name}.nix"; - getModules = map (x: getModule x); -in { - imports = getModules [ - "shell/fish" - - "cli/git" - "cli/bat" - "cli/btop" - "cli/tmux" - - "editor/helix" - ]; - - nixpkgs.config.allowUnfreePredicate = pkg: - builtins.elem (lib.GetName pkg) [ - "vscode-extension-ms-dotnettools-csharp" - ]; - - home = { - stateVersion = config.cerulean.stateVersion; # DO NOT MODIFY - - username = config.cerulean.username; - homeDirectory = "/home/${config.cerulean.username}"; - - shellAliases = { - rg = "batgrep"; # bat + ripgrep - man = "batman"; # bat + man - }; - - sessionVariables = { - NIX_SHELL_PRESERVE_PROMPT = 1; - }; - - packages = with pkgs; [ - # for services.gnome-keyring - gcr # provides org.gnome.keyring.SystemPrompter - speedtest-cli - ]; - }; - - programs = { - home-manager.enable = true; - - zsh = { - enable = true; - enableCompletion = true; - autosuggestion.enable = true; - syntaxHighlighting.enable = true; - - history = { - size = 10000; - ignoreAllDups = true; - path = "$HOME/.zsh_history"; - ignorePatterns = [ - "rm *" - ]; - }; - }; - - # set ssh profiles - # NOTE: (IMPORTANT) this DOES NOT start the ssh-agent - # for that you need to use `services.ssh-agent.enable` - ssh = { - enable = true; - forwardAgent = false; - addKeysToAgent = "no"; - }; - }; - - services = { - # enable OpenSSH private key agent - ssh-agent.enable = true; - - gnome-keyring.enable = true; - }; - - # the ssh-agent won't set this for itself... - systemd.user.sessionVariables.SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/ssh-agent"; - # Nicely reload system units when changing configs - systemd.user.startServices = "sd-switch"; -}