Compare commits

..

25 commits

Author SHA1 Message Date
087f679e67 add modifiable homeManager 2026-02-18 23:56:05 +10:00
d5211287bd TEMP: use base 2026-02-18 20:13:43 +10:00
18e1a2c890 don't add pkgs to _module.args 2026-02-18 20:13:36 +10:00
232837d34a update TODO 2026-02-18 20:13:05 +10:00
f34c2fba39 rename base -> decl (easily confusable) 2026-02-18 20:12:58 +10:00
870bbb1f37 i cried 2026-02-18 17:24:28 +10:00
0c5387fd61 nixpkgs.channels disregards contextName 2026-02-17 17:27:31 +10:00
d85a6b963f restruct args into specialArgs._cerulean 2026-02-17 17:10:43 +10:00
59d1028e19 add CHANGELOG.md 2026-02-17 12:41:53 +10:00
04d6bd04c3 v0.2.2-alpha 2026-02-17 11:48:10 +10:00
0d85fe39a6 rename extraModules -> modules 2026-02-17 11:48:10 +10:00
af1da3dbc3 rename specialArgs -> args 2026-02-17 11:48:10 +10:00
ce996f9956 update construction README 2026-02-17 11:48:10 +10:00
c5ef764e27 update README 2026-02-17 11:48:10 +10:00
a2ac6b5da3 ok maybe leave nixpkgs...
we won't depend on it (i force that)
but it's good to allow following
2026-02-17 11:48:10 +10:00
fd3b11c7cf force system to be specified 2026-02-17 11:48:10 +10:00
272b03aa6e update TODO 2026-02-17 11:48:10 +10:00
dc37c482a8 remove nixpkgs dependency
YIPPIE YIPPIE YIPPIE
2026-02-17 11:48:10 +10:00
8dc975fc89 fix dont use microvm.nixosModules.microvm by default 2026-02-17 11:48:10 +10:00
c24cc9d46f fix [] ++ {} (im oopid) 2026-02-17 11:48:09 +10:00
803f759472 fix self not propagated 2026-02-17 11:48:09 +10:00
2cff3119cd fix nt not propagated 2026-02-17 11:48:09 +10:00
9127e64fed more TODO.md 2026-02-17 11:48:09 +10:00
e07047ab50 move nixos-modules/ -> nixos/ 2026-02-17 11:48:09 +10:00
c5c867b43f always use root group 2026-02-17 11:48:09 +10:00
15 changed files with 545 additions and 250 deletions

25
CHANGELOG.md Normal file
View file

