Compare commits

...

336 Commits

Author SHA1 Message Date
DavHau
a0b16e30b6 wireguard: optional internet access for external peers
Add an option to allow external peers to route all their internet traffic through a controller.

Also add options to enable ipv4 and assign v4 addresses manually as this is needed for proper internet access for some regions
2025-10-21 11:49:37 +07:00
DavHau
9e36b00b48 wireguard: make external peers connect to all controllers 2025-10-21 11:49:37 +07:00
DavHau
c48be6b34f wireguard/test: update vars 2025-10-21 11:49:37 +07:00
DavHau
6a3f5e077b wireguard: add support for external peers
This adds support for external peers via the instance option `roles.controller.<name>.settings.externalPeers = ["external1"]`.

External peers are peers which are not associated wth a machine inside the clan, for example a mobile phone or a device that cannot be managed via clan for some reason.
2025-10-21 11:49:37 +07:00
hsjobeki
0d088cac7e Merge pull request 'modules-1' (#5598) from modules-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5598
2025-10-20 16:56:29 +00:00
Johannes Kirschbauer
3ffad3f97f inventory: add docs for available specialArgs in service submodules 2025-10-20 16:53:56 +00:00
Johannes Kirschbauer
3d0c281fd6 inventory: add clanLib to specialArgs 2025-10-20 16:53:56 +00:00
Mic92
5b399fd447 Merge pull request 'vars: respect deploy flag for shared secrets' (#5572) from oneingan/clan-core:vars-no-deploy into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5572
2025-10-20 15:37:03 +00:00
clan-bot
bfedc93f2c Merge pull request 'Update test-fixtures in devFlake' (#5597) from update-devFlake-test-fixtures into main 2025-10-20 15:06:46 +00:00
clan-bot
c63e706fe9 Merge pull request 'Update nixpkgs-dev in devFlake' (#5596) from update-devFlake-nixpkgs-dev into main 2025-10-20 15:06:26 +00:00
clan-bot
dfc241c62d Update test-fixtures in devFlake 2025-10-20 15:01:44 +00:00
clan-bot
6fcdc05911 Update nixpkgs-dev in devFlake 2025-10-20 15:01:40 +00:00
hsjobeki
137f22b39e Merge pull request 'docs: add docs for clanLib' (#5594) from inventory-fixes-3 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5594
2025-10-20 14:24:57 +00:00
Johannes Kirschbauer
9857a395f1 docs: add docs for clanLib 2025-10-20 14:57:10 +02:00
hsjobeki
4302b06715 Merge pull request 'docs: add docs for finalSettings' (#5593) from inventory-fixes-3 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5593
2025-10-20 12:46:06 +00:00
Johannes Kirschbauer
064bc43f27 docs: add docs for finalSettings 2025-10-20 14:41:06 +02:00
hsjobeki
7ab1b6823f Merge pull request 'inventory: expose finalSettings of every machine' (#5581) from inventory-fixes-3 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5581
2025-10-20 12:38:50 +00:00
Johannes Kirschbauer
f96a487bc3 inventory: expose finalSettings of every machine 2025-10-20 14:32:49 +02:00
Mic92
e6a1953785 Merge pull request 'ci/build-clan-app: drop --system' (#5592) from mic92-patch-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5592
2025-10-20 12:30:03 +00:00
Mic92
4bedb380b8 ci/build-clan-app: drop --system
this changes nix into believing it can run darwin, when it cannot, it should however do remote builds
2025-10-20 12:27:12 +00:00
clan-bot
3b070ae1f3 Merge pull request 'Update treefmt-nix' (#5587) from update-treefmt-nix into main 2025-10-20 10:10:25 +00:00
clan-bot
bdb0a97285 Merge pull request 'Update flake-parts' (#5586) from update-flake-parts into main 2025-10-20 10:10:03 +00:00
clan-bot
a0cce07259 Merge pull request 'Update treefmt-nix in devFlake' (#5588) from update-devFlake-treefmt-nix into main 2025-10-20 10:09:53 +00:00
clan-bot
1edf576702 Update treefmt-nix in devFlake 2025-10-20 10:01:43 +00:00
clan-bot
7824ee99cb Update treefmt-nix 2025-10-20 10:01:21 +00:00
clan-bot
13c20242ad Update flake-parts 2025-10-20 10:00:47 +00:00
clan-bot
ba81b1ae12 Merge pull request 'Update nixpkgs-dev in devFlake' (#5585) from update-devFlake-nixpkgs-dev into main 2025-10-20 05:07:22 +00:00
clan-bot
7eb54b6564 Update nixpkgs-dev in devFlake 2025-10-20 05:01:42 +00:00
clan-bot
5c007edd9f Merge pull request 'Update treefmt-nix' (#5583) from update-treefmt-nix into main 2025-10-19 20:07:55 +00:00
clan-bot
03ba598842 Merge pull request 'Update treefmt-nix in devFlake' (#5584) from update-devFlake-treefmt-nix into main 2025-10-19 20:07:52 +00:00
clan-bot
d699f0b66a Update treefmt-nix in devFlake 2025-10-19 20:01:46 +00:00
clan-bot
65e599b92a Update treefmt-nix 2025-10-19 20:01:21 +00:00
hsjobeki
788f8beea4 Merge pull request 'inventory: remove role.settings' (#5579) from inventory-fixes-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5579
2025-10-19 16:54:31 +00:00
hsjobeki
da8768c4c0 Merge pull request 'helloWorld: bring back example code' (#5582) from dos into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5582
2025-10-19 16:12:00 +00:00
Johannes Kirschbauer
eb11054f65 helloWorld: bring back example code 2025-10-19 18:07:14 +02:00
clan-bot
5922b4617c Merge pull request 'Update nixpkgs-dev in devFlake' (#5580) from update-devFlake-nixpkgs-dev into main 2025-10-19 15:06:11 +00:00
clan-bot
5286994288 Update nixpkgs-dev in devFlake 2025-10-19 15:01:39 +00:00
pinpox
8ad025b462 Merge pull request 'Fix deprecated test names' (#5575) from fix-borgbackup-vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5575
Reviewed-by: Kenji Berthold <aks.kenji@protonmail.com>
Reviewed-by: hsjobeki <hsjobeki@gmail.com>
2025-10-19 14:47:22 +00:00
Johannes Kirschbauer
4442cb2fe0 inventory: remove role.settings
Within a clan.service the module can access 'role.peer.settings' and 'role.peer.machine.jon.settings'
While the current machine is jon, accessing the role settings is arguably a design mistake.
I didn't catch that problem, unfortunately this might be a breaking change
2025-10-19 16:43:21 +02:00
hsjobeki
460c6d4fc9 Merge pull request 'inventory: fix internal indentifier' (#5576) from inventory-fixes-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5576
2025-10-19 14:25:45 +00:00
pinpox
893fa47a50 Run treefmt 2025-10-19 15:17:41 +02:00
pinpox
62d3a18783 clanServices/wireguard: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 15:09:42 +02:00
pinpox
ac1cd5114a clanServices/admin: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 15:07:25 +02:00
pinpox
e0b5855013 clanServices/trusted-nix-caches: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 15:01:39 +02:00
pinpox
4fd057413f clanServices/sshd: fix deprecated test name
- fix test name to new format
- regenrate vars via update-vars
2025-10-19 14:59:40 +02:00
pinpox
96fcc41b19 clanServices/zerotier: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:55:03 +02:00
pinpox
811b994d57 clanServices/wireguard: fix deprecated test name
- fix test name to new format
2025-10-19 14:54:01 +02:00
pinpox
87aa62e128 clanServices/wifi: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:53:48 +02:00
pinpox
612275477a clanServices/users: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:52:55 +02:00
pinpox
046cfcb4d7 clanServices/syncthing: fix deprecated test name
- fix test name to new format
2025-10-19 14:52:21 +02:00
pinpox
965d41b37d clanServices/sshd: fix deprecated test name
- fix test name to new format
2025-10-19 14:52:08 +02:00
pinpox
c36935d81a clanServices/packages: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:51:54 +02:00
pinpox
ae4197277a clanServices/mycelium: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:51:22 +02:00
pinpox
0cc7bd7066 clanServices/localbackup: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:50:50 +02:00
pinpox
31f77f7a56 clanServices/hello-world: fix deprecated test name
- fix test name to new format
2025-10-19 14:50:19 +02:00
pinpox
d3d56e83e7 clanServices/garage: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:50:05 +02:00
pinpox
c725fc9fa3 clanServices/dyndns: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:49:27 +02:00
pinpox
7d6d5967dc clanServices/data-mesher: fix deprecated test name
- fix test name to new format
- regenerate vars via update-vars
2025-10-19 14:45:45 +02:00
Johannes Kirschbauer
afcc5d9e26 inventory: fix internal indentifier 2025-10-19 14:32:16 +02:00
hsjobeki
0e9931d749 Merge pull request 'app: typography fixes' (#5574) from ui-fix-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5574
2025-10-19 12:29:18 +00:00
pinpox
b4d1f07ed9 Fix borgbackup test name
- Fix deprecated name structure
- Re-generate vars
2025-10-19 14:26:45 +02:00
Johannes Kirschbauer
0d182f4431 app: fix 'added' tag typography; test linaria 2025-10-19 14:25:25 +02:00
Johannes Kirschbauer
20a6a5684d app: add typography tokens 2025-10-19 14:22:01 +02:00
pinpox
e5967bb0de Merge pull request 'Replace deprecated --fast nixos-rebuild option' (#4042) from deprecate-fast into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4042
2025-10-19 10:49:36 +00:00
pinpox
dcd7b6a8a2 Replace depracated --fast nix option
The option is throwing a deprecation warning on current nix versions.
See for details: https://github.com/NixOS/nixpkgs/issues/417609#issuecomment-2981327326
2025-10-19 12:45:27 +02:00
oneingan
a48451cc8f Merge branch 'main' into vars-no-deploy 2025-10-19 08:01:36 +00:00
clan-bot
7580475cb6 Merge pull request 'Update sops-nix' (#5573) from update-sops-nix into main 2025-10-19 05:06:41 +00:00
clan-bot
ebe7a8ed0b Update sops-nix 2025-10-19 05:01:34 +00:00
Juanjo Presa
c7cee905d1 vars: respect deploy flag for shared secrets 2025-10-18 23:09:31 +02:00
clan-bot
5b7925c079 Merge pull request 'Update treefmt-nix' (#5569) from update-treefmt-nix into main 2025-10-18 20:08:40 +00:00
clan-bot
5e56f746ad Merge pull request 'Update treefmt-nix in devFlake' (#5571) from update-devFlake-treefmt-nix into main 2025-10-18 20:08:25 +00:00
clan-bot
4f5abe32f9 Merge pull request 'Update flake-parts' (#5568) from update-flake-parts into main 2025-10-18 20:08:07 +00:00
clan-bot
64a0dcb37f Merge pull request 'Update nixpkgs-dev in devFlake' (#5570) from update-devFlake-nixpkgs-dev into main 2025-10-18 20:07:35 +00:00
clan-bot
422f3da9df Update treefmt-nix in devFlake 2025-10-18 20:01:47 +00:00
clan-bot
f7e20f70a8 Update nixpkgs-dev in devFlake 2025-10-18 20:01:42 +00:00
clan-bot
cbabcd91ed Update treefmt-nix 2025-10-18 20:01:22 +00:00
clan-bot
5221d34448 Update flake-parts 2025-10-18 20:00:46 +00:00
clan-bot
5ab3c86b68 Merge pull request 'Update nixpkgs-dev in devFlake' (#5566) from update-devFlake-nixpkgs-dev into main 2025-10-18 15:05:13 +00:00
clan-bot
0324f68709 Update nixpkgs-dev in devFlake 2025-10-18 15:01:39 +00:00
clan-bot
7cd14a5959 Merge pull request 'Update nix-darwin' (#5562) from update-nix-darwin into main 2025-10-17 20:07:30 +00:00
clan-bot
a6584023ae Merge pull request 'Update nixpkgs-dev in devFlake' (#5563) from update-devFlake-nixpkgs-dev into main 2025-10-17 20:06:23 +00:00
clan-bot
2f381bf677 Update nixpkgs-dev in devFlake 2025-10-17 20:01:42 +00:00
clan-bot
a1c29f8aed Update nix-darwin 2025-10-17 20:00:49 +00:00
hsjobeki
42eb8e7a05 Merge pull request 'docs: show {internet,tor} in docs; with experimental notice' (#5557) from fix-deletions into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5557
2025-10-17 18:17:08 +00:00
clan-bot
890cd47b2a Merge pull request 'Update disko' (#5561) from update-disko into main 2025-10-17 15:05:38 +00:00
clan-bot
cf4622052d Update disko 2025-10-17 15:00:46 +00:00
Luis Hebendanz
88bf893228 Merge pull request 'docs: Fix missing direnv installation steps' (#5560) from Qubasa/clan-core:fix_nix_direnv_docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5560
2025-10-17 14:46:27 +00:00
Qubasa
0b1f711f2c docs: Fix missing direnv installation steps 2025-10-17 16:44:00 +02:00
Johannes Kirschbauer
39d9f44286 app: init linaria 2025-10-17 11:05:14 +02:00
Johannes Kirschbauer
f91aca959f docs: show {internet,tor} in docs; with experimental notice 2025-10-17 09:37:45 +02:00
clan-bot
8af166b899 Merge pull request 'Update nuschtos in devFlake' (#5556) from update-devFlake-nuschtos into main 2025-10-17 05:04:03 +00:00
clan-bot
61a185f947 Update nuschtos in devFlake 2025-10-17 05:01:45 +00:00
clan-bot
6ad2b0b124 Merge pull request 'Update nixpkgs-dev in devFlake' (#5555) from update-devFlake-nixpkgs-dev into main 2025-10-16 20:06:57 +00:00
clan-bot
b70c20b260 Update nixpkgs-dev in devFlake 2025-10-16 20:01:41 +00:00
Luis Hebendanz
9821e39b06 Merge pull request 'clanServices: add warning if manifest.readme is not set' (#5537) from Qubasa/clan-core:fix_manifest_readmes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5537
2025-10-16 17:12:46 +00:00
Qubasa
2ac65b9c83 clan_lib/modules.py: get_service_readmes now logs an error if the readme is empty 2025-10-16 19:07:49 +02:00
Qubasa
18dc042a0b inventory: Add warning if manifest.readme is missing 2025-10-16 19:07:49 +02:00
Qubasa
7a4a940e83 clanServices: add READMEs to internet and tor modules 2025-10-16 19:07:49 +02:00
Qubasa
df73169392 clanServices: Add missing manifest.readme to some services 2025-10-16 19:07:49 +02:00
clan-bot
50e4b7a2f4 Merge pull request 'Update data-mesher' (#5554) from update-data-mesher into main 2025-10-16 15:06:32 +00:00
clan-bot
e836ff86b4 Update data-mesher 2025-10-16 15:00:45 +00:00
hsjobeki
714bc58573 Merge pull request 'inventoryStore: align class names and methods' (#5551) from fix-deletions into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5551
2025-10-16 11:09:29 +00:00
Johannes Kirschbauer
17c35c4259 persistence: align some more variable names 2025-10-16 13:04:24 +02:00
Johannes Kirschbauer
727474055e persistence: invert all writeability logic into not readonly 2025-10-16 13:01:34 +02:00
Johannes Kirschbauer
892cb1baae inventoryStore: invert writeability terms to readonly 2025-10-16 13:00:21 +02:00
brianmcgee
186656999f Merge pull request 'Update copyright dates in license file' (#5552) from brianmcgee-patch-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5552
2025-10-16 10:58:34 +00:00
brianmcgee
00b7347d00 Update copyright dates in license file 2025-10-16 10:54:54 +00:00
Johannes Kirschbauer
5eb6b703f0 inventoryStore: align class names and methods 2025-10-16 12:50:54 +02:00
hsjobeki
3d436b3c6b Merge pull request 'api: check deletions if possible' (#5538) from fix-deletions into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5538
2025-10-16 10:50:15 +00:00
Johannes Kirschbauer
d78dca47e2 modules: update service test 2025-10-16 12:42:49 +02:00
Johannes Kirschbauer
8254d197f0 api: persistence allow path prefix 2025-10-16 12:42:45 +02:00
Johannes Kirschbauer
a4839f9cf2 api: persistence, fix regressions 2025-10-16 11:57:38 +02:00
DavHau
bb4b43f5be Merge pull request 'sshd: fix crash: attribute 'openssh-cert' missing' (#5546) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5546
2025-10-16 09:56:39 +00:00
DavHau
4c7699b205 sshd: fix crash: attribute 'openssh-cert' missing 2025-10-16 16:50:38 +07:00
DavHau
b7013dc795 Merge pull request 'wireguard/test: move test to service directory' (#5507) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5507
2025-10-16 07:55:53 +00:00
clan-bot
617e4b0ce1 Merge pull request 'Update nixpkgs-dev in devFlake' (#5541) from update-devFlake-nixpkgs-dev into main 2025-10-15 20:08:37 +00:00
clan-bot
600d37682c Update nixpkgs-dev in devFlake 2025-10-15 20:01:40 +00:00
clan-bot
ac4800a7df Merge pull request 'Update nixpkgs-dev in devFlake' (#5540) from update-devFlake-nixpkgs-dev into main 2025-10-15 15:05:45 +00:00
clan-bot
0af64dad01 Update nixpkgs-dev in devFlake 2025-10-15 15:01:48 +00:00
Johannes Kirschbauer
a32a5151dc api: remove unused validation method 2025-10-15 16:19:21 +02:00
Johannes Kirschbauer
16d245b179 api: check deletions if possible 2025-10-15 16:15:54 +02:00
Luis Hebendanz
24ecdb227e Merge pull request 'clan_lib: Add get_service_readmes api function' (#5530) from Qubasa/clan-core:add_get_readme into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5530
2025-10-14 16:59:42 +00:00
Qubasa
867fa5140b clan_lib: Add get_service_readmes api function
Returns the README.md for one or multiple clan services, needed for the
clan ai feature
2025-10-14 18:54:22 +02:00
Luis Hebendanz
891aac8381 Merge pull request 'clan_lib: init platform independent service_runner' (#5382) from service_runner into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5382
2025-10-14 16:47:31 +00:00
Qubasa
2b616575e1 service_runner: Fix starting a service twice 2025-10-14 17:32:21 +02:00
Qubasa
3f07f6ac79 service_runner: add grouping feature 2025-10-14 17:32:21 +02:00
Qubasa
c6b0b114c5 clan_lib: init platform independent service_runner 2025-10-14 17:31:37 +02:00
hsjobeki
8803343ae1 Merge pull request 'persistence: generate properties for data by traversing data' (#5502) from persistence_attributes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5502
2025-10-14 15:27:10 +00:00
hsjobeki
4cfe866079 Merge pull request 'lib/cli: tests collect coverage' (#5528) from test-cov into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5528
2025-10-14 15:23:28 +00:00
Johannes Kirschbauer
8609538756 clan_lib: allow explicit readonly access to inventory attributes 2025-10-14 17:21:39 +02:00
clan-bot
5ea0e7776e Merge pull request 'Update nixpkgs-dev in devFlake' (#5527) from update-devFlake-nixpkgs-dev into main 2025-10-14 15:08:17 +00:00
Johannes Kirschbauer
a296b8a1fe lib/cli: tests collect coverage 2025-10-14 17:07:19 +02:00
clan-bot
ebbbdcaa59 Update nixpkgs-dev in devFlake 2025-10-14 15:01:54 +00:00
Mic92
ccf64d5951 Merge pull request 'fix: handle OSError when age keys are too long to be file paths' (#5523) from clan-secrets into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5523
2025-10-14 14:35:05 +00:00
pinpox
16e20e159f Merge pull request 'Fix module mention in docs generation' (#5526) from fix-docs-service-roles into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5526
2025-10-14 14:18:08 +00:00
pinpox
43a5a5db5a Merge pull request 'Merge pull request 'clanServices: add kde module' (#5487) from desktop-service into main' (#5525) from desktop-service into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5525
2025-10-14 14:14:56 +00:00
pinpox
c1686691fa Fix module mention in docs generation 2025-10-14 16:14:40 +02:00
pinpox
115d0a05b7 Merge pull request 'clanServices: add kde module' (#5487) from desktop-service into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5487
2025-10-14 16:10:55 +02:00
pinpox
4cfef1e21c Merge pull request 'clanServices: add kde module' (#5487) from desktop-service into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5487
2025-10-14 14:08:04 +00:00
pinpox
42e3fea9e5 clanServices: add desktop module 2025-10-14 16:02:20 +02:00
DavHau
6b7530f27d wireguard/test: move test to service directory 2025-10-14 20:34:51 +07:00
DavHau
7e00a08111 Merge pull request 'lib/test/container-test-driver: Fix extraPythonPackages support' (#5491) from ke-test-extra-packages into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5491
2025-10-14 13:33:08 +00:00
Johannes Kirschbauer
0c245f8eda persistence: generate properties for data by traversing data 2025-10-14 14:51:06 +02:00
Jörg Thalheim
9469968851 fix: handle OSError when age keys are too long to be file paths
Prevents "File name too long" errors when users provide age keys directly
to 'clan secrets users add', as Path.is_file() would fail before the key
validation could run.

Fixes: https://git.clan.lol/clan/clan-core/issues/5522
2025-10-14 13:15:54 +01:00
Luis Hebendanz
c2a71fb423 Merge pull request 'docs: add Vaultwarden, Easytier and Nix Cache to community modules' (#5521) from Qubasa/clan-core:add_community_role into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5521
2025-10-14 11:23:50 +00:00
Qubasa
13d3bc9391 docs: add Vaultwarden, Easytier and Nix Cache to community modules 2025-10-14 13:07:18 +02:00
pinpox
3161ab3903 Merge pull request 'Add more community services' (#5517) from doc-community-services-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5517
2025-10-14 10:39:14 +00:00
pinpox
6df67aee00 Add more community services 2025-10-14 12:36:39 +02:00
pinpox
ed9f9c0d9d Merge pull request 'Document community service' (#5515) from doc-community-services into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5515
2025-10-14 10:29:29 +00:00
pinpox
969c17e410 Document community service 2025-10-14 12:27:13 +02:00
Luis Hebendanz
3c7c52e35a Merge pull request 'clan_cli: Add typeAlias support for api.py' (#5509) from Qubasa/clan-core:fix_jsonschema_gen into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5509
2025-10-14 10:21:11 +00:00
pinpox
b0e327e0d1 Merge pull request 'Document community service' (#5513) from doc-community-services into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5513
2025-10-14 10:21:09 +00:00
pinpox
550b374d20 Document community service 2025-10-14 12:17:29 +02:00
Qubasa
23008d1f73 openapi: Add a test for TypeAliasing 2025-10-14 12:06:04 +02:00
hsjobeki
733d80d0b2 Merge pull request 'app: use geist font' (#5508) from fix-font into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5508
2025-10-14 09:48:53 +00:00
Johannes Kirschbauer
9dceddc6c2 app: remove 'condensed' variant 2025-10-14 11:46:28 +02:00
Qubasa
f1747079c8 clan_cli: Add typeAlias support for api.py 2025-10-14 11:30:48 +02:00
Johannes Kirschbauer
ffdcd9b41e app: use geist font
Drop Archivo, ArchivoSemicondensed, CommitMono
in favour of only one
2025-10-14 11:19:57 +02:00
Luis Hebendanz
2ef56aff70 Merge pull request 'Fix sshd docs' (#5492) from Qubasa/clan-core:fix_sshd_docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5492
2025-10-14 08:56:32 +00:00
pinpox
2ca4abbfef Merge pull request 'wireguard/docs: fix nix code in examples' (#5506) from wg-docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5506
Reviewed-by: pinpox <clan@pablo.tools>
2025-10-14 07:06:53 +00:00
clan-bot
1344466097 Merge pull request 'Update sops-nix' (#5504) from update-sops-nix into main 2025-10-14 05:04:24 +00:00
DavHau
b1b68c514d wireguard/docs: fix nix code in examples
This was using outdated syntax
2025-10-14 12:02:59 +07:00
clan-bot
08072b3850 Update sops-nix 2025-10-14 05:01:51 +00:00
clan-bot
67637007a2 Merge pull request 'Update nuschtos in devFlake' (#5503) from update-devFlake-nuschtos into main 2025-10-13 20:11:04 +00:00
clan-bot
558dd55058 Update nuschtos in devFlake 2025-10-13 20:02:04 +00:00
Qubasa
63ccbd7ca7 clanServices: improve sshd docs 2025-10-13 19:56:09 +02:00
hsjobeki
d9f6b7e3fb Merge pull request 'api: prepare persistence_attributes' (#5453) from persistence_attributes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5453
2025-10-13 15:23:03 +00:00
clan-bot
254f9b9c5f Merge pull request 'Update nixpkgs-dev in devFlake' (#5498) from update-devFlake-nixpkgs-dev into main 2025-10-13 15:12:22 +00:00
clan-bot
44ff545436 Merge pull request 'Update sops-nix' (#5496) from update-sops-nix into main 2025-10-13 15:11:34 +00:00
Johannes Kirschbauer
40de60946a api: migrate to use persistence attributes everywhere 2025-10-13 17:04:01 +02:00
clan-bot
f25d17d9c2 Update nixpkgs-dev in devFlake 2025-10-13 15:02:14 +00:00
clan-bot
70233b5e53 Update sops-nix 2025-10-13 15:01:44 +00:00
clan-bot
044d5f1c7d Merge pull request 'Update clan-core-for-checks in devFlake' (#5497) from update-devFlake-clan-core-for-checks into main 2025-10-13 15:01:42 +00:00
clan-bot
389c586a26 Merge pull request 'Update nix-darwin' (#5494) from update-nix-darwin into main 2025-10-13 14:59:12 +00:00
clan-bot
e01a79696b Update clan-core-for-checks in devFlake 2025-10-13 14:30:29 +00:00
clan-bot
aade61b019 Update nix-darwin 2025-10-13 14:29:54 +00:00
Qubasa
6956858d61 clanServices: Fix sshd vars dependency 2025-10-13 16:05:51 +02:00
Michael Hoang
7e7e58eb64 Merge pull request 'Update nixpkgs' (#5211) from update-nixpkgs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5211
2025-10-13 13:19:45 +00:00
Michael Hoang
46f746d09c cli: fix installation test with latest release of nixos-anywhere 2025-10-13 15:06:20 +02:00
clan-bot
56e03d1f25 Update nixpkgs 2025-10-13 14:51:00 +02:00
Kenji Berthold
0343e4b91a Merge branch 'main' into ke-test-extra-packages 2025-10-13 12:31:37 +00:00
a-kenji
137d505c3b lib/test/container-test-driver: Fix extraPythonPackages support
Fix `extraPythonPackages` support in the container test driver.

It triggered the following warning from `nixpkgs`:
```
python3Packages = throw "do not use python3Packages when building Python packages, specify each used package as a separate argument"; # do not remove
```

The following `callPackage` usage triggered the `throw`:

```
hostPackages.python3.pkgs.callPackage
```

The change to a regular `callPackage` i`nvocation fixes this issue.

Added a container test with a popular package to ensure compatibility in the future.

Closes: #5459
2025-10-13 14:19:01 +02:00
DavHau
dd783bdf85 Merge pull request 'vars/sops: stop writing on clan vars check' (#5490) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5490
2025-10-13 11:51:29 +00:00
DavHau
bf41a9ef00 vars/sops: stop writing on clan vars check
This fixes an issue where check_vars() would add machine keys or authorize machines for shared vars.

These write operations should only ever be done on a `clan vars generate`, which `clan vars check` should be a read-only operation
2025-10-13 18:43:49 +07:00
Qubasa
d8c9508507 Revert "Fix ssh docs"
This reverts commit fe8f7e919e.
2025-10-13 13:09:13 +02:00
pinpox
f313ace19a Merge pull request 'Revert SSH docs' (#5488) from revert-ssh-docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5488
2025-10-13 10:56:54 +00:00
pinpox
fe8f7e919e Fix ssh docs 2025-10-13 12:51:42 +02:00
hsjobeki
c64276b64e Merge pull request 'lib: remove unused facts utils' (#5480) from fix-b into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5480
2025-10-13 10:06:42 +00:00
hsjobeki
436da16bf9 Merge pull request 'facts: add bigger migration warnings' (#5484) from fix-c into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5484
2025-10-13 08:11:38 +00:00
Johannes Kirschbauer
1c3282bb63 vars: simplify collectFiles 2025-10-13 10:05:53 +02:00
Johannes Kirschbauer
3c4b3e180e facts: add bigger migration warnings 2025-10-13 10:05:53 +02:00
hsjobeki
3953715b48 Merge pull request 'clan-cli: remove unused test fixture' (#5482) from fix-c into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5482
2025-10-12 16:07:44 +00:00
Johannes Kirschbauer
7b95fa039f clan-cli: remove unused test fixture 2025-10-12 18:00:52 +02:00
Johannes Kirschbauer
347668a57f lib: remove unused facts utils 2025-10-12 17:49:05 +02:00
Johannes Kirschbauer
63fdc13928 persist: add attributes props to accumulator 2025-10-12 17:45:14 +02:00
Johannes Kirschbauer
9b0557803e introspection: update test 2025-10-12 17:45:14 +02:00
Johannes Kirschbauer
c13879ce69 persist: rename write map to attribute map 2025-10-12 17:45:14 +02:00
Johannes Kirschbauer
f57bc30c5a persist/writeability: rename non_writeable to readonly 2025-10-12 17:45:14 +02:00
hsjobeki
38712d6fe0 Merge pull request 'clan-core/nixos: remove autoloading magic in favour of simple code' (#5476) from fix-a into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5476
2025-10-12 14:39:17 +00:00
Johannes Kirschbauer
1d38ffa9c2 inventory: unit test autoloading with a virtual fs 2025-10-12 16:32:55 +02:00
clan-bot
665f036dec Merge pull request 'Update clan-core-for-checks in devFlake' (#5478) from update-devFlake-clan-core-for-checks into main 2025-10-12 00:12:04 +00:00
clan-bot
b74b6ff449 Update clan-core-for-checks in devFlake 2025-10-12 00:01:53 +00:00
clan-bot
9c8797e770 Merge pull request 'Update clan-core-for-checks in devFlake' (#5477) from update-devFlake-clan-core-for-checks into main 2025-10-11 20:12:29 +00:00
clan-bot
2be6cedec4 Update clan-core-for-checks in devFlake 2025-10-11 20:01:49 +00:00
Johannes Kirschbauer
7f49449f94 clan-core/nixos: remove autoloading magic in favour of simple code 2025-10-11 18:02:32 +02:00
hsjobeki
1f7bfa4e34 Merge pull request 'inventory: wrap autoloaded machines with correct file' (#5474) from fix-a into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5474
2025-10-11 16:00:37 +00:00
clan-bot
67fab4b11d Merge pull request 'Update clan-core-for-checks in devFlake' (#5475) from update-devFlake-clan-core-for-checks into main 2025-10-11 15:11:33 +00:00
clan-bot
18e3c72ef0 Update clan-core-for-checks in devFlake 2025-10-11 15:01:51 +00:00
Johannes Kirschbauer
84d4660a8d inventory: wrap autoloaded machines with correct file 2025-10-11 15:57:42 +02:00
clan-bot
13c3e1411a Merge pull request 'Update nixpkgs-dev in devFlake' (#5472) from update-devFlake-nixpkgs-dev into main 2025-10-11 10:14:29 +00:00
clan-bot
3c3a505aca Merge pull request 'Update clan-core-for-checks in devFlake' (#5471) from update-devFlake-clan-core-for-checks into main 2025-10-11 10:13:33 +00:00
clan-bot
f33c8e98fe Update nixpkgs-dev in devFlake 2025-10-11 10:02:05 +00:00
clan-bot
869a04e5af Update clan-core-for-checks in devFlake 2025-10-11 10:01:50 +00:00
clan-bot
d09fdc3528 Merge pull request 'Update clan-core-for-checks in devFlake' (#5470) from update-devFlake-clan-core-for-checks into main 2025-10-11 05:09:16 +00:00
clan-bot
652677d06f Update clan-core-for-checks in devFlake 2025-10-11 05:01:53 +00:00
clan-bot
ec163657cd Merge pull request 'Update clan-core-for-checks in devFlake' (#5469) from update-devFlake-clan-core-for-checks into main 2025-10-11 00:09:33 +00:00
clan-bot
7d3aa5936d Update clan-core-for-checks in devFlake 2025-10-11 00:01:51 +00:00
clan-bot
f8f8efbb88 Merge pull request 'Update treefmt-nix' (#5466) from update-treefmt-nix into main 2025-10-10 20:12:14 +00:00
clan-bot
8887e209d6 Merge pull request 'Update clan-core-for-checks in devFlake' (#5467) from update-devFlake-clan-core-for-checks into main 2025-10-10 20:10:50 +00:00
clan-bot
a72f74a36e Merge pull request 'Update treefmt-nix in devFlake' (#5468) from update-devFlake-treefmt-nix into main 2025-10-10 20:10:42 +00:00
clan-bot
0e0f8e73ec Update treefmt-nix in devFlake 2025-10-10 20:02:13 +00:00
clan-bot
f15a113f52 Update clan-core-for-checks in devFlake 2025-10-10 20:01:50 +00:00
clan-bot
1fbb4f5014 Update treefmt-nix 2025-10-10 20:01:49 +00:00
Michael Hoang
980a3c90b5 Merge pull request 'cli: ensure init-hardware-config passes Nix options to nixos-anywhere' (#5465) from push-mwotvwkqsluy into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5465
2025-10-10 15:40:34 +00:00
clan-bot
c01b14aef5 Merge pull request 'Update clan-core-for-checks in devFlake' (#5464) from update-devFlake-clan-core-for-checks into main 2025-10-10 15:10:05 +00:00
clan-bot
0a3e564ec0 Update clan-core-for-checks in devFlake 2025-10-10 15:01:52 +00:00
Michael Hoang
bc09d5c886 cli: ensure init-hardware-config passes Nix options to nixos-anywhere 2025-10-10 17:00:10 +02:00
Michael Hoang
f6b8d660d8 Merge pull request 'checks: fix SSH debugging over vsock not working' (#5463) from push-yplypuoxymkt into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5463
2025-10-10 14:40:10 +00:00
Michael Hoang
6014ddcd9a checks: fix SSH debugging over vsock not working 2025-10-10 16:32:54 +02:00
hsjobeki
551f5144c7 Merge pull request 'docs: Remove surprising statement on the front of documentation' (#5460) from kenji/ke-docs-fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5460
2025-10-10 12:24:49 +00:00
a-kenji
9a664c323c docs: Remove surprising statement on the front of documentation 2025-10-10 13:35:29 +02:00
clan-bot
7572dc8c2b Merge pull request 'Update clan-core-for-checks in devFlake' (#5454) from update-devFlake-clan-core-for-checks into main 2025-10-10 10:09:30 +00:00
clan-bot
e22f0d9e36 Merge pull request 'Update nixpkgs-dev in devFlake' (#5455) from update-devFlake-nixpkgs-dev into main 2025-10-10 10:07:47 +00:00
clan-bot
f93ae13448 Update nixpkgs-dev in devFlake 2025-10-10 10:02:12 +00:00
clan-bot
749bac63f4 Update clan-core-for-checks in devFlake 2025-10-10 10:01:53 +00:00
clan-bot
2bac2ec7ee Merge pull request 'Update clan-core-for-checks in devFlake' (#5452) from update-devFlake-clan-core-for-checks into main 2025-10-10 05:09:28 +00:00
clan-bot
f224d4b20c Update clan-core-for-checks in devFlake 2025-10-10 05:01:54 +00:00
clan-bot
47aa0a3b8e Merge pull request 'Update clan-core-for-checks in devFlake' (#5451) from update-devFlake-clan-core-for-checks into main 2025-10-10 00:11:09 +00:00
clan-bot
dd1cab5daa Update clan-core-for-checks in devFlake 2025-10-10 00:01:51 +00:00
clan-bot
32edae4ebd Merge pull request 'Update clan-core-for-checks in devFlake' (#5450) from update-devFlake-clan-core-for-checks into main 2025-10-09 20:09:43 +00:00
clan-bot
d829aa5838 Update clan-core-for-checks in devFlake 2025-10-09 20:01:50 +00:00
clan-bot
fd6619668b Merge pull request 'Update clan-core-for-checks in devFlake' (#5449) from update-devFlake-clan-core-for-checks into main 2025-10-09 15:09:37 +00:00
clan-bot
50a26ece32 Update clan-core-for-checks in devFlake 2025-10-09 15:01:53 +00:00
brianmcgee
8f224b00a6 Merge pull request 'various-ui-fixes' (#5448) from various-ui-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5448
2025-10-09 14:22:06 +00:00
Brian McGee
27d43ee21d fix(storybook): disable Sidebar story until we have a better mock data approach 2025-10-09 14:57:22 +01:00
Brian McGee
9626e22db7 fix(storybook): adjust flash installer on mount
It needs to handle possible missing state in the store on mount.
2025-10-09 14:57:22 +01:00
Brian McGee
1df329fe0d fix(storybook): disable service workflow stories
Temporary until we can decide how best to mock state.
2025-10-09 14:57:21 +01:00
Brian McGee
9da38abc77 fix(storybook): clan settings mock data shape changed 2025-10-09 14:57:20 +01:00
Brian McGee
2814c46e68 fix(storybook): button stories
- role="button" was removed at some point during refactoring which broke how the story was finding buttons
- button no longer has automatic loading state, instead it is now controlled.
2025-10-09 14:56:39 +01:00
Brian McGee
feef0a513e fix(storybook): remove cubes storybook
It wasn't adding much value and requires a mock Clan context which is a lot of effort at the min.
2025-10-09 14:56:38 +01:00
Brian McGee
9cc85b36c6 feat(ui): switch to webkit for storybook tests 2025-10-09 14:56:38 +01:00
hsjobeki
1465b18820 Merge pull request 'app: fix ClanSettings story' (#5447) from ui-cleanup into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5447
2025-10-09 13:27:56 +00:00
Johannes Kirschbauer
6fa0062573 app: fix ClanSettings story 2025-10-09 15:24:30 +02:00
clan-bot
6cd68c23f5 Merge pull request 'Update clan-core-for-checks in devFlake' (#5444) from update-devFlake-clan-core-for-checks into main 2025-10-09 10:09:50 +00:00
clan-bot
fdddc60676 Merge pull request 'Update nixpkgs-dev in devFlake' (#5445) from update-devFlake-nixpkgs-dev into main 2025-10-09 10:08:18 +00:00
clan-bot
684aa27068 Update nixpkgs-dev in devFlake 2025-10-09 10:02:12 +00:00
clan-bot
35d8deb393 Update clan-core-for-checks in devFlake 2025-10-09 10:01:53 +00:00
DavHau
e2f20b5ffc Merge pull request 'vars: refactor - make shared generators carry machines list' (#5443) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5443
2025-10-09 09:03:09 +00:00
DavHau
fd5d7934a0 vars: refactor - make shared generators carry machines list
This should make it simpler to improve the implementation of granting a new machine access to a shared secret.
The current approach using the health_check is  pretty hacky
2025-10-09 15:41:04 +07:00
Kenji Berthold
f194c31e0e Merge pull request 'Fix typo in "Authoring a 'clan.service' module"' (#5439) from nickdichev/clan-core:nickdichev-patch-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5439
2025-10-09 08:32:40 +00:00
DavHau
061b598adf Merge pull request 'vars: cleanup + fix wording' (#5442) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5442
2025-10-09 05:44:14 +00:00
DavHau
744f35e0cc vars: cleanup + fix wording 2025-10-09 07:38:00 +02:00
clan-bot
4a6d46198c Merge pull request 'Update clan-core-for-checks in devFlake' (#5441) from update-devFlake-clan-core-for-checks into main 2025-10-09 05:11:10 +00:00
clan-bot
82d5ca9a0b Update clan-core-for-checks in devFlake 2025-10-09 05:01:51 +00:00
clan-bot
28d8a91a30 Merge pull request 'Update clan-core-for-checks in devFlake' (#5440) from update-devFlake-clan-core-for-checks into main 2025-10-09 00:09:59 +00:00
clan-bot
18f8d69728 Update clan-core-for-checks in devFlake 2025-10-09 00:01:50 +00:00
nickdichev
1feead4ce4 Fix typo in "Authoring a 'clan.service' module" 2025-10-08 20:16:16 +00:00
clan-bot
7f28110558 Merge pull request 'Update clan-core-for-checks in devFlake' (#5438) from update-devFlake-clan-core-for-checks into main 2025-10-08 20:09:55 +00:00
clan-bot
38787da891 Update clan-core-for-checks in devFlake 2025-10-08 20:01:48 +00:00
clan-bot
2b587da9fe Merge pull request 'Update clan-core-for-checks in devFlake' (#5437) from update-devFlake-clan-core-for-checks into main 2025-10-08 15:10:06 +00:00
clan-bot
acd2c1654b Update clan-core-for-checks in devFlake 2025-10-08 15:01:52 +00:00
hsjobeki
2ecb1399c3 Merge pull request 'docs: move generated markdown into a package' (#5436) from docs-source into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5436
2025-10-08 14:40:41 +00:00
Johannes Kirschbauer
46ae6b49c1 docs: move generated markdown into a package 2025-10-08 16:37:31 +02:00
hsjobeki
50a8a69719 Merge pull request 'fix: pull request template folder' (#5435) from fix-j into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5435
2025-10-08 14:28:00 +00:00
Johannes Kirschbauer
203761a99c fix: pull request template folder 2025-10-08 16:24:52 +02:00
hsjobeki
990b4e0223 Merge pull request 'docs: move option-search into own package' (#5434) from docs-source into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5434
2025-10-08 14:05:38 +00:00
Johannes Kirschbauer
032f54cbfb docs: fix links 2025-10-08 16:02:31 +02:00
hsjobeki
47146efa0f Merge pull request 'PR: add pull request template' (#5428) from team-workflow into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5428
2025-10-08 13:44:14 +00:00
Johannes Kirschbauer
c031abcd9e docs: move option-search into own package 2025-10-08 15:42:18 +02:00
Kenji Berthold
6b5dca5842 Merge pull request 'docs: Improve list view on testing' (#5433) from kenji/ke-docs-testing-display into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5433
2025-10-08 12:31:43 +00:00
a-kenji
016fe3d114 docs: Improve list view on testing 2025-10-08 14:29:01 +02:00
DavHau
9b60b4a989 Merge pull request 'lib/introspection: Test skipping instrospection of oneOf' (#5432) from ke-oneof-test into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5432
2025-10-08 12:07:58 +00:00
a-kenji
3088ce025b lib/introspection: Test skipping instrospection of oneOf
This builds on top of #5422.
And tests it's behavior.
2025-10-08 13:17:55 +02:00
hsjobeki
4f1fda3de6 Merge pull request 'docs: remove unused asciinema player' (#5431) from cus-docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5431
2025-10-08 11:08:09 +00:00
Johannes Kirschbauer
57f14827c2 docs: remove unused asciinema player 2025-10-08 13:01:26 +02:00
Johannes Kirschbauer
0390d5999d PR: add pull request template 2025-10-08 12:44:36 +02:00
clan-bot
58e9a28f14 Merge pull request 'Update clan-core-for-checks in devFlake' (#5429) from update-devFlake-clan-core-for-checks into main 2025-10-08 10:14:43 +00:00
clan-bot
b4ad5ca1bd Merge pull request 'Update nixpkgs-dev in devFlake' (#5430) from update-devFlake-nixpkgs-dev into main 2025-10-08 10:14:17 +00:00
clan-bot
84ecb1aae6 Update nixpkgs-dev in devFlake 2025-10-08 10:02:10 +00:00
clan-bot
2b9971f538 Update clan-core-for-checks in devFlake 2025-10-08 10:01:51 +00:00
pinpox
81e15cab34 Merge pull request 'Fix capitalization issue' (#5427) from doc-fixes-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5427
2025-10-08 09:24:34 +00:00
pinpox
215c808071 Fix capitalization issue
fixes #4574
2025-10-08 11:21:06 +02:00
DavHau
4de052e58b Merge pull request 'lib/instrospection: Skip either(oneOf)' (#5422) from ke-introspection-either-or into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5422
2025-10-08 07:42:12 +00:00
Louis Opter
a06a7a7a2c clan-cli/secrets: update some error message in encrypt_secret (#5271)
Found that while reading through some code.

Co-authored-by: Jörg Thalheim <joerg@thalheim.io>
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5271
Co-authored-by: Louis Opter <louis@opter.org>
Co-committed-by: Louis Opter <louis@opter.org>
2025-10-08 07:41:14 +00:00
DavHau
94df3855b5 Merge pull request 'vars: raise error when shared generators differ between machines' (#5425) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5425
2025-10-08 07:20:03 +00:00
DavHau
a83f3c23f4 vars: raise error when shared generators differ between machines
When generators are shared between machines, their definition has to be the same across all machines. If not, it might lead to unexpected problems, as the architecture assumes that all definitions are the same.

fixes https://git.clan.lol/clan/clan-core/issues/5253
2025-10-08 14:02:39 +07:00
DavHau
da6cd324f0 Merge pull request 'vars/performance: aggregate selects over all machines and generators' (#5402) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5402
2025-10-08 06:04:50 +00:00
DavHau
c5b96df7b0 vars/performance: aggregate selects over all machines and generators
This improves the performance of deployment, by aggregating uncached select calls for vars generate into two batches.
batch 1: Get all generators of all machines
batch 2: get all final scripts for generators which need to run
2025-10-08 13:00:20 +07:00
clan-bot
c4feeace31 Merge pull request 'Update clan-core-for-checks in devFlake' (#5424) from update-devFlake-clan-core-for-checks into main 2025-10-08 05:06:31 +00:00
clan-bot
6117b664ae Update clan-core-for-checks in devFlake 2025-10-08 05:02:02 +00:00
clan-bot
b8fdb48fd8 Merge pull request 'Update clan-core-for-checks in devFlake' (#5423) from update-devFlake-clan-core-for-checks into main 2025-10-08 00:06:18 +00:00
clan-bot
9165f7ccaf Update clan-core-for-checks in devFlake 2025-10-08 00:01:52 +00:00
a-kenji
8058a7c158 lib/instrospection: Skip either(oneOf)
For either(oneOf) types, we skip introspection as we cannot
determine which branch of the union was taken without more context
This *should* be safe, as it can currently mostly be triggered through
The `extraModules` setting of inventory modules.

Example:

```
importer.roles.default.extraModules = [
    ../../modules/nixos/common.nix
];
```

Error Message:

```
Traceback (most recent call last):
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_lib/templates/handler.py", line 91, in machine_template
    yield dst_machine_dir
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_cli/machines/create.py", line 95, in create_machine
    inventory_store.write(inventory, message=f"machine '{machine_name}'")
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_lib/persist/inventory_store.py", line 269, in write
    write_info = self._write_map()
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_lib/persist/inventory_store.py", line 214, in _write_map
    current_priority = self._get_inventory_current_priority()
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_lib/persist/inventory_store.py", line 206, in _get_inventory_current_priority
    return self._flake.select("clanInternals.inventoryClass.introspection")
           ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_lib/flake/flake.py", line 1129, in select
    self.get_from_nix([selector])
    ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "/nix/store/zaz4r4fic03m4whgz46p5jjszzlkq694-clan-cli/lib/python3.13/site-packages/clan_lib/flake/flake.py", line 1054, in get_from_nix
    raise ClanSelectError(
    ...<3 lines>...
    ) from e
clan_lib.flake.flake.ClanSelectError: Error on: $ clan select 'clanInternals.inventoryClass.introspection'
  Reason: Yet Unsupported type: either
Removing left-over machine directory: /tmp/hyperconfig/machines/trooo
Error on: $ clan select 'clanInternals.inventoryClass.introspection'
  Reason: Yet Unsupported type: either

```

Closes: #5387
2025-10-07 22:58:51 +02:00
clan-bot
fed61f49f9 Merge pull request 'Update clan-core-for-checks in devFlake' (#5421) from update-devFlake-clan-core-for-checks into main 2025-10-07 20:06:46 +00:00
clan-bot
f1f05c7e6b Update clan-core-for-checks in devFlake 2025-10-07 20:01:53 +00:00
clan-bot
7597d1560f Merge pull request 'Update nixpkgs-dev in devFlake' (#5419) from update-devFlake-nixpkgs-dev into main 2025-10-07 15:06:44 +00:00
clan-bot
f739e1b66d Merge pull request 'Update clan-core-for-checks in devFlake' (#5418) from update-devFlake-clan-core-for-checks into main 2025-10-07 15:06:44 +00:00
clan-bot
5d3609aacd Update nixpkgs-dev in devFlake 2025-10-07 15:02:06 +00:00
clan-bot
7aa51d6bd7 Update clan-core-for-checks in devFlake 2025-10-07 15:01:48 +00:00
pinpox
af91ae8c7f Merge pull request 'Add internal services guide' (#5254) from internal-service-doc into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5254
2025-10-07 14:39:52 +00:00
pinpox
077bf55fd7 Add internal services guide 2025-10-07 16:37:22 +02:00
hsjobeki
1f6dcb910f Merge pull request 'clan: ignore nixpkgs version checks in core' (#5416) from fix-override into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5416
2025-10-07 14:08:30 +00:00
Johannes Kirschbauer
6363d9c99c clan: ignore nixpkgs version checks in core 2025-10-07 16:03:56 +02:00
Kenji Berthold
fd30dbd1be Merge pull request 'docs: Fix typos' (#5415) from kenji/ke-docs-typo into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5415
2025-10-07 12:15:11 +00:00
a-kenji
ba4dc36ddf docs: Fix typos 2025-10-07 14:09:38 +02:00
Mic92
5abac04b15 Merge pull request 'network: fix generator cleanup in nested context manager' (#5412) from no-leaks into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5412
2025-10-07 11:51:38 +00:00
Kenji Berthold
8c84d32b13 Merge pull request 'docs: document vars generation requirement for service tests' (#5409) from kenji/ke-document-update-vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5409
2025-10-07 11:48:46 +00:00
a-kenji
c083548795 docs: document vars generation requirement for service tests
Add documentation explaining that services defining vars need to run
update-vars before tests can execute. Clarifies how `clan.directory`
determines where vars are generated and loaded from during testing.

Closes: #5380
2025-10-07 13:45:39 +02:00
Kenji Berthold
11af5c3471 Merge pull request 'docs: docs-integrity enable UTF-8 support' (#5413) from kenji/ke-html-proofer into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5413
2025-10-07 11:23:06 +00:00
a-kenji
dac8a40b9f docs: docs-integrity enable UTF-8 support 2025-10-07 13:13:55 +02:00
Jörg Thalheim
204f9d09e3 network: refactor get_best_remote to class-based context manager
Resolves the "RuntimeError: generator didn't stop after throw()" issue
by replacing the generator-based @contextmanager with an explicit class.

This maintains backward compatibility through a factory function.
2025-10-07 13:05:20 +02:00
Mic92
668067080d Merge pull request 'sops: don't leak secret key in debug logs' (#5411) from no-leaks into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5411
2025-10-07 10:00:47 +00:00
Jörg Thalheim
10ed2cc7f7 sops: don't leak secret key in debug logs 2025-10-07 11:31:12 +02:00
Kenji Berthold
060b22cf21 Merge pull request 'docs: Fix nixpkgs hierarchy' (#5410) from kenji/ke-qa-nixpkgs-input into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5410
2025-10-07 08:50:00 +00:00
a-kenji
965dddfee1 docs: Fix nixpkgs hierarchy 2025-10-07 10:34:22 +02:00
clan-bot
6e5d74ba22 Merge pull request 'Update nixpkgs-dev in devFlake' (#5408) from update-devFlake-nixpkgs-dev into main 2025-10-07 05:06:29 +00:00
clan-bot
4257f47a1a Merge pull request 'Update clan-core-for-checks in devFlake' (#5407) from update-devFlake-clan-core-for-checks into main 2025-10-07 05:06:22 +00:00
clan-bot
72b64a8b70 Update nixpkgs-dev in devFlake 2025-10-07 05:02:09 +00:00
clan-bot
e46e0543cd Update clan-core-for-checks in devFlake 2025-10-07 05:01:51 +00:00
clan-bot
0de79962ea Merge pull request 'Update clan-core-for-checks in devFlake' (#5406) from update-devFlake-clan-core-for-checks into main 2025-10-07 00:06:50 +00:00
clan-bot
6209816115 Update clan-core-for-checks in devFlake 2025-10-07 00:01:50 +00:00
clan-bot
ec21cda0cf Merge pull request 'Update clan-core-for-checks in devFlake' (#5404) from update-devFlake-clan-core-for-checks into main 2025-10-06 20:06:46 +00:00
clan-bot
8a29d102cd Merge pull request 'Update nixpkgs-dev in devFlake' (#5405) from update-devFlake-nixpkgs-dev into main 2025-10-06 20:06:28 +00:00
clan-bot
22787e7c93 Update nixpkgs-dev in devFlake 2025-10-06 20:02:12 +00:00
clan-bot
19fd72e075 Update clan-core-for-checks in devFlake 2025-10-06 20:01:53 +00:00
clan-bot
50be33088c Merge pull request 'Update clan-core-for-checks in devFlake' (#5403) from update-devFlake-clan-core-for-checks into main 2025-10-06 15:06:19 +00:00
282 changed files with 5235 additions and 1832 deletions

View File

@@ -0,0 +1,12 @@
## Description of the change
<!-- Brief summary of the change if not already clear from the title -->
## Checklist
- [ ] Updated Documentation
- [ ] Added tests
- [ ] Doesn't affect backwards compatibility - or check the next points
- [ ] Add the breaking change and migration details to docs/release-notes.md
- !!! Review from another person is required *BEFORE* merge !!!
- [ ] Add introduction of major feature to docs/release-notes.md

View File

@@ -17,4 +17,4 @@ jobs:
- name: Build clan-app for x86_64-darwin
run: |
nix build .#packages.x86_64-darwin.clan-app --system x86_64-darwin --log-format bar-with-logs
nix build .#packages.x86_64-darwin.clan-app --log-format bar-with-logs

View File

@@ -1,4 +1,4 @@
Copyright 2023-2024 Clan contributors
Copyright 2023-2025 Clan contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -19,28 +19,19 @@ let
nixosLib = import (self.inputs.nixpkgs + "/nixos/lib") { };
in
{
imports =
let
clanCoreModulesDir = ../nixosModules/clanCore;
getClanCoreTestModules =
let
moduleNames = attrNames (builtins.readDir clanCoreModulesDir);
testPaths = map (
moduleName: clanCoreModulesDir + "/${moduleName}/tests/flake-module.nix"
) moduleNames;
in
filter pathExists testPaths;
in
getClanCoreTestModules
++ filter pathExists [
./devshell/flake-module.nix
./flash/flake-module.nix
./installation/flake-module.nix
./update/flake-module.nix
./morph/flake-module.nix
./nixos-documentation/flake-module.nix
./dont-depend-on-repo-root.nix
];
imports = filter pathExists [
./devshell/flake-module.nix
./flash/flake-module.nix
./installation/flake-module.nix
./update/flake-module.nix
./morph/flake-module.nix
./nixos-documentation/flake-module.nix
./dont-depend-on-repo-root.nix
# clan core submodule tests
../nixosModules/clanCore/machine-id/tests/flake-module.nix
../nixosModules/clanCore/postgresql/tests/flake-module.nix
../nixosModules/clanCore/state-version/tests/flake-module.nix
];
flake.check = genAttrs [ "x86_64-linux" "aarch64-darwin" ] (
system:
let
@@ -95,11 +86,12 @@ in
# Container Tests
nixos-test-container = self.clanLib.test.containerTest ./container nixosTestArgs;
nixos-systemd-abstraction = self.clanLib.test.containerTest ./systemd-abstraction nixosTestArgs;
nixos-test-user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
nixos-test-user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
nixos-test-extra-python-packages = self.clanLib.test.containerTest ./test-extra-python-packages nixosTestArgs;
service-dummy-test = import ./service-dummy-test nixosTestArgs;
wireguard = import ./wireguard nixosTestArgs;
service-dummy-test-from-flake = import ./service-dummy-test-from-flake nixosTestArgs;
};
@@ -120,7 +112,7 @@ in
) (self.darwinConfigurations or { })
// lib.mapAttrs' (n: lib.nameValuePair "package-${n}") (
if system == "aarch64-darwin" then
lib.filterAttrs (n: _: n != "docs" && n != "deploy-docs" && n != "docs-options") packagesToBuild
lib.filterAttrs (n: _: n != "docs" && n != "deploy-docs" && n != "option-search") packagesToBuild
else
packagesToBuild
)

View File

@@ -15,7 +15,6 @@ let
networking.useNetworkd = true;
services.openssh.enable = true;
services.openssh.settings.UseDns = false;
services.openssh.settings.PasswordAuthentication = false;
system.nixos.variant_id = "installer";
environment.systemPackages = [
pkgs.nixos-facter

View File

@@ -27,6 +27,7 @@
modules.new-service = {
_class = "clan.service";
manifest.name = "new-service";
manifest.readme = "Just a sample readme to not trigger the warning.";
roles.peer = {
description = "A peer that uses the new-service to generate some files.";
};

View File

@@ -34,6 +34,7 @@ nixosLib.runTest (
modules.new-service = {
_class = "clan.service";
manifest.name = "new-service";
manifest.readme = "Just a sample readme to not trigger the warning.";
roles.peer = {
description = "A peer that uses the new-service to generate some files.";
};

View File

@@ -0,0 +1,67 @@
{ self, pkgs, ... }:
let
cli = self.packages.${pkgs.hostPlatform.system}.clan-cli-full;
in
{
name = "systemd-abstraction";
nodes = {
peer1 = {
users.users.text-user = {
isNormalUser = true;
linger = true;
uid = 1000;
extraGroups = [ "systemd-journal" ];
};
# Set environment variables for user systemd
environment.extraInit = ''
if [ "$(id -u)" = "1000" ]; then
export XDG_RUNTIME_DIR="/run/user/1000"
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
fi
'';
# Enable PAM for user systemd sessions
security.pam.services.systemd-user = {
startSession = true;
# Workaround for containers - use pam_permit to avoid helper binary issues
text = pkgs.lib.mkForce ''
account required pam_permit.so
session required pam_permit.so
session required pam_env.so conffile=/etc/pam/environment readenv=0
session required ${pkgs.systemd}/lib/security/pam_systemd.so
'';
};
environment.systemPackages = [
cli
(cli.pythonRuntime.withPackages (
ps: with ps; [
pytest
pytest-xdist
]
))
];
};
};
testScript =
{ ... }:
''
start_all()
peer1.wait_for_unit("multi-user.target")
peer1.wait_for_unit("user@1000.service")
# Fix user journal permissions so text-user can read their own logs
peer1.succeed("chown text-user:systemd-journal /var/log/journal/*/user-1000.journal*")
peer1.succeed("chmod 640 /var/log/journal/*/user-1000.journal*")
# Run tests as text-user (environment variables are set automatically)
peer1.succeed("su - text-user -c 'pytest -s -n0 ${cli}/${cli.pythonRuntime.sitePackages}/clan_lib/service_runner'")
'';
}

View File

@@ -0,0 +1,26 @@
(
{ ... }:
{
name = "test-extra-python-packages";
extraPythonPackages = ps: [ ps.numpy ];
nodes.machine =
{ ... }:
{
networking.hostName = "machine";
};
testScript = ''
import numpy as np
start_all()
machine.wait_for_unit("multi-user.target")
# Test availability of numpy
arr = np.array([1, 2, 3])
print(f"Numpy array: {arr}")
assert len(arr) == 3
'';
}
)

View File

@@ -1,115 +0,0 @@
{
pkgs,
nixosLib,
clan-core,
lib,
...
}:
nixosLib.runTest (
{ ... }:
let
machines = [
"controller1"
"controller2"
"peer1"
"peer2"
"peer3"
];
in
{
imports = [
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;
name = "wireguard";
clan = {
directory = ./.;
modules."@clan/wireguard" = import ../../clanServices/wireguard/default.nix;
inventory = {
machines = lib.genAttrs machines (_: { });
instances = {
/*
wg-test-one
controller2 controller1
peer2 peer1 peer3
*/
wg-test-one = {
module.name = "@clan/wireguard";
module.input = "self";
roles.controller.machines."controller1".settings = {
endpoint = "192.168.1.1";
};
roles.controller.machines."controller2".settings = {
endpoint = "192.168.1.2";
};
roles.peer.machines = {
peer1.settings.controller = "controller1";
peer2.settings.controller = "controller2";
peer3.settings.controller = "controller1";
};
};
# TODO: Will this actually work with conflicting ports? Can we re-use interfaces?
#wg-test-two = {
# module.name = "@clan/wireguard";
# roles.controller.machines."controller1".settings = {
# endpoint = "192.168.1.1";
# port = 51922;
# };
# roles.peer.machines = {
# peer1 = { };
# };
#};
};
};
};
testScript = ''
start_all()
# Show all addresses
machines = [peer1, peer2, peer3, controller1, controller2]
for m in machines:
m.systemctl("start network-online.target")
for m in machines:
m.wait_for_unit("network-online.target")
m.wait_for_unit("systemd-networkd.service")
print("\n\n" + "="*60)
print("STARTING PING TESTS")
print("="*60)
for m1 in machines:
for m2 in machines:
if m1 != m2:
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
'';
}
)

View File

@@ -0,0 +1,25 @@
The admin service aggregates components that allow an administrator to log in to and manage the machine.
The following configuration:
1. Enables OpenSSH with root login and adds an SSH public key named`myusersKey` to the machine's authorized_keys via the `allowedKeys` setting.
2. Automatically generates a password for the root user.
```nix
instances = {
admin = {
roles.default.tags = {
all = { };
};
roles.default.settings = {
allowedKeys = {
myusersKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFDNnynMbFWatSFdANzbJ8iiEKL7+9ZpDaMLrWRQjyH lhebendanz@wintux";
};
};
};
};
```

View File

@@ -3,6 +3,7 @@
manifest.name = "clan-core/admin";
manifest.description = "Adds a root user with ssh access";
manifest.categories = [ "Utility" ];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
description = "Placeholder role to apply the admin service";

View File

@@ -2,7 +2,7 @@ let
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
in
{
name = "service-admin";
name = "admin";
clan = {
directory = ./.;

View File

@@ -3,7 +3,7 @@
...
}:
{
name = "service-borgbackup";
name = "borgbackup";
clan = {
directory = ./.;

View File

@@ -9,7 +9,7 @@ in
perSystem =
{ ... }:
{
clan.nixosTests.service-data-mesher = {
clan.nixosTests.data-mesher = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/data-mesher" = module;
};

View File

@@ -2,7 +2,7 @@
...
}:
{
name = "service-data-mesher";
name = "data-mesher";
clan = {
directory = ./.;

View File

@@ -3,7 +3,7 @@
...
}:
{
name = "service-dyndns";
name = "dyndns";
clan = {
directory = ./.;

View File

@@ -0,0 +1,6 @@
[
{
"publickey": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
"type": "age"
}
]

View File

@@ -0,0 +1,14 @@
{
"data": "ENC[AES256_GCM,data:seLxbv590dO0KvMJmtN7WVvUcH27VYwAc3rmyD7q6ZmwCgswOKx55LFnh0stRDKSZa8K7Dq1x7D9adhZtPAMWX8tbJswBeNMPt8=,iv:G52eugxfTi0tTzH4EN4CWmpyv6feSL34++UVSjb0aAo=,tag:6r10/a7kD2hBAmae0nz2OQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHVC8wZUZJYUl5MXVNa2k5\ndGV1MnFWbUNLNVdxeEtCVUc3MTd0ck9aeFFBCnFhZW40amVYc3FlN1FPRTFSWTJR\nQzhNOERKbnRnSlJVeElNSEM5ZUJsZGsKLS0tIG1uNnlNN3MweHlYczNRTW9xSytu\neThzUmxKZTJBT2lCcTdiNUI4N3paTVEKgS9j2/GVt1KBoggUj9d6UK/mIlK4niLQ\nzVq2BHt3irxQpkpGUogXH2b86zSAOEJFzsL1Rk8HM1mogTG8jqf0qA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-10-19T12:49:11Z",
"mac": "ENC[AES256_GCM,data:T/2xw2mvUi8YALyxz78qG/g/xguoUTeHNzcZfXwwSyCXMg9ircsGGLO9SOVWy/QNkibnw3Yp80tXNJyr4oJH28PhFH7RrRp8jzNdopF49ZNJb2IqJ3C7xNYRZMHfjOCd/raka+ehZq8YGilEpXUWLRk1ere9lbBMh1ycL7jJS3c=,iv:FZbY/jTNPM+p4qD41FD0K7B9zoppGuvnUY5hL/EkmYM=,tag:IF5QTyUkHXWthlAGBn9R8w==,type:str]",
"version": "3.11.0"
}
}

View File

@@ -0,0 +1 @@
../../../../../sops/machines/server

View File

@@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:Zu+n+DDYP7rQRTS17PJ6Apo=,iv:5WOs81Pj+S85kdC1AlOXSyPMGDfwM5UD8x7nyRZtRYQ=,tag:2JYkGnLugAni49Upv43o2g==,type:str]",
"sops": {
"age": [
{
"recipient": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlR3RGQ2ZLTkR3ZWxNVCsv\naXJHRjBiVUVYZVRIY2swY2xubGhmb3pLRkNvCldhQUV2WDlqYjZ4ZUFWYXkvUEEw\nZi9XRWw0Mi9mRENDcnI0aENDR2Z4MHcKLS0tIGFQU3Q4WEErbnBjOHpNR1BSR2cr\nRFg0anE1cHExT0sySmxuUks1R05nczAKZO3R6+f9co2+YGO8HPufoq1fLqqrdTWD\n4zqemMmG2BjMRDumxtcKp8CLaZWlJoP4e/+tonfdoe42qmNF5NJcFw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzZWo4WGh1cWxKeDhDdlBm\nTVFjVFBIUU9xaGRkanNHaUVUUHN1czNRSUhNCkp5MmwzSGdycmsrZGhaRUhEbXBF\nNUhtdEF6bHZQOGJYUVhFVHlYc3FPODAKLS0tIDBRQ2VGT2IvU1F4MEVabzhYSFJq\nOWZmbGpkQmNSMnNKa0s4K2JXdGgwRlkKUQRREpG5H1mNHSc/cZrdMiSz0veJFR4N\n+W49XL/wQUZwajykwYj++G+dWDO7DQ+fpbB9w4mzbsAmCsXirseTLA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-10-19T12:49:11Z",
"mac": "ENC[AES256_GCM,data:0msda7WbQQxXQ+juT7yErgT7NADgnzqEZLTQw+4JPuAE4xcqRIYwrrAALaA0GCCM2aIWlICzJigLCuzQUfSUbIzeP79tEHiKez+NOt/xgSM9ljz7GlsmLd0vzkxdt3WSxP+sHxy0S866N2sLMUkLqPGdqeTjB+Jji5ghGhzk9ys=,iv:8UU7iA4SdR6ZlVolm708l2Iea0sQYRT+5wPBBP5tpS0=,tag:VQXslAlqLqs1QEkwW6x6qg==,type:str]",
"version": "3.11.0"
}
}

View File

@@ -0,0 +1 @@
../../../../../sops/users/admin

View File

@@ -0,0 +1,12 @@
[Garage](https://garagehq.deuxfleurs.fr/) is an open-source, S3-compatible distributed object storage service for self-hosting.
This module provisions a single-instance S3 bucket. To customize its behavior, set `services.garage.settings` in your Nix configuration.
Example configuration:
```
instances = {
garage = {
roles.default.machines."server" = {};
};
};
```

View File

@@ -4,6 +4,7 @@
manifest.name = "clan-core/garage";
manifest.description = "S3-compatible object store for small self-hosted geo-distributed deployments";
manifest.categories = [ "System" ];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
description = "Placeholder role to apply the garage service";

View File

@@ -3,7 +3,7 @@
...
}:
{
name = "service-garage";
name = "garage";
clan = {
directory = ./.;

View File

@@ -0,0 +1 @@
This a test README just to appease the eval warnings if we don't have one

View File

@@ -9,6 +9,7 @@
_class = "clan.service";
manifest.name = "clan-core/hello-word";
manifest.description = "This is a test";
manifest.readme = builtins.readFile ./README.md;
# This service provides two roles: "morning" and "evening". Roles can be
# defined in this file directly (e.g. the "morning" role) or split up into a
@@ -34,10 +35,13 @@
settings,
# The name of this instance of the service
instanceName,
# The current machine
machine,
# All roles of this service, with their assigned machines
roles,
...
}:
{

View File

@@ -1,5 +1,5 @@
{
name = "service-hello-service";
name = "hello-service";
clan = {
directory = ./.;

View File

@@ -0,0 +1,27 @@
🚧🚧🚧 Experimental 🚧🚧🚧
Use at your own risk.
We are still refining its interfaces, instability and breakages are expected.
---
This module is part of Clan's [networking interface](https://docs.clan.lol/guides/networking/networking/).
Clan's networking module automatically manages connections across available network transports and falls back intelligently. When you run `clan ssh` or `clan machines update`, Clan attempts each configured network in priority order until a connection succeeds.
The example below shows how to configure a domain so server1 is reachable over the clearnet. By default, the `internet` module has the highest priority among networks.
```nix
inventory.instances = {
# Direct SSH with fallback support
internet = {
roles.default.machines.server1 = {
settings.host = "server1.example.com";
};
roles.default.machines.server2 = {
settings.host = "192.168.1.100";
};
};
};
```

View File

@@ -7,6 +7,7 @@
"System"
"Network"
];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
description = "Placeholder role to apply the internet service";
interface =

View File

@@ -0,0 +1,28 @@
This module sets up the [KDE Plasma](https://kde.org) Desktop environment.
!!! Note "Customisation"
This service intentionally does not provide any settings or customisation
options, as desktop preferences are highly subjective. Clan currently
supports only this default desktop configuration. Any additional
customisation can be done via the `extraModules` option. Furthermore, if you
want to use a different desktop environment or compositor (e.g. Gnome or
sway), we encourage you to to build your own
[Clan Service](https://docs.clan.lol/guides/services/community/) or have a
look at the [Community Services](https://docs.clan.lol/services/community/).
## Example Usage
```nix
inventory = {
instances = {
kde = {
# Deploy on all machines
roles.default.tags.all = { };
# Or individual hosts
roles.default.machines.laptop = { };
};
};
};
```

View File

@@ -0,0 +1,19 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "clan-core/kde";
manifest.description = "Sets up a graphical desktop environment";
manifest.categories = [ "Desktop" ];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
description = "KDE/Plasma (wayland): Full-featured desktop environment with modern Qt-based interface";
perInstance.nixosModule = {
services = {
displayManager.sddm.enable = true;
displayManager.sddm.wayland.enable = true;
desktopManager.plasma6.enable = true;
};
};
};
}

View File

@@ -0,0 +1,24 @@
{
self,
lib,
...
}:
let
module = lib.modules.importApply ./default.nix {
inherit (self) packages;
};
in
{
clan.modules = {
kde = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.kde = {
imports = [ ./tests/vm/default.nix ];
clan.modules.kde = module;
};
};
}

View File

@@ -0,0 +1,30 @@
{
name = "kde";
clan = {
directory = ./.;
inventory = {
machines.client = { };
instances = {
kde = {
module.name = "kde";
module.input = "self";
roles.default.machines."client" = { };
};
};
};
};
testScript = ''
start_all()
client.systemctl("start network-online.target")
client.wait_for_unit("network-online.target")
client.wait_for_unit("graphical.target")
client.wait_for_unit("display-manager.service")
client.succeed("systemctl status display-manager.service")
'';
}

View File

@@ -0,0 +1,4 @@
{
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"type": "age"
}

View File

@@ -1,6 +1,6 @@
{ ... }:
{
name = "service-localbackup";
name = "localbackup";
clan = {
directory = ./.;

View File

@@ -0,0 +1,4 @@
{
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"type": "age"
}

View File

@@ -0,0 +1,23 @@
This NixOS module installs and configures Synapse — a federated Matrix homeserver with end-to-end encryption — and optionally provides the Element web client.
The example below demonstrates a minimal setup that includes:
- Element web client.
- Synapse backed by PostgreSQL and nginx.
- An admin user and an additional regular user.
Example configuration:
```nix
instances = {
matrix-synapse = {
roles.default.machines."jon".settings = {
acmeEmail = "admins@clan.lol";
server_tld = "clan.test";
app_domain = "matrix.clan.test";
users.admin.admin = true;
users.someuser = { };
};
};
};
```

View File

@@ -4,6 +4,7 @@
manifest.name = "clan-core/matrix-synapese";
manifest.description = "A federated messaging server with end-to-end encryption.";
manifest.categories = [ "Social" ];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
description = "Placeholder role to apply the matrix-synapse service";

View File

@@ -0,0 +1,20 @@
[Mycelium](https://github.com/threefoldtech/mycelium) is an end-to-end encrypted IPv6 overlay network that spans the globe.
## Features
- Locality-aware routing: finds the shortest path between nodes.
- All traffic is end-to-end encrypted.
- Can route traffic via friend nodes and is location-aware.
- Automatic rerouting if a physical link goes down.
- IPv6 addresses are derived from private keys.
- A simple, reliable message bus is implemented on top of Mycelium.
- Supports multiple transports (QUIC, TCP, …). Hole punching for QUIC is in progress to enable true P2P connectivity behind NATs.
- Designed for planetary-scale scalability; previous overlay networks reached practical limits, and Mycelium focuses on scaling.
- Can run without a TUN device and be used solely as a reliable message bus.
Example configuration below connects all your machines to the Mycelium network:
```nix
mycelium = {
roles.peer.tags.all = {};
};
```

View File

@@ -7,6 +7,7 @@
"System"
"Network"
];
manifest.readme = builtins.readFile ./README.md;
roles.peer = {
description = "A peer in the mycelium network";

View File

@@ -3,7 +3,7 @@
...
}:
{
name = "service-mycelium";
name = "mycelium";
clan = {
test.useContainers = false;

View File

@@ -0,0 +1,11 @@
This service is meant to be consumed by the UI / API, and exposes a JSON serializable interface to add packages to a machine over the inventory.
The example below demonstrates installing the "cbonsai" application to a machine named "server.
```
instances.packages = {
roles.default.machines."server".settings = {
packages = [ "cbonsai" ];
};
};
```

View File

@@ -6,6 +6,7 @@
manifest.categories = [
"System"
];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
description = "Placeholder role to apply the packages service";

View File

@@ -1,5 +1,5 @@
{
name = "service-packages";
name = "packages";
clan = {
directory = ./.;

View File

@@ -1,16 +1,16 @@
# Clan service: sshd
What it does
## What it does
- Generates and persists SSH host keys via `vars`.
- Optionally issues CAsigned host certificates for servers.
- Installs the `server` CA public key into `clients` `known_hosts` for TOFUless verification.
- Optionally issues CA-signed host certificates for servers.
- Installs the `server` CA public key into `clients` `known_hosts` for TOFU-less verification.
When to use it
- ZeroTOFU SSH for dynamic fleets: admins/CI can connect to frequently rebuilt hosts (e.g., server-1.example.com) without prompts or perhost `known_hosts` churn.
## When to use it
- Zero-TOFU SSH for dynamic fleets: admins/CI can connect to frequently rebuilt hosts (e.g., server-1.example.com) without prompts or per-host `known_hosts` churn.
Roles
- Server: runs sshd, presents a CAsigned host certificate for `<machine>.<domain>`.
- Client: trusts the CA for the given domains to verify servers certificates.
### Roles
- Server: runs sshd, presents a CA-signed host certificate for `<machine>.<domain>`.
- Client: trusts the CA for the given domains to verify servers' certificates.
Tip: assign both roles to a machine if it should both present a cert and verify others.
Quick start (with host certificates)
@@ -80,12 +80,13 @@ Admins should trust only production; CI should trust prod and staging. Servers a
};
}
```
- Admin -> server1.prod.example.com: zeroTOFU (verified via cert).
### Explanation
- Admin -> server1.prod.example.com: zero-TOFU (verified via cert).
- Admin -> server1.staging.example.com: falls back to TOFU (or is blocked by policy).
- CI -> either prod or staging: zeroTOFU for both.
Note: server and client searchDomains dont have to be identical; they only need to overlap for the hostnames you actually use.
- CI -> either prod or staging: zero-TOFU for both.
Note: server and client searchDomains don't have to be identical; they only need to overlap for the hostnames you actually use.
Notes
### Notes
- Connect using a name that matches a cert principal (e.g., `server1.example.com`); wildcards are not allowed inside the certificate.
- CA private key stays in `vars` (not deployed); only the CA public key is distributed.
- Logins still require your user SSH keys on the server (passwords are disabled).

View File

@@ -2,7 +2,7 @@
{
_class = "clan.service";
manifest.name = "clan-core/sshd";
manifest.description = "Enables secure remote access to the machine over SSH";
manifest.description = "Enables secure remote access to the machine over SSH with automatic host key management and optional CA-signed host certificates.";
manifest.categories = [
"System"
"Network"
@@ -180,7 +180,9 @@
settings.PasswordAuthentication = false;
settings.HostCertificate = lib.mkIf (
# this check needs to go first, as otherwise generators.openssh-cert does not exist
settings.certificate.searchDomains != [ ]
&& config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".exists
) config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".path;
hostKeys = [

View File

@@ -13,6 +13,11 @@ in
clan.nixosTests.sshd = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/sshd" = module;
};
clan.nixosTests.sshd-no-search-domains = {
imports = [ ./tests/vm/no-search-domains.nix ];
clan.modules."@clan/sshd" = module;
};
};

View File

@@ -3,7 +3,7 @@
...
}:
{
name = "service-sshd";
name = "sshd";
clan = {
directory = ./.;

View File

@@ -0,0 +1,45 @@
/*
This is a regression test for the following error:
error: attribute 'openssh-cert' missing
at /nix/store/y1k4bqwjql6bhlry456cs4marpamiqlr-source/clanServices/sshd/default.nix:184:17:
183| # this check needs to go first, as otherwise generators.openssh-cert does not exist
184| config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".exists
| ^
185| && settings.certificate.searchDomains != [ ]
*/
{
...
}:
{
name = "sshd";
clan = {
directory = ./.;
inventory = {
machines.server = { };
machines.client = { };
instances = {
sshd-test = {
module.name = "@clan/sshd";
module.input = "self";
roles.server.machines."server".settings = {
hostKeys.rsa.enable = true;
};
roles.client.machines."client".settings = {
};
};
};
};
};
nodes = {
server = { };
client = { };
};
testScript = ''
# don't do anything, just evaluate the machines
exit(0)
'';
}

View File

@@ -0,0 +1 @@
../../../../../sops/machines/client

View File

@@ -0,0 +1 @@
../../../../../sops/machines/server

View File

@@ -2,9 +2,17 @@
"data": "ENC[AES256_GCM,data:Qje3bXRHcAiFCslFfAeUTcOn2woc06e1sLAoH16x1sZ7N0i07rHqwsBjn7nKvMee6tktIjLMGTPOQL9TLgYI+wDgU5MHqlZlVBnYLk+VXYEKhymDlS3RAg5pbrmJzkucl/Vw5VBlDK+n8qnrgFG2pgpiC6Lzb5f4I7pxUl4zcz9jCf0Stj10lVQgkbvnr8UMUvcb1vUF/EAhF6WhhhgrhpbYrK+PkNW6EXmxIXdUdXvSqVWvJby2NgBaGOM1lwnWv4LOOiJ1BNXnOnLE0a8+8SjqahzqroeFvUCtoFxJ45/LqFTtgS9cQ44FaqrMRSWlOgsNR2BkeT449fKUCwYfEW1g/R47I9hAm/bcKrOBpHdAji/hpcDy73Qb9ZKrY6/0kRXl/ECI3YVX8nrHIjEJpoZ7a/dxJu7z8OOdb7gP2mVPTiWcbpD/KwpefDWLKnYhBrXUNaqSajf95Ahln2Vn6sALbbjcUzs/x5OqchYe1/kYy7MaGbEFNPeINnGid73c7xfUoyI90Ho4azLW8Q/n,iv:9heXX8g1P8/4gGT3+RYYmz6rJ5EnIDr5w1OAbGybL+I=,tag:p6mHZ8+EaJ+Nyn59n2TQ4g==,type:str]",
"sops": {
"age": [
{
"recipient": "age124l8cfswl97ck0e0qw8l47usf375srn69e4mhxr3gr40erxw7pesftxshx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5b0Y3aldQWXJyZzU3aGZU\naWpOK1VXdUVlSUVvZzJqSDVCekQ0Z2JxblRvCmFWd0c1SC9jckMweTIrNmg0VnN3\ncTNwMkVTL0ZyT3RGeUs2NnlNb21GWTQKLS0tIEpGM2FacUNoakJ0dlJwMWZMNU0x\nVWhmV1pDOTRFNExpVHBTRUx2L2ZaMVUK+ka9oqcvoLjwwUqIol0rU1VsJHhs4S1P\nWpKKPetUPEF4xxWj0OdeMc40XCTjl6CBdbtcrslH3tuZHjeSWQ6QCg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkNlpCNGR0SHVtVzJ2K0hM\ncng1ZWlTSGQzWndXVWhlbEZMN25TUklXV1I4Cm9PZkJ3Zi81YXoxdzVPTFI3dE1a\nUnJnUmJPbi9CYmdFL2ltaTRSQ1MreFUKLS0tIDE4Y05IamJjL0huY2l2YU4zbDJs\ndTl1b0wzaTM4MndlcFZYVThqbWtVeFUKuSZLJpUrccuusJPU2xWHw19wTN8mKZW3\n1GJJjlb79rZp/RbSMxFxkyVHgu+F9kbpRgViICJSWkeR495786oArA==\n-----END AGE ENCRYPTED FILE-----\n"
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLM3lNL1UyUjhRdFBvenlv\naXBTYXJva0hCTS8vK1hCYmdQdlpBNGFNTkNrCmVTbFROTWVWRzZyc2E0SjVDT1hs\nMm9qT0plcHNJaWczcWJTd0llYldGMVkKLS0tIGh6M04yQ3RiMGVYbTNYMEdCVTNK\nUDhaS3FSVWl4ZGlPYTRodW80VElsZ1UKxi48UZpxuu7gkRtQrCi4//suOpuFY6sl\n8b1xcN/tMn2MWW9hvx4K4qJLXTWOm+9GiZqJ51JBb0hihRh7fC3SfA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1f39qxz84yv272wk636el0kdyagzudcs99ucpkjarsj2rey6yvccse9lwet",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGK2Z5OGFsVjBJcGFITENH\nL205TDBaNkRvQ3ZBbGVDU0wrWnl5QkJaSFZNCjhNSXpMTTd1ejlqbVNBUDZ2TlFn\neUhNdEh4M1RhQnFabHpaMVd5eG11THcKLS0tIE9PS3JlVFVPNG5sM3hpWG95V1ho\nSXBySU1SUExkVHNHZElmQWExTVN3cHMKvzdlCWP8/9xviu/9AMxw/4ZyXo4O3AE9\n84IQBDO4GYrqnXvOroxjsNCDrCBDH0WPuYAphctJvyI5SSAtL4uHhQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-06-09T19:51:28Z",

View File

@@ -1,20 +1,24 @@
## Usage
This service configures Syncthing to continuously synchronize a folder peer-to-peer across your machines.
Example configuration:
```nix
{
instances.syncthing = {
roles.peer.tags.all = { };
roles.peer.settings.folders = {
documents = {
path = "~/syncthing/documents";
};
};
instances.syncthing = {
roles.peer.tags.all = { };
roles.peer.settings.folders = {
documents = {
path = "/home/youruser/syncthing/documents";
};
};
};
}
```
Now the folder `~/syncthing/documents` will be shared and kept in sync with all your machines.
Notes:
- Each key under `folders` is a folder ID (an arbitrary identifier for Syncthing).
- Prefer absolute paths (example shown). `~` may work in some environments but can be ambiguous in service contexts.
## Documentation
Extensive documentation is available on the [Syncthing](https://docs.syncthing.net/) website.
## Documentation
See the official Syncthing docs: https://docs.syncthing.net/

View File

@@ -1,5 +1,5 @@
{
name = "service-syncthing-service";
name = "syncthing-service";
clan = {
directory = ./.;

View File

@@ -0,0 +1,22 @@
🚧🚧🚧 Experimental 🚧🚧🚧
Use at your own risk.
We are still refining its interfaces, instability and breakages are expected.
---
This module is part of Clan's [networking interface](https://docs.clan.lol/guides/networking/networking/).
Clan's networking module automatically manages connections across available network transports and falls back intelligently. When you run `clan ssh` or `clan machines update`, Clan attempts each configured network in priority order until a connection succeeds.
The example below configures all your nixos machines to be reachable over the Tor network. By default, the `tor` module has the lowest priority among networks, as it's the slowest.
```nix
inventory.instances = {
# Fallback: Secure connections via Tor
tor = {
roles.server.tags.nixos = { };
};
};
```

View File

@@ -7,6 +7,7 @@
"System"
"Network"
];
manifest.readme = builtins.readFile ./README.md;
roles.client = {
description = ''

View File

@@ -1,5 +1,5 @@
{
name = "service-trusted-nix-caches";
name = "trusted-nix-caches";
clan = {
directory = ./.;

View File

@@ -1,5 +1,5 @@
{
name = "service-users";
name = "users";
clan = {
directory = ./.;

View File

@@ -1,5 +1,5 @@
{
name = "service-wifi";
name = "wifi";
clan = {
directory = ./.;

View File

@@ -0,0 +1,6 @@
[
{
"publickey": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
"type": "age"
}
]

View File

@@ -0,0 +1,14 @@
{
"data": "ENC[AES256_GCM,data:xAQ6TcwttQNb1BXlq2j+xZX+vGbqV5XKZyZMBAnQ00hWLu6Ba6pN2qR4HItKQ1KWza8WGhzgGdcwZv6Qobgmp9wAcwWlAubS7FU=,iv:KalRsDqWxqscJOeZcnQfFkP7QTBVZpP8XAdPHvikfaM=,tag:EAndFTqRYRcCgD5/ixniBA==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjZnpWd0grazhjak0ra3NK\nSEpVTWVEaXEzc3ZIeloySXBqVk01SVNsVmtzCk5weWJCSGNlb2FRM0RWVEYwTHlC\nTVFBd1cvYlZrNlQ4TFRydFNzWXNicE0KLS0tIFZ5WllRNEI0Q3hQaVU2WjhGNDFr\nLy9pSXU5Y2FINy9LbXg4dzdHREQveE0KyxWDDyRpo0eTIXj0lHQtOunLtAP/Q+70\n+GvfjW7WXHXvXyg6CXzpCy6F6UWie4LHO9VrJM2mTjoh+q4l5DT6CA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-10-19T12:53:35Z",
"mac": "ENC[AES256_GCM,data:P6Wcm7daPMe6laceFIiIzhcGa9k37Fo5ZnBFhdVmkATuR2oqMZp9Ke5r73SbC5B95QoPnWVNNnrxkn/oiVQmSiiDaf718isLAfU+7zGkV0BZCtfCrqe82JzH2iQ0tKSxsVJqklCijAfUBGpt/EYN6c4QnM2IFulbiWs2kqWMi4I=,iv:mRuTg2RblZCNX3yQNFKCtuwjwIptZ5VGpSyLV6Ah5NI=,tag:Xl8/jrtIhxfAi+FrnwKh7Q==,type:str]",
"version": "3.11.0"
}
}

View File

@@ -0,0 +1 @@
../../../../../sops/machines/second

View File

@@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:B08uqk2DxB8QJ93QBM71,iv:XawCB0nwWxso5+yC8az33cFnt/qKzITOwUP0ZFI20Ho=,tag:mZg5U4t9beHch+Oic2VsVw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLWEV0STNnMlRreElVSk1y\nRTB6cCtWc0tkNUEycklSU0x5cHZwN3FIQkcwCkJQemRZOWZFSit3QmZ2a3RrOGFh\nUEhLSEZLRW9lWkN2b1VKK2EybUYvcTQKLS0tIGt6VWFmVHpNc2c0T3E0TjBYeWp1\ncjFCcEd3MTlYVGRsRlpXWWRsWlU0dkEKe5NUijC+GVxzj8bMEY6v+qHw9iylpwQz\nFLKneLikKVcRYoTYecimaQdUbYCiEwUB7KCpENcNmjZx6eVmTvGeMQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6T1hheHNaZ2h6Mlc5WEJq\nUk8zTC82N2ZHUUJQK0VLdXBkNEFnNlRHamh3CitrWGpVVGQreDRZdTF5L2VXNENn\neThUd0tjUWpCNW01QklZakx6NnNoT28KLS0tIGVOLytqUGtsaWhFbi9mU2ttMmow\nOFhwVmkyVDdZK09ramZOYktFdkV5R1EKWGseGbOtLS45gb6fb8LFzlfdsRGC7x9B\ncn03oAcfC2Yo/kqoT4tjQF/COn408SBkytwZ3GbL8Bnul/RyjcHJNQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-10-19T12:53:38Z",
"mac": "ENC[AES256_GCM,data:MneMlobCnJZVn5QEwxL1os48TOJhrfETry39G2Si1kT5OKq6SlNB2mtVOshmGv21Cue/JNZWr9kwO0SS4egs4CsWaW8MMoR+84KIGIu9uol3vieEayd8nOjJfCKp0fRQKi1ElJRUtjLApA1KQ05WjG+vlb2JxNl67NWRqtykA44=,iv:f91eVJiSfmvM9ym8a3VYlijNZW5SoGUCUqAgFEax6Bo=,tag:ciANv3ov6p0gCJTIQwBoJg==,type:str]",
"version": "3.11.0"
}
}

View File

@@ -0,0 +1 @@
../../../../../sops/users/admin

View File

@@ -0,0 +1 @@
../../../../../sops/machines/second

View File

@@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:PCpXPkFa5FzHArW1/g3QF9A=,iv:yKGtX4ZqiFYE/bvMAEIUmGQB7Oklo++vbed+K2JPxuA=,tag:UiiuchttMIv+T2TuXcpjZg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvcGJEM3ZLYUJleStRWkpy\nSmwzZXVXWUZTY2htbzk0UGlxV2gwWExyT21nCjRGYmFyRnNBYnJQa0hSRGtCZDdG\nTjdHMG94Q3diZnVsRy84TXJXKzJrTW8KLS0tIEF2dk1uSW5NQ0JxRFdmczNSYmJF\nRThyTnY5QVlOTEZ4eThpdEJmOFhvVFEKA7oltxLLS3w3LOOS2S4RZNJreZftJD2m\niXtDAfWOKLGYTdhfttzWWfxFHt/72OCL1WKm1COgmzBznJJ+RBehEw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5ZmZ3d0xNRkQycnFaM2pB\nL1ZLeVRFQXozeGFpMGtnc1FBR20ycXl2UmxvCk42QVVieC8waDBwenhVdVFTc2M0\nL2lSM0QvUzhDMXFjTVVnZGY2YXcxakUKLS0tIHZiTGZsMEZ3elVkK2p2Q1kyNXFZ\nTmJybzJaSnZyZE5sb2ZPUjZyNjRhak0KjIyzfPw1BHYJ5REWRSoKG9cY2b23dbdt\ndHioloXv3tW5bTSWytuDSQ5+xzruJqr1w099EZ6Gl6aeeo0oQQkpyw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-10-19T12:53:38Z",
"mac": "ENC[AES256_GCM,data:jtj+zGk6D+a+R45wmWD/g2lNWfAPCAAXtwPxZLOOYVZ0IizwqOhsQ6IYtGvKqty0nsr//pCihhazJGFSiGT4fDv6eYOO83+JLTWdvHbfJjMCPsD+Shbjenu/m8dbifsEcnrLkAgzMin2nOeUdRombz91K7O8hbDrcIkS0AXh5G4=,iv:G0l+5SkAj5ii4Us+WG1/xWspglD0xa7viKyZQt2nF9Q=,tag:F48Ry3rmB/Y6nHyikB5Pjw==,type:str]",
"version": "3.11.0"
}
}

View File

@@ -0,0 +1 @@
../../../../../sops/users/admin

View File

@@ -0,0 +1 @@
../../../../../sops/machines/second

View File

@@ -3,12 +3,16 @@
"sops": {
"age": [
{
"recipient": "age13ahclyps97532zt2sfta5zrfx976d3r2jmctj8d36vj9x5v5ffqq304fqf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxN2EwVHN3SENVTjdjZGRi\nQmJOWlNGYmpmM1BnZnpYWGhaSlRaUVJIODFRCkhhMUhyZzVWWk53SDBwSVBVZGVY\nVUpMTm9qWTIzc3VwdGJHcUVWVzFlV0UKLS0tIDBBVXdlS1FFbzNPSnlZWWtEaDJi\nK215OWQvMVRCRUZyQjFZckJFbHBZeDQK2cqgDnGM5uIm834dbQ3bi3nQA5nPq6Bf\n0+sezXuY55GdFS6OxIgI5/KcitHzDE0WHOvklIGDCSysoXIQ3QXanA==\n-----END AGE ENCRYPTED FILE-----\n"
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUdDNFSE8zdm00QTc1L3kx\nUkZYMFRwVTZkZDQxZTZEWlZBV2pSZ1NidGxvCk5MRE5Da0I1R0MxRzBFYVpNNWwz\nNGdDazh4cll5MHlDUGZ4N1lZb242UlUKLS0tIFBwWVhpS1JEc2JBWDZKdFBCUUF3\nRlVRZTR4YW93SXZlNXhjWlFDYnd5UEEKcZ7sbVO4ZhhTV4pNinJhk7+qWk4nr2E9\nvjQCXZvAMhXP485S+Dbiuvc426cOOL+KrOelMFRJgZg3sDtuN4AFLw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0NDB5SVcrU0V6akYwbDlv\na1BuSm5XbjYwN2ZkZWtIcnhBVHBTWGFxd24wCnZTVGlPRm5uZEd3QXYwdFRMS09K\nWWw5N2RJZ3d4N0VDMWZmM2lkYVM4VncKLS0tIGplTDVka1VoUVdXMU9VS3hYSlZ1\nRjZGL25hQWxHWEx3OXdQamJiNG9KaDgKk94uXPuCE/M4Hz/7hVKJPHuzQfbOQi/9\nVfR2i17Hjcq08l68Xzn+DllQEAFdts2fS96Pu4FFKfiLK7INl/fUOg==\n-----END AGE ENCRYPTED FILE-----\n"
"recipient": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6RHhiQVFKMCs2NkZ6NENl\nRzUxVWRXWmxzcGhRSXNxNjBIQ1RkN2tpN0RRCmF3QzRvQXdzSVFFcnpBOHdmRFpL\nVzBoSWZKQjJLVDRkZDdlbEVZR2ZzRTAKLS0tIHlOR1dmWEk0UTNYa05nbVR6Q2pn\nVXFDMnNxZ0xJd1ZnVWhJSVlJYmZxQUkKnWc72eUjsVpeipP76ZoiPSGockLXMR/p\nUswkQR01sCcvuPV0sJLBUK+PRMEKBjUH7O9opOvzCsTTzIVaJyLpRg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age13ahclyps97532zt2sfta5zrfx976d3r2jmctj8d36vj9x5v5ffqq304fqf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSVXUxNGpGYnFEdlpNNUwv\nTEo3a25sSnhHNmlZb0h0QTBwUlpjTFBtZXljCngxcUpxTEZRZlJoTHAxeFRGWXpL\nUzM0eTFOMXQzS0ZEak9NOEJzbHlGS1kKLS0tIFpkWGcwVnVIVUZEYkNlcWVMUTdE\nR21qaTgxT3BpUzVoRUlQODlyRUxodFkKYQPKrDaogCO3m9JfFHc8IrGauipcWPRF\n4P51UqhAUtWwZLdiUIoY5ucG+NaDzBxxUJqJYlUqkQMbW/OvHihu9g==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-05-29T13:15:02Z",

View File

@@ -0,0 +1 @@
../../../../../sops/machines/second

View File

@@ -3,12 +3,16 @@
"sops": {
"age": [
{
"recipient": "age13ahclyps97532zt2sfta5zrfx976d3r2jmctj8d36vj9x5v5ffqq304fqf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPdkQyYnQ1UzlCWEFtdnJh\nMWlBK0RGcENTMmRITWM5SSs2Mkt2N0ZKdm5VClNTS0NuR05OVHY3QkFLZWt6bTUx\nMzJLc2Vib1ZUbW1VM0lhYXFFeEhOaEEKLS0tIHVoODVOK3BUU2JDZkJkN2I2Wm1L\nMWM0TUNQazljZS9uWXRKRFlxWmd0clUKg1YhJoRea05c24hCuZKYvqyvjuu965KD\nr4GLtyqQ6wt9sn50Rzx5cAY/Ac684DNFJVZ1RwG1NTB2kmXcVP8SJA==\n-----END AGE ENCRYPTED FILE-----\n"
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBYS83dDhMV1JINWtyT3Rp\ndlRBcjIyNEZuOTBaY24zMGZYdGQwRkIzTzBFCm1VVEN5bllBbklpcDBsNzZ3V1dy\nQ3owdm5RUWlEQzI0Y21NQ1lqcjR1UWcKLS0tIFpwYlVHTUtUR0tDL1BZcWtNMUo5\nUzVwcFh3MDVZTWJCRTkzUm5pc0d6UnMKlCvwvAvS2tvZel8VrHpU1B76owilCgnV\narlc+s7i2lBIyEW5npkZGkn8RgI558C34SPRhM2+c+ennSVIYZM56g==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoZTA5QXpsOXR3L2FKcnJD\neUxzNVp3M2VQMFFaUUxwNXQ4UTlXa01rR0IwCjkyU2hmdlVYbWY4WUpVK0J1ZC9Q\nRjVkYWlGTlh1MFY3R3FxMEZHODZXMmcKLS0tIFV3bGdvUEtnT21wRWJveEQwdTBV\nbGFUUExBZWR1enQ0c0l0dUY3TnErM3cKutl5cv8dSlpQA7SXUYWJq1M0yLmko/Bx\nUvxxGGLQaK0Mp81Z5mOsjNhcVQrY160AyVnWJ0z39cqOJq9PpXRP+A==\n-----END AGE ENCRYPTED FILE-----\n"
"recipient": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvUTlBZ3NKNFVQVzdWMnFv\neHVsTStkdHJ0dmVCRFVxODhxbWZwdHlOMEZNCjUrRENVNUxDWnZJQWhKYzJUVnNK\ncXNqSWdvajlUYkdjNEVYaDdxTVZKQ0EKLS0tIFM3WWxSOGU4Yk1Wb3B3VHBtRFlj\nemFIZ0xNTnNiaSttcU1lR0xMSzVXWDQKhY4zo/aoePu1kZ1uvvu+za2vkZVNFqO0\nBYYt88gOBS7Wb2N4+54w6CIKZy7oYljY+MRwlifArFIMpCt/EF473Q==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age13ahclyps97532zt2sfta5zrfx976d3r2jmctj8d36vj9x5v5ffqq304fqf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHalgveTJwYWEyZDRMZVB0\naVFWTnM3K1VQQzBYckVzbVVqREIxUXBsOUN3ClVRRzl5c2dqbkdTdFRUdmxtRmh0\nV1NCYURxT1d1MFdCUVRWV1hmNVh2L2MKLS0tIEdGQkFoc3FtbWQxUW43WTVwUDJr\nYlZrTmlXNVBhN3dSajlCaWxGb3JCQjAKDWYtDWKDoK6FybakbUOz1X82egHlkHte\n4noQjZ4yESGCWr9Pi3S+14IYItFObP1zh//Sab4e3uR9uVFBWLiVEw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-05-29T13:15:02Z",

View File

@@ -85,22 +85,27 @@ graph TB
### Basic Setup with Single Controller
```nix
# In your flake.nix or inventory
# In your clan.nix
{
services.wireguard.server1 = {
roles.controller = {
# Public endpoint where this controller can be reached
endpoint = "vpn.example.com";
# Optional: Change the UDP port (default: 51820)
port = 51820;
instances = {
wireguard = {
module.name = "wireguard";
module.input = "clan-core";
roles.controller = {
machines.server1 = {};
settings = {
# Public endpoint where this controller can be reached
endpoint = "vpn.example.com";
# Optional: Change the UDP port (default: 51820)
port = 51820;
};
};
roles.peer = {
# No configuration needed if only one controller exists
machines.laptop1 = {};
};
};
};
services.wireguard.laptop1 = {
roles.peer = {
# No configuration needed if only one controller exists
};
};
}
}
```
@@ -108,29 +113,95 @@ graph TB
```nix
{
services.wireguard.server1 = {
roles.controller = {
endpoint = "vpn1.example.com";
instances = {
wireguard = {
module.name = "wireguard";
module.input = "clan-core";
roles.controller.machines = {
server1.settings.endpoint = "vpn1.example.com";
server2.settings.endpoint = "vpn2.example.com";
server3.settings.endpoint = "vpn3.example.com";
};
roles.peer.machines.laptop1 = {
# Must specify which controller subnet is exposed as the default in /etc/hosts, when multiple controllers exist
settings.controller = "server1";
};
};
};
services.wireguard.server2 = {
roles.controller = {
endpoint = "vpn2.example.com";
};
};
services.wireguard.laptop1 = {
roles.peer = {
# Must specify which controller subnet is exposed as the default in /etc/hosts, when multiple controllers exist
controller = "server1";
};
};
}
}
```
### Advanced Options
#### External Peers
External peers are devices outside of your clan (like phones, laptops, etc.) that can connect to the mesh network through controllers. Each external peer gets its own keypair and can be configured with specific options.
##### IPv6-only external peers
```nix
{
instances = {
wireguard = {
module.name = "wireguard";
module.input = "clan-core";
roles.controller.machines.server1.settings = {
endpoint = "vpn.example.com";
# Define external peers with configuration options
externalPeers = {
dave = {
# No internet access - can only reach clan mesh
allowInternetAccess = false;
};
moms-phone = {
# Internet access enabled - IPv6 traffic routed through VPN
allowInternetAccess = true;
};
};
};
roles.peer.machines.laptop1 = {};
};
}
}
```
##### IPv4 support for external peers
If you need IPv4 internet access for external peers, you can enable IPv4 on the controller and assign IPv4 addresses to external peers:
```nix
{
instances = {
wireguard = {
module.name = "wireguard";
module.input = "clan-core";
roles.controller.machines.server1.settings = {
endpoint = "vpn.example.com";
# Enable IPv4 with controller's address
ipv4.enable = true;
ipv4.address = "10.42.1.1/24";
externalPeers = {
dave = {
# No internet access - can only reach clan mesh
allowInternetAccess = false;
ipv4.address = "10.42.1.50/32";
};
moms-phone = {
# Internet access enabled - IPv4 and IPv6 traffic routed through VPN
allowInternetAccess = true;
ipv4.address = "10.42.1.51/32";
};
};
};
roles.peer.machines.laptop1 = {};
};
}
}
```
**Note:** IPv4 addresses for external peers are only used for internet access through the controller, not for mesh communication (which uses IPv6).
External peers can connect to multiple controllers by adding the same peer name to multiple controllers' `externalPeers` configuration.
### Automatic Hostname Resolution

View File

@@ -105,9 +105,31 @@ let
peerIP = controllerPrefix + ":" + peerSuffix;
in
"${peerIP} ${peerName}.${domain}"
) roles.peer.machines;
) roles.peer.machines or { };
# External peers
externalPeerHosts = lib.flatten (
lib.mapAttrsToList (
ctrlName: _ctrlValue:
lib.mapAttrsToList (
peer: _peerSettings:
let
peerSuffix = builtins.readFile (
config.clan.core.settings.directory
+ "/vars/shared/wireguard-network-${instanceName}-external-peer-${peer}/suffix/value"
);
controllerPrefix = builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${ctrlName}/wireguard-network-${instanceName}/prefix/value"
);
peerIP = controllerPrefix + ":" + peerSuffix;
in
"${peerIP} ${peer}.${domain}"
) (roles.controller.machines.${ctrlName}.settings.externalPeers)
) roles.controller.machines
);
in
builtins.concatStringsSep "\n" (controllerHosts ++ peerHosts);
builtins.concatStringsSep "\n" (controllerHosts ++ peerHosts ++ externalPeerHosts);
};
# Shared interface options
@@ -268,12 +290,89 @@ in
{
imports = [ sharedInterface ];
options.endpoint = lib.mkOption {
type = lib.types.str;
example = "vpn.clan.lol";
description = ''
Endpoint where the controller can be reached
'';
options = {
endpoint = lib.mkOption {
type = lib.types.str;
example = "vpn.clan.lol";
description = ''
Endpoint where the controller can be reached
'';
};
ipv4 = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Enable IPv4 support for external peers on this controller.
When enabled, the controller will have an IPv4 address and can route IPv4 traffic.
IPv4 is only used for internet access, not for mesh communication (which uses IPv6).
'';
};
address = lib.mkOption {
type = lib.types.str;
example = "10.42.1.1/24";
description = ''
IPv4 address for this controller in CIDR notation.
External peers with IPv4 addresses must be within the same subnet.
IPv4 is only used for internet access, not for mesh communication (which uses IPv6).
'';
};
};
externalPeers = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
allowInternetAccess = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to allow this external peer to access the internet through the controller.
When enabled, the controller will route internet traffic for this peer.
IPv4 is only used for internet access, not for mesh communication (which uses IPv6).
'';
};
ipv4.address = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "10.42.1.50/32";
description = ''
IPv4 address for this external peer in CIDR notation.
The peer must be within the controller's IPv4 subnet.
Only used when the controller has IPv4 enabled.
IPv4 is only used for internet access, not for mesh communication (which uses IPv6).
'';
};
};
}
);
default = { };
example = {
dave = {
allowInternetAccess = false;
};
"moms-phone" = {
allowInternetAccess = true;
ipv4.address = "10.42.1.51/32";
};
};
description = ''
External peers that are not part of the clan.
For every entry here, a key pair for an external device will be generated.
This key pair can then be displayed via `clan vars get` and inserted into an external device, like a phone or laptop.
Each external peer can connect to the mesh through one or more controllers.
To connect to multiple controllers, add the same peer name to multiple controllers' `externalPeers`, or simply set set `roles.controller.settings.externalPeers`.
The external peer names must not collide with machine names in the clan.
The machines which are part of the clan will be able to resolve the external peers via their host names, but not vice versa.
External peers can still reach machines from within the clan via their IPv6 addresses.
'';
};
};
};
perInstance =
@@ -296,7 +395,37 @@ in
}:
let
allOtherControllers = lib.filterAttrs (name: _v: name != machine.name) roles.controller.machines;
allPeers = roles.peer.machines;
allPeers = roles.peer.machines or { };
# Collect all external peers from all controllers
allExternalPeers = lib.unique (
lib.flatten (
lib.mapAttrsToList (_: ctrl: lib.attrNames ctrl.settings.externalPeers) roles.controller.machines
)
);
controllerPrefix =
controllerName:
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${controllerName}/wireguard-network-${instanceName}/prefix/value"
);
peerSuffix =
peerName:
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${peerName}/wireguard-network-${instanceName}/suffix/value"
);
externalPeerSuffix =
externalName:
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/shared/wireguard-network-${instanceName}-external-peer-${externalName}/suffix/value"
);
thisControllerPrefix =
config.clan.core.vars.generators."wireguard-network-${instanceName}".files.prefix.value;
in
{
imports = [
@@ -310,93 +439,172 @@ in
;
})
];
# Network allocation generator for this controller
clan.core.vars.generators."wireguard-network-${instanceName}" = {
files.prefix.secret = false;
# Network prefix allocation generator for this controller
clan.core.vars.generators = {
"wireguard-network-${instanceName}" = {
files.prefix.secret = false;
runtimeInputs = with pkgs; [
python3
];
runtimeInputs = with pkgs; [
python3
];
# Invalidate on network or hostname changes
validation.hostname = machine.name;
# Invalidate on network or hostname changes
validation.hostname = machine.name;
script = ''
${pkgs.python3}/bin/python3 ${./ipv6_allocator.py} "$out" "${instanceName}" controller "${machine.name}"
'';
script = ''
${pkgs.python3}/bin/python3 ${./ipv6_allocator.py} "$out" "${instanceName}" controller "${machine.name}"
'';
};
}
# For external peers, generate: suffix, public key, private key
// lib.genAttrs' (lib.attrNames settings.externalPeers) (peer: {
name = "wireguard-network-${instanceName}-external-peer-${peer}";
value = {
files.suffix.secret = false;
files.publickey.secret = false;
files.privatekey.secret = true;
files.privatekey.deploy = false;
# The external peers keys are not deployed and are globally unique.
# Even if an external peer is connected to more than one controller,
# its private keys will remain the same.
share = true;
runtimeInputs = with pkgs; [
python3
wireguard-tools
];
# Invalidate on hostname changes
validation.hostname = peer;
script = ''
${pkgs.python3}/bin/python3 ${./ipv6_allocator.py} "$out" "${instanceName}" peer "${peer}"
wg genkey > $out/privatekey
wg pubkey < $out/privatekey > $out/publickey
'';
};
});
# Enable ip forwarding, so wireguard peers can reach each other
boot.kernel.sysctl = {
"net.ipv6.conf.all.forwarding" = 1;
}
// lib.optionalAttrs settings.ipv4.enable {
"net.ipv4.conf.all.forwarding" = 1;
};
# Enable ip forwarding, so wireguard peers can reach eachother
boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1;
networking.firewall.allowedUDPPorts = [ settings.port ];
networking.firewall.extraCommands =
let
peersWithInternetAccess = lib.filterAttrs (
_: peerConfig: peerConfig.allowInternetAccess
) settings.externalPeers;
peerInfo = lib.mapAttrs (
peer: peerConfig:
let
ipv6Address = "${thisControllerPrefix}:${externalPeerSuffix peer}";
ipv4Address =
if settings.ipv4.enable && peerConfig.ipv4.address != null then
lib.head (lib.splitString "/" peerConfig.ipv4.address)
else
null;
in
{
inherit ipv6Address ipv4Address;
}
) peersWithInternetAccess;
in
lib.concatStringsSep "\n" (
(lib.mapAttrsToList (_peer: info: ''
ip6tables -t nat -A POSTROUTING -s ${info.ipv6Address}/128 ! -o '${instanceName}' -j MASQUERADE
'') peerInfo)
++ (lib.mapAttrsToList (
_peer: info:
lib.optionalString (info.ipv4Address != null) ''
iptables -t nat -A POSTROUTING -s ${info.ipv4Address} ! -o '${instanceName}' -j MASQUERADE
''
) peerInfo)
);
# Single wireguard interface
networking.wireguard.interfaces."${instanceName}" = {
listenPort = settings.port;
ips = [
# Controller uses ::1 in its /56 subnet but with /40 prefix for proper routing
"${config.clan.core.vars.generators."wireguard-network-${instanceName}".files.prefix.value}::1/40"
];
"${thisControllerPrefix}::1/40"
]
++ lib.optional settings.ipv4.enable settings.ipv4.address;
privateKeyFile =
config.clan.core.vars.generators."wireguard-keys-${instanceName}".files."privatekey".path;
# Connect to all peers and other controllers
peers = lib.mapAttrsToList (
name: value:
if allPeers ? ${name} then
# For peers: they now have our entire /56 subnet
{
publicKey = (
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${name}/wireguard-keys-${instanceName}/publickey/value"
)
);
peers =
# Peers configuration
(lib.mapAttrsToList (name: _value: {
publicKey = (
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${name}/wireguard-keys-${instanceName}/publickey/value"
)
);
# Allow the peer's /96 range in ALL controller subnets
allowedIPs = lib.mapAttrsToList (
ctrlName: _:
let
controllerPrefix = builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${ctrlName}/wireguard-network-${instanceName}/prefix/value"
);
peerSuffix = builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${name}/wireguard-network-${instanceName}/suffix/value"
);
in
"${controllerPrefix}:${peerSuffix}/96"
) roles.controller.machines;
# Allow the peer's /96 range in ALL controller subnets
allowedIPs = lib.mapAttrsToList (
ctrlName: _: "${controllerPrefix ctrlName}:${peerSuffix name}/96"
) roles.controller.machines;
persistentKeepalive = 25;
}
else
# For other controllers: use their /56 subnet
{
publicKey = (
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${name}/wireguard-keys-${instanceName}/publickey/value"
)
);
persistentKeepalive = 25;
}) allPeers)
++
# External peers configuration - includes all external peers from all controllers
(map (
peer:
let
# IPv6 allowed IPs for mesh communication
ipv6AllowedIPs = lib.mapAttrsToList (
ctrlName: _: "${controllerPrefix ctrlName}:${externalPeerSuffix peer}/96"
) roles.controller.machines;
allowedIPs = [
"${
# IPv4 allowed IP (only if this controller manages this peer and has IPv4 enabled)
ipv4AllowedIPs = lib.optional (
settings.ipv4.enable
&& settings.externalPeers ? ${peer}
&& settings.externalPeers.${peer}.ipv4.address != null
) settings.externalPeers.${peer}.ipv4.address;
in
{
publicKey = (
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${name}/wireguard-network-${instanceName}/prefix/value"
+ "/vars/shared/wireguard-network-${instanceName}-external-peer-${peer}/publickey/value"
)
}::/56"
];
);
allowedIPs = ipv6AllowedIPs ++ ipv4AllowedIPs;
persistentKeepalive = 25;
}
) allExternalPeers)
++
# Other controllers configuration
(lib.mapAttrsToList (name: value: {
publicKey = (
builtins.readFile (
config.clan.core.settings.directory
+ "/vars/per-machine/${name}/wireguard-keys-${instanceName}/publickey/value"
)
);
allowedIPs = [ "${controllerPrefix name}::/56" ];
endpoint = "${value.settings.endpoint}:${toString value.settings.port}";
persistentKeepalive = 25;
}
) (allPeers // allOtherControllers);
}) allOtherControllers);
};
};
};
@@ -416,7 +624,7 @@ in
let
isController =
instanceInfo.roles ? controller && instanceInfo.roles.controller.machines ? ${machine.name};
isPeer = instanceInfo.roles ? peer && instanceInfo.roles.peer.machines ? ${machine.name};
isPeer = instanceInfo.roles ? peer && instanceInfo.roles.peer.machines or { } ? ${machine.name};
in
lib.optional (isController && isPeer) {
inherit instanceName;

View File

@@ -4,4 +4,12 @@ let
in
{
clan.modules.wireguard = module;
perSystem =
{ ... }:
{
clan.nixosTests.wireguard = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/wireguard" = module;
};
};
}

View File

@@ -0,0 +1,228 @@
{
lib,
config,
...
}:
let
machines = [
"controller1"
"controller2"
"peer1"
"peer2"
"peer3"
# external machine for external peer testing
"external1"
];
controllerPrefix =
controllerName:
builtins.readFile (
config.clan.directory
+ "/vars/per-machine/${controllerName}/wireguard-network-wg-test-one/prefix/value"
);
peerSuffix =
peerName:
builtins.readFile (
config.clan.directory + "/vars/per-machine/${peerName}/wireguard-network-wg-test-one/suffix/value"
);
# external peer suffixes are stored via shared vars
externalPeerSuffix =
externalName:
builtins.readFile (
config.clan.directory
+ "/vars/shared/wireguard-network-wg-test-one-external-peer-${externalName}/suffix/value"
);
in
{
name = "wireguard";
clan = {
directory = ./.;
inventory = {
machines = lib.genAttrs machines (_: { });
instances = {
/*
wg-test-one
controller2 controller1
peer2 peer1 peer3
*/
wg-test-one = {
module.name = "@clan/wireguard";
module.input = "self";
roles.controller.machines."controller1".settings = {
endpoint = "192.168.1.1";
# Enable IPv4 for external peers
ipv4.enable = true;
ipv4.address = "10.42.1.1/24";
# add an external peer to controller1 with IPv4
externalPeers.external1 = {
ipv4.address = "10.42.1.50/32";
};
};
roles.controller.machines."controller2".settings = {
endpoint = "192.168.1.2";
# add the same external peer to controller2 to test multi-controller connection
externalPeers.external1 = { };
};
roles.peer.machines = {
peer1.settings.controller = "controller1";
peer2.settings.controller = "controller2";
peer3.settings.controller = "controller1";
};
};
# TODO: Will this actually work with conflicting ports? Can we re-use interfaces?
#wg-test-two = {
# module.name = "@clan/wireguard";
# roles.controller.machines."controller1".settings = {
# endpoint = "192.168.1.1";
# port = 51922;
# };
# roles.peer.machines = {
# peer1 = { };
# };
#};
};
};
};
nodes.external1 =
let
controller1Prefix = controllerPrefix "controller1";
controller2Prefix = controllerPrefix "controller2";
external1Suffix = externalPeerSuffix "external1";
in
{
networking.extraHosts = ''
${controller1Prefix}::1 controller1.wg-test-one
${controller2Prefix}::1 controller2.wg-test-one
'';
networking.wireguard.interfaces."wg0" = {
# Multiple IPs, one in each controller's subnet (IPv6) plus IPv4
ips = [
"${controller1Prefix + ":" + external1Suffix}/56"
"${controller2Prefix + ":" + external1Suffix}/56"
"10.42.1.50/32" # IPv4 address for controller1
];
privateKeyFile =
builtins.toFile "wg-priv-key"
# This needs to be updated whenever update-vars was executed
# Get the value from the generated vars via this command:
# echo "AGE-SECRET-KEY-1PL0M9CWRCG3PZ9DXRTTLMCVD57U6JDFE8K7DNVQ35F4JENZ6G3MQ0RQLRV" | SOPS_AGE_KEY_FILE=/dev/stdin nix run nixpkgs#sops decrypt clanServices/wireguard/tests/vm/vars/shared/wireguard-network-wg-test-one-external-peer-external1/privatekey/secret
"wO8dl3JWgV5J+0D/2UDcLsxTD25IWTvd5ed6vv2Nikk=";
# Connect to both controllers
peers = [
# Controller 1
{
publicKey = (
builtins.readFile (
config.clan.directory + "/vars/per-machine/controller1/wireguard-keys-wg-test-one/publickey/value"
)
);
# Allow controller1's /56 subnet (IPv6) and IPv4 subnet
allowedIPs = [
"${controller1Prefix}::/56"
"10.42.1.0/24" # IPv4 subnet for internet access
];
endpoint = "controller1:51820";
persistentKeepalive = 25;
}
# Controller 2
{
publicKey = (
builtins.readFile (
config.clan.directory + "/vars/per-machine/controller2/wireguard-keys-wg-test-one/publickey/value"
)
);
# Allow controller2's /56 subnet
allowedIPs = [ "${controller2Prefix}::/56" ];
endpoint = "controller2:51820";
persistentKeepalive = 25;
}
];
};
};
testScript = ''
start_all()
# Start network on all machines including external1
machines = [peer1, peer2, peer3, controller1, controller2, external1]
for m in machines:
m.systemctl("start network-online.target")
for m in machines:
m.wait_for_unit("network-online.target")
m.wait_for_unit("systemd-networkd.service")
print("\n\n" + "="*60)
print("STARTING PING TESTS")
print("="*60)
# Test mesh connectivity between regular clan machines
clan_machines = [peer1, peer2, peer3, controller1, controller2]
for m1 in clan_machines:
for m2 in clan_machines:
if m1 != m2:
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
# Test that external peer can reach both controllers (multi-controller connection)
print("\n--- Testing external1 -> controller1 (direct connection) ---")
external1.wait_until_succeeds("ping -c1 controller1.wg-test-one >&2")
print("\n--- Testing external1 -> controller2 (direct connection) ---")
external1.wait_until_succeeds("ping -c1 controller2.wg-test-one >&2")
# Test IPv4 connectivity
print("\n--- Testing external1 -> controller1 (IPv4) ---")
external1.wait_until_succeeds("ping -c1 10.42.1.1 >&2")
# Test that all clan machines can reach the external peer
for m in clan_machines:
print(f"\n--- Pinging from {m.name} to external1.wg-test-one ---")
m.wait_until_succeeds("ping -c1 external1.wg-test-one >&2")
# Test that external peer can reach a regular peer via controller1
print("\n--- Testing external1 -> peer1 (via controller1) ---")
external1.wait_until_succeeds("ping -c1 ${controllerPrefix "controller1"}:${peerSuffix "peer1"} >&2")
# Test controller failover
print("\n--- Shutting down controller1 ---")
controller1.shutdown()
print("\n--- Testing external1 -> peer1 (via controller2 after controller1 shutdown) ---")
external1.wait_until_succeeds("ping -c1 ${controllerPrefix "controller2"}:${peerSuffix "peer1"} >&2")
'';
}

Some files were not shown because too many files have changed in this diff Show More