@ -0,0 +1,25 @@
# Changelog
## v0.2.0-alpha
Initial "stable" release. Cerulean is currently usable and supports:
1. local & remote deployment configuration
2. nixos/homemanager module-level support for any number of nixpkg branches
3. use of the [nix-systems standard](https://github.com/nix-systems/nix-systems), the introduction of the `snow/flake` standard, and the introduction of the `nixpkgs.nix` standard module.
4. hierarchical groups for NixOS hosts via `snow.nix`
This is still a alpha-build of Cerulean. Everything will break in the future as I change the internals a bunch. I'll aim to write documentation in future cause currently there's no guide.
## v0.2.1-alpha
Minor patches
- cerulean no longer has a `inputs.nixpkgs-unstable` (the `nixpkgs.nix` is the new alternative)
- `home-manager.nixosModules.default` and `microvm.nixosModules.microvm` are added as default modules
- fixed `groups.all` not being added to nodes with `groups = []`
## v0.2.2-alpha
Minor patches
- fixed `nexus.groups.all` not added to empty `nexus.nodes.*.groups` declarations
- fixed bad propagation of inputs
- forced system architecture to be specified per node
- cerulean no longer depends on `nixpkgs`, `base` package set should be set instead
- rename `extraModules` -> `modules`
- rename `specialArgs` -> `args`

View file

@ -1,19 +1,51 @@
![enbyware](https://pride-badges.pony.workers.dev/static/v1?label=enbyware&labelColor=%23555&stripeWidth=8&stripeColors=FCF434%2CFFFFFF%2C9C59D1%2C2C2C2C)
![repo size](https://img.shields.io/github/repo-size/cry128/cerulean)
>[!WARNING] >[!WARNING]
> ✨ **Under Construction** > ✨ **Under Construction**
> Cerulean has lived rent free in my head for the last 12 months. >
> I'm developing this project for personal use and especially > Cerulean is in an **experimental alpha release stage**.<br/>
> for use at my workplace. **Be not afraid!** It's only a matter > **Be not afraid!** It's only a matter of time until Cerulean is ready for use!
> of time until Cerulean is ready for use! >
> If you're curious about or want to use Cerulean then<br/>
> *please please please* contact me on Bluesky [@dobutterfliescry.net](https://bsky.app/profile/dobutterfliescry.net).<br/>
> (i would actually *melt* and fall in love with you...)
# 🌌 🚀 Cerulean Nexus
The culmination of 2 years designing better Nix flakes. Cerulean removes the boilerplate of managing
NixOS infrastructure by declaring each machine as a **node** and their relationships as *"Nexus Networks"*,
virtual networks of servers that Cerulean can manage. Each Nexus is **very powerful**. Allowing for simple
distributed computing, automatic construction of VPNs, DNS for local hostnames, and that's just scratching the surface...
- Is your node a VPS? Set `deploy.ssh.host = "example.com"` and Cerulean will configure custom build users,
ssh deployment via custom PAM modules, etc etc
- Is your node a VM? Set `vms = [ nodes.VM_NODE ]` on your host node, and Cerulean will configure
all the bridging, NAT, and other networking you so desire!
## 🩷💜 Motivation
Nix is intended as a non-restrictive & unopinionated system, which is amazing, but it also means
every user develops their own standards to simplify their config. Cerulean however is very much
opinionated and contains all the standards I personally believe should be sane defaults for every NixOS machine.
> Flakes are not designed for NixOS, they're designed for Nix, and that's an important distinction.
Flakes and NixOS don't offer anything to simplify managing interconnected nodes of machines.
But this ends with *extremely messy configs* with **a lot of footguns**. You shouldn't have to spend
days reading about networking and learning to work with other peoples' modules.
Finally, the Nix module system assumes you only use one channel of `github:NixOS/nixpkgs` but this
just isn't realistic. Most people have both `inputs.nixpkgs` and `inputs.nixpkgs-unstable` defined.
So cerulean declares the `nixpkgs.channels.*` option so you don't have to import your channels
manually!
## 💙 Same Colour, More Control ## 💙 Same Colour, More Control
Cerulean is what you wish Azure could be. An expansive collection of microservices, pre-configured systems, >[!NOTE]
> This section is *mostly* for the business minded people.
Cerulean is what you wish Azure could be. Providing an expansive collection of microservices, pre-configured systems,
and entirely self-hosted! Cerulean is built using NixOS as a foundation so you know it's never going to break randomly. and entirely self-hosted! Cerulean is built using NixOS as a foundation so you know it's never going to break randomly.
NixOS backing makes Cerulean **extremely scalable**! Just rent a new VPS and Cerulean will build an ISO of your configuration. NixOS backing makes Cerulean **extremely scalable**! Just rent a new VPS and Cerulean will build an ISO of your configuration.
No stress, no hassle! No stress, no hassle!
Say goodbye to Azure! And say goodbye to Kubernetes! You're taking life into your own hands 💙 Say goodbye to Azure! And say goodbye to Kubernetes! You're taking life into your own hands 💙
### 🌌 🚀 Nexus
Cerulean allows you to declare *"Nexus Networks"*, virtual networks of servers that Cerulean can manage.
Each Nexus is **very powerful**. Allowing for simple distributed computing, automatic construction of a wireguard
VPN, distributed DNS for local hostnames, and that's just scratching the surface...

60
TODO.md
View file

@ -1,14 +1,64 @@
- [ ] base should automatically be set as the default (dont do anything with the default)
- [ ] try to remove common foot guns, ie abort if the user provides the home-manager or microvm nixosModules
since cerulean ALREADY provides these
- [ ] deploy port should default to the first port given to `services.openssh`
- [ ] use the Nix module system instead of projectOnto for `cerulean.mkNexus` - [ ] 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 - [ ] 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 github:microvm-nix/microvm.nix
- [ ] add support for sops-nix - [ ] add support for sops-nix
- [ ] create an alternative to nixos-install called cerulean-install that - [ ] it would be cool to enable/disable groups and hosts
allows people to easily bootstrap new machines - [ ] 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
- [X] rename extraModules to modules?
- [X] 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)
- [ ] rename nixos-modules/ to nixos/ - [ ] 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
- [ ] add the ceru-build user - [ ] rewrite the ceru cli in rust
- [ ] ensure all machines are in groups.all by default - [ ] make `ceru` do local and remote deployments
- [ ] support `legacyImports`
```nix
# REF: foxora
vms = {
home-assistant = {
autostart = true;
# matches in vms/*
image = "home-assistant";
options = {
mem = 2048;
};
};
equinox = {
image = "home-assistant";
};
};
```

View file

@ -21,11 +21,11 @@ mix.newMixture args (mixture: {
./nexus ./nexus
]; ];
version = "0.2.1"; version = "0.2.2";
nixosModules = rec { nixosModules = rec {
default = cerulean; default = cerulean;
cerulean = ./nixos-module; cerulean = ./nixos;
}; };
overlays = [ overlays = [

View file

@ -15,12 +15,12 @@
self, self,
this, this,
nt, nt,
lib,
inputs, inputs,
... ...
}: let }: let
inherit inherit
(builtins) (builtins)
all
attrNames attrNames
concatLists concatLists
concatStringsSep concatStringsSep
@ -50,15 +50,11 @@
(nt.naive.terminal) (nt.naive.terminal)
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 { in {
extraModules = []; base = null;
specialArgs = Terminal {}; modules = [];
args = Terminal {};
homeManager = null;
groups = Terminal {}; groups = Terminal {};
nodes = Terminal {}; nodes = Terminal {};
@ -96,15 +92,15 @@
assert isAttrs nexus assert isAttrs nexus
|| abort '' || abort ''
Cerulean Nexus config must be provided as an attribute set, got "${typeOf nexus}" instead! 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 ''; let
base = nt.projectOnto templateNexus nexus; decl = nt.projectOnto templateNexus nexus;
in in
# XXX: TODO: create a different version of nt.projectOnto that can actually # XXX: TODO: create a different version of nt.projectOnto that can actually
# XXX: TODO: handle applying a transformation to the result of each datapoint # XXX: TODO: handle applying a transformation to the result of each datapoint
base decl
// { // {
groups = parseGroupDecl base.groups; groups = parseGroupDecl decl.groups;
}; };
parseDecl = outputsBuilder: let parseDecl = outputsBuilder: let
@ -133,7 +129,14 @@
Cerulean Nexus node "${nodeName}" does not declare group membership as a list, got "${typeOf node.groups}" instead! 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 `nexus.nodes.${nodeName}.groups` is a list under your call to `cerulean.mkNexus`.
''; '';
node.groups # ensure root group is always added
(node.groups
++ [
{
_parent = null;
_name = ROOT_GROUP_NAME;
}
])
# ensure all members are actually groups # ensure all members are actually groups
|> map (group: let |> map (group: let
got = got =
@ -181,38 +184,63 @@ in {
customOutputs = removeAttrs decl ["nexus"]; customOutputs = removeAttrs decl ["nexus"];
outputs = rec { outputs = rec {
nixosConfigurations = mapNodes nexus.nodes ( nixosConfigurations = mapNodes nexus (
nodeName: node: let {
nixosDecl = lib.nixosSystem { base,
system = node.system; lib,
specialArgs = let nodeName,
specialArgs = node,
nexus.specialArgs ...
// node.specialArgs }: let
// { nixosDecl = let
inherit root specialArgs; homeManager =
if node.homeManager != null
then node.homeManager
else nexus.homeManager;
userArgs = nexus.args // node.args;
ceruleanArgs = {
inherit root base;
inherit (node) system; inherit (node) system;
_deploy-rs = inputs.deploy-rs; _cerulean = {
inherit inputs userArgs ceruleanArgs homeManager;
specialArgs = userArgs // ceruleanArgs;
}; };
};
specialArgs = assert (userArgs
|> attrNames
|> all (argName:
! ceruleanArgs ? argName
|| abort ''
`specialArgs` are like super important to Cerulean my love... </3
But `args.${argName}` is a reserved argument name :(
''));
ceruleanArgs._cerulean.specialArgs;
in in
specialArgs; lib.nixosSystem {
inherit (node) system;
inherit specialArgs;
modules = modules =
[ [
self.nixosModules.default self.nixosModules.default
(findImport (root + "/hosts/${nodeName}")) (findImport (root + "/hosts/${nodeName}"))
inputs.home-manager.nixosModules.default # inputs.microvm.nixosModules.microvm
inputs.microvm.nixosModules.microvm
] ]
++ (homeManager.nixosModules.default or [])
++ (getGroupModules root nodeName node) ++ (getGroupModules root nodeName node)
++ node.extraModules ++ node.modules
++ nexus.extraModules; ++ nexus.modules;
}; };
in in
nixosDecl nixosDecl
); );
deploy.nodes = mapNodes nexus.nodes (nodeName: node: let deploy.nodes = mapNodes nexus ({
nodeName,
node,
...
}: let
inherit inherit
(node.deploy) (node.deploy)
activationTimeout activationTimeout

View file

@ -25,11 +25,22 @@ in rec {
(nt.naive.terminal) (nt.naive.terminal)
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 { in {
system = "x86_64-linux"; # sane default (i hope...) enabled = true;
system = missing "its system architecture" "system";
groups = []; groups = [];
extraModules = []; modules = [];
specialArgs = Terminal {}; args = Terminal {};
homeManager = null;
base = null;
deploy = { deploy = {
user = "root"; user = "root";
@ -66,7 +77,25 @@ in rec {
in in
nt.projectOnto templateAttrs nodeAttrs; nt.projectOnto templateAttrs nodeAttrs;
mapNodes = nodes: f: mapNodes = nexus: f:
nodes nexus.nodes
|> mapAttrs (nodeName: nodeAttrs: f nodeName (parseNode nodeName nodeAttrs)); |> 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 base;
inherit (base) lib;
});
} }

108
cerulean/nexus/snow.nix Normal file
View file

@ -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 {
modules = mkOption {
type = types.listOf types.path;
};
args = 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 = {
};
}

View file

@ -1,101 +0,0 @@
# 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 {};
};
}

View file

@ -0,0 +1,36 @@
# 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,
_cerulean,
...
} @ args: {
imports =
[
# user configuration
(import (root + "/nixpkgs.nix"))
# options declarations
(import ./nixpkgs.nix (args // {contextName = "hosts";}))
]
++ (
if _cerulean.homeManager != null
then [./home-manager.nix]
else []
);
environment.systemPackages = with _cerulean.inputs; [
deploy-rs.packages.${system}.default
];
}

View file

@ -13,10 +13,9 @@
# limitations under the License. # limitations under the License.
{ {
root, root,
system,
config, config,
lib, lib,
specialArgs, _cerulean,
... ...
} @ args: let } @ args: let
inherit inherit
@ -26,25 +25,21 @@
pathExists pathExists
; ;
in { in {
config = {
home-manager = { home-manager = {
users = users =
config.users.users config.users.users
|> attrNames |> attrNames
|> filter (x: pathExists (root + "/homes/${x}")) |> filter (x: pathExists (root + "/homes/${x}"))
|> (x: lib.genAttrs x (y: import (root + "/homes/${y}"))); |> (x:
lib.genAttrs x (y:
import (root + "/homes/${y}")));
extraSpecialArgs = {inherit root system;} // (specialArgs.inputs or {}); extraSpecialArgs = _cerulean.specialArgs;
sharedModules = [ sharedModules = [
# user configuration # user configuration
(import (root + "/nixpkgs.nix")) (import (root + "/nixpkgs.nix"))
# options declarations # options declarations
(import ./nixpkgs.nix (args // {contextName = "homes";})) (import ./nixpkgs.nix (args // {contextName = "homes";}))
]; ];
# disable home-manager trying anything fancy
# we control the pkgs now!!
# useGlobalPkgs = true;
};
}; };
} }

View file

@ -11,22 +11,3 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
{
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
];
}

View file

@ -0,0 +1,13 @@
# 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.

View file

@ -0,0 +1,94 @@
# 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.
{
base,
lib,
system,
config,
contextName,
...
}: let
inherit
(builtins)
mapAttrs
;
cfg = config.nixpkgs.channels;
in {
options.nixpkgs.channels = lib.mkOption {
type = lib.types.attrs;
default = {};
description = "Declare package repositories";
example = {
"pkgs" = {
source = "inputs.nixpkgs";
system = "x86-64-linux";
config = {
allowUnfree = true;
allowBroken = false;
};
};
"upkgs" = {
source = "inputs.nixpkgs-unstable";
system = "x86-64-linux";
config = {
allowUnfree = false;
allowBroken = true;
};
};
};
};
config = let
repos =
cfg
|> (xs: removeAttrs xs ["default"])
|> mapAttrs (
name: args:
lib.mkForce (
assert args ? source
|| abort ''
`nixpkgs.channels.${name}` missing required attribute "source"
'';
import args.source ({inherit system;} // (removeAttrs args ["source"]))
)
);
# XXX: TODO: would it work to use `base` instead of having default?
defaultPkgs =
cfg.default or (throw ''
Your `nixpkgs.nix` file does not declare a default package source.
Ensure you set `nixpkgs.channels.*.default = ...;`
'');
in {
# NOTE: _module.args is a special option that allows us to
# NOTE: set extend specialArgs from inside the modules.
# WARNING: pkgs is a reserved specialArg
_module.args = removeAttrs repos ["pkgs"];
nixpkgs =
if contextName == "hosts"
then {
flake.source = lib.mkOverride 200 base; # DEBUG: temp while getting base to work
overlays = lib.mkOverride 200 (defaultPkgs.overlays or {});
config = lib.mkOverride 200 (defaultPkgs.config or {});
}
else if contextName == "homes"
then {
config = lib.mkOverride 200 (defaultPkgs.config or {});
overlays = lib.mkOverride 200 (defaultPkgs.overlays or []);
}
else {};
};
}

81
flake.lock generated
View file

@ -3,7 +3,9 @@
"deploy-rs": { "deploy-rs": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"nixpkgs": "nixpkgs", "nixpkgs": [
"nixpkgs"
],
"utils": "utils" "utils": "utils"
}, },
"locked": { "locked": {
@ -58,6 +60,27 @@
"type": "github" "type": "github"
} }
}, },
"microvm": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"spectrum": "spectrum"
},
"locked": {
"lastModified": 1771365290,
"narHash": "sha256-1XJOslVyF7yzf6yd/yl1VjGLywsbtwmQh3X1LuJcLI4=",
"owner": "microvm-nix",
"repo": "microvm.nix",
"rev": "789c90b164b55b4379e7a94af8b9c01489024c18",
"type": "github"
},
"original": {
"owner": "microvm-nix",
"repo": "microvm.nix",
"type": "github"
}
},
"nix-github-actions": { "nix-github-actions": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -105,38 +128,6 @@
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": {
"lastModified": 1743014863,
"narHash": "sha256-jAIUqsiN2r3hCuHji80U7NNEafpIMBXiwKlSrjWMlpg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bd3bac8bfb542dbde7ffffb6987a1a1f9d41699f",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1768305791,
"narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1768323494, "lastModified": 1768323494,
"narHash": "sha256-yBXJLE6WCtrGo7LKiB6NOt6nisBEEkguC/lq/rP3zRQ=", "narHash": "sha256-yBXJLE6WCtrGo7LKiB6NOt6nisBEEkguC/lq/rP3zRQ=",
@ -152,7 +143,7 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs_3": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1767313136, "lastModified": 1767313136,
"narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=", "narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=",
@ -171,7 +162,7 @@
"nt": { "nt": {
"inputs": { "inputs": {
"nix-unit": "nix-unit", "nix-unit": "nix-unit",
"nixpkgs": "nixpkgs_3", "nixpkgs": "nixpkgs_2",
"systems": "systems_2" "systems": "systems_2"
}, },
"locked": { "locked": {
@ -191,12 +182,28 @@
"root": { "root": {
"inputs": { "inputs": {
"deploy-rs": "deploy-rs", "deploy-rs": "deploy-rs",
"nixpkgs": "nixpkgs_2", "microvm": "microvm",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs": "nixpkgs",
"nt": "nt", "nt": "nt",
"systems": "systems_3" "systems": "systems_3"
} }
}, },
"spectrum": {
"flake": false,
"locked": {
"lastModified": 1759482047,
"narHash": "sha256-H1wiXRQHxxPyMMlP39ce3ROKCwI5/tUn36P8x6dFiiQ=",
"ref": "refs/heads/main",
"rev": "c5d5786d3dc938af0b279c542d1e43bce381b4b9",
"revCount": 996,
"type": "git",
"url": "https://spectrum-os.org/git/spectrum"
},
"original": {
"type": "git",
"url": "https://spectrum-os.org/git/spectrum"
}
},
"systems": { "systems": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,

View file

@ -16,13 +16,12 @@
inputs = { inputs = {
systems.url = "github:nix-systems/default"; systems.url = "github:nix-systems/default";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nt.url = "github:cry128/nt";
home-manager = { # WARNING: nixpkgs is ONLY included so flakes using Cerulean can
url = "github:nix-community/home-manager/release-25.11"; # WARNING: force Cerulean's inputs to follow a specific revision.
inputs.nixpkgs.follows = "nixpkgs"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
};
nt.url = "github:cry128/nt";
deploy-rs = { deploy-rs = {
url = "github:serokell/deploy-rs"; url = "github:serokell/deploy-rs";
@ -36,14 +35,13 @@
}; };
outputs = { outputs = {
nixpkgs, self,
nt, nt,
... ...
} @ inputs: } @ inputs:
import ./cerulean import ./cerulean
{ {
inherit inputs; inherit inputs self nt;
inherit (nixpkgs) lib;
inherit (nt) mix; inherit (nt) mix;
}; };
} }