Compare commits

...

710 Commits

Author SHA1 Message Date
Qubasa
da84b911b0 fix pnpm build error on zfs 2025-09-10 14:02:48 +02:00
clan-bot
a6214f431d Merge pull request 'Update nixpkgs-dev in devFlake' (#5131) from update-devFlake-nixpkgs-dev into main 2025-09-10 00:12:29 +00:00
clan-bot
b8890f6732 Update nixpkgs-dev in devFlake 2025-09-10 00:01:36 +00:00
Luis Hebendanz
370b4f535d Merge pull request 'vars: docs' (#4119) from vars-docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4119
2025-09-09 20:59:52 +00:00
Qubasa
ef66c9b5be docs: vars ai fixups 2025-09-09 22:53:15 +02:00
Jörg Thalheim
79d44f7c30 vars: docs
re-add vars-backend.md

re-add vars-backend.md
2025-09-09 22:12:07 +02:00
clan-bot
e72e100965 Merge pull request 'Update nixpkgs-dev in devFlake' (#5129) from update-devFlake-nixpkgs-dev into main 2025-09-09 20:10:13 +00:00
clan-bot
180e2a601c Merge pull request 'Update nix-darwin' (#5128) from update-nix-darwin into main 2025-09-09 20:06:57 +00:00
clan-bot
90d265089b Update nixpkgs-dev in devFlake 2025-09-09 20:01:39 +00:00
clan-bot
a0fa52fded Update nix-darwin 2025-09-09 20:00:41 +00:00
Luis Hebendanz
af4e9e784b Merge pull request 'docs: Add secure boot info to disk encryption guide' (#5127) from docs_fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5127
2025-09-09 17:46:09 +00:00
Qubasa
cb162a53b8 docs: Add secure boot info to disk encryption guide
fix wrong link
2025-09-09 19:41:59 +02:00
Luis Hebendanz
16e506ea1a Merge pull request 'doc: use clan-core as inputs name' (#5126) from Mayeu-doc/clan-core-input2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5126
2025-09-09 17:29:06 +00:00
Mayeu
11ec94c17f doc: use clan-core as inputs name 2025-09-09 19:18:35 +02:00
clan-bot
8468b1ebaf Merge pull request 'Update nixpkgs-dev in devFlake' (#5123) from update-devFlake-nixpkgs-dev into main 2025-09-09 15:08:55 +00:00
clan-bot
ec83130fa4 Update nixpkgs-dev in devFlake 2025-09-09 15:01:38 +00:00
Luis Hebendanz
c1e41f8fd9 Merge pull request 'docs: update concepts/inventory to match new option structure' (#5121) from friedow/clan-core:docs/concept-inventory into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5121
2025-09-09 14:44:30 +00:00
Christian Friedow
3630e778ad docs: update concepts/inventory to match new option structure 2025-09-09 15:35:23 +02:00
Luis Hebendanz
916186c465 Merge pull request 'webview: update to support displaying app icon on macOS' (#5120) from Qubasa/clan-core:demo_fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5120
2025-09-09 10:12:56 +00:00
clan-bot
25e733b8d7 Merge pull request 'Update nixpkgs-dev in devFlake' (#5112) from update-devFlake-nixpkgs-dev into main 2025-09-09 10:11:14 +00:00
Luis Hebendanz
2599998b17 Merge pull request 'add apply "machine" as an alias to clan machines create' (#5005) from apply into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5005
2025-09-09 10:08:58 +00:00
clan-bot
56649b7fe2 Merge pull request 'Update data-mesher' (#5111) from update-data-mesher into main 2025-09-09 10:07:57 +00:00
Luis Hebendanz
fc85622e01 Merge pull request 'ui/imports: fix asset imports' (#5119) from fix-imports into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5119
2025-09-09 10:02:29 +00:00
clan-bot
c499c563bb Update nixpkgs-dev in devFlake 2025-09-09 10:02:19 +00:00
clan-bot
b255ba0367 Update data-mesher 2025-09-09 10:01:18 +00:00
Luis Hebendanz
493adebd7c Merge pull request 'docs: Fix minor typo' (#5110) from vorburger/clan-core:docs-typo into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5110
2025-09-09 09:59:21 +00:00
Qubasa
cac2866356 webview: update to support displaying app icon on macOS 2025-09-09 11:54:18 +02:00
Qubasa
981f6052ad zerotierone: Add restartUnit to vars generators 2025-09-09 09:49:38 +00:00
Michael Vorburger
6e888c38fa docs: Fix minor typo 2025-09-08 01:03:55 +02:00
clan-bot
e953f807de Merge pull request 'Update disko' (#5108) from update-disko into main 2025-09-07 15:07:42 +00:00
clan-bot
c2534e9a42 Update disko 2025-09-07 15:00:37 +00:00
clan-bot
b0feef1a40 Merge pull request 'Update nixpkgs-dev in devFlake' (#5101) from update-devFlake-nixpkgs-dev into main 2025-09-07 05:08:56 +00:00
clan-bot
d4c26087df Update nixpkgs-dev in devFlake 2025-09-07 05:01:56 +00:00
clan-bot
1a9bbab667 Merge pull request 'Update nix-darwin' (#5100) from update-nix-darwin into main 2025-09-06 05:08:32 +00:00
clan-bot
b23171f291 Update nix-darwin 2025-09-06 05:00:40 +00:00
clan-bot
087423597b Merge pull request 'Update nixpkgs-dev in devFlake' (#5099) from update-devFlake-nixpkgs-dev into main 2025-09-05 10:08:09 +00:00
clan-bot
602dc192f3 Update nixpkgs-dev in devFlake 2025-09-05 10:01:37 +00:00
clan-bot
dba166cc8a Merge pull request 'Update nixpkgs-dev in devFlake' (#5097) from update-devFlake-nixpkgs-dev into main 2025-09-05 00:09:56 +00:00
clan-bot
21b872a1c9 Merge pull request 'Update nix-darwin' (#5096) from update-nix-darwin into main 2025-09-05 00:07:04 +00:00
clan-bot
be48ffe724 Update nixpkgs-dev in devFlake 2025-09-05 00:01:40 +00:00
clan-bot
7673b72991 Update nix-darwin 2025-09-05 00:00:43 +00:00
Johannes Kirschbauer
42bbd7c5fd ui/imports: fix asset imports 2025-09-04 19:35:06 +02:00
clan-bot
823114435a Merge pull request 'Update nixpkgs-dev in devFlake' (#5095) from update-devFlake-nixpkgs-dev into main 2025-09-04 15:08:37 +00:00
clan-bot
e7efbb701b Update nixpkgs-dev in devFlake 2025-09-04 15:01:35 +00:00
hsjobeki
30d9c86015 Merge pull request 'ui/move: fix bug, with interleaving positions' (#5094) from ui/password-input-reveal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5094
2025-09-03 20:00:53 +00:00
Johannes Kirschbauer
313b77be79 ui/move: fix bug, with interleaving positions 2025-09-03 21:57:27 +02:00
hsjobeki
6229e62281 Merge pull request 'ui/services: fix reactivity issue when switching between services' (#5093) from ui/password-input-reveal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5093
2025-09-03 19:53:56 +00:00
Johannes Kirschbauer
49ff4da6be ui/services: fix reactivity issue when switching between services 2025-09-03 21:50:15 +02:00
hsjobeki
6d6521803d Merge pull request 'ui/move: fix bug, when long press without moving' (#5092) from ui/password-input-reveal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5092
2025-09-03 19:44:14 +00:00
Johannes Kirschbauer
afd7bfc8c0 ui/move: fix bug, when long press without moving 2025-09-03 21:40:46 +02:00
hsjobeki
88fa3dff83 Merge pull request 'ui/3d-fonts: replace troika with 3d rendered default font' (#5091) from ui/password-input-reveal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5091
2025-09-03 19:38:05 +00:00
Johannes Kirschbauer
629ef65ce5 ui/3d-fonts: replace troika with 3d rendered default font 2025-09-03 21:34:26 +02:00
Johannes Kirschbauer
92151331f3 ui/devShell: remove fonts directory if exists 2025-09-03 21:33:40 +02:00
Johannes Kirschbauer
67dcd45dd5 ui/services: simplify and sort 2025-09-03 21:15:06 +02:00
hsjobeki
95a4a69ffb Merge pull request 'ui/fieldset: use normal div, due to webkit layout bug for fieldsets' (#5090) from ui/password-input-reveal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5090
2025-09-03 19:11:47 +00:00
Johannes Kirschbauer
88343ce523 ui/sidebar: remove spurious console.log 2025-09-03 21:05:58 +02:00
Johannes Kirschbauer
fd9dd6f872 ui/fieldset: use normal div, due to webkit layout bug for fieldsets 2025-09-03 21:05:35 +02:00
Brian McGee
aaaa310c7f feat(ui): refine input to allow start and end components 2025-09-03 21:05:35 +02:00
Luis Hebendanz
ffbf22eb60 Merge pull request 'docs: Fixup out of date networking docs' (#5089) from Qubasa/clan-core:fix_docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5089
2025-09-03 16:39:22 +00:00
Qubasa
8d3e0d2209 docs: Fixup out of date networking docs 2025-09-03 18:35:55 +02:00
Luis Hebendanz
c05a890d50 Merge pull request 'clanServices: telegraf -> fix telegraf-json failing because file does not yet exist' (#5088) from Qubasa/clan-core:telegraf_fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5088
2025-09-03 16:08:07 +00:00
Qubasa
03458ffbd8 clanServices: telegraf -> fix telegraf-json failing because file does not yet exist 2025-09-03 17:51:51 +02:00
clan-bot
ea098048c8 Merge pull request 'Update nixpkgs-dev in devFlake' (#5086) from update-devFlake-nixpkgs-dev into main 2025-09-03 15:07:41 +00:00
brianmcgee
838ed6ead7 Merge pull request 'feat(ui): refine input to allow start and end components' (#5080) from ui/password-input-reveal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5080
2025-09-03 15:02:30 +00:00
clan-bot
7e7278b99b Update nixpkgs-dev in devFlake 2025-09-03 15:01:36 +00:00
Brian McGee
f4d7728f3f feat(ui): refine input to allow start and end components 2025-09-03 15:55:49 +01:00
brianmcgee
c9b71496eb Merge pull request 'feat(ui): improve placeholder to MachineTags' (#5085) from ui/improve-tags-placeholder into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5085
2025-09-03 14:42:14 +00:00
Brian McGee
cd1f9c5a8b feat(ui): improve placeholder to MachineTags 2025-09-03 15:38:57 +01:00
hsjobeki
56379510d0 Merge pull request 'ui/sidebar: max-width of section, scroll within sections' (#5083) from ui/update-machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5083
2025-09-03 12:49:22 +00:00
Johannes Kirschbauer
389299ac7d ui/refetch: don't block button clicks, move context out of modal 2025-09-03 14:45:55 +02:00
Johannes Kirschbauer
9cf04bcb5f ui/services: pass instance to ServiceRoute 2025-09-03 14:31:42 +02:00
Johannes Kirschbauer
c370598564 ui/sidebar: max-width of section, scroll within sections 2025-09-03 14:31:05 +02:00
brianmcgee
04001ff178 Merge pull request 'feat(ui): refresh state after machine install or update' (#5081) from ui/refresh-state into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5081
2025-09-03 11:22:15 +00:00
Brian McGee
194c3080ea feat(ui): refresh state after machine install or update
Closes #5071
2025-09-03 12:10:35 +01:00
hsjobeki
60d1e524ac Merge pull request 'ui/update: integrate with api' (#5079) from ui/update-machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5079
2025-09-03 10:46:45 +00:00
Johannes Kirschbauer
672af1c63d ui/update: fix cancel/close 2025-09-03 12:41:26 +02:00
Johannes Kirschbauer
6cb728a4ca ui/update: integrate with api 2025-09-03 12:29:23 +02:00
hsjobeki
a074650947 Merge pull request 'ui/install: vars fix loading screen' (#5077) from ui/update-machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5077
2025-09-03 06:34:29 +00:00
Johannes Kirschbauer
f169a40c69 ui/install: fix onClose not called 2025-09-03 08:30:57 +02:00
Johannes Kirschbauer
480d5ee18c ui/install: vars fix loading screen 2025-09-03 08:28:51 +02:00
hsjobeki
ba47d797e4 Merge pull request 'ui/update: init update machine' (#5076) from ui/update-machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5076
2025-09-02 20:18:01 +00:00
Johannes Kirschbauer
3e5f84dcb4 ui/update: init update machine 2025-09-02 22:14:34 +02:00
brianmcgee
e398d98b42 Merge pull request 'fix(ui): re-enable machine state query but disable polling' (#5075) from ui/fix-machine-status into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5075
2025-09-02 20:13:22 +00:00
Brian McGee
09e5f78aae fix(ui): re-enable machine state query but disable polling 2025-09-02 21:09:13 +01:00
clan-bot
ae1680a720 Merge pull request 'Update nixpkgs-dev in devFlake' (#5074) from update-devFlake-nixpkgs-dev into main 2025-09-02 20:07:56 +00:00
clan-bot
9abf557353 Update nixpkgs-dev in devFlake 2025-09-02 20:01:33 +00:00
brianmcgee
dc0ec3443e Merge pull request 'feat(ui): simplify machine status' (#5073) from ui/update-machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5073
2025-09-02 19:28:09 +00:00
Brian McGee
d6c6918f85 feat(ui): simplify machine status 2025-09-02 21:20:25 +02:00
hsjobeki
24756442c8 Merge pull request 'feat(ui): services in sidebar and sidebar pane' (#5072) from ui/list-services-sidebar into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5072
2025-09-02 19:16:49 +00:00
Johannes Kirschbauer
c61a0f0712 ui/services: wire up with sidebar and router 2025-09-02 21:13:10 +02:00
Johannes Kirschbauer
f05bfcb13d ui/services: refactor services 2025-09-02 20:41:51 +02:00
Brian McGee
6d8ea1f2c5 feat(ui): services in sidebar and sidebar pane 2025-09-02 20:39:24 +02:00
Luis Hebendanz
f1de0e28ff Merge pull request 'clan-app: Add password input' (#5068) from Qubasa/clan-core:password_prompt into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5068
2025-09-02 15:48:24 +00:00
Qubasa
53ce3cf53d clan-app: Add password input 2025-09-02 17:41:07 +02:00
brianmcgee
0ac6d7be87 Merge pull request 'fix(ui): add loader sizes' (#5067) from ui/fix-loader-scaling into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5067
2025-09-02 15:09:42 +00:00
Brian McGee
e55401ecd9 fix(ui): add loader sizes 2025-09-02 16:04:41 +01:00
DavHau
37a49a14f4 vars: fix re-generate behavior for dependencies of shared vars (#5001)
fixes https://git.clan.lol/clan/clan-core/issues/3791

This fixes multiple issues we had when re-generating shared vars.

Problem 1: shared vars are re-generated for each individual machine instead of just once (see #3791)

Problem 2: When a shared var was re-generated for one machine, dependent vars on other machines did not get re-generated, leading to broken state

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5001
2025-09-02 14:54:24 +00:00
brianmcgee
7f68b10611 Merge pull request 'fix(ui): remove empty strings from add machine api call' (#5066) from ui/refine-add-machine-api-call into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5066
2025-09-02 14:43:57 +00:00
Brian McGee
a2867ba29d fix(ui): remove empty strings from add machine api call 2025-09-02 15:40:32 +01:00
pinpox
0817cf868b Merge pull request 'Change default coredns port' (#5065) from fixes-coredns into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5065
2025-09-02 13:28:57 +00:00
pinpox
018ffdaeeb Change default coredns port
This removes a conflict with systemd-resolved and provides an option to
set your own port
2025-09-02 15:23:12 +02:00
hsjobeki
eebb9b6a12 Merge pull request 'ui/fix: some more fixes' (#5063) from ui-more-3 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5063
2025-09-02 12:12:25 +00:00
Johannes Kirschbauer
36f73d40b3 ui/scene: fix double click on move 2025-09-02 14:09:16 +02:00
Johannes Kirschbauer
db84369000 ui/toolbar: shrink width avoid blocking interactions 2025-09-02 14:08:48 +02:00
Johannes Kirschbauer
359b2d4e7a ui/fix: move machine into starting position 2025-09-02 12:40:44 +02:00
Johannes Kirschbauer
2af9bd5003 ui/fix: frozen map after clicking machine 2025-09-02 12:40:23 +02:00
Johannes Kirschbauer
a8cbfcbd18 ui/toolbar: increase stacking index 2025-09-02 12:38:42 +02:00
Johannes Kirschbauer
dc17d62131 ui/contextMenu: prevent duplicate context menu 2025-09-02 12:38:15 +02:00
lassulus
f97e22e125 Merge pull request 'fix: network checking triggering fail2ban' (#5047) from MoritzBoehme/clan-core:fix-network-check into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5047
2025-09-02 09:49:33 +00:00
hsjobeki
1d9ad2ae54 Merge pull request 'ui/labels: fix font, bg radius' (#5061) from ui-more-3 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5061
2025-09-02 09:38:38 +00:00
pinpox
c266261d3b Merge pull request 'Add certificates service' (#4780) from certificates into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4780
2025-09-02 09:36:18 +00:00
Johannes Kirschbauer
93c31d4c26 ui/labels: fix font, bg radius 2025-09-02 11:34:55 +02:00
pinpox
c9275db377 update vars 2025-09-02 11:27:31 +02:00
brianmcgee
cf83833d8b Merge pull request 'fix(ui): reactivity within machine detail view' (#5060) from ui/fix-machine-detail into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5060
2025-09-02 08:05:03 +00:00
Brian McGee
494f79edb4 fix(ui): reactivity within machine detail view 2025-09-02 09:01:23 +01:00
clan-bot
de3102614a Merge pull request 'Update flake-parts' (#5059) from update-flake-parts into main 2025-09-02 00:06:18 +00:00
clan-bot
a6f0924c05 Update flake-parts 2025-09-02 00:00:42 +00:00
pinpox
99dc4f6787 Fix update-vars script 2025-09-01 22:31:09 +02:00
hsjobeki
5f2ad6432e Merge pull request 'ui/machines: some scenen improvements' (#5058) from ui-more-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5058
2025-09-01 18:52:20 +00:00
Johannes Kirschbauer
f8c34caaab ui/machines: add background to 3d labels 2025-09-01 20:48:02 +02:00
hsjobeki
8c2399446b Merge pull request 'ui/machineTags: remove spurious console.logs' (#5056) from ui-more-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5056
2025-09-01 18:39:11 +00:00
Johannes Kirschbauer
95c781bf4d ui/machines: move on long press 2025-09-01 19:14:32 +02:00
Johannes Kirschbauer
fe58de0997 ui/machineTags: remove spurious logging 2025-09-01 18:23:39 +02:00
hsjobeki
7582458bae Merge pull request 'ui/machineTags: fix keyboard and select logic' (#5055) from ui-more-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5055
2025-09-01 16:20:37 +00:00
Johannes Kirschbauer
3a7d7afaab ui/machineTags: fix keyboard and select logic 2025-09-01 18:15:48 +02:00
Luis Hebendanz
321eeacff0 Merge pull request 'clan-app: Now displays runtime icon correctly in process overview' (#5019) from Qubasa/clan-core:fix_runtime_icon into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5019
2025-09-01 15:37:51 +00:00
Qubasa
8ae43ff9a0 clan-app: display runtime icon on macOS too 2025-09-01 17:34:30 +02:00
Qubasa
e6efd5e731 clan-app: display runtime icon correctly in process overview 2025-09-01 17:34:07 +02:00
clan-bot
7c1c8a5486 Merge pull request 'Update nuschtos in devFlake' (#5053) from update-devFlake-nuschtos into main 2025-09-01 15:10:50 +00:00
clan-bot
7932562fa6 Merge pull request 'Update nixpkgs-dev in devFlake' (#5052) from update-devFlake-nixpkgs-dev into main 2025-09-01 15:10:24 +00:00
clan-bot
ac22843abc Merge pull request 'Update disko' (#5051) from update-disko into main 2025-09-01 15:10:23 +00:00
clan-bot
eb83386098 Update nuschtos in devFlake 2025-09-01 15:01:33 +00:00
clan-bot
7877075847 Update nixpkgs-dev in devFlake 2025-09-01 15:01:30 +00:00
clan-bot
7206dd8219 Update disko 2025-09-01 15:00:34 +00:00
hsjobeki
f21e1e7641 Merge pull request 'api/machines: move configuration data into subattribute' (#5048) from api-list-machines into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5048
2025-09-01 14:55:26 +00:00
Johannes Kirschbauer
c2a3f5e498 api/machines: populate instance_refs 2025-09-01 16:47:47 +02:00
pinpox
63c0db482f rename TLDs to tlds 2025-09-01 15:49:53 +02:00
pinpox
d2456be3dd Add certificates service 2025-09-01 15:49:53 +02:00
pinpox
c3c08482ac Merge pull request 'Fix update-vars, add shell' (#5050) from fix-update-vars-new into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5050
2025-09-01 13:38:25 +00:00
brianmcgee
62126f0c32 Merge pull request 'feat(ui): refine styling for MachineTags and fix inverted mode' (#5049) from ui/refine-machine-tags into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5049
2025-09-01 13:32:06 +00:00
pinpox
28139560c2 Fix update-vars, add shell 2025-09-01 15:31:54 +02:00
Brian McGee
45c916fb6d feat(ui): refine styling for MachineTags and fix inverted mode
Closes #5045
2025-09-01 14:27:47 +01:00
Johannes Kirschbauer
727d4e70ae api/machines: move configuration data into subattribute
This helps to make room for 'instance_refs'
And potentially other metadata that we want to compute and expose
2025-09-01 14:42:12 +02:00
Moritz Böhme
261c5d2be8 fix: network checking triggering fail2ban 2025-09-01 14:17:10 +02:00
clan-bot
87ea942399 Merge pull request 'Update data-mesher' (#5044) from update-data-mesher into main 2025-09-01 07:49:03 +00:00
clan-bot
39a032a285 Update data-mesher 2025-09-01 05:00:37 +00:00
clan-bot
a06940e981 Merge pull request 'Update treefmt-nix in devFlake' (#5043) from update-devFlake-treefmt-nix into main 2025-08-31 20:13:10 +00:00
clan-bot
4aebfadc8a Merge pull request 'Update nixpkgs-dev in devFlake' (#5042) from update-devFlake-nixpkgs-dev into main 2025-08-31 20:11:27 +00:00
clan-bot
f45f26994e Merge pull request 'Update treefmt-nix' (#5041) from update-treefmt-nix into main 2025-08-31 20:11:10 +00:00
clan-bot
c777a1a2b9 Update treefmt-nix in devFlake 2025-08-31 20:01:38 +00:00
clan-bot
36fe7822f7 Update nixpkgs-dev in devFlake 2025-08-31 20:01:33 +00:00
clan-bot
0ccf3310f9 Update treefmt-nix 2025-08-31 20:01:10 +00:00
clan-bot
a8d6552caa Merge pull request 'Update nixos-facter-modules' (#5032) from update-nixos-facter-modules into main 2025-08-31 19:39:40 +00:00
hsjobeki
a131448dcf Merge pull request 'ui/scene: init move machine' (#5031) from ui-more-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5031
2025-08-31 15:22:32 +00:00
hsjobeki
14a52dbc2e Merge pull request 'api/modules: improve logic for builtin modules' (#5040) from fix-modules-spagetti-other into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5040
2025-08-31 15:12:31 +00:00
Johannes Kirschbauer
565391bd8c ui/modules: deduplicate information 2025-08-31 17:09:36 +02:00
Johannes Kirschbauer
9bffa2a774 ui/clanContext: simplify
Try to avoid classes for use cases like this
2025-08-31 17:04:03 +02:00
Johannes Kirschbauer
e42a07423e ui/machineLabels: use troika for label rendering 2025-08-31 17:04:03 +02:00
Johannes Kirschbauer
c5178ac16a ui/fonts: use ttf font for 3d texture rendering 2025-08-31 17:04:03 +02:00
Johannes Kirschbauer
33791e06cd ui: cleanup unused code 2025-08-31 17:04:03 +02:00
Johannes Kirschbauer
c7e3bf624e ui/scene: replace 2d labels 2025-08-31 17:04:03 +02:00
Johannes Kirschbauer
ba027c2239 ui/scene: init move machine 2025-08-31 17:04:03 +02:00
Johannes Kirschbauer
25fdabee29 ui/menu: add simple context menu 2025-08-31 17:04:03 +02:00
clan-bot
de69c63ee3 Update nixos-facter-modules 2025-08-31 15:00:41 +00:00
Johannes Kirschbauer
b9573636d8 ui/modules: simplify ui logic 2025-08-31 15:58:39 +02:00
Johannes Kirschbauer
3862ad2a06 api/modules: add foreign key to instances 2025-08-31 15:58:39 +02:00
Johannes Kirschbauer
c447aec9d3 api/modules: improve logic for builtin modules 2025-08-31 15:58:39 +02:00
Johannes Kirschbauer
5137d19b0f nix_modules: fix and update None types 2025-08-31 15:58:39 +02:00
Johannes Kirschbauer
453f2649d3 clanInternals: expose builtin modules 2025-08-31 15:58:39 +02:00
Johannes Kirschbauer
58cfcf3d25 api/modules: delete instances.py duplicate 2025-08-31 15:58:39 +02:00
clan-bot
c260a97cc1 Merge pull request 'Update nixpkgs-dev in devFlake' (#5033) from update-devFlake-nixpkgs-dev into main 2025-08-31 13:49:44 +00:00
clan-bot
3eb64870b0 Update nixpkgs-dev in devFlake 2025-08-31 13:44:23 +00:00
Mic92
7412b958c6 Merge pull request 'disable state-version in right place' (#5038) from private-flake-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5038
2025-08-31 13:43:07 +00:00
Jörg Thalheim
a0c27194a6 disable state-version in right place 2025-08-31 15:37:25 +02:00
Mic92
3437af29cb Merge pull request 'vars: fix var name in error message' (#5037) from private-flake-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5037
2025-08-31 13:33:01 +00:00
Jörg Thalheim
0b1c12d2e5 flash-installer: disable state-version
We cannot have vars in here because it breaks:

```
  clan flash write --flake https://git.clan.lol/clan/clan-core/archive/main.tar.gz   --ssh-pubkey $HOME/.ssh/id_ed25519.pub   --keymap us   --language en_US.UTF-8   --disk main /dev/sdb   flash-installer
```
2025-08-31 15:26:04 +02:00
Jörg Thalheim
8620761bbd vars: fix var name in error message 2025-08-31 15:23:24 +02:00
Mic92
d793b6ca07 Merge pull request 'vars: improve error message when storing trying to store a var in a read-only flake' (#5036) from private-flake-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5036
2025-08-31 13:20:13 +00:00
Jörg Thalheim
17e9231657 vars: improve error message when storing trying to store a var in a read-only flake 2025-08-31 14:14:56 +02:00
Mic92
acc2674d79 Merge pull request 'fix: check if phases are non-default when installing' (#5024) from sachk/clan-core:main into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5024
2025-08-29 16:16:01 +00:00
Jörg Thalheim
c34a21a3bb install: make Step a String enum 2025-08-29 17:45:16 +02:00
Mic92
275bff23da Merge pull request 'zfs-latest: fix eval errors' (#5029) from zfs-latest into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5029
2025-08-29 15:26:58 +00:00
Sacha Korban
1a766a3447 fix: check if phases are non-default when running 2025-08-29 17:26:49 +02:00
Jörg Thalheim
c22844c83b zfs-latest: fix eval errors 2025-08-29 17:20:56 +02:00
clan-bot
5472ca0e21 Merge pull request 'Update nixpkgs-dev in devFlake' (#5028) from update-devFlake-nixpkgs-dev into main 2025-08-29 15:08:13 +00:00
clan-bot
ad890b0b6b Update nixpkgs-dev in devFlake 2025-08-29 15:01:35 +00:00
DavHau
a364b5ebf3 API/list_service_instances: add module metadata (#5023)
@hsjobeki

Co-authored-by: Johannes Kirschbauer <hsjobeki@gmail.com>
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5023
2025-08-29 13:14:19 +00:00
brianmcgee
d0134d131e Merge pull request 'feat(ui): display add machine in sidebar when machine list is empty' (#5027) from ui/refine-add-machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5027
2025-08-29 12:27:33 +00:00
Brian McGee
ccf0dace11 feat(ui): display add machine in sidebar when machine list is empty 2025-08-29 13:23:45 +01:00
hsjobeki
9977a903ce Merge pull request 'ui/scene: cursor and mode fixes' (#5026) from ui-more-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5026
2025-08-29 12:01:56 +00:00
Johannes Kirschbauer
dc9bf5068e ui/scene: make 'select' the default mode 2025-08-29 13:58:35 +02:00
Johannes Kirschbauer
6b4f79c9fa ui/scene: add different cursor type 2025-08-29 13:54:32 +02:00
brianmcgee
b2985b59e9 Merge pull request 'feat(ui): stop reloading sidebar when moving between machine' (#5025) from ui/stop-sidebar-pane-re-opening into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5025
2025-08-29 11:27:03 +00:00
Brian McGee
d4ac3b83ee feat(ui): stop reloading sidebar when moving between machine 2025-08-29 12:06:28 +01:00
hsjobeki
00bf55be5a Merge pull request 'ui/implement-add-machine-workflow' (#5021) from ui/implement-add-machine-workflow into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5021
2025-08-29 08:42:31 +00:00
Johannes Kirschbauer
851d6aaa89 ui/machines: hook up create machine with scene workflow 2025-08-29 10:39:05 +02:00
Johannes Kirschbauer
f007279bee ui: format and debug messages 2025-08-29 10:38:39 +02:00
Brian McGee
5a3381d9ff ui/machines: add machine workflow 2025-08-29 10:34:03 +02:00
clan-bot
83e51db2e7 Merge pull request 'Update nixpkgs-dev in devFlake' (#5022) from update-devFlake-nixpkgs-dev into main 2025-08-29 00:11:06 +00:00
clan-bot
4e4af8a52f Update nixpkgs-dev in devFlake 2025-08-29 00:01:29 +00:00
Brian McGee
54a8ec717e chore(ui): rename install workflow to InstallMachine 2025-08-28 22:44:27 +02:00
hsjobeki
d3e5e6edf1 Merge pull request 'ui/service: rewire to allow external selection' (#5020) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5020
2025-08-28 20:43:07 +00:00
Johannes Kirschbauer
a4277ad312 ui/service: rewire to allow external selection 2025-08-28 22:39:49 +02:00
Johannes Kirschbauer
8877f2d451 ui/scene: lift state signals to allow external access 2025-08-28 22:39:23 +02:00
Johannes Kirschbauer
9275b66bd9 ui/machine: remove unsued imports 2025-08-28 22:38:19 +02:00
Johannes Kirschbauer
6a964f37d5 ui/machineRepr: listen to highlight state 2025-08-28 22:38:19 +02:00
Johannes Kirschbauer
73f2a4f56f ui/hooks: add clickOutside hook 2025-08-28 22:37:34 +02:00
Johannes Kirschbauer
85fb0187ee ui/typography: add missing label xxs 2025-08-28 22:37:15 +02:00
Johannes Kirschbauer
db9812a08b ui/sidebar: remove unused imports 2025-08-28 22:37:05 +02:00
Johannes Kirschbauer
ca69530591 ui/search: fix divider and text styles 2025-08-28 22:36:50 +02:00
Johannes Kirschbauer
fc5b0e4113 ui/multisearch: make controlled for now 2025-08-28 22:36:21 +02:00
Johannes Kirschbauer
278af5f0f4 ui/queries: add instances query 2025-08-28 22:35:58 +02:00
Johannes Kirschbauer
e7baf25ff7 ui/toast: add toast temporarily 2025-08-28 22:35:33 +02:00
Johannes Kirschbauer
fada75144c ui/highlight: add global highlighter store 2025-08-28 22:35:15 +02:00
brianmcgee
803ef5476f Merge pull request 'feat(ui): disable button when loading state is active' (#5018) from ui/disable-button-when-loading into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5018
2025-08-28 16:00:57 +00:00
brianmcgee
016bd263d0 Merge pull request 'ui/refine-sidebar-sidepane' (#5017) from ui/refine-sidebar-sidepane into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5017
2025-08-28 15:44:27 +00:00
Brian McGee
f9143f8a5d feat(ui): disable button when loading state is active 2025-08-28 16:43:23 +01:00
Brian McGee
92eb27fcb1 feat(ui): reduce size of sidebar when selecting a machine 2025-08-28 16:40:47 +01:00
Brian McGee
0cc9b91ae8 fix(ui): quirks with sidebar sizing 2025-08-28 15:56:37 +01:00
hsjobeki
2ed3608e34 Merge pull request 'ui/clan: wire up service create' (#5016) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5016
2025-08-28 12:17:03 +00:00
Johannes Kirschbauer
a92a1a7dd1 ui/clan: wire up service create 2025-08-28 14:13:39 +02:00
Johannes Kirschbauer
9a903be6d4 ui/services: add submit handler to create the instance 2025-08-28 14:13:26 +02:00
Johannes Kirschbauer
adea270b27 ui/tagSelect: remove left over console.log 2025-08-28 14:13:05 +02:00
clan-bot
765eb142a5 Merge pull request 'Update nixpkgs-dev in devFlake' (#5014) from update-devFlake-nixpkgs-dev into main 2025-08-28 10:08:09 +00:00
clan-bot
faa1405d6b Update nixpkgs-dev in devFlake 2025-08-28 10:01:48 +00:00
hsjobeki
0c93aab818 Merge pull request 'ui/services: workflow init' (#5013) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5013
2025-08-28 08:19:01 +00:00
Johannes Kirschbauer
56923ae2c3 ui/services: workflow init 2025-08-28 10:11:15 +02:00
Johannes Kirschbauer
e2f64e1d40 ui/stepper: forward props in backButton 2025-08-28 10:10:52 +02:00
Johannes Kirschbauer
c574b84278 ui/tagSelect: simplify by requiring objects with value key 2025-08-28 10:10:25 +02:00
Johannes Kirschbauer
640f15d55e ui/search: remove portal, fix styling 2025-08-28 10:09:41 +02:00
Johannes Kirschbauer
789d326273 ui/queries: add list tags query 2025-08-28 10:09:03 +02:00
clan-bot
1763d85d91 Merge pull request 'Update nixpkgs-dev in devFlake' (#5011) from update-devFlake-nixpkgs-dev into main 2025-08-27 20:10:01 +00:00
clan-bot
082fa05083 Update nixpkgs-dev in devFlake 2025-08-27 20:01:45 +00:00
brianmcgee
9ed7190606 Merge pull request 'fix(ui): icon alignment in alerts' (#5008) from ui/fix-icon-misalignment into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5008
2025-08-27 16:33:29 +00:00
Brian McGee
6c22539dd4 fix(ui): icon alignment in alerts
Closes #5004
2025-08-27 17:30:08 +01:00
Luis Hebendanz
e6819ede61 Merge pull request 'docs/update: refactor machine update guide' (#4997) from docs-10 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4997
2025-08-27 15:40:34 +00:00
Qubasa
186a760529 docs: fixup links to networking guide, improve introduction. 2025-08-27 17:37:15 +02:00
clan-bot
a84aee7b0c Merge pull request 'Update nixos-facter-modules' (#5007) from update-nixos-facter-modules into main 2025-08-27 15:10:12 +00:00
clan-bot
cab2fa44ba Update nixos-facter-modules 2025-08-27 15:00:55 +00:00
Jörg Thalheim
758eacd27e add apply "machine" as an alias to clan machines create
I was a bit confused that I was able to list templates but not
apply them. Turns out that "apply" only supported disk templates
2025-08-27 13:39:39 +00:00
Mic92
5962149e55 Merge pull request 'remove diskId from existing templates' (#5006) from drop-diskid into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5006
2025-08-27 13:31:23 +00:00
Jörg Thalheim
00f9d08a4b remove diskId from existing templates
we don't have a replacement yet, but at least this will work.
2025-08-27 15:24:59 +02:00
clan-bot
3d0c843308 Merge pull request 'Update nixpkgs-dev in devFlake' (#5003) from update-devFlake-nixpkgs-dev into main 2025-08-27 10:08:09 +00:00
clan-bot
847138472b Update nixpkgs-dev in devFlake 2025-08-27 10:01:50 +00:00
Johannes Kirschbauer
c7786a59fd docs/update: refactor machine update guide
Restructured page: core workflow first, advanced usage after.

Improved grammar, phrasing, and capitalization (Clan CLI, apostrophes).

Added warnings/notes for buildHost and CPU architecture.

Polished code snippets and CLI examples for clarity.
2025-08-27 10:26:53 +02:00
hsjobeki
3b2d357f10 Merge pull request 'api/modules: unify duplicate endpoints for {modules, instances}' (#4994) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4994
2025-08-27 07:13:46 +00:00
DavHau
a83dbf604c Merge pull request 'vars: always generate dependents' (#4996) from vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4996
2025-08-27 05:59:13 +00:00
DavHau
f77456a123 vars: simplify graph implementation, remove obsolete closure functions
- full_closure is obsolete since it is the same as calling requested_closure with the full list of generators.
- minimal_closure is obsolete as well. Since the recent addition of dependents to the closure via 3d2127ce1e it is essentially the same as the all_missing_closure
2025-08-27 12:50:59 +07:00
DavHau
6e4c3a638d vars: move graph tests to separate file 2025-08-27 11:47:46 +07:00
DavHau
3d2127ce1e vars: always generate dependents
Even for the minimal closure case (when a specific generator was picked), we should still force regeneration of all dependents, as otherwise we risk keeping outdated dependents from previous generations
2025-08-27 11:47:46 +07:00
DavHau
a4a5916fa2 vars: generate over multiple machines at once 2025-08-27 11:45:45 +07:00
Johannes Kirschbauer
f6727055cd api/modules: unify duplicate endpoints for {modules, instances} 2025-08-26 21:44:58 +02:00
hsjobeki
0517d87caa Merge pull request 'api/instances: add list service instances' (#4993) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4993
2025-08-26 16:52:53 +00:00
Johannes Kirschbauer
89e587592c api/instances: add list service instances 2025-08-26 18:47:08 +02:00
hsjobeki
439495d738 Merge pull request 'ui/search: fix height of overflow' (#4992) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4992
2025-08-26 16:46:29 +00:00
Johannes Kirschbauer
0b2fd681be ui/search: fix height of overflow 2025-08-26 18:43:09 +02:00
hsjobeki
41de615331 Merge pull request 'ui/services: add more features to components' (#4988) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4988
2025-08-26 16:40:51 +00:00
Johannes Kirschbauer
b7639b1d81 ui/services: fix some background colors 2025-08-26 18:35:43 +02:00
Johannes Kirschbauer
602879c9e4 ui/services: workflow select service 2025-08-26 18:35:43 +02:00
Johannes Kirschbauer
53e16242b9 ui/search: add loading state 2025-08-26 18:35:43 +02:00
Johannes Kirschbauer
24c5146763 ui/search: fix height calculate to avoid overlaying components 2025-08-26 18:35:43 +02:00
Johannes Kirschbauer
dca7aa0487 ui/modules: hook up list modules query 2025-08-26 18:35:43 +02:00
Johannes Kirschbauer
647bc4e4df api/list_modules: return a simpler list of modules 2025-08-26 18:35:43 +02:00
brianmcgee
1c80223fe3 Merge pull request 'feat(ui): remove light typography weight' (#4991) from misc/fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4991
2025-08-26 16:18:21 +00:00
Brian McGee
7ac9b00398 feat(ui): remove light typography weight 2025-08-26 16:13:53 +01:00
brianmcgee
d37c9e3b04 Merge pull request 'feat(ui): refine remove clan button copy' (#4986) from ui/refine-remove-clan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4986
2025-08-26 14:44:12 +00:00
Brian McGee
0fe9d0e157 feat(ui): refine remove clan button copy 2025-08-26 15:40:24 +01:00
Mic92
5479c767c1 Merge pull request 'try{300,301,400}: fix' (#4984) from checkout-update into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4984
2025-08-26 14:31:57 +00:00
brianmcgee
edc389ba4b Merge pull request 'feat(ui): change button font to normal instead of monospace' (#4985) from ui/change-button-font into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4985
2025-08-26 14:23:10 +00:00
Jörg Thalheim
4cb17d42e1 PLR2004: fix 2025-08-26 16:21:15 +02:00
Jörg Thalheim
f26499edb8 pyproject.toml: add descriptions to each rule 2025-08-26 16:21:15 +02:00
Jörg Thalheim
2857cb7ed8 remove various ignores that had no actual issue 2025-08-26 16:21:15 +02:00
Jörg Thalheim
3168fecd52 PT100: fix 2025-08-26 16:21:15 +02:00
Jörg Thalheim
24c20ff243 TRY400: fix 2025-08-26 16:21:15 +02:00
Jörg Thalheim
8ba8fda54b RUF100: fix 2025-08-26 16:21:15 +02:00
Brian McGee
0992a47b00 feat(ui): change button font to normal instead of monospace 2025-08-26 15:13:30 +01:00
Jörg Thalheim
d5b09f18ed RET504: fix 2025-08-26 15:55:23 +02:00
Jörg Thalheim
fb2fe36c87 SIM112: fix 2025-08-26 15:55:23 +02:00
hsjobeki
3db51887b1 Merge pull request 'ui/select machines/tags: add custom combobox' (#4983) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4983
2025-08-26 13:51:50 +00:00
Johannes Kirschbauer
24f3bcca57 ui/select: rename to tagSelect 2025-08-26 15:48:28 +02:00
Johannes Kirschbauer
85006c8103 ui/select machines/tags: add custom combobox
This just renders machines and tags as chips
onclick will open another combobox
2025-08-26 15:47:22 +02:00
Jörg Thalheim
db5571d623 SIM108: fix 2025-08-26 15:23:36 +02:00
Jörg Thalheim
d4bdaec586 SIM102: fix 2025-08-26 15:22:25 +02:00
Jörg Thalheim
cb9c8e5b5a try{300,301,400}: fix 2025-08-26 15:17:16 +02:00
Mic92
0a1802c341 Merge pull request 'github/repo-sync: v4 -> v5' (#4982) from checkout-update into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4982
2025-08-26 12:59:10 +00:00
Mic92
dfae1a4429 Merge pull request 'PLC0415: fix' (#4981) from ruff into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4981
2025-08-26 12:58:37 +00:00
Jörg Thalheim
c1dc73a21b github/repo-sync: v4 -> v5 2025-08-26 14:54:41 +02:00
Jörg Thalheim
8145740cc1 api: lazly load Api options 2025-08-26 14:48:20 +02:00
Jörg Thalheim
b2a54f5b0d PLC0415: fix 2025-08-26 14:46:42 +02:00
hsjobeki
9c9adc6e16 Merge pull request 'ui/tags: refactor generic children and icon' (#4960) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4960
2025-08-26 12:14:41 +00:00
Johannes Kirschbauer
f7cde8eb0f ui/tags: refactor generic children and icon 2025-08-26 14:11:14 +02:00
DavHau
501d020562 vars: retrieve generators for multiple machines
This is necessary ground work for fixing regeneration behavior spanning over multiple machines
2025-08-26 18:55:54 +07:00
Mic92
a9bafd71e1 Merge pull request 'templates/list: we can compute the lenght of an dictionary directly' (#4980) from ruff into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4980
2025-08-26 11:45:44 +00:00
Mic92
166e4b8081 Merge pull request 'add feature: ask for vars input confirmation, and fail after 3 attempts. fixes accidental misinputs when typing passwords!' (#4920) from adeci-2xconfirm into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4920
2025-08-26 11:41:16 +00:00
Jörg Thalheim
c3eb40f17a templates/list: we can compute the lenght of an dictionary directly 2025-08-26 13:39:49 +02:00
Jörg Thalheim
7330285150 prompt/multiline: strip final newline just like hidden prompt 2025-08-26 13:35:12 +02:00
Luis Hebendanz
8cf8573c61 Merge pull request 'clan-app: Maybe fix the logging errror ValueError: I/O operation on closed file.' (#4974) from Qubasa/clan-core:fix_logging into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4974
2025-08-26 11:32:48 +00:00
Jörg Thalheim
5bfa0d7a9d prompt: catch EOF errors 2025-08-26 13:26:49 +02:00
adeci
8ea2dd9b72 add feature: ask for vars input confirmation, and fail after 3 attempts. fixes accidental misinputs when typing passwords! 2025-08-26 13:26:49 +02:00
Mic92
6efcade56a Merge pull request 'Enable "all" ruff lint fixes' (#4978) from ruff into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4978
2025-08-26 11:26:47 +00:00
Jörg Thalheim
6d2372be56 machines/update: fix incorrecct nixos-rebuild command 2025-08-26 13:11:43 +02:00
brianmcgee
626af4691b Merge pull request 'feat(ui): pin stepper buttons to the bottom' (#4979) from ui/pinned-stepper-buttons into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4979
2025-08-26 11:07:30 +00:00
Jörg Thalheim
63697ac4b1 various fixes 2025-08-26 13:07:22 +02:00
Brian McGee
0ebb1f0c66 feat(ui): pin stepper buttons to the bottom
Closes #4968
2025-08-26 12:02:28 +01:00
Jörg Thalheim
1dda60847e PLW0602: fix 2025-08-26 12:57:31 +02:00
Jörg Thalheim
a7bce4cb19 pyproject: enable all lints 2025-08-26 12:57:31 +02:00
Mic92
a5474bc25f Merge pull request 'ruff-7-misc' (#4939) from ruff-7-misc into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4939
2025-08-26 10:43:12 +00:00
Jörg Thalheim
f634b8f1fb merge-after-ci: move away from writePython3Bin
this is one is doing checks we don't want because we already have ruff.
2025-08-26 12:39:50 +02:00
brianmcgee
0ad40a0233 Merge pull request 'ui/refine-select-folder-onboarding' (#4977) from ui/refine-select-folder-onboarding into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4977
2025-08-26 10:30:23 +00:00
Luis Hebendanz
78abc36cd3 Merge pull request 'clan-cli: clan machines update-hardware-config now uses kexec, and supports non NixOS targets' (#4948) from Qubasa/clan-core:fix_update_hardware_config into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4948
2025-08-26 10:16:59 +00:00
Brian McGee
f5158b068f feat(ui): reduce size of sidebar pane
Make it clearer the distinction between parent and child panes.
2025-08-26 11:16:03 +01:00
Jörg Thalheim
e6066a6cb1 spawn_tor: catch OSError and wrap as ClanError 2025-08-26 12:12:29 +02:00
clan-bot
fc8b66effa Merge pull request 'Update nixpkgs-dev in devFlake' (#4972) from update-devFlake-nixpkgs-dev into main 2025-08-26 10:09:59 +00:00
Qubasa
16b92963fd clan-app: Maybe fix the logging errror ValueError: I/O operation on closed file. 2025-08-26 12:08:45 +02:00
Brian McGee
2ff3d871ac feat(ui): allow placing machines directly next to each other 2025-08-26 11:02:58 +01:00
clan-bot
108936ef07 Update nixpkgs-dev in devFlake 2025-08-26 10:01:48 +00:00
Jörg Thalheim
c45d4cfec9 D413/D212: fix 2025-08-26 12:01:47 +02:00
Jörg Thalheim
64217e1281 G001: fix 2025-08-26 12:01:47 +02:00
Jörg Thalheim
d1421bb534 EXE002: fix 2025-08-26 12:01:47 +02:00
Jörg Thalheim
ac20514a8e EXE001: fix 2025-08-26 12:01:47 +02:00
Jörg Thalheim
79c4e73a15 test_http_api: remove unused logging middleware 2025-08-26 12:01:47 +02:00
Jörg Thalheim
61a647b436 PLR1704: fix 2025-08-26 12:01:47 +02:00
Jörg Thalheim
c9a709783a BLE001: fix 2025-08-26 12:01:47 +02:00
Kenji Berthold
c55b369899 Merge pull request 'docs: Add edit button to documentation pages' (#4969) from kenji/ke-add-repo-url into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4969
2025-08-26 09:59:14 +00:00
Brian McGee
084b8bacd3 fix(ui): typos in install machine workflow 2025-08-26 10:52:52 +01:00
a-kenji
47ad7d8a95 docs: Add edit button to documentation pages
Closes: #4966
2025-08-26 11:52:08 +02:00
a-kenji
3798808013 docs: Fix edit uri 2025-08-26 11:51:53 +02:00
Brian McGee
43a39267f3 feat(ui): make the intention of the select folder button clearer in Onboarding 2025-08-26 10:44:42 +01:00
Mic92
db94ea2d2e Merge pull request 'Misc ruff fixes' (#4965) from ruff-foo into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4965
2025-08-26 09:44:06 +00:00
hsjobeki
f0533f9bba Merge pull request 'ui/scene: dont snap to occupied positions' (#4967) from fixes-ui into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4967
2025-08-26 09:43:59 +00:00
Johannes Kirschbauer
360048fd04 ui/scene: dont snap to occupied positions 2025-08-26 11:40:38 +02:00
Jörg Thalheim
8f8426de52 PGH003: fix 2025-08-26 11:36:38 +02:00
Qubasa
4bce390e64 clan-cli: clan machiens update-hardware-config now uses kexec, and supports non NixOS targets 2025-08-26 11:35:44 +02:00
DavHau
2b7837e2b6 Merge pull request 'GUI: add port option for ssh remote' (#4961) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4961
2025-08-26 09:33:26 +00:00
Jörg Thalheim
cbf9678534 flake/prefetch: Fix unconditional truthy string causes always-True 2025-08-26 11:07:57 +02:00
Jörg Thalheim
b38b10c9a6 automatic ruff fixes 2025-08-26 11:07:57 +02:00
Jörg Thalheim
31cbb7dc00 PLC0415: fix 2025-08-26 11:07:57 +02:00
hsjobeki
0fa4377793 Merge pull request 'ui/scene: add reload button' (#4962) from fixes-ui into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4962
2025-08-26 09:01:45 +00:00
Johannes Kirschbauer
7b0d10e8c2 ui/queries: remove annoying refetch interval, invalidate on change instead 2025-08-26 10:58:39 +02:00
Johannes Kirschbauer
bb41adab4b ui/scene: fix syncing remote and local state 2025-08-26 10:40:09 +02:00
DavHau
648aa7dc59 Merge pull request 'API: fix serialization of union types' (#4963) from serde into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4963
2025-08-26 08:26:13 +00:00
DavHau
3073969c92 vars/tests: add comments 2025-08-26 15:17:41 +07:00
DavHau
2f1dc3a33d API: fix serialization of union types
Due to this bug in serde.py, the run_generators API id not work for the frontend
2025-08-26 15:16:55 +07:00
Johannes Kirschbauer
b707dcea2d ui/scene: add reload button 2025-08-26 10:08:05 +02:00
Johannes Kirschbauer
4f0c8025b2 ui/queries: remove annoying refetch interval, invalidate on change instead 2025-08-26 10:07:41 +02:00
pinpox
b91bee537a Merge pull request 'Enable state-version in defaults' (#4711) from default-state-version into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4711
2025-08-26 07:49:46 +00:00
pinpox
7207a3e8cd Cleanup state-version test 2025-08-26 09:44:01 +02:00
pinpox
ac675a5af0 Merge pull request 'Add coredns module' (#4837) from coredns into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4837
2025-08-26 07:39:57 +00:00
pinpox
64caebde62 service/state-version: drop 2025-08-26 09:32:36 +02:00
pinpox
4934884e0c Enable state-version in defaults 2025-08-26 09:32:36 +02:00
pinpox
22cd9baee2 Merge pull request 'Improve inventory docs' (#4933) from inventory-docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4933
2025-08-26 07:32:23 +00:00
pinpox
84232b5355 Improve inventory docs 2025-08-26 09:29:25 +02:00
DavHau
5bc7c255c1 GUI: add port option for ssh remote
I need this for testing with a local VM, which ahs a different port than 22.

This also disables host key checking, as there is currently no workflow int he GUI which can handle a mismatch, which mismatches are common.
2025-08-26 13:28:27 +07:00
clan-bot
d11d83f699 Merge pull request 'Update clan-core-for-checks in devFlake' (#4959) from update-devFlake-clan-core-for-checks into main 2025-08-26 05:08:08 +00:00
clan-bot
2ef1b2a8fa Update clan-core-for-checks in devFlake 2025-08-26 05:01:46 +00:00
clan-bot
f7414d7e6e Merge pull request 'Update clan-core-for-checks in devFlake' (#4957) from update-devFlake-clan-core-for-checks into main 2025-08-26 00:08:04 +00:00
clan-bot
ab384150b2 Merge pull request 'Update nixpkgs-dev in devFlake' (#4958) from update-devFlake-nixpkgs-dev into main 2025-08-26 00:07:37 +00:00
clan-bot
0b6939ffee Update nixpkgs-dev in devFlake 2025-08-26 00:01:48 +00:00
clan-bot
bc6a1a9d17 Update clan-core-for-checks in devFlake 2025-08-26 00:01:28 +00:00
clan-bot
7055461cf0 Merge pull request 'Update clan-core-for-checks in devFlake' (#4956) from update-devFlake-clan-core-for-checks into main 2025-08-25 20:10:56 +00:00
clan-bot
a9564df6a9 Update clan-core-for-checks in devFlake 2025-08-25 20:01:26 +00:00
brianmcgee
e2dfc74d02 Merge pull request 'feat(ui): fix layout and size of install progress and done screens' (#4954) from ui/fix-install-modal-sizes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4954
2025-08-25 16:55:48 +00:00
Brian McGee
326cb60aea feat(ui): fix layout and size of install progress and done screens 2025-08-25 17:51:20 +01:00
brianmcgee
68b264970a Merge pull request 'feat(ui): set loading status on update hardware report button in install workflow' (#4951) from ui/update-hardware-report-loading-state into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4951
2025-08-25 16:46:16 +00:00
Brian McGee
1fa4ef82e9 feat(ui): set loading status on update hardware report button in install workflow 2025-08-25 17:32:15 +01:00
Kenji Berthold
bd93651f12 Merge pull request 'pkgs/clan-app: Refactor debugger' (#4949) from kenji/ke-debug-view-simplify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4949
2025-08-25 16:30:48 +00:00
a-kenji
85ad51ce4c pkgs/clan-app: Refactor debugger 2025-08-25 18:25:02 +02:00
Luis Hebendanz
59e50c6150 Merge pull request 'clan-app: Add new icons' (#4947) from Qubasa/clan-core:new_app_icons into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4947
2025-08-25 16:11:15 +00:00
Qubasa
f347568de3 clan-app: Add new icons 2025-08-25 18:07:11 +02:00
brianmcgee
bdad7d81b2 Merge pull request 'Clan Settings modal' (#4941) from ui/clan-settings-modal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4941
2025-08-25 15:33:31 +00:00
Brian McGee
b8203cdf73 feat(ui): support removing a clan
Also fixes:
- close modal on escape key
- handle class attribute in form components correctly
2025-08-25 16:28:13 +01:00
Brian McGee
431e45cc3a feat(ui): support editing basic metadata for a Clan 2025-08-25 16:28:12 +01:00
brianmcgee
f185d28f68 Merge pull request 'ui/fix-clan-list-select-same-clan' (#4944) from ui/fix-clan-list-select-same-clan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4944
2025-08-25 15:26:05 +00:00
Brian McGee
d8e6fcf773 chore(ui): move list clans modal into modals directory 2025-08-25 16:22:58 +01:00
Brian McGee
23b7d24399 fix(ui): allow reloading the failed active clan in clan list modal 2025-08-25 16:19:07 +01:00
clan-bot
a1ed512da4 Merge pull request 'Update clan-core-for-checks in devFlake' (#4943) from update-devFlake-clan-core-for-checks into main 2025-08-25 15:09:34 +00:00
clan-bot
40ac96cd10 Update clan-core-for-checks in devFlake 2025-08-25 15:01:41 +00:00
hsjobeki
c4da43da0f Merge pull request 'ui: add multiple search for machines and tags' (#4942) from search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4942
2025-08-25 14:57:06 +00:00
Johannes Kirschbauer
8822f6dadc ui: add multiple search for machines and tags 2025-08-25 16:53:49 +02:00
Mic92
b5a7a91612 Merge pull request 'ruff-6-warnings' (#4937) from ruff-6-warnings into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4937
2025-08-25 14:06:20 +00:00
Mic92
453b1a91a8 Merge pull request 'ruff-5-docstring-fixes' (#4938) from ruff-5-docstring-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4938
2025-08-25 14:03:43 +00:00
Jörg Thalheim
70274d69e9 templates/list: “Last input” detection is off when some inputs don’t define this template_type.
is_last_input compares against len(templates.custom.items()) - 1, but you continue past inputs that lack template_type,
so the ASCII tree may render └ on non-final printed items. Compute the filtered inputs list first.
2025-08-25 15:59:54 +02:00
Jörg Thalheim
c57d8b30d3 vms/qemu: Fix CID range to exclude reserved vsock IDs 2025-08-25 15:27:03 +02:00
Jörg Thalheim
7407fef21b zerotier/generate: use with for urlopen and also set a 5s timeout 2025-08-25 15:25:50 +02:00
Jörg Thalheim
23c152541a docs/getting-started: remove duplicate nixosConfigurations 2025-08-25 15:22:30 +02:00
Jörg Thalheim
6765e27031 pkgs/clan-cli/clan_lib/services/modules.py: fix Exception in docs 2025-08-25 15:20:15 +02:00
Jörg Thalheim
cbb789bc69 PLW1508: fix 2025-08-25 15:17:06 +02:00
Jörg Thalheim
7f68a21257 PLW1641: fix 2025-08-25 15:17:06 +02:00
Jörg Thalheim
fc66dc78c3 PLW0603: fix 2025-08-25 15:17:06 +02:00
Jörg Thalheim
1d0e0f243e PLW2901: fix 2025-08-25 15:17:06 +02:00
Mic92
8134ffd787 Merge pull request 'ruff-4-perf-fixes' (#4935) from ruff-4-perf-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4935
2025-08-25 13:12:14 +00:00
Jörg Thalheim
7f1590c729 PERF403: fix 2025-08-25 15:06:32 +02:00
Jörg Thalheim
c65bb0b1ce PERF401: fix 2025-08-25 15:06:32 +02:00
Mic92
d8bc5269ee Merge pull request 'ruff-5-docstring-fixes' (#4936) from ruff-5-docstring-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4936
2025-08-25 13:04:05 +00:00
Jörg Thalheim
917407c475 D210: fix 2025-08-25 14:56:48 +02:00
Jörg Thalheim
d9e6e0c540 D417: fix 2025-08-25 14:56:48 +02:00
Jörg Thalheim
ef5ab0c2f4 D404: fix 2025-08-25 14:56:48 +02:00
Jörg Thalheim
34816013ad D106: fix 2025-08-25 14:56:48 +02:00
Mic92
05665b1c7e Merge pull request 'ruff-3-arg-fixes' (#4934) from ruff-3-arg-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4934
2025-08-25 12:54:04 +00:00
Jörg Thalheim
2bebcab736 zerotier-members: fix passing member_ip 2025-08-25 14:46:12 +02:00
Jörg Thalheim
306f83e357 flash: skip test on aarch64-linux 2025-08-25 14:46:12 +02:00
Jörg Thalheim
04457b1272 ARG001: fix 2025-08-25 14:46:12 +02:00
Jörg Thalheim
4986fe30c3 ARG002/ARG005: fix 2025-08-25 14:36:36 +02:00
Mic92
de33a07875 Merge pull request 'ruff-2-security-fixes' (#4931) from ruff-2-security-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4931
2025-08-25 12:30:20 +00:00
Jörg Thalheim
5233eb7fdb ARG002: fix 2025-08-25 14:24:21 +02:00
Jörg Thalheim
94a158b77a ARG001: fix 2025-08-25 14:24:21 +02:00
hsjobeki
98af47d0b5 Merge pull request 'docs: change wording, update links' (#4929) from cleanup-again into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4929
2025-08-25 12:18:55 +00:00
Johannes Kirschbauer
4470bb886e docs: move 'migrate-flake' to 'convert existing nixos' 2025-08-25 14:11:31 +02:00
Jörg Thalheim
f4feac0d6b logmanager: fix exceptions in python docs 2025-08-25 14:11:25 +02:00
Jörg Thalheim
7547761812 zerotier-members: validate hex input to prevent ValueError
Add proper validation for network_id and identity parameters to ensure
they contain valid hexadecimal characters. Previously, non-hex input
would raise ValueError instead of the expected ClanError, bypassing
proper error handling.
2025-08-25 14:11:25 +02:00
Jörg Thalheim
23d11651fc Preserve symlinks during store copy 2025-08-25 14:11:25 +02:00
Jörg Thalheim
03a4ac5bde sudo_askpass_proxy: check for stdin before print 2025-08-25 14:11:25 +02:00
Jörg Thalheim
ab50b433ee type_to_jsonschema: throw correct Error 2025-08-25 14:11:25 +02:00
Jörg Thalheim
123e8398d8 S310: fix 2025-08-25 14:11:25 +02:00
Jörg Thalheim
6a2dfb8176 S101: fix 2025-08-25 14:11:25 +02:00
Jörg Thalheim
332d10e306 s110: address 2025-08-25 14:07:59 +02:00
Jörg Thalheim
f3f6692e4d S102: ignore 2025-08-25 14:07:59 +02:00
Jörg Thalheim
954301465f s608: ignore 2025-08-25 14:07:59 +02:00
Jörg Thalheim
2199f4efd5 S324: ignore 2025-08-25 14:07:59 +02:00
Jörg Thalheim
e208c02be7 S311: fix random usage 2025-08-25 14:07:59 +02:00
Jörg Thalheim
7747e3cc0d S604: ignore 2025-08-25 14:07:59 +02:00
Jörg Thalheim
1c24b4c6cb S604: fix 2025-08-25 14:07:59 +02:00
Jörg Thalheim
4b1ab4cdde S105: fix 2025-08-25 13:43:33 +02:00
Jörg Thalheim
4852e79c3c S310: fix 2025-08-25 13:43:33 +02:00
Jörg Thalheim
0a70ed6268 S108: ignore our uses 2025-08-25 13:43:33 +02:00
Mic92
136acc7901 Merge pull request 'ruff-1-initial-fixes' (#4930) from ruff-1-initial-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4930
2025-08-25 11:38:36 +00:00
Jörg Thalheim
70d1dd0deb nix_setup/cp: remove xcp again 2025-08-25 13:33:13 +02:00
Jörg Thalheim
df32da304f drop agit 2025-08-25 13:06:04 +02:00
Jörg Thalheim
76eb3c13e9 add various module docstrings 2025-08-25 13:06:04 +02:00
Jörg Thalheim
6e88046fd4 PERF404: fix 2025-08-25 13:06:04 +02:00
Jörg Thalheim
b3cafa4a8c log_manager: drop example usage
don't need this.
2025-08-25 13:06:04 +02:00
Jörg Thalheim
d1cf87d2ce BLE001: don't catch blind errors 2025-08-25 13:06:04 +02:00
Jörg Thalheim
dc5485d9f1 ruff: replace asserts outside of tests with Exceptions 2025-08-25 13:06:04 +02:00
Johannes Kirschbauer
1b12882e29 docs: change wording, update links 2025-08-25 12:42:03 +02:00
hsjobeki
5be9b8383b Merge pull request 'clan/inventory: allow list usage of roles via polymorphism' (#4918) from cleanup-again into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4918
2025-08-25 10:41:49 +00:00
DavHau
c308fd63a7 vars: delete old var when changing share
When changing a password from non-shared to shared, we want to remove the old one
2025-08-25 10:37:46 +00:00
clan-bot
fcdfd80b34 Merge pull request 'Update clan-core-for-checks in devFlake' (#4925) from update-devFlake-clan-core-for-checks into main 2025-08-25 10:37:07 +00:00
clan-bot
c5d975542d Merge pull request 'Update nixos-facter-modules' (#4832) from update-nixos-facter-modules into main 2025-08-25 10:25:02 +00:00
clan-bot
526eccdf16 Merge pull request 'Update nixpkgs-dev in devFlake' (#4926) from update-devFlake-nixpkgs-dev into main 2025-08-25 10:23:25 +00:00
clan-bot
f7dd34be21 Merge pull request 'Update disko' (#4924) from update-disko into main 2025-08-25 10:22:23 +00:00
Mic92
289732ad20 Merge pull request 'Replace funky utf-8 singlequotes with decent ones' (#4923) from replace-backticks into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4923
2025-08-25 10:03:46 +00:00
pinpox
a50b6f7bc7 Merge pull request 'Allow shared user password' (#4921) from TilmanBaumann/clan-core:main into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4921
Reviewed-by: pinpox <clan@pablo.tools>
2025-08-25 10:02:59 +00:00
clan-bot
51c679d3a9 Update nixpkgs-dev in devFlake 2025-08-25 10:01:50 +00:00
clan-bot
470c3d330f Update clan-core-for-checks in devFlake 2025-08-25 10:01:32 +00:00
clan-bot
df596ed59f Update nixos-facter-modules 2025-08-25 10:00:58 +00:00
clan-bot
f2c1202b03 Update disko 2025-08-25 10:00:51 +00:00
pinpox
cdd241d8ff Replace funky utf-8 singlequotes with decent ones 2025-08-25 11:56:29 +02:00
Mic92
0803d9c864 Merge pull request 'Apply automatic ruff lints' (#4919) from ruff-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4919
2025-08-25 09:53:41 +00:00
Tilman Baumann
7171864a5e Allow shared user password
By default each user gets a new password on every host.

Now you can use a shared vars.
2025-08-25 11:46:09 +02:00
Mic92
7aa9a34168 Merge pull request 'services/user: add migration guide for root-password' (#4917) from root-password into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4917
2025-08-25 09:36:02 +00:00
Jörg Thalheim
0ec2c32ff8 ruff: apply automatic unsafe fixes 2025-08-25 11:34:41 +02:00
Jörg Thalheim
ea2d6aab65 ruff: apply automatic fixes 2025-08-25 11:34:41 +02:00
Jörg Thalheim
4101ebc45b services/user: add migration guide for root-password 2025-08-25 11:29:56 +02:00
Johannes Kirschbauer
4414403dec clan/inventory: allow list usage of roles via polymorphism 2025-08-25 11:27:38 +02:00
Johannes Kirschbauer
2d78730037 clan/schema: rename json schemas consistent {clanSchemaNix, clanSchemaJson} 2025-08-25 11:27:03 +02:00
hsjobeki
45c7c42634 Merge pull request 'tests/dirs: unify test files' (#4916) from cleanup-again into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4916
2025-08-25 09:26:12 +00:00
Johannes Kirschbauer
8baf4fcedd docs: refine autoincludes 2025-08-25 11:19:39 +02:00
Johannes Kirschbauer
a41e0ba80f nix_models: fix typo 2025-08-25 11:19:39 +02:00
DavHau
798d445f3e docs: move options search to separate page 2025-08-25 15:51:24 +07:00
Johannes Kirschbauer
00bd003be4 tests/dirs: unify test files 2025-08-25 10:14:02 +02:00
clan-bot
5841432b6f Merge pull request 'Update data-mesher' (#4914) from update-data-mesher into main 2025-08-25 05:24:10 +00:00
clan-bot
1fb91ec161 Merge pull request 'Update clan-core-for-checks in devFlake' (#4915) from update-devFlake-clan-core-for-checks into main 2025-08-25 05:23:55 +00:00
clan-bot
fc16879336 Update clan-core-for-checks in devFlake 2025-08-25 05:01:34 +00:00
clan-bot
290510ae74 Update data-mesher 2025-08-25 05:00:51 +00:00
clan-bot
7b926d43dc Merge pull request 'Update clan-core-for-checks in devFlake' (#4913) from update-devFlake-clan-core-for-checks into main 2025-08-25 00:21:50 +00:00
clan-bot
d91a44c7c5 Update clan-core-for-checks in devFlake 2025-08-25 00:01:31 +00:00
clan-bot
a47ed71bb7 Merge pull request 'Update clan-core-for-checks in devFlake' (#4911) from update-devFlake-clan-core-for-checks into main 2025-08-24 20:19:28 +00:00
clan-bot
18f9df29da Merge pull request 'Update nixpkgs-dev in devFlake' (#4912) from update-devFlake-nixpkgs-dev into main 2025-08-24 20:09:41 +00:00
clan-bot
2438dc09a2 Update nixpkgs-dev in devFlake 2025-08-24 20:01:48 +00:00
clan-bot
420412e60c Update clan-core-for-checks in devFlake 2025-08-24 20:01:29 +00:00
clan-bot
aee6bc335b Merge pull request 'Update clan-core-for-checks in devFlake' (#4910) from update-devFlake-clan-core-for-checks into main 2025-08-24 15:18:34 +00:00
clan-bot
6ae679fb3d Update clan-core-for-checks in devFlake 2025-08-24 15:01:31 +00:00
clan-bot
b40a13b4c5 Merge pull request 'Update clan-core-for-checks in devFlake' (#4906) from update-devFlake-clan-core-for-checks into main 2025-08-24 10:18:53 +00:00
clan-bot
dd2aa70efd Merge pull request 'Update nixpkgs-dev in devFlake' (#4907) from update-devFlake-nixpkgs-dev into main 2025-08-24 10:09:48 +00:00
clan-bot
2a9c9f7f2c Update nixpkgs-dev in devFlake 2025-08-24 10:01:51 +00:00
clan-bot
82001544fd Update clan-core-for-checks in devFlake 2025-08-24 10:01:32 +00:00
brianmcgee
9f352aa362 Merge pull request 'feat(ui): remove focus-visible state from readonly form inputs' (#4905) from ui/disable-active-status-readonly-input into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4905
2025-08-24 09:53:06 +00:00
Brian McGee
35177ead40 feat(ui): remove focus-visible state from readonly form inputs 2025-08-24 10:49:34 +01:00
brianmcgee
1931c17513 Merge pull request 'feat(ui): make save button clearer in sidebar section forms' (#4904) from ui/sidebar-section-save-button into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4904
2025-08-24 09:45:23 +00:00
Brian McGee
b12debf373 feat(ui): make save button clearer in sidebar section forms 2025-08-24 10:42:01 +01:00
clan-bot
0b3d362357 Merge pull request 'Update clan-core-for-checks in devFlake' (#4903) from update-devFlake-clan-core-for-checks into main 2025-08-24 05:21:48 +00:00
clan-bot
d8119f2308 Update clan-core-for-checks in devFlake 2025-08-24 05:01:46 +00:00
clan-bot
ce36894ab1 Merge pull request 'Update clan-core-for-checks in devFlake' (#4902) from update-devFlake-clan-core-for-checks into main 2025-08-24 00:19:01 +00:00
clan-bot
c5f4f2e1d6 Update clan-core-for-checks in devFlake 2025-08-24 00:01:33 +00:00
clan-bot
c861ffe07b Merge pull request 'Update clan-core-for-checks in devFlake' (#4900) from update-devFlake-clan-core-for-checks into main 2025-08-23 20:17:58 +00:00
clan-bot
6df980bc57 Merge pull request 'Update nixpkgs-dev in devFlake' (#4901) from update-devFlake-nixpkgs-dev into main 2025-08-23 20:09:30 +00:00
clan-bot
9d1d07b0ca Update nixpkgs-dev in devFlake 2025-08-23 20:01:48 +00:00
clan-bot
24a774b5d6 Update clan-core-for-checks in devFlake 2025-08-23 20:01:29 +00:00
clan-bot
442f673128 Merge pull request 'Update clan-core-for-checks in devFlake' (#4898) from update-devFlake-clan-core-for-checks into main 2025-08-23 15:20:43 +00:00
clan-bot
8905b5c5f1 Merge pull request 'Update nixpkgs-dev in devFlake' (#4899) from update-devFlake-nixpkgs-dev into main 2025-08-23 15:12:14 +00:00
clan-bot
3eff656dfa Update nixpkgs-dev in devFlake 2025-08-23 15:01:50 +00:00
clan-bot
79e6f34c9e Update clan-core-for-checks in devFlake 2025-08-23 15:01:31 +00:00
clan-bot
9c6e8f7735 Merge pull request 'Update treefmt-nix' (#4894) from update-treefmt-nix into main 2025-08-23 10:24:13 +00:00
clan-bot
cc4fd1369e Merge pull request 'Update clan-core-for-checks in devFlake' (#4895) from update-devFlake-clan-core-for-checks into main 2025-08-23 10:23:54 +00:00
clan-bot
7f32d6f81a Merge pull request 'Update treefmt-nix in devFlake' (#4897) from update-devFlake-treefmt-nix into main 2025-08-23 10:17:23 +00:00
clan-bot
a450ca10b8 Merge pull request 'Update nixpkgs-dev in devFlake' (#4896) from update-devFlake-nixpkgs-dev into main 2025-08-23 10:17:07 +00:00
clan-bot
06fbf32691 Update treefmt-nix in devFlake 2025-08-23 10:01:56 +00:00
clan-bot
d4bd297439 Update nixpkgs-dev in devFlake 2025-08-23 10:01:51 +00:00
clan-bot
acc8043f26 Update clan-core-for-checks in devFlake 2025-08-23 10:01:32 +00:00
clan-bot
35e5d0daab Update treefmt-nix 2025-08-23 10:01:29 +00:00
clan-bot
e51c9ef1ad Merge pull request 'Update clan-core-for-checks in devFlake' (#4892) from update-devFlake-clan-core-for-checks into main 2025-08-23 05:19:20 +00:00
clan-bot
cdcbe3359a Update clan-core-for-checks in devFlake 2025-08-23 05:01:32 +00:00
clan-bot
e5b51e6a2b Merge pull request 'Update clan-core-for-checks in devFlake' (#4891) from update-devFlake-clan-core-for-checks into main 2025-08-23 00:20:46 +00:00
clan-bot
694ebc5b30 Update clan-core-for-checks in devFlake 2025-08-23 00:01:30 +00:00
lassulus
ff2555cc4a Merge pull request 'Enable network configuration in iwd settings' (#4886) from RuboGubo/clan-core:fixDHCPinstaller into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4886
2025-08-22 22:34:07 +00:00
lassulus
016255459c Merge pull request 'clan_lib flake: fix handling of maybes and empty sets' (#4890) from select_fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4890
2025-08-22 22:31:29 +00:00
lassulus
14f03bcab0 Merge pull request 'vars: add .exists to files' (#4889) from vars_exist into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4889
2025-08-22 21:47:16 +00:00
lassulus
4dc90b3d39 clan_lib flake: fix handling of maybes and empty sets 2025-08-22 23:44:14 +02:00
lassulus
8cdce6c0c8 vars: add .exists to files 2025-08-22 23:30:19 +02:00
clan-bot
8904cf27a4 Merge pull request 'Update clan-core-for-checks in devFlake' (#4888) from update-devFlake-clan-core-for-checks into main 2025-08-22 20:19:40 +00:00
clan-bot
493194c124 Merge pull request 'Update nix-select' (#4887) from update-nix-select into main 2025-08-22 20:15:43 +00:00
clan-bot
5d1600a077 Update clan-core-for-checks in devFlake 2025-08-22 20:01:38 +00:00
clan-bot
7daaacbddf Update nix-select 2025-08-22 20:01:00 +00:00
RuboGubo
30e18bbc66 Enable network configuration in iwd settings
closes #4885
2025-08-22 20:20:37 +01:00
hsjobeki
16dffa99c0 Merge pull request 'ui/search: add search with virtualized scrolling' (#4884) from ui-search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4884
2025-08-22 16:07:54 +00:00
Johannes Kirschbauer
58ad50b749 ui/search: add search with virtualized scrolling 2025-08-22 17:52:48 +02:00
clan-bot
bc25074f5b Merge pull request 'Update clan-core-for-checks in devFlake' (#4882) from update-devFlake-clan-core-for-checks into main 2025-08-22 15:18:46 +00:00
clan-bot
c79916d06c Merge pull request 'Update nixpkgs-dev in devFlake' (#4883) from update-devFlake-nixpkgs-dev into main 2025-08-22 15:09:43 +00:00
clan-bot
4d53542f79 Update nixpkgs-dev in devFlake 2025-08-22 15:01:50 +00:00
clan-bot
d3ef03aeb3 Update clan-core-for-checks in devFlake 2025-08-22 15:01:31 +00:00
brianmcgee
9949fac5ea Merge pull request 'feat(ui): refine spacing in NavSection' (#4881) from ui/navigation-section into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4881
2025-08-22 12:32:10 +00:00
Brian McGee
6d236a6282 feat(ui): refine spacing in NavSection 2025-08-22 13:28:06 +01:00
brianmcgee
6e6a920796 Merge pull request 'ui/navigation-section' (#4880) from ui/navigation-section into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4880
2025-08-22 11:20:14 +00:00
Brian McGee
99092a6ef2 chore(ui): lint 2025-08-22 12:16:21 +01:00
Brian McGee
1897b7bb06 feat(ui): use NavSection in installer workflow 2025-08-22 12:15:16 +01:00
Brian McGee
878789cf38 feat(ui): use NavSection in ListClansModal 2025-08-22 12:11:22 +01:00
Brian McGee
8a59cf7ea3 feat(ui): add NavSection component 2025-08-22 12:07:26 +01:00
brianmcgee
7ade9cd222 Merge pull request 'Handle error cases when switching clan' (#4879) from feat/handle-clan-switch-errors into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4879
2025-08-22 10:47:35 +00:00
Brian McGee
447f619ecc feat(ui): handle when a clan folder has been moved/renamed 2025-08-22 11:44:16 +01:00
clan-bot
657a55517b Merge pull request 'Update clan-core-for-checks in devFlake' (#4878) from update-devFlake-clan-core-for-checks into main 2025-08-22 10:20:14 +00:00
clan-bot
16a5b34ddf Update clan-core-for-checks in devFlake 2025-08-22 10:01:32 +00:00
Luis Hebendanz
23f303b6ba Merge pull request 'clan_lib: Fix run_machine_install incorrect pesist_state path' (#4877) from Qubasa/clan-core:fix_install into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4877
2025-08-22 09:36:34 +00:00
Qubasa
84bf9f3bc5 clan_lib: Fix run_machine_install incorrect pesist_state path 2025-08-22 11:21:44 +02:00
brianmcgee
48736011de Merge pull request 'fix(ui): remove custom viewboxes for some icons' (#4876) from ui/fix-icons into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4876
2025-08-22 08:14:22 +00:00
Brian McGee
cf5675b7f3 fix(ui): remove custom viewboxes for some icons 2025-08-22 09:11:09 +01:00
Brian McGee
f0bbdad9ef feat(ui): improve clan list logic in SidebarHeader 2025-08-22 08:51:27 +01:00
Brian McGee
5f83fe02a1 feat(ui): move isLoading logic into ClanContext 2025-08-22 08:51:26 +01:00
Brian McGee
8cb92e143d feat(ui): by default do not retry queries 2025-08-22 08:51:26 +01:00
Brian McGee
73f5f887f3 feat(ui): add clanURI to ClanContext 2025-08-22 08:51:25 +01:00
clan-bot
db4e6c0be5 Merge pull request 'Update nix-darwin' (#4872) from update-nix-darwin into main 2025-08-22 05:22:33 +00:00
clan-bot
c24892f865 Merge pull request 'Update clan-core-for-checks in devFlake' (#4873) from update-devFlake-clan-core-for-checks into main 2025-08-22 05:20:02 +00:00
clan-bot
6badc14936 Update clan-core-for-checks in devFlake 2025-08-22 05:01:33 +00:00
clan-bot
3d1fb401fd Update nix-darwin 2025-08-22 05:00:53 +00:00
clan-bot
f2cdac75e2 Merge pull request 'Update clan-core-for-checks in devFlake' (#4871) from update-devFlake-clan-core-for-checks into main 2025-08-22 00:19:10 +00:00
clan-bot
5d6e35832c Update clan-core-for-checks in devFlake 2025-08-22 00:01:33 +00:00
Luis Hebendanz
9aa9ba500e Merge pull request 'clan-lib: Make Flake throw more concrete errors if the flake path is invalid or non existend' (#4870) from Qubasa/clan-core:fix_ui_stuff2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4870
2025-08-21 22:08:28 +00:00
Qubasa
2934269279 clan-lib: Make Flake throw more concrete errors if the flake path is invalid or non existend
treefmt
2025-08-21 23:53:26 +02:00
clan-bot
1c7323c90a Merge pull request 'Update clan-core-for-checks in devFlake' (#4869) from update-devFlake-clan-core-for-checks into main 2025-08-21 20:18:08 +00:00
clan-bot
e667e03832 Update clan-core-for-checks in devFlake 2025-08-21 20:01:29 +00:00
brianmcgee
7f227b232c Merge pull request 'ui/icons: update app icons' (#4867) from ui-search into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4867
Reviewed-by: brianmcgee <brian@bmcgee.ie>
2025-08-21 17:14:34 +00:00
Johannes Kirschbauer
9d887805a8 ui/icons: update app icons 2025-08-21 19:11:08 +02:00
hsjobeki
244e1c7447 Merge pull request 'ui/cubes: scene add tooltip descriptions to toolbar' (#4866) from api-modules-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4866
2025-08-21 16:25:11 +00:00
Johannes Kirschbauer
78911063a6 ui/tooltip: cleanup hostfileInput
Components should not rely on any global css classes
This can have bad side effects
2025-08-21 18:22:15 +02:00
hsjobeki
d86509e97b Merge pull request 'feat(ui): history stack for stepper' (#4834) from ui/fix-backwards-nav-installer into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4834
2025-08-21 16:15:26 +00:00
Johannes Kirschbauer
6de431df2c ui/stepper: use initial step from opts 2025-08-21 18:12:06 +02:00
Johannes Kirschbauer
cda49b5b20 ui/cubes: scene add tooltip descriptions to toolbar 2025-08-21 18:04:12 +02:00
brianmcgee
678841e64c Merge pull request 'fix(ui): blurry bold variants for CommitMono' (#4864) from fix/commit-mono-bold into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4864
2025-08-21 15:37:21 +00:00
Johannes Kirschbauer
74549164e4 ui/toolbarButton: wrap in tooltip for always having more information 2025-08-21 17:36:01 +02:00
Johannes Kirschbauer
6afe8695de ui/tooltip: refactor tooltip 2025-08-21 17:35:13 +02:00
Brian McGee
460800b6fb fix(ui): blurry bold variants for CommitMono 2025-08-21 16:33:51 +01:00
clan-bot
5558bf3b9a Merge pull request 'Update clan-core-for-checks in devFlake' (#4862) from update-devFlake-clan-core-for-checks into main 2025-08-21 15:18:02 +00:00
clan-bot
62701f7730 Merge pull request 'Update nixpkgs-dev in devFlake' (#4863) from update-devFlake-nixpkgs-dev into main 2025-08-21 15:11:45 +00:00
clan-bot
a2f3e2e513 Update nixpkgs-dev in devFlake 2025-08-21 15:01:50 +00:00
clan-bot
4867d467de Update clan-core-for-checks in devFlake 2025-08-21 15:01:31 +00:00
brianmcgee
d9685acc37 Merge pull request 'feat(ui): introduce a top-level Clan context' (#4860) from feat/handle-clan-switch-errors into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4860
2025-08-21 13:57:13 +00:00
pinpox
1aaa157f20 Merge pull request 'Cleanup machine-id,postgresql test' (#4858) from cleanup-tests into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4858
2025-08-21 12:58:36 +00:00
hsjobeki
9a0ad4182f Merge pull request 'api/modules: unify frontmatter with module manifest' (#4847) from api-modules-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4847
Reviewed-by: lassulus <clanlol@lassul.us>
2025-08-21 12:56:19 +00:00
pinpox
65d194af58 Cleanup machine-id,postgresql test 2025-08-21 14:52:13 +02:00
Johannes Kirschbauer
1f2f71ab03 lib/modules: make categories class method 2025-08-21 14:41:03 +02:00
Brian McGee
f985187999 feat(ui): introduce a top-level Clan context 2025-08-21 12:20:51 +01:00
clan-bot
396a8d1e5e Merge pull request 'Update clan-core-for-checks in devFlake' (#4857) from update-devFlake-clan-core-for-checks into main 2025-08-21 10:23:58 +00:00
clan-bot
651f630080 Merge pull request 'Update nix-darwin' (#4856) from update-nix-darwin into main 2025-08-21 10:21:19 +00:00
clan-bot
21de41f1c0 Update clan-core-for-checks in devFlake 2025-08-21 10:01:29 +00:00
clan-bot
98e5987e22 Update nix-darwin 2025-08-21 10:00:54 +00:00
brianmcgee
a77af2d379 Merge pull request 'ui/misc-fixes' (#4855) from ui/misc-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4855
2025-08-21 09:58:34 +00:00
Brian McGee
ccde9e0ba6 feat(ui): replace modal backdrop blur with opacity 2025-08-21 10:14:17 +01:00
Brian McGee
6f6f582fe3 feat(ui): improve spacing in sidebar dropdown 2025-08-21 10:04:21 +01:00
pinpox
ec70de406b Add coredns module 2025-08-21 10:29:54 +02:00
clan-bot
29a3140702 Merge pull request 'Update clan-core-for-checks in devFlake' (#4854) from update-devFlake-clan-core-for-checks into main 2025-08-21 05:20:25 +00:00
clan-bot
465eda24bc Update clan-core-for-checks in devFlake 2025-08-21 05:01:37 +00:00
clan-bot
2888907109 Merge pull request 'Update clan-core-for-checks in devFlake' (#4852) from update-devFlake-clan-core-for-checks into main 2025-08-21 00:19:00 +00:00
clan-bot
f770f600c6 Merge pull request 'Update nixpkgs-dev in devFlake' (#4853) from update-devFlake-nixpkgs-dev into main 2025-08-21 00:10:35 +00:00
clan-bot
729f1673b3 Update nixpkgs-dev in devFlake 2025-08-21 00:01:46 +00:00
clan-bot
7c95cb0177 Update clan-core-for-checks in devFlake 2025-08-21 00:01:30 +00:00
clan-bot
b7f159aea3 Merge pull request 'Update clan-core-for-checks in devFlake' (#4850) from update-devFlake-clan-core-for-checks into main 2025-08-20 20:20:07 +00:00
clan-bot
06a0062311 Update clan-core-for-checks in devFlake 2025-08-20 20:01:29 +00:00
Luis Hebendanz
aa840d9758 Merge pull request 'working check_machine_up_to_date' (#4754) from Qubasa/clan-core:build_is_installed_api into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4754
2025-08-20 19:12:53 +00:00
hsjobeki
d1e6da0779 Merge pull request 'api/install: set install date after install' (#4838) from install-done into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4838
Reviewed-by: brianmcgee <brian@bmcgee.ie>
2025-08-20 19:02:13 +00:00
Johannes Kirschbauer
e6981ddd72 cli/install: add --no-persist-state
Skip persisting the current date after successful install
This is a workaround due to incomplete test setup - installing a clan machine without having a clan
2025-08-20 20:46:44 +02:00
Qubasa
101c52f7c2 clan_lib: Add 'address' field to LocalHost 2025-08-20 20:28:21 +02:00
Johannes Kirschbauer
a83f301e59 docs/render: remove dead code 2025-08-20 20:19:49 +02:00
Qubasa
5120d90b85 clanService: telegraf.nix add json exporter over http 2025-08-20 20:17:49 +02:00
Qubasa
ea1e470502 clan_lib: add 'get_metrics' API endpoint 2025-08-20 20:17:14 +02:00
Johannes Kirschbauer
f4d6edc501 api/modules: unify frontmatter with module manifest 2025-08-20 20:15:41 +02:00
Johannes Kirschbauer
cbbc235570 api/modules: rename Frontmatter -> ModulesFrontmatter to make room for other disk templates metadata 2025-08-20 19:46:28 +02:00
brianmcgee
56d9256c02 Merge pull request 'chore(ui): remove close this clan button' (#4846) from chore/remove-close-clan-button into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4846
2025-08-20 15:55:50 +00:00
Brian McGee
e131d3d036 chore(ui): remove close this clan button 2025-08-20 16:52:47 +01:00
brianmcgee
7f5b7b5057 Merge pull request 'ui/clan-switching' (#4844) from ui/clan-switching into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4844
2025-08-20 15:46:11 +00:00
brianmcgee
c27fa9f56e Merge pull request 'fix(ui): inverted dividers in SectionGeneral component' (#4845) from fix/inverted-dividers-in-sidebar-pane into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4845
2025-08-20 15:41:31 +00:00
Brian McGee
1a1addb19d fix(ui): cancel loading state properly for select folder button in onboarding 2025-08-20 16:40:50 +01:00
Brian McGee
349da24b29 feat(ui): enable switching between clans 2025-08-20 16:40:49 +01:00
Brian McGee
717f66b613 fix(ui): inverted dividers in SectionGeneral component
Closes #4836
2025-08-20 16:37:33 +01:00
clan-bot
dcbc8c9a50 Merge pull request 'Update clan-core-for-checks in devFlake' (#4842) from update-devFlake-clan-core-for-checks into main 2025-08-20 15:21:49 +00:00
Brian McGee
9834f413cc feat(ui): introduce Add clan button into sidebar 2025-08-20 16:21:40 +01:00
Brian McGee
fb5645ae33 fix(ui): mock machine state in Sidebar stories 2025-08-20 16:21:39 +01:00
Brian McGee
dc311d78e2 fix(ui): add mock api client provider to Sidebar stories 2025-08-20 16:21:39 +01:00
clan-bot
f0b1d8b2af Merge pull request 'Update nixpkgs-dev in devFlake' (#4843) from update-devFlake-nixpkgs-dev into main 2025-08-20 15:12:06 +00:00
clan-bot
7f0d55ef74 Update nixpkgs-dev in devFlake 2025-08-20 15:01:51 +00:00
clan-bot
6e8860b3a0 Update clan-core-for-checks in devFlake 2025-08-20 15:01:31 +00:00
Mic92
5a5ec468c7 Merge pull request 'clan-cli: use automatic networking for vars upload and machines update' (#4792) from networking_4 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4792
2025-08-20 12:42:56 +00:00
Kenji Berthold
fbc2b889b5 Merge pull request 'docs: Fix migration docs for clan modules' (#4839) from kenji/ke-fix-migration-docs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4839
2025-08-20 12:27:09 +00:00
lassulus
fb094e8f3b add tor network to default template 2025-08-20 14:24:43 +02:00
lassulus
e2eb26345f networking: add documentation, unhide from CLI 2025-08-20 14:22:58 +02:00
a-kenji
6f1a94e825 docs: Fix migration docs for clan modules 2025-08-20 14:13:27 +02:00
Johannes Kirschbauer
05951ffdb9 api/install: set install date after install 2025-08-20 13:39:32 +02:00
clan-bot
69de5f10c0 Merge pull request 'Update clan-core-for-checks in devFlake' (#4833) from update-devFlake-clan-core-for-checks into main 2025-08-20 10:20:20 +00:00
Brian McGee
c01a191f3a feat(ui): history stack for stepper 2025-08-20 11:02:38 +01:00
clan-bot
dfe1a3e67f Update clan-core-for-checks in devFlake 2025-08-20 10:01:34 +00:00
brianmcgee
e975b67fad Merge pull request 'fix(ui): de-duplicate clan uris when adding to local storage' (#4831) from ui/deduplicate-clan-storage into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4831
2025-08-20 09:38:02 +00:00
Brian McGee
5c08893db0 fix(ui): de-duplicate clan uris when adding to local storage 2025-08-20 10:34:53 +01:00
brianmcgee
cb679dbee2 Merge pull request 'ui/install-workflow-refinements' (#4827) from ui/install-workflow-refinements into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4827
2025-08-20 09:23:04 +00:00
Brian McGee
f339ca0d85 feat(ui): allow installer splash screens to change modal size 2025-08-20 10:19:19 +01:00
Brian McGee
547ba4276e feat(ui): improve copy in create installer intro 2025-08-20 10:01:40 +01:00
Brian McGee
cae63cc45d fix(ui): spelling mistake 2025-08-20 10:01:39 +01:00
DavHau
527b4b2e40 vars: ensure shared generators don't depend on machine specific generators
A dependency relation like this would not make sense as it would not be clear which machines generator the shared generator would depend on
2025-08-20 15:39:17 +07:00
DavHau
de0b1b2d70 vars: fix regenerating a specific generator
This was broken after re-designing the API -> added a test
2025-08-20 14:49:27 +07:00
clan-bot
6996a6340a Merge pull request 'Update clan-core-for-checks in devFlake' (#4824) from update-devFlake-clan-core-for-checks into main 2025-08-20 05:25:25 +00:00
clan-bot
3c433da8f5 Update clan-core-for-checks in devFlake 2025-08-20 05:01:28 +00:00
DavHau
ef2a2bdb67 vars: improve tests for --regenerate
Ensures that all generators values actually change after running with --regenerate
2025-08-20 11:59:18 +07:00
DavHau
7b61a668e9 vars: refactor: use Machine objects instead of base_dir strings
Replace base_dir string parameters with Machine objects throughout the vars
module for better type safety and consistency.
2025-08-20 11:59:18 +07:00
clan-bot
bdab3e23af Merge pull request 'Update clan-core-for-checks in devFlake' (#4822) from update-devFlake-clan-core-for-checks into main 2025-08-20 00:18:32 +00:00
clan-bot
2b068928a2 Merge pull request 'Update nixpkgs-dev in devFlake' (#4823) from update-devFlake-nixpkgs-dev into main 2025-08-20 00:10:20 +00:00
clan-bot
ec798f89fd Update nixpkgs-dev in devFlake 2025-08-20 00:01:49 +00:00
clan-bot
9efee40477 Update clan-core-for-checks in devFlake 2025-08-20 00:01:30 +00:00
lassulus
448c22c280 clan-cli: use automatic networking for vars upload and machines update
This uses the networking module to find the best_host, as we already do
with ssh and install. So if we don't supply a --target-host and a
networking module is configured, the remote should be autodetected.

Since vars upload doesn't have a --target-host argument, we always try
to use get_best_remote
2025-08-19 23:40:57 +02:00
lassulus
6c6e30ae60 Merge pull request 'Add type to group and owner vars options' (#4819) from fix-4814 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4819
Reviewed-by: lassulus <clanlol@lassul.us>
2025-08-19 21:13:51 +00:00
pinpox
b27ff67a14 Add type to group and owner vars options 2025-08-19 22:46:30 +02:00
clan-bot
c0ffb17e00 Merge pull request 'Update nixpkgs' (#4818) from update-nixpkgs into main 2025-08-19 20:21:34 +00:00
Mic92
e9ccf157b6 Merge pull request 'Update clan-core-for-checks in devFlake' (#4744) from update-devFlake-clan-core-for-checks into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4744
2025-08-19 20:21:18 +00:00
clan-bot
451f2427fe Merge pull request 'Update nixos-facter-modules' (#4724) from update-nixos-facter-modules into main 2025-08-19 20:15:55 +00:00
clan-bot
1676cdd9a4 Update clan-core-for-checks in devFlake 2025-08-19 20:01:30 +00:00
clan-bot
109e6473ab Update nixpkgs 2025-08-19 20:01:23 +00:00
clan-bot
55acff50d0 Update nixos-facter-modules 2025-08-19 20:00:54 +00:00
hsjobeki
eee1bd1ae0 Merge pull request 'ui/select: display no options placeholder' (#4817) from install-story into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4817
2025-08-19 19:50:56 +00:00
Johannes Kirschbauer
e46d5870ff ui/select: display no options placeholder 2025-08-19 21:46:26 +02:00
hsjobeki
f6ec32a5d1 Merge pull request 'ui/modal/select: fix z-index stacking' (#4816) from render-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4816
2025-08-19 17:19:18 +00:00
Johannes Kirschbauer
e336d1b19c ui/modal/select: fix z-index stacking 2025-08-19 19:15:40 +02:00
brianmcgee
7399f59652 Merge pull request 'fix(ui): reload machine list in sidebar after adding a machine' (#4815) from ui/invalidate-list-query-on-add into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4815
2025-08-19 16:41:31 +00:00
Brian McGee
088abe396e fix(ui): reload machine list in sidebar after adding a machine 2025-08-19 17:37:53 +01:00
Mic92
26b31e24a3 Merge pull request 'Make most vm tests pure.' (#4796) from no-impure into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4796
2025-08-19 16:10:08 +00:00
brianmcgee
099f4c2b8b Merge pull request 'feat(api): define list machine options as data class' (#4811) from api/list-machine-data-class into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4811
2025-08-19 16:07:13 +00:00
brianmcgee
b43605c168 Merge pull request 'ui/filter-usb-devices' (#4813) from ui/filter-usb-devices into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4813
2025-08-19 15:58:27 +00:00
Jörg Thalheim
899dba5a08 tests/vms: add chroot-realpath (needed on aarch64) 2025-08-19 15:53:46 +00:00
Brian McGee
d2b94ced5a feat(api): define list machine options as data class 2025-08-19 16:51:30 +01:00
Jörg Thalheim
cdf9fa1753 move vm configuration into a stand-alone module and include it in our test vms
This hasn't reduced the extra deps we have to pass to our nixos build
unfortunally, but maybe at least it can safe us a few in the future.
2025-08-19 15:45:57 +00:00
Brian McGee
d1e7e2993d feat(ui): filter block devices in flash installer
Only display usb or mmc (SD card) drives.
2025-08-19 16:45:47 +01:00
Brian McGee
e05d85c759 feat(ui): darken modal overlay 2025-08-19 16:13:19 +01:00
clan-bot
53873411a6 Merge pull request 'Update disko' (#4793) from update-disko into main 2025-08-19 14:42:47 +00:00
clan-bot
39e0ab21bd Merge pull request 'Update nixpkgs-dev in devFlake' (#4794) from update-devFlake-nixpkgs-dev into main 2025-08-19 14:28:48 +00:00
clan-bot
8269d869c3 Update disko 2025-08-19 14:24:27 +00:00
clan-bot
e19d1c8122 Update nixpkgs-dev in devFlake 2025-08-19 14:24:17 +00:00
brianmcgee
0cd4ff1b12 Merge pull request 'tracking machine install state' (#4803) from feat/machine-install-state into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4803
2025-08-19 14:23:35 +00:00
Brian McGee
9aebf02f05 feat(ui): display machine install state and install button 2025-08-19 15:09:34 +01:00
Jörg Thalheim
ffb7b91da7 drop impure checks from ci 2025-08-19 15:28:25 +02:00
Jörg Thalheim
2d264a8e5e mark vm tests as pure 2025-08-19 15:28:25 +02:00
Mic92
abf6893714 Merge pull request 'Fix aarch64-linux vm support' (#4810) from various-fixes into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4810
2025-08-19 13:21:28 +00:00
Jörg Thalheim
699c56c721 qemu: enable usb tablet option only on x86_64-linux
at least on aarch64-linux this locks up the hypervisor
2025-08-19 15:16:56 +02:00
Jörg Thalheim
2ce5388a75 qemu: fix machine types for various platforms 2025-08-19 15:16:56 +02:00
Jörg Thalheim
3e664255d6 speed up tests by doing reflink copies 2025-08-19 15:16:56 +02:00
Jörg Thalheim
5b1a9d6848 vms: also prebuild for aarch64 2025-08-19 14:49:52 +02:00
Jörg Thalheim
1850abdd0d clan-cli/vms/run: generate secret before inspect_vm
inspect_vm does some caching, which lead to secrets not beeing found.
2025-08-19 14:49:52 +02:00
Jörg Thalheim
ed503f64da vms/run: move python import to the top. 2025-08-19 14:49:52 +02:00
Jörg Thalheim
4074a184b2 make vm test pure 2025-08-19 14:47:12 +02:00
Jörg Thalheim
6fe2b06f09 qemu: fix nix chroot store support 2025-08-19 14:47:12 +02:00
Jörg Thalheim
8fe7cb1b3d virtiofsd: fix nix chroot store support 2025-08-19 14:47:12 +02:00
DavHau
815c6c9438 vars: move generation functions to clan_lib 2025-08-19 18:05:53 +07:00
DavHau
9ce563aa08 vars: log var updates under specific machine
This makes it easier in the logs to identify which machine a var update belongs to
2025-08-19 11:03:36 +00:00
hsjobeki
c25844dd07 Merge pull request 'ui/modal: refactor mounting and controlled state' (#4807) from render-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4807
2025-08-19 10:55:43 +00:00
Johannes Kirschbauer
a167e70e63 ui/modal: refactor mounting and controlled state 2025-08-19 12:52:20 +02:00
hsjobeki
dd96fe6b73 Merge pull request 'ui/routing: re-route on changes not only on page load' (#4805) from render-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4805
2025-08-19 10:15:59 +00:00
Johannes Kirschbauer
40d35d37e2 ui/routing: re-route on changes not only on page load 2025-08-19 12:10:04 +02:00
Luis Hebendanz
071f0f8034 Merge pull request 'codeowners: init team code owners' (#4786) from codeowners-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4786
Reviewed-by: lassulus <clanlol@lassul.us>
Reviewed-by: pinpox <clan@pablo.tools>
Reviewed-by: DavHau <d.hauer.it@gmail.com>
Reviewed-by: brianmcgee <brian@bmcgee.ie>
2025-08-19 09:54:33 +00:00
Johannes Kirschbauer
81d88fe253 codeowners: init team code owners 2025-08-19 11:35:10 +02:00
DavHau
ab274ce932 vars: refactor - remove generate_vars() in favor of run_generators()
The motivation is to have one shared entry point for the CLI as well as API/GUI
2025-08-19 16:26:53 +07:00
hsjobeki
ba1e598a76 Merge pull request 'ui/alert: migrate to css modules' (#4802) from css-modules into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4802
2025-08-19 08:58:22 +00:00
Johannes Kirschbauer
b5d29bd301 ui/alert: migrate to css modules 2025-08-19 10:27:55 +02:00
Johannes Kirschbauer
e174e8e029 css-modules: add typechecking for css module classes 2025-08-19 10:20:50 +02:00
Kenji Berthold
453d2b4a0a Merge pull request 'pkgs/remove-moonlight-sunshine-accept: drop' (#4798) from remove-moonlight-sunshine-accept into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4798
Reviewed-by: Kenji Berthold <aks.kenji@protonmail.com>
2025-08-19 07:50:41 +00:00
DavHau
aadc8a1d63 vars: refactor - remove _generate_vars_for_machine function
This became unnecessary by now
2025-08-19 07:41:31 +00:00
DavHau
aaca8f4763 vars: refactor - move generator specific code to Generator class
Several functions in generate.py were specific to generator instances. Let's move them into the Generator class
2025-08-19 07:41:31 +00:00
DavHau
0a1a63dfdd Merge pull request 'vars: refactor - remove create_machine_vars_interactive in favor of run_generators' (#4795) from vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4795
2025-08-19 06:41:12 +00:00
DavHau
ee87f20471 vars: refactor - remove create_machine_vars_interactive in favor of run_generators
The motivation is to create one powerful entrypoint shared by the GUI as well as the CLI in order to not having to maintain too much separate code paths.

As a next step, generate_vars can probably also be removed.
2025-08-19 13:26:38 +07:00
hsjobeki
43febe5f33 Merge pull request 'Typography and contrast improvements for the UI' (#4797) from ui/typography-size-increases into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4797
2025-08-19 06:25:37 +00:00
clan-bot
c63bbabceb Merge pull request 'Update nuschtos in devFlake' (#4800) from update-devFlake-nuschtos into main 2025-08-19 00:10:33 +00:00
clan-bot
8f1b270b59 Update nuschtos in devFlake 2025-08-19 00:01:53 +00:00
hsjobeki
da0af8bd53 Merge pull request 'Api/schema: improve types top schema conversion' (#4799) from api-types into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4799
2025-08-18 17:48:36 +00:00
Johannes Kirschbauer
f82d18d649 API: rename util file to 'type_to_jsonschema' 2025-08-18 19:30:43 +02:00
Johannes Kirschbauer
287a303484 API/schema: make type conversion more strict in terms of undefined fields 2025-08-18 19:29:54 +02:00
Johannes Kirschbauer
1213608f30 API: init support for narrowing union types
This allows to relax constraints on functions using overloaded interfaces
I.e. for unifying logic this allows passing 'callable | dict'
Conretely useful for prompt values that are asked on demand in the cli, vs upfront in the ui
2025-08-18 19:28:47 +02:00
pinpox
fa1693e8c0 pkgs/remove-moonlight-sunshine-accept: drop
Removes this package as the module has already be deprecated and removed
2025-08-18 14:39:08 +02:00
Brian McGee
ed3ed7cb2a chore(ui): lint 2025-08-18 12:52:33 +01:00
Brian McGee
b2e88fb3fa chore(ui): fmt 2025-08-18 12:52:33 +01:00
Brian McGee
d6ca50218a feat(ui): increase fg/def/4 from 500 to 600 2025-08-18 12:52:32 +01:00
Brian McGee
7d1f0956d6 feat(ui): refine Tag and line-height for labels 2025-08-18 12:52:32 +01:00
Brian McGee
d150c80854 feat(ui): move sidebar section header outside content 2025-08-18 12:52:31 +01:00
Brian McGee
2d1828d088 feat(ui): better contrast in sidebar 2025-08-18 12:52:31 +01:00
Brian McGee
f7f897a311 feat(ui): add xs button type 2025-08-18 12:52:30 +01:00
Brian McGee
683ffbdc76 feat(ui): refine Select with new typography sizes 2025-08-18 12:52:30 +01:00
Brian McGee
480ad3a5f1 feat(ui): increase label font sizes 2025-08-18 12:52:29 +01:00
Brian McGee
16361f03e9 feat(ui): typography size increases 2025-08-18 12:52:27 +01:00
594 changed files with 25353 additions and 8713 deletions

View File

@@ -1,9 +0,0 @@
name: checks
on:
pull_request:
jobs:
checks-impure:
runs-on: nix
steps:
- uses: actions/checkout@v4
- run: nix run .#impure-checks

View File

@@ -10,7 +10,7 @@ jobs:
if: github.repository_owner == 'clan-lol'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
- uses: actions/create-github-app-token@v2

View File

@@ -0,0 +1,20 @@
clanServices/.* @pinpox @kenji
lib/test/container-test-driver/.* @DavHau @mic92
lib/modules/inventory/.* @hsjobeki
lib/modules/inventoryClass/.* @hsjobeki
pkgs/clan-app/ui/.* @hsjobeki @brianmcgee
pkgs/clan-app/clan_app/.* @qubasa @hsjobeki
pkgs/clan-cli/clan_cli/.* @lassulus @mic92 @kenji
pkgs/clan-cli/clan_cli/(secrets|vars)/.* @DavHau @lassulus
pkgs/clan-cli/clan_lib/log_machines/.* @Qubasa
pkgs/clan-cli/clan_lib/ssh/.* @Qubasa @Mic92 @lassulus
pkgs/clan-cli/clan_lib/tags/.* @hsjobeki
pkgs/clan-cli/clan_lib/persist/.* @hsjobeki
pkgs/clan-cli/clan_lib/flake/.* @lassulus
pkgs/clan-cli/api.py @hsjobeki
pkgs/clan-cli/openapi.py @hsjobeki

View File

@@ -8,7 +8,7 @@ Our mission is simple: to democratize computing by providing tools that empower
## Features of Clan
- **Full-Stack System Deployment:** Utilize Clans toolkit alongside Nix's reliability to build and manage systems effortlessly.
- **Full-Stack System Deployment:** Utilize Clan's toolkit alongside Nix's reliability to build and manage systems effortlessly.
- **Overlay Networks:** Secure, private communication channels between devices.
- **Virtual Machine Integration:** Seamless operation of VM applications within the main operating system.
- **Robust Backup Management:** Long-term, self-hosted data preservation.

View File

@@ -1,6 +0,0 @@
{ fetchgit }:
fetchgit {
url = "https://git.clan.lol/clan/clan-core.git";
rev = "5d884cecc2585a29b6a3596681839d081b4de192";
sha256 = "09is1afmncamavb2q88qac37vmsijxzsy1iz1vr6gsyjq2rixaxc";
}

View File

@@ -36,7 +36,6 @@ in
++ filter pathExists [
./devshell/flake-module.nix
./flash/flake-module.nix
./impure/flake-module.nix
./installation/flake-module.nix
./update/flake-module.nix
./morph/flake-module.nix

View File

@@ -50,12 +50,14 @@
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.toplevel
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript.drvPath
(import ../installation/facter-report.nix pkgs.hostPlatform.system)
]
++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
in
{
checks = pkgs.lib.mkIf pkgs.stdenv.isLinux {
# Skip flash test on aarch64-linux for now as it's too slow
checks = lib.optionalAttrs (pkgs.stdenv.isLinux && pkgs.hostPlatform.system != "aarch64-linux") {
nixos-test-flash = self.clanLib.test.baseTest {
name = "flash";
nodes.target = {

View File

@@ -1,51 +0,0 @@
{
perSystem =
{
pkgs,
lib,
self',
...
}:
{
# a script that executes all other checks
packages.impure-checks = pkgs.writeShellScriptBin "impure-checks" ''
#!${pkgs.bash}/bin/bash
set -euo pipefail
unset CLAN_DIR
export PATH="${
lib.makeBinPath (
[
pkgs.gitMinimal
pkgs.nix
pkgs.coreutils
pkgs.rsync # needed to have rsync installed on the dummy ssh server
]
++ self'.packages.clan-cli-full.runtimeDependencies
)
}"
ROOT=$(git rev-parse --show-toplevel)
cd "$ROOT/pkgs/clan-cli"
# Set up custom git configuration for tests
export GIT_CONFIG_GLOBAL=$(mktemp)
git config --file "$GIT_CONFIG_GLOBAL" user.name "Test User"
git config --file "$GIT_CONFIG_GLOBAL" user.email "test@example.com"
export GIT_CONFIG_SYSTEM=/dev/null
# this disables dynamic dependency loading in clan-cli
export CLAN_NO_DYNAMIC_DEPS=1
jobs=$(nproc)
# Spawning worker in pytest is relatively slow, so we limit the number of jobs to 13
# (current number of impure tests)
jobs="$((jobs > 6 ? 6 : jobs))"
nix develop "$ROOT#clan-cli" -c bash -c "TMPDIR=/tmp python -m pytest -n $jobs -m impure ./clan_cli $@"
# Clean up temporary git config
rm -f "$GIT_CONFIG_GLOBAL"
'';
};
}

View File

@@ -0,0 +1,10 @@
system:
builtins.fetchurl {
url = "https://git.clan.lol/clan/test-fixtures/raw/commit/4a2bc56d886578124b05060d3fb7eddc38c019f8/nixos-vm-facter-json/${system}.json";
sha256 =
{
aarch64-linux = "sha256:1rlfymk03rmfkm2qgrc8l5kj5i20srx79n1y1h4nzlpwaz0j7hh2";
x86_64-linux = "sha256:16myh0ll2gdwsiwkjw5ba4dl23ppwbsanxx214863j7nvzx42pws";
}
.${system};
}

View File

@@ -18,27 +18,23 @@
fileSystems."/".device = lib.mkDefault "/dev/vda";
boot.loader.grub.device = lib.mkDefault "/dev/vda";
imports = [ self.nixosModules.test-install-machine-without-system ];
imports = [
self.nixosModules.test-install-machine-without-system
];
};
clan.machines.test-install-machine-with-system =
{ pkgs, ... }:
{
# https://git.clan.lol/clan/test-fixtures
facter.reportPath = builtins.fetchurl {
url = "https://git.clan.lol/clan/test-fixtures/raw/commit/4a2bc56d886578124b05060d3fb7eddc38c019f8/nixos-vm-facter-json/${pkgs.hostPlatform.system}.json";
sha256 =
{
aarch64-linux = "sha256:1rlfymk03rmfkm2qgrc8l5kj5i20srx79n1y1h4nzlpwaz0j7hh2";
x86_64-linux = "sha256:16myh0ll2gdwsiwkjw5ba4dl23ppwbsanxx214863j7nvzx42pws";
}
.${pkgs.hostPlatform.system};
};
facter.reportPath = import ./facter-report.nix pkgs.hostPlatform.system;
fileSystems."/".device = lib.mkDefault "/dev/vda";
boot.loader.grub.device = lib.mkDefault "/dev/vda";
imports = [ self.nixosModules.test-install-machine-without-system ];
};
flake.nixosModules = {
test-install-machine-without-system =
{ lib, modulesPath, ... }:
@@ -159,6 +155,7 @@
pkgs.stdenv.drvPath
pkgs.bash.drvPath
pkgs.buildPackages.xorg.lndir
(import ./facter-report.nix pkgs.hostPlatform.system)
]
++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
};
@@ -232,6 +229,7 @@
"-i", ssh_conn.ssh_key,
"--option", "store", os.environ['CLAN_TEST_STORE'],
"--update-hardware-config", "nixos-facter",
"--no-persist-state",
]
subprocess.run(clan_cmd, check=True)
@@ -275,7 +273,7 @@
"${self.checks.x86_64-linux.clan-core-for-checks}",
"${closureInfo}"
)
# Set up SSH connection
ssh_conn = setup_ssh_connection(
target,
@@ -301,7 +299,8 @@
"test-install-machine-without-system",
"-i", ssh_conn.ssh_key,
"--option", "store", os.environ['CLAN_TEST_STORE'],
f"nonrootuser@localhost:{ssh_conn.host_port}"
"--target-host", f"nonrootuser@localhost:{ssh_conn.host_port}",
"--yes"
]
result = subprocess.run(clan_cmd, capture_output=True, cwd=flake_dir)
@@ -325,7 +324,9 @@
"test-install-machine-without-system",
"-i", ssh_conn.ssh_key,
"--option", "store", os.environ['CLAN_TEST_STORE'],
f"nonrootuser@localhost:{ssh_conn.host_port}"
"--target-host",
f"nonrootuser@localhost:{ssh_conn.host_port}",
"--yes"
]
result = subprocess.run(clan_cmd, capture_output=True, cwd=flake_dir)

View File

@@ -35,6 +35,7 @@
pkgs.stdenv.drvPath
pkgs.stdenvNoCC
self.nixosConfigurations.test-morph-machine.config.system.build.toplevel
(import ../installation/facter-report.nix pkgs.hostPlatform.system)
]
++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };

View File

@@ -112,6 +112,7 @@
pkgs.stdenv.drvPath
pkgs.bash.drvPath
pkgs.buildPackages.xorg.lndir
(import ../installation/facter-report.nix pkgs.hostPlatform.system)
]
++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
};

View File

@@ -5,7 +5,7 @@ inventory.instances = {
borgbackup = {
module = {
name = "borgbackup";
input = "clan";
input = "clan-core";
};
roles.client.machines."jon".settings = {
destinations."storagebox" = {

View File

@@ -0,0 +1,32 @@
This service sets up a certificate authority (CA) that can issue certificates to
other machines in your clan. For this the `ca` role is used.
It additionally provides a `default` role, that can be applied to all machines
in your clan and will make sure they trust your CA.
## Example Usage
The following configuration would add a CA for the top level domain `.foo`. If
the machine `server` now hosts a webservice at `https://something.foo`, it will
get a certificate from `ca` which is valid inside your clan. The machine
`client` will trust this certificate if it makes a request to
`https://something.foo`.
This clan service can be combined with the `coredns` service for easy to deploy,
SSL secured clan-internal service hosting.
```nix
inventory = {
machines.ca = { };
machines.client = { };
machines.server = { };
instances."certificates" = {
module.name = "certificates";
module.input = "self";
roles.ca.machines.ca.settings.tlds = [ "foo" ];
roles.default.machines.client = { };
roles.default.machines.server = { };
};
};
```

View File

@@ -0,0 +1,245 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "certificates";
manifest.description = "Sets up a certificates internal to your Clan";
manifest.categories = [ "Network" ];
manifest.readme = builtins.readFile ./README.md;
roles.ca = {
interface =
{ lib, ... }:
{
options.acmeEmail = lib.mkOption {
type = lib.types.str;
default = "none@none.tld";
description = ''
Email address for account creation and correspondence from the CA.
It is recommended to use the same email for all certs to avoid account
creation limits.
'';
};
options.tlds = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "Top level domain for this CA. Certificates will be issued and trusted for *.<tld>";
};
options.expire = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "When the certificate should expire.";
default = "8760h";
example = "8760h";
};
};
perInstance =
{ settings, ... }:
{
nixosModule =
{
config,
pkgs,
lib,
...
}:
let
domains = map (tld: "ca.${tld}") settings.tlds;
in
{
security.acme.defaults.email = settings.acmeEmail;
security.acme = {
certs = builtins.listToAttrs (
map (domain: {
name = domain;
value = {
server = "https://${domain}:1443/acme/acme/directory";
};
}) domains
);
};
networking.firewall.allowedTCPPorts = [
80
443
];
services.nginx = {
enable = true;
recommendedProxySettings = true;
virtualHosts = builtins.listToAttrs (
map (domain: {
name = domain;
value = {
addSSL = true;
enableACME = true;
locations."/".proxyPass = "https://localhost:1443";
locations."= /ca.crt".alias =
config.clan.core.vars.generators.step-intermediate-cert.files."intermediate.crt".path;
};
}) domains
);
};
clan.core.vars.generators = {
# Intermediate key generator
"step-intermediate-key" = {
files."intermediate.key" = {
secret = true;
deploy = true;
owner = "step-ca";
group = "step-ca";
};
runtimeInputs = [ pkgs.step-cli ];
script = ''
step crypto keypair --kty EC --curve P-256 --no-password --insecure $out/intermediate.pub $out/intermediate.key
'';
};
# Intermediate certificate generator
"step-intermediate-cert" = {
files."intermediate.crt".secret = false;
dependencies = [
"step-ca"
"step-intermediate-key"
];
runtimeInputs = [ pkgs.step-cli ];
script = ''
# Create intermediate certificate
step certificate create \
--ca $in/step-ca/ca.crt \
--ca-key $in/step-ca/ca.key \
--ca-password-file /dev/null \
--key $in/step-intermediate-key/intermediate.key \
--template ${pkgs.writeText "intermediate.tmpl" ''
{
"subject": {{ toJson .Subject }},
"keyUsage": ["certSign", "crlSign"],
"basicConstraints": {
"isCA": true,
"maxPathLen": 0
},
"nameConstraints": {
"critical": true,
"permittedDNSDomains": [${
(lib.strings.concatStringsSep "," (map (tld: ''"${tld}"'') settings.tlds))
}]
}
}
''} ${lib.optionalString (settings.expire != null) "--not-after ${settings.expire}"} \
--not-before=-12h \
--no-password --insecure \
"Clan Intermediate CA" \
$out/intermediate.crt
'';
};
};
services.step-ca = {
enable = true;
intermediatePasswordFile = "/dev/null";
address = "0.0.0.0";
port = 1443;
settings = {
root = config.clan.core.vars.generators.step-ca.files."ca.crt".path;
crt = config.clan.core.vars.generators.step-intermediate-cert.files."intermediate.crt".path;
key = config.clan.core.vars.generators.step-intermediate-key.files."intermediate.key".path;
dnsNames = domains;
logger.format = "text";
db = {
type = "badger";
dataSource = "/var/lib/step-ca/db";
};
authority = {
provisioners = [
{
type = "ACME";
name = "acme";
forceCN = true;
}
];
claims = {
maxTLSCertDuration = "2160h";
defaultTLSCertDuration = "2160h";
};
backdate = "1m0s";
};
tls = {
cipherSuites = [
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
];
minVersion = 1.2;
maxVersion = 1.3;
renegotiation = false;
};
};
};
};
};
};
# Empty role, so we can add non-ca machins to the instance to trust the CA
roles.default = {
interface =
{ lib, ... }:
{
options.acmeEmail = lib.mkOption {
type = lib.types.str;
default = "none@none.tld";
description = ''
Email address for account creation and correspondence from the CA.
It is recommended to use the same email for all certs to avoid account
creation limits.
'';
};
};
perInstance =
{ settings, ... }:
{
nixosModule.security.acme.defaults.email = settings.acmeEmail;
};
};
# All machines (independent of role) will trust the CA
perMachine.nixosModule =
{ pkgs, config, ... }:
{
# Root CA generator
clan.core.vars.generators = {
"step-ca" = {
share = true;
files."ca.key" = {
secret = true;
deploy = false;
};
files."ca.crt".secret = false;
runtimeInputs = [ pkgs.step-cli ];
script = ''
step certificate create --template ${pkgs.writeText "root.tmpl" ''
{
"subject": {{ toJson .Subject }},
"issuer": {{ toJson .Subject }},
"keyUsage": ["certSign", "crlSign"],
"basicConstraints": {
"isCA": true,
"maxPathLen": 1
}
}
''} "Clan Root CA" $out/ca.crt $out/ca.key \
--kty EC --curve P-256 \
--not-after=8760h \
--not-before=-12h \
--no-password --insecure
'';
};
};
security.pki.certificateFiles = [ config.clan.core.vars.generators."step-ca".files."ca.crt".path ];
environment.systemPackages = [ pkgs.openssl ];
security.acme.acceptTerms = true;
};
}

View File

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

View File

@@ -0,0 +1,84 @@
{
name = "certificates";
clan = {
directory = ./.;
inventory = {
machines.ca = { }; # 192.168.1.1
machines.client = { }; # 192.168.1.2
machines.server = { }; # 192.168.1.3
instances."certificates" = {
module.name = "certificates";
module.input = "self";
roles.ca.machines.ca.settings.tlds = [ "foo" ];
roles.default.machines.client = { };
roles.default.machines.server = { };
};
};
};
nodes =
let
hostConfig = ''
192.168.1.1 ca.foo
192.168.1.3 test.foo
'';
in
{
client.networking.extraHosts = hostConfig;
ca.networking.extraHosts = hostConfig;
server = {
networking.extraHosts = hostConfig;
# TODO: Could this be set automatically?
# I would like to get this information from the coredns module, but we
# cannot model dependencies yet
security.acme.certs."test.foo".server = "https://ca.foo/acme/acme/directory";
# Host a simple service on 'server', with SSL provided via our CA. 'client'
# should be able to curl it via https and accept the certificates
# presented
networking.firewall.allowedTCPPorts = [
80
443
];
services.nginx = {
enable = true;
virtualHosts."test.foo" = {
enableACME = true;
forceSSL = true;
locations."/" = {
return = "200 'test server response'";
extraConfig = "add_header Content-Type text/plain;";
};
};
};
};
};
testScript = ''
start_all()
import time
time.sleep(3)
ca.succeed("systemctl restart acme-order-renew-ca.foo.service ")
time.sleep(3)
server.succeed("systemctl restart acme-test.foo.service")
# It takes a while for the correct certs to appear (before that self-signed
# are presented by nginx) so we wait for a bit.
client.wait_until_succeeds("curl -v https://test.foo")
# Show certificate information for debugging
client.succeed("openssl s_client -connect test.foo:443 -servername test.foo </dev/null 2>/dev/null | openssl x509 -text -noout 1>&2")
'';
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:6+XilULKRuWtAZ6B8Lj9UqCfi1T6dmqrDqBNXqS4SvBwM1bIWiL6juaT1Q7ByOexzID7tY740gmQBqTey54uLydh8mW0m4ZtUqw=,iv:9kscsrMPBGkutTnxrc5nrc7tQXpzLxw+929pUDKqTu0=,tag:753uIjm8ZRs0xsjiejEY8g==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1d3kycldZRXhmR0FqTXJp\nWWU0MDBYNmxxbFE5M2xKYm5KWnQ0MXBHNEM4CjN4RFFVcFlkd3pjTFVDQ3Vackdj\nVTVhMWoxdFpsWHp5S1p4L05kYk5LUkkKLS0tIENtZFZZTjY2amFVQmZLZFplQzBC\nZm1vWFI4MXR1ZHIxTTQ5VXdSYUhvOTQKte0bKjXQ0xA8FrpuChjDUvjVqp97D8kT\n3tVh6scdjxW48VSBZP1GRmqcMqCdj75GvJTbWeNEV4PDBW7GI0UW+Q==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-09-02T08:42:39Z",
"mac": "ENC[AES256_GCM,data:AftMorrH7qX5ctVu5evYHn5h9pC4Mmm2VYaAV8Hy0PKTc777jNsL6DrxFVV3NVqtecpwrzZFWKgzukcdcRJe4veVeBrusmoZYtifH0AWZTEVpVlr2UXYYxCDmNZt1WHfVUo40bT//X6QM0ye6a/2Y1jYPbMbryQNcGmnpk9PDvU=,iv:5nk+d8hzA05LQp7ZHRbIgiENg2Ha6J6YzyducM6zcNU=,tag:dy1hqWVzMu/+fSK57h9ZCA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

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

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:jdTuGQUYvT1yXei1RHKsOCsABmMlkcLuziHDVhA7NequZeNu0fSbrJTXQDCHsDGhlYRcjU5EsEDT750xdleXuD3Gs9zWvPVobI4=,iv:YVow3K1j6fzRF9bRfIEpuOkO/nRpku/UQxWNGC+UJQQ=,tag:cNLM5R7uu6QpwPB9K6MYzg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvOVF2WXRSL0NpQzFZR01I\nNU85TGcyQmVDazN1dmpuRFVTZEg5NDRKTGhrCk1IVjFSU1V6WHBVRnFWcHkyVERr\nTjFKbW1mQ2FWOWhjN2VPamMxVEQ5VkkKLS0tIENVUGlhanhuWGtDKzBzRmk2dE4v\nMXZBRXNMa3IrOTZTNHRUWVE3UXEwSWMK2cBLoL/H/Vxd/klVrqVLdX9Mww5j7gw/\nEWc5/hN+km6XoW+DiJxVG4qaJ7qqld6u5ZnKgJT+2h9CfjA04I2akg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-09-02T08:42:51Z",
"mac": "ENC[AES256_GCM,data:zOBQVM2Ydu4v0+Fw3p3cEU+5+7eKaadV0tKro1JVOxclG1Vs6Myq57nw2eWf5JxIl0ulL+FavPKY26qOQ3aqcGOT3PMRlCda9z+0oSn9Im9bE/DzAGmoH/bp76kFkgTTOCZTMUoqJ+UJqv0qy1BH/92sSSKmYshEX6d1vr5ISrw=,iv:i9ZW4sLxOCan4UokHlySVr1CW39nCTusG4DmEPj/gIw=,tag:iZBDPHDkE3Vt5mFcFu1TPQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

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

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:5CJuHcxJMXZJ8GqAeG3BrbWtT1kade4kxgJsn1cRpmr1UgN0ZVYnluPEiBscClNSOzcc6vcrBpfTI3dj1tASKTLP58M+GDBFQDo=,iv:gsK7XqBGkYCoqAvyFlIXuJ27PKSbTmy7f6cgTmT2gow=,tag:qG5KejkBvy9ytfhGXa/Mnw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxbzVqYkplTzJKN1pwS3VM\naFFIK2VsR3lYUVExYW9ieERBL0tlcFZtVzJRCkpiLzdmWmFlOUZ5QUJ4WkhXZ2tQ\nZm92YXBCV0RpYnIydUdEVTRiamI4bjAKLS0tIG93a2htS1hFcjBOeVFnNCtQTHVr\na2FPYjVGbWtORjJVWXE5bndPU1RWcXMKikMEB7X+kb7OtiyqXn3HRpLYkCdoayDh\n7cjGnplk17q25/lRNHM4JVS5isFfuftCl01enESqkvgq+cwuFwa9DQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-09-02T08:42:59Z",
"mac": "ENC[AES256_GCM,data:xybV2D0xukZnH2OwRpIugPnS7LN9AbgGKwFioPJc1FQWx9TxMUVDwgMN6V5WrhWkXgF2zP4krtDYpEz4Vq+LbOjcnTUteuCc+7pMHubuRuip7j+M32MH1kuf4bVZuXbCfvm7brGxe83FzjoioLqzA8g/X6Q1q7/ErkNeFjluC3Q=,iv:QEW3EUKSRZY3fbXlP7z+SffWkQeXwMAa5K8RQW7NvPE=,tag:DhFxY7xr7H1Wbd527swD0Q==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

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

View File

@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBsDCCAVegAwIBAgIQbT1Ivm+uwyf0HNkJfan2BTAKBggqhkjOPQQDAjAXMRUw
EwYDVQQDEwxDbGFuIFJvb3QgQ0EwHhcNMjUwOTAxMjA0MzAzWhcNMjYwOTAyMDg0
MzAzWjAfMR0wGwYDVQQDExRDbGFuIEludGVybWVkaWF0ZSBDQTBZMBMGByqGSM49
AgEGCCqGSM49AwEHA0IABDXCNrUIotju9P1U6JxLV43sOxLlRphQJS4dM+lvjTZc
aQ+HwQg0AHVlQNRwS3JqKrJJtJVyKbZklh6eFaDPoj6jfTB7MA4GA1UdDwEB/wQE
AwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRKHaccHgP2ccSWVBWN
zGoDdTg7aTAfBgNVHSMEGDAWgBSfsnz4phMJx9su/kgeF/FbZQCBgzAVBgNVHR4B
Af8ECzAJoAcwBYIDZm9vMAoGCCqGSM49BAMCA0cAMEQCICiUDk1zGNzpS/iVKLfW
zUGaCagpn2mCx4xAXQM9UranAiAn68nVYGWjkzhU31wyCAupxOjw7Bt96XXqIAz9
hLLtMA==
-----END CERTIFICATE-----

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:Auonh9fa7jSkld1Zyxw74x5ydj6Xc+0SOgiqumVETNCfner9K96Rmv1PkREuHNGWPsnzyEM3pRT8ijvu3QoKvy9QPCCewyT07Wqe4G74+bk1iMeAHsV3To6kHs6M8OISvE+CmG0+hlLmdfRSabTzyWPLHbOjvFTEEuA5G7xiryacSYOE++eeEHdn+oUDh/IMTcfLjCGMjsXFikx1Hb+ofeRTlCg47+0w4MXVvQkOzQB5V2C694jZXvZ19jd/ioqr8YASz2xatGvqwW6cpZxqOWyZJ0UAj/6yFk6tZWifqVB3wgU=,iv:ITFCrDkeWl4GWCebVq15ei9QmkOLDwUIYojKZ2TU6JU=,tag:8k4iYbCIusUykY79H86WUQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsT25UbjJTQ2tzbnQyUm9p\neWx1UlZIeVpocnBqUCt0YnFlN2FOU25Lb0hNCmdXUUsyalRTbHRRQ0NLSGc1YllV\nUXRwaENhaXU1WmdnVDE0UWprUUUyeDAKLS0tIHV3dHU3aG5JclM0V3FadzN0SU14\ndFptbEJUNXQ4QVlqbkJ1TjAvdDQwSGsKcKPWUjhK7wzIpdIdksMShF2fpLdDTUBS\nZiU7P1T+3psxad9qhapvU0JrAY+9veFaYVEHha2aN/XKs8HqUcTp3A==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yd2cden7jav8x4nzx2fwze2fsa5j0qm2m3t7zum765z3u4gj433q7dqj43",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjZFVteVZwVGVmRE9NT3hG\nNGMyS3FSaXluM1FpeUp6SDVMUEpwYzg5SmdvCkRPU0QyU1JicGNkdlMyQWVkT0k3\nL2YrbDhWeGk4WFhxcUFmTmhZQ0pEQncKLS0tIG85Ui9rKzBJQ2VkMFBUQTMvSTlu\nbm8rZ09Wa24rQkNvTTNtYTZBN3MrZlkK7cjNhlUKZdOrRq/nKUsbUQgNTzX8jO+0\nzADpz6WCMvsJ15xazc10BGh03OtdMWl5tcoWMaZ71HWtI9Gip5DH0w==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-09-02T08:42:42Z",
"mac": "ENC[AES256_GCM,data:9xlO5Yis8DG/y8GjvP63NltD4xEL7zqdHL2cQE8gAoh/ZamAmK5ZL0ld80mB3eIYEPKZYvmUYI4Lkrge2ZdqyDoubrW+eJ3dxn9+StxA9FzXYwUE0t+bbsNJfOOp/kDojf060qLGsu0kAGKd2ca4WiDccR0Cieky335C7Zzhi/Q=,iv:bWQ4wr0CJHSN+6ipUbkYTDWZJyFQjDKszfpVX9EEUsY=,tag:kADIFgJBEGCvr5fPbbdEDA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

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

View File

@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBcTCCARigAwIBAgIRAIix99+AE7Y+uyiLGaRHEhUwCgYIKoZIzj0EAwIwFzEV
MBMGA1UEAxMMQ2xhbiBSb290IENBMB4XDTI1MDkwMTIwNDI1N1oXDTI2MDkwMjA4
NDI1N1owFzEVMBMGA1UEAxMMQ2xhbiBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZI
zj0DAQcDQgAEk7nn9kzxI+xkRmNMlxD+7T78UqV3aqus0foJh6uu1CHC+XaebMcw
JN95nAe3oYA3yZG6Mnq9nCxsYha4EhzGYqNFMEMwDgYDVR0PAQH/BAQDAgEGMBIG
A1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFJ+yfPimEwnH2y7+SB4X8VtlAIGD
MAoGCCqGSM49BAMCA0cAMEQCIBId/CcbT5MPFL90xa+XQz+gVTdRwsu6Bg7ehMso
Bj0oAiBjSlttd5yeuZGXBm+O0Gl+WdKV60QlrWutNewXFS4UpQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:PnEXteU3I7U0OKgE+oR3xjHdLWYTpJjM/jlzxtGU0uP2pUBuQv3LxtEz+cP0ZsafHLNq2iNJ7xpUEE0g4d3M296S56oSocK3fREWBiJFiaC7SAEUiil1l3UCwHn7LzmdEmn8Kq7T+FK89wwqtVWIASLo2gZC/yHE5eEanEATTchGLSNiHJRzZ8n0Ekm8EFUA6czOqA5nPQHaSmeLzu1g80lSSi1ICly6dJksa6DVucwOyVFYFEeq8Dfyc1eyP8L1ee0D7QFYBMduYOXTKPtNnyDmdaQMj7cMMvE7fn04idIiAqw=,iv:nvLmAfFk2GXnnUy+Afr648R60Ou13eu9UKykkiA8Y+4=,tag:lTTAxfG0EDCU6u7xlW6xSQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEMjNWUm5NbktQeTRWRjJE\nWWFZc2Rsa3I5aitPSno1WnhORENNcng5OHprCjNUQVhBVHFBcWFjaW5UdmxKTnZw\nQlI4MDk5Wkp0RElCeWgzZ2dFQkF2dkkKLS0tIDVreTkydnJ0RDdHSHlQeVV6bGlP\nTmpJOVBSb2dkVS9TZG5SRmFjdnQ1b3cKQ5XvwH1jD4XPVs5RzOotBDq8kiE6S5k2\nDBv6ugjsM5qV7/oGP9H69aSB4jKPZjEn3yiNw++Oorc8uXd5kSGh7w==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-09-02T08:43:00Z",
"mac": "ENC[AES256_GCM,data:3jFf66UyZUWEtPdPu809LCS3K/Hc6zbnluystl3eXS+KGI+dCoYmN9hQruRNBRxf6jli2RIlArmmEPBDQVt67gG/qugTdT12krWnYAZ78iocmOnkf44fWxn/pqVnn4JYpjEYRgy8ueGDnUkwvpGWVZpcXw5659YeDQuYOJ2mq0U=,iv:3k7fBPrABdLItQ2Z+Mx8Nx0eIEKo93zG/23K+Q5Hl3I=,tag:aehAObdx//DEjbKlOeM7iQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

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

View File

@@ -0,0 +1,68 @@
This module enables hosting clan-internal services easily, which can be resolved
inside your VPN. This allows defining a custom top-level domain (e.g. `.clan`)
and exposing endpoints from a machine to others, which will be
accessible under `http://<service>.clan` in your browser.
The service consists of two roles:
- A `server` role: This is the DNS-server that will be queried when trying to
resolve clan-internal services. It defines the top-level domain.
- A `default` role: This does two things. First, it sets up the nameservers so
thatclan-internal queries are resolved via the `server` machine, while
external queries are resolved as normal via DHCP. Second, it allows exposing
services (see example below).
## Example Usage
Here the machine `dnsserver` is designated as internal DNS-server for the TLD
`.foo`. `server01` will host an application that shall be reachable at
`http://one.foo` and `server02` is going to be reachable at `http://two.foo`.
`client` is any other machine that is part of the clan but does not host any
services.
When `client` tries to resolve `http://one.foo`, the DNS query will be
routed to `dnsserver`, which will answer with `192.168.1.3`. If it tries to
resolve some external domain (e.g. `https://clan.lol`), the query will not be
routed to `dnsserver` but resolved as before, via the nameservers advertised by
DHCP.
```nix
inventory = {
machines = {
dnsserver = { }; # 192.168.1.2
server01 = { }; # 192.168.1.3
server02 = { }; # 192.168.1.4
client = { }; # 192.168.1.5
};
instances = {
coredns = {
module.name = "@clan/coredns";
module.input = "self";
# Add the default role to all machines, including `client`
roles.default.tags.all = { };
# DNS server
roles.server.machines."dnsserver".settings = {
ip = "192.168.1.2";
tld = "foo";
};
# First service
roles.default.machines."server01".settings = {
ip = "192.168.1.3";
services = [ "one" ];
};
# Second service
roles.default.machines."server02".settings = {
ip = "192.168.1.4";
services = [ "two" ];
};
};
};
};
```

View File

@@ -0,0 +1,176 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "coredns";
manifest.description = "Clan-internal DNS and service exposure";
manifest.categories = [ "Network" ];
manifest.readme = builtins.readFile ./README.md;
roles.server = {
interface =
{ lib, ... }:
{
options.tld = lib.mkOption {
type = lib.types.str;
default = "clan";
description = ''
Top-level domain for this instance. All services below this will be
resolved internally.
'';
};
options.ip = lib.mkOption {
type = lib.types.str;
# TODO: Set a default
description = "IP for the DNS to listen on";
};
options.dnsPort = lib.mkOption {
type = lib.types.int;
default = 1053;
description = "Port of the clan-internal DNS server";
};
};
perInstance =
{
roles,
settings,
...
}:
{
nixosModule =
{
lib,
pkgs,
...
}:
{
networking.firewall.allowedTCPPorts = [ settings.dnsPort ];
networking.firewall.allowedUDPPorts = [ settings.dnsPort ];
services.coredns =
let
# Get all service entries for one host
hostServiceEntries =
host:
lib.strings.concatStringsSep "\n" (
map (
service: "${service} IN A ${roles.default.machines.${host}.settings.ip} ; ${host}"
) roles.default.machines.${host}.settings.services
);
zonefile = pkgs.writeTextFile {
name = "db.${settings.tld}";
text = ''
$TTL 3600
@ IN SOA ns.${settings.tld}. admin.${settings.tld}. 1 7200 3600 1209600 3600
IN NS ns.${settings.tld}.
ns IN A ${settings.ip} ; DNS server
''
+ (lib.strings.concatStringsSep "\n" (
map (host: hostServiceEntries host) (lib.attrNames roles.default.machines)
));
};
in
{
enable = true;
config =
let
dnsPort = builtins.toString settings.dnsPort;
in
''
.:${dnsPort} {
forward . 1.1.1.1
cache 30
}
${settings.tld}:${dnsPort} {
file ${zonefile}
}
'';
};
};
};
};
roles.default = {
interface =
{ lib, ... }:
{
options.services = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Service endpoints this host exposes (without TLD). Each entry will
be resolved to <entry>.<tld> using the configured top-level domain.
'';
};
options.ip = lib.mkOption {
type = lib.types.str;
# TODO: Set a default
description = "IP on which the services will listen";
};
options.dnsPort = lib.mkOption {
type = lib.types.int;
default = 1053;
description = "Port of the clan-internal DNS server";
};
};
perInstance =
{ roles, settings, ... }:
{
nixosModule =
{ lib, ... }:
{
networking.nameservers = map (m: "127.0.0.1:5353#${roles.server.machines.${m}.settings.tld}") (
lib.attrNames roles.server.machines
);
services.resolved.domains = map (m: "~${roles.server.machines.${m}.settings.tld}") (
lib.attrNames roles.server.machines
);
services.unbound = {
enable = true;
settings = {
server = {
port = 5353;
verbosity = 2;
interface = [ "127.0.0.1" ];
access-control = [ "127.0.0.0/8 allow" ];
do-not-query-localhost = "no";
domain-insecure = map (m: "${roles.server.machines.${m}.settings.tld}.") (
lib.attrNames roles.server.machines
);
};
# Default: forward everything else to DHCP-provided resolvers
forward-zone = [
{
name = ".";
forward-addr = "127.0.0.53@53"; # Forward to systemd-resolved
}
];
stub-zone = map (m: {
name = "${roles.server.machines.${m}.settings.tld}.";
stub-addr = "${roles.server.machines.${m}.settings.ip}@${builtins.toString settings.dnsPort}";
}) (lib.attrNames roles.server.machines);
};
};
};
};
};
}

View File

@@ -3,14 +3,16 @@ let
module = lib.modules.importApply ./default.nix { };
in
{
clan.modules.state-version = module;
clan.modules = {
coredns = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.state-version = {
clan.nixosTests.coredns = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/state-version" = module;
clan.modules."@clan/coredns" = module;
};
};
}

View File

@@ -0,0 +1,110 @@
{
...
}:
{
name = "coredns";
clan = {
directory = ./.;
test.useContainers = true;
inventory = {
machines = {
dns = { }; # 192.168.1.2
server01 = { }; # 192.168.1.3
server02 = { }; # 192.168.1.4
client = { }; # 192.168.1.1
};
instances = {
coredns = {
module.name = "@clan/coredns";
module.input = "self";
roles.default.tags.all = { };
# First service
roles.default.machines."server01".settings = {
ip = "192.168.1.3";
services = [ "one" ];
};
# Second service
roles.default.machines."server02".settings = {
ip = "192.168.1.4";
services = [ "two" ];
};
# DNS server
roles.server.machines."dns".settings = {
ip = "192.168.1.2";
tld = "foo";
};
};
};
};
};
nodes = {
dns =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.net-tools ];
};
client =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.net-tools ];
};
server01 = {
services.nginx = {
enable = true;
virtualHosts."one.foo" = {
locations."/" = {
return = "200 'test server response one'";
extraConfig = "add_header Content-Type text/plain;";
};
};
};
};
server02 = {
services.nginx = {
enable = true;
virtualHosts."two.foo" = {
locations."/" = {
return = "200 'test server response two'";
extraConfig = "add_header Content-Type text/plain;";
};
};
};
};
};
testScript = ''
import json
start_all()
machines = [server01, server02, dns, client]
for m in machines:
m.systemctl("start network-online.target")
for m in machines:
m.wait_for_unit("network-online.target")
# This should work, but is borken in tests i think? Instead we dig directly
# client.succeed("curl -k -v http://one.foo")
# client.succeed("curl -k -v http://two.foo")
answer = client.succeed("dig @192.168.1.2 -p 1053 one.foo")
assert "192.168.1.3" in answer, "IP not found"
answer = client.succeed("dig @192.168.1.2 -p 1053 two.foo")
assert "192.168.1.4" in answer, "IP not found"
'';
}

View File

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

View File

@@ -10,22 +10,34 @@
lib,
...
}:
let
jsonpath = "/tmp/telegraf.json";
auth_user = "prometheus";
in
{
networking.firewall.interfaces = lib.mkIf (settings.allowAllInterfaces == false) (
builtins.listToAttrs (
map (name: {
inherit name;
value.allowedTCPPorts = [ 9273 ];
value.allowedTCPPorts = [
9273
9990
];
}) settings.interfaces
)
);
networking.firewall.allowedTCPPorts = lib.mkIf (settings.allowAllInterfaces == true) [ 9273 ];
networking.firewall.allowedTCPPorts = lib.mkIf (settings.allowAllInterfaces == true) [
9273
9990
];
clan.core.vars.generators."telegraf-password" = {
files.telegraf-password.neededFor = "users";
files.telegraf-password.restartUnits = [ "telegraf.service" ];
clan.core.vars.generators."telegraf" = {
files.password.restartUnits = [ "telegraf.service" ];
files.password-env.restartUnits = [ "telegraf.service" ];
files.miniserve-auth.restartUnits = [ "telegraf.service" ];
runtimeInputs = [
pkgs.coreutils
@@ -35,16 +47,27 @@
script = ''
PASSWORD=$(xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n")
echo "BASIC_AUTH_PWD=$PASSWORD" > "$out"/telegraf-password
echo "BASIC_AUTH_PWD=$PASSWORD" > "$out"/password-env
echo "${auth_user}:$PASSWORD" > "$out"/miniserve-auth
echo "$PASSWORD" | tr -d "\n" > "$out"/password
'';
};
systemd.services.telegraf-json = {
enable = true;
wantedBy = [ "multi-user.target" ];
after = [ "telegraf.service" ];
wants = [ "telegraf.service" ];
serviceConfig = {
Restart = "on-failure";
};
script = "${pkgs.miniserve}/bin/miniserve -p 9990 ${jsonpath} --auth-file ${config.clan.core.vars.generators.telegraf.files.miniserve-auth.path}";
};
services.telegraf = {
enable = true;
environmentFiles = [
(builtins.toString
config.clan.core.vars.generators."telegraf-password".files.telegraf-password.path
)
(builtins.toString config.clan.core.vars.generators.telegraf.files.password-env.path)
];
extraConfig = {
agent.interval = "60s";
@@ -59,25 +82,35 @@
exec =
let
currentSystemScript = pkgs.writeShellScript "current-system" ''
printf "current_system,path=%s present=0\n" $(readlink /run/current-system)
nixosSystems = pkgs.writeShellScript "current-system" ''
printf "nixos_systems,current_system=%s,booted_system=%s,current_kernel=%s,booted_kernel=%s present=0\n" \
"$(readlink /run/current-system)" "$(readlink /run/booted-system)" \
"$(basename $(echo /run/current-system/kernel-modules/lib/modules/*))" \
"$(basename $(echo /run/booted-system/kernel-modules/lib/modules/*))"
'';
in
[
{
# Expose the path to current-system as metric. We use
# this to check if the machine is up-to-date.
commands = [ currentSystemScript ];
commands = [ nixosSystems ];
data_format = "influx";
}
];
};
# sadly there doesn'T seem to exist a telegraf http_client output plugin
outputs.prometheus_client = {
listen = ":9273";
metric_version = 2;
basic_username = "prometheus";
basic_username = "${auth_user}";
basic_password = "$${BASIC_AUTH_PWD}";
};
outputs.file = {
files = [ jsonpath ];
data_format = "json";
json_timestamp_units = "1s";
};
};
};
};

View File

@@ -1,37 +0,0 @@
This service generates the `system.stateVersion` of the nixos installation
automatically.
Possible values:
[system.stateVersion](https://search.nixos.org/options?channel=unstable&show=system.stateVersion&from=0&size=50&sort=relevance&type=packages&query=stateVersion)
## Usage
The following configuration will set `stateVersion` for all machines:
```
inventory.instances = {
state-version = {
module = {
name = "state-version";
input = "clan";
};
roles.default.tags.all = { };
};
```
## Migration
If you are already setting `system.stateVersion`, either let the automatic
generation happen, or trigger the generation manually for the machine. The
service will take the specified version, if one is already supplied through the
config.
To manually generate the version for a specified machine run:
```
clan vars generate [MACHINE]
```
If the setting was already set, you can then remove `system.stateVersion` from
your machine configuration. For new machines, just import the service as shown
above.

View File

@@ -1,50 +0,0 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "clan-core/state-version";
manifest.description = "Automatically generate the state version of the nixos installation.";
manifest.categories = [ "System" ];
manifest.readme = builtins.readFile ./README.md;
roles.default = {
perInstance =
{ ... }:
{
nixosModule =
{
config,
lib,
...
}:
let
var = config.clan.core.vars.generators.state-version.files.version or { };
in
{
warnings = [
''
The clan.state-version service is deprecated and will be
removed on 2025-07-15 in favor of a nix option.
Please migrate your configuration to use `clan.core.settings.state-version.enable = true` instead.
''
];
system.stateVersion = lib.mkDefault (lib.removeSuffix "\n" var.value);
clan.core.vars.generators.state-version = {
files.version = {
secret = false;
value = lib.mkDefault config.system.nixos.release;
};
runtimeInputs = [ ];
script = ''
echo -n ${config.system.stateVersion} > "$out"/version
'';
};
};
};
};
}

View File

@@ -1,22 +0,0 @@
{ lib, ... }:
{
name = "service-state-version";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances.default = {
module.name = "@clan/state-version";
module.input = "self";
roles.default.machines."server" = { };
};
};
};
nodes.server = { };
testScript = lib.mkDefault ''
start_all()
'';
}

View File

@@ -7,7 +7,7 @@ inventory.instances = {
clan-cache = {
module = {
name = "trusted-nix-caches";
input = "clan";
input = "clan-core";
};
roles.default.machines.draper = { };
};

View File

@@ -8,7 +8,7 @@
user-alice = {
module = {
name = "users";
input = "clan";
input = "clan-core";
};
roles.default.tags.all = { };
roles.default.settings = {
@@ -17,11 +17,25 @@
};
};
# Deploy user Carol on all machines. Prompt only once and use the
# same password on all machines. (`share = true`)
user-carol = {
module = {
name = "users";
input = "clan";
};
roles.default.tags.all = { };
roles.default.settings = {
user = "carol";
share = true;
};
};
# Deploy user bob only on his laptop. Prompt for a password.
user-bob = {
module = {
name = "users";
input = "clan";
input = "clan-core";
};
roles.default.machines.bobs-laptop = { };
roles.default.settings.user = "bob";
@@ -29,3 +43,44 @@
};
}
```
## Migration from `root-password` module
The deprecated `clan.root-password` module has been replaced by the `users` module. Here's how to migrate:
### 1. Update your flake configuration
Replace the `root-password` module import with a `users` service instance:
```nix
# OLD - Remove this from your nixosModules:
imports = [
self.inputs.clan-core.clanModules.root-password
];
# NEW - Add to inventory.instances or machines/flake-module.nix:
instances = {
users-root = {
module.name = "users";
module.input = "clan-core";
roles.default.tags.nixos = { };
roles.default.settings = {
user = "root";
prompt = false; # Set to true if you want to be prompted
groups = [ ];
};
};
};
```
### 2. Migrate vars
The vars structure has changed from `root-password` to `user-password-root`:
```bash
# For each machine, rename the vars directories:
cd vars/per-machine/<machine-name>/
mv root-password user-password-root
mv user-password-root/password-hash user-password-root/user-password-hash
mv user-password-root/password user-password-root/user-password
```

View File

@@ -59,6 +59,17 @@
- "input" - Allows the user to access input devices.
'';
};
share = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Weather the user should have the same password on all machines.
By default, you will be prompted for a new password for every host.
Unless `generate` is set to `true`.
'';
};
};
};
@@ -82,7 +93,6 @@
};
clan.core.vars.generators."user-password-${settings.user}" = {
files.user-password-hash.neededFor = "users";
files.user-password-hash.restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
files.user-password.deploy = false;
@@ -107,6 +117,8 @@
pkgs.mkpasswd
];
share = settings.share;
script =
(
if settings.prompt then

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python3
"""
IPv6 address allocator for WireGuard networks.
"""IPv6 address allocator for WireGuard networks.
Network layout:
- Base network: /40 ULA prefix (fd00::/8 + 32 bits from hash)
@@ -13,6 +12,11 @@ import ipaddress
import sys
from pathlib import Path
# Constants for argument count validation
MIN_ARGS_BASE = 4
MIN_ARGS_CONTROLLER = 5
MIN_ARGS_PEER = 5
def hash_string(s: str) -> str:
"""Generate SHA256 hash of string."""
@@ -20,8 +24,7 @@ def hash_string(s: str) -> str:
def generate_ula_prefix(instance_name: str) -> ipaddress.IPv6Network:
"""
Generate a /40 ULA prefix from instance name.
"""Generate a /40 ULA prefix from instance name.
Format: fd{32-bit hash}/40
This gives us fd00:0000:0000::/40 through fdff:ffff:ff00::/40
@@ -41,15 +44,14 @@ def generate_ula_prefix(instance_name: str) -> ipaddress.IPv6Network:
prefix = f"fd{prefix_bits:08x}"
prefix_formatted = f"{prefix[:4]}:{prefix[4:8]}::/40"
network = ipaddress.IPv6Network(prefix_formatted)
return network
return ipaddress.IPv6Network(prefix_formatted)
def generate_controller_subnet(
base_network: ipaddress.IPv6Network, controller_name: str
base_network: ipaddress.IPv6Network,
controller_name: str,
) -> ipaddress.IPv6Network:
"""
Generate a /56 subnet for a controller from the base /40 network.
"""Generate a /56 subnet for a controller from the base /40 network.
We have 16 bits (40 to 56) to allocate controller subnets.
This allows for 65,536 possible controller subnets.
@@ -62,14 +64,11 @@ def generate_controller_subnet(
# The controller subnet is at base_prefix:controller_id::/56
base_int = int(base_network.network_address)
controller_subnet_int = base_int | (controller_id << (128 - 56))
controller_subnet = ipaddress.IPv6Network((controller_subnet_int, 56))
return controller_subnet
return ipaddress.IPv6Network((controller_subnet_int, 56))
def generate_peer_suffix(peer_name: str) -> str:
"""
Generate a unique 64-bit host suffix for a peer.
"""Generate a unique 64-bit host suffix for a peer.
This suffix will be used in all controller subnets to create unique addresses.
Format: :xxxx:xxxx:xxxx:xxxx (64 bits)
@@ -79,14 +78,13 @@ def generate_peer_suffix(peer_name: str) -> str:
suffix_bits = h[:16]
# Format as IPv6 suffix without leading colon
suffix = f"{suffix_bits[0:4]}:{suffix_bits[4:8]}:{suffix_bits[8:12]}:{suffix_bits[12:16]}"
return suffix
return f"{suffix_bits[0:4]}:{suffix_bits[4:8]}:{suffix_bits[8:12]}:{suffix_bits[12:16]}"
def main() -> None:
if len(sys.argv) < 4:
if len(sys.argv) < MIN_ARGS_BASE:
print(
"Usage: ipv6_allocator.py <output_dir> <instance_name> <controller|peer> <machine_name>"
"Usage: ipv6_allocator.py <output_dir> <instance_name> <controller|peer> <machine_name>",
)
sys.exit(1)
@@ -98,7 +96,7 @@ def main() -> None:
base_network = generate_ula_prefix(instance_name)
if node_type == "controller":
if len(sys.argv) < 5:
if len(sys.argv) < MIN_ARGS_CONTROLLER:
print("Controller name required")
sys.exit(1)
@@ -114,7 +112,7 @@ def main() -> None:
(output_dir / "prefix").write_text(prefix_str)
elif node_type == "peer":
if len(sys.argv) < 5:
if len(sys.argv) < MIN_ARGS_PEER:
print("Peer name required")
sys.exit(1)

View File

@@ -5,7 +5,7 @@ inventory.instances = {
zerotier = {
module = {
name = "zerotier";
input = "clan";
input = "clan-core";
};
roles.peer.tags.all = { };
roles.controller.machines.jon = { };
@@ -18,7 +18,6 @@ All machines will be peers and connected to the zerotier network.
Jon is the controller machine, which will will accept other machines into the network.
Sara is a moon and sets the `stableEndpoint` setting with a publicly reachable IP, the moon is optional.
## Overview
This guide explains how to set up and manage a [ZeroTier VPN](https://zerotier.com) for a clan network. Each VPN requires a single controller and can support multiple peers and optional moons for better connectivity.

28
devFlake/flake.lock generated
View File

@@ -3,10 +3,10 @@
"clan-core-for-checks": {
"flake": false,
"locked": {
"lastModified": 1755093452,
"narHash": "sha256-NKBss7QtNnOqYVyJmYCgaCvYZK0mpQTQc9fLgE1mGyk=",
"lastModified": 1756166884,
"narHash": "sha256-skg4rwpbCjhpLlrv/Pndd43FoEgrJz98WARtGLhCSzo=",
"ref": "main",
"rev": "7e97734797f0c6bd3c2d3a51cf54a2a6b371c222",
"rev": "f7414d7e6e58709af27b6fe16eb530278e81eaaf",
"shallow": true,
"type": "git",
"url": "https://git.clan.lol/clan/clan-core"
@@ -84,11 +84,11 @@
},
"nixpkgs-dev": {
"locked": {
"lastModified": 1755375481,
"narHash": "sha256-43PgCQFgFD1nM/7dncytV0c5heNHe/gXrEud18ZWcZU=",
"lastModified": 1757449886,
"narHash": "sha256-XNhjHidr4i581CVyufJtrleYYgn/55cQONYG3uvIYEY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "35f1742e4f1470817ff8203185e2ce0359947f12",
"rev": "1779f9e0d8b45d88d7525665dd4d2a5b65041248",
"type": "github"
},
"original": {
@@ -107,15 +107,15 @@
]
},
"locked": {
"lastModified": 1754869408,
"narHash": "sha256-G1zNuxiCDfqNQVoL9j5v+ZYfUER7AI158ev98/JC8LI=",
"owner": "NuschtOS",
"lastModified": 1757505024,
"narHash": "sha256-AI4TKqIcUobFVqWD0N+6CWlJC5VMK7+HFtKKKyojG74=",
"owner": "Qubasa",
"repo": "search",
"rev": "2f5478267557a0f7a70d953b6c0867a5b4282739",
"rev": "ad978b39eba41d1cb5cf525fa146f91e6db2a895",
"type": "github"
},
"original": {
"owner": "NuschtOS",
"owner": "Qubasa",
"repo": "search",
"type": "github"
}
@@ -165,11 +165,11 @@
"nixpkgs": []
},
"locked": {
"lastModified": 1754847726,
"narHash": "sha256-2vX8QjO5lRsDbNYvN9hVHXLU6oMl+V/PsmIiJREG4rE=",
"lastModified": 1756662192,
"narHash": "sha256-F1oFfV51AE259I85av+MAia221XwMHCOtZCMcZLK2Jk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "7d81f6fb2e19bf84f1c65135d1060d829fae2408",
"rev": "1aabc6c05ccbcbf4a635fb7a90400e44282f61c4",
"type": "github"
},
"original": {

View File

@@ -7,7 +7,8 @@
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.flake-utils.inputs.systems.follows = "systems";
inputs.nuschtos.url = "github:NuschtOS/search";
# Using my fork till this is merged: https://github.com/NuschtOS/search/pull/255
inputs.nuschtos.url = "github:Qubasa/search";
inputs.nuschtos.inputs.nixpkgs.follows = "nixpkgs-dev";
inputs.treefmt-nix.url = "github:numtide/treefmt-nix";

View File

@@ -33,7 +33,6 @@
self'.packages.tea-create-pr
self'.packages.merge-after-ci
self'.packages.pending-reviews
self'.packages.agit
# treefmt with config defined in ./flake-parts/formatting.nix
config.treefmt.build.wrapper
];
@@ -46,7 +45,7 @@
ln -sfT ${inputs.nix-select} "$PRJ_ROOT/pkgs/clan-cli/clan_lib/select"
# Generate classes.py from schemas
${self'.packages.classgen}/bin/classgen ${self'.legacyPackages.schemas.clan-schema-abstract}/schema.json $PRJ_ROOT/pkgs/clan-cli/clan_lib/nix_models/clan.py
${self'.packages.classgen}/bin/classgen ${self'.legacyPackages.schemas.clanSchemaJson}/schema.json $PRJ_ROOT/pkgs/clan-cli/clan_lib/nix_models/clan.py
'';
};
};

2
docs/.gitignore vendored
View File

@@ -1,5 +1,5 @@
/site/reference
/site/static
/site/options-page
/site/options
/site/openapi.json
!/site/static/extra.css

View File

@@ -1,13 +1,11 @@
{
lib,
config,
...
}:
let
suffix = config.clan.core.vars.generators.disk-id.files.diskId.value;
mirrorBoot = idx: {
# suffix is to prevent disk name collisions
name = idx + suffix;
name = idx;
type = "disk";
device = "/dev/disk/by-id/${idx}";
content = {

View File

@@ -1,13 +1,11 @@
{
lib,
config,
...
}:
let
suffix = config.clan.core.vars.generators.disk-id.files.diskId.value;
mirrorBoot = idx: {
# suffix is to prevent disk name collisions
name = idx + suffix;
name = idx;
type = "disk";
device = "/dev/disk/by-id/${idx}";
content = {

View File

@@ -2,11 +2,11 @@ site_name: Clan Documentation
site_url: https://docs.clan.lol
repo_url: https://git.clan.lol/clan/clan-core/
repo_name: "_>"
edit_uri: _edit/main/docs/docs/
edit_uri: _edit/main/docs/site/
validation:
omitted_files: warn
absolute_links: warn
absolute_links: ignore
unrecognized_links: warn
markdown_extensions:
@@ -59,14 +59,21 @@ nav:
- Configure Disk Config: guides/getting-started/choose-disk.md
- Update Machine: guides/getting-started/update.md
- Continuous Integration: guides/getting-started/flake-check.md
- Using Services: guides/clanServices.md
- Convert Existing NixOS Config: guides/getting-started/convert-flake.md
- ClanServices: guides/clanServices.md
- Backup & Restore: guides/backups.md
- Disk Encryption: guides/disk-encryption.md
- Vars:
- Overview: guides/vars-overview.md
- Getting Started: guides/vars-backend.md
- Concepts: guides/vars-concepts.md
- Advanced Examples: guides/vars-advanced-examples.md
- Troubleshooting: guides/vars-troubleshooting.md
- Age Plugins: guides/age-plugins.md
- Secrets management: guides/secrets.md
- Target Host: guides/target-host.md
- Networking: guides/networking.md
- Zerotier VPN: guides/mesh-vpn.md
- Secure Boot: guides/secure-boot.md
- How to disable Secure Boot: guides/secure-boot.md
- Flake-parts: guides/flake-parts.md
- macOS: guides/macos.md
- Contributing:
@@ -77,8 +84,7 @@ nav:
- Writing a Service Module: guides/services/community.md
- Writing a Disko Template: guides/disko-templates/community.md
- Migrations:
- Migrate existing Flakes: guides/migrations/migration-guide.md
- Migrate inventory Services: guides/migrations/migrate-inventory-services.md
- Migrate from clan modules to services: guides/migrations/migrate-inventory-services.md
- Facts Vars Migration: guides/migrations/migration-facts-vars.md
- Disk id: guides/migrations/disk-id.md
- Concepts:
@@ -88,12 +94,14 @@ nav:
- Templates: concepts/templates.md
- Reference:
- Overview: reference/index.md
- Clan Options: options.md
- Browse Options: "/options"
- Services:
- Overview:
- reference/clanServices/index.md
- reference/clanServices/admin.md
- reference/clanServices/borgbackup.md
- reference/clanServices/certificates.md
- reference/clanServices/coredns.md
- reference/clanServices/data-mesher.md
- reference/clanServices/dyndns.md
- reference/clanServices/emergency-access.md
@@ -106,7 +114,6 @@ nav:
- reference/clanServices/monitoring.md
- reference/clanServices/packages.md
- reference/clanServices/sshd.md
- reference/clanServices/state-version.md
- reference/clanServices/syncthing.md
- reference/clanServices/trusted-nix-caches.md
- reference/clanServices/users.md
@@ -155,6 +162,7 @@ nav:
- 05-deployment-parameters: decisions/05-deployment-parameters.md
- Template: decisions/_template.md
- Glossary: reference/glossary.md
- Browse Options: "/options"
docs_dir: site
site_dir: out
@@ -172,6 +180,7 @@ theme:
- content.code.annotate
- content.code.copy
- content.tabs.link
- content.action.edit
icon:
repo: fontawesome/brands/git
custom_dir: overrides

View File

@@ -54,9 +54,9 @@ pkgs.stdenv.mkDerivation {
chmod -R +w ./site/reference
echo "Generated API documentation in './site/reference/' "
rm -r ./site/options-page || true
cp -r ${docs-options} ./site/options-page
chmod -R +w ./site/options-page
rm -rf ./site/options
cp -r ${docs-options} ./site/options
chmod -R +w ./site/options
mkdir -p ./site/static/asciinema-player
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js

View File

@@ -25,7 +25,7 @@
serviceModules = self.clan.modules;
baseHref = "/options-page/";
baseHref = "/options/";
getRoles =
module:
@@ -126,7 +126,7 @@
nestedSettingsOption = mkOption {
type = types.raw;
description = ''
See [instances.${name}.roles.${roleName}.settings](${baseHref}?option_scope=0&option=instances.${name}.roles.${roleName}.settings)
See [instances.${name}.roles.${roleName}.settings](${baseHref}?option_scope=0&option=inventory.instances.${name}.roles.${roleName}.settings)
'';
};
settingsOption = mkOption {
@@ -161,6 +161,42 @@
}
];
baseModule =
# Module
{ config, ... }:
{
imports = (import (pkgs.path + "/nixos/modules/module-list.nix"));
nixpkgs.pkgs = pkgs;
clan.core.name = "dummy";
system.stateVersion = config.system.nixos.release;
# Set this to work around a bug where `clan.core.settings.machine.name`
# is forced due to `networking.interfaces` being forced
# somewhere in the nixpkgs options
facter.detected.dhcp.enable = lib.mkForce false;
};
evalClanModules =
let
evaled = lib.evalModules {
class = "nixos";
modules = [
baseModule
{
clan.core.settings.directory = self;
}
self.nixosModules.clanCore
];
};
in
evaled;
coreOptions =
(pkgs.nixosOptionsDoc {
options = (evalClanModules.options).clan.core or { };
warningsAreErrors = true;
transformOptions = self.clanLib.docs.stripStorePathsFromDeclarations;
}).optionsJSON;
in
{
# Uncomment for debugging
@@ -175,10 +211,17 @@
# scopes = mapAttrsToList mkScope serviceModules;
scopes = [
{
name = "Clan";
inherit baseHref;
name = "Flake Options (clan.nix file)";
modules = docModules;
urlPrefix = "https://git.clan.lol/clan/clan-core/src/branch/main/";
}
{
name = "Machine Options (clan.core NixOS options)";
optionsJSON = "${coreOptions}/share/doc/nixos/options.json";
urlPrefix = "https://git.clan.lol/clan/clan-core/src/branch/main/";
}
];
};
};

View File

@@ -1,3 +1,5 @@
"""Module for rendering NixOS options documentation from JSON format."""
# Options are available in the following format:
# https://github.com/nixos/nixpkgs/blob/master/nixos/lib/make-options-doc/default.nix
#
@@ -32,7 +34,7 @@ from typing import Any
from clan_lib.errors import ClanError
from clan_lib.services.modules import (
CategoryInfo,
Frontmatter,
ModuleManifest,
)
# Get environment variables
@@ -46,7 +48,7 @@ CLAN_SERVICE_INTERFACE = os.environ.get("CLAN_SERVICE_INTERFACE")
CLAN_MODULES_VIA_SERVICE = os.environ.get("CLAN_MODULES_VIA_SERVICE")
OUT = os.environ.get("out")
OUT = os.environ.get("out") # noqa: SIM112
def sanitize(text: str) -> str:
@@ -66,8 +68,7 @@ def render_option_header(name: str) -> str:
def join_lines_with_indentation(lines: list[str], indent: int = 4) -> str:
"""
Joins multiple lines with a specified number of whitespace characters as indentation.
"""Joins multiple lines with a specified number of whitespace characters as indentation.
Args:
lines (list of str): The lines of text to join.
@@ -75,6 +76,7 @@ def join_lines_with_indentation(lines: list[str], indent: int = 4) -> str:
Returns:
str: The indented and concatenated string.
"""
# Create the indentation string (e.g., four spaces)
indent_str = " " * indent
@@ -161,7 +163,10 @@ def render_option(
def print_options(
options_file: str, head: str, no_options: str, replace_prefix: str | None = None
options_file: str,
head: str,
no_options: str,
replace_prefix: str | None = None,
) -> str:
res = ""
with (Path(options_file) / "share/doc/nixos/options.json").open() as f:
@@ -170,15 +175,16 @@ def print_options(
res += head if len(options.items()) else no_options
for option_name, info in options.items():
if replace_prefix:
option_name = option_name.replace(replace_prefix + ".", "")
display_name = option_name.replace(replace_prefix + ".", "")
else:
display_name = option_name
res += render_option(option_name, info, 4)
res += render_option(display_name, info, 4)
return res
def module_header(module_name: str, has_inventory_feature: bool = False) -> str:
indicator = " 🔹" if has_inventory_feature else ""
return f"# {module_name}{indicator}\n\n"
def module_header(module_name: str) -> str:
return f"# {module_name}\n\n"
clan_core_descr = """
@@ -236,7 +242,7 @@ def produce_clan_core_docs() -> None:
for submodule_name, split_options in split.items():
outfile = f"{module_name}/{submodule_name}.md"
print(
f"[clan_core.{submodule_name}] Rendering option of: {submodule_name}... {outfile}"
f"[clan_core.{submodule_name}] Rendering option of: {submodule_name}... {outfile}",
)
init_level = 1
root = options_to_tree(split_options, debug=True)
@@ -271,56 +277,9 @@ def produce_clan_core_docs() -> None:
of.write(output)
def render_roles(roles: list[str] | None, module_name: str) -> str:
if roles:
roles_list = "\n".join([f"- `{r}`" for r in roles])
return (
f"""
### Roles
This module can be used via predefined roles
{roles_list}
"""
"""
Every role has its own configuration options, which are each listed below.
For more information, see the [inventory guide](../../concepts/inventory.md).
??? Example
For example the `admin` module adds the following options globally to all machines where it is used.
`clan.admin.allowedkeys`
```nix
clan-core.lib.clan {
inventory.services = {
admin.me = {
roles.default.machines = [ "jon" ];
config.allowedkeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD..." ];
};
};
};
```
"""
)
return ""
clan_modules_descr = """
Clan modules are [NixOS modules](https://wiki.nixos.org/wiki/NixOS_modules)
which have been enhanced with additional features provided by Clan, with
certain option types restricted to enable configuration through a graphical
interface.
!!! note "🔹"
Modules with this indicator support the [inventory](../../concepts/inventory.md) feature.
"""
def render_categories(
categories: list[str], categories_info: dict[str, CategoryInfo]
categories: list[str],
categories_info: dict[str, CategoryInfo],
) -> str:
res = """<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">"""
for cat in categories:
@@ -385,10 +344,10 @@ Learn how to use `clanServices` in practice in the [Using clanServices guide](..
# output += f"`clan.modules.{module_name}`\n"
output += f"*{module_info['manifest']['description']}*\n"
fm = Frontmatter("")
# output += "## Categories\n\n"
output += render_categories(
module_info["manifest"]["categories"], fm.categories_info
module_info["manifest"]["categories"],
ModuleManifest.categories_info(),
)
output += f"{module_info['manifest']['readme']}\n"
@@ -397,7 +356,7 @@ Learn how to use `clanServices` in practice in the [Using clanServices guide](..
output += f"The {module_name} module has the following roles:\n\n"
for role_name, _ in module_info["roles"].items():
for role_name in module_info["roles"]:
output += f"- {role_name}\n"
for role_name, role_filename in module_info["roles"].items():
@@ -417,35 +376,8 @@ Learn how to use `clanServices` in practice in the [Using clanServices guide](..
of.write(output)
def build_option_card(module_name: str, frontmatter: Frontmatter) -> str:
"""
Build the overview index card for each reference target option.
"""
def indent_all(text: str, indent_size: int = 4) -> str:
"""
Indent all lines in a string.
"""
indent = " " * indent_size
lines = text.split("\n")
indented_text = indent + ("\n" + indent).join(lines)
return indented_text
def to_md_li(module_name: str, frontmatter: Frontmatter) -> str:
md_li = (
f"""- **[{module_name}](./{"-".join(module_name.split(" "))}.md)**\n\n"""
)
md_li += f"""{indent_all("---", 4)}\n\n"""
fmd = f"\n{frontmatter.description.strip()}" if frontmatter.description else ""
md_li += f"""{indent_all(fmd, 4)}"""
return md_li
return f"{to_md_li(module_name, frontmatter)}\n\n"
def split_options_by_root(options: dict[str, Any]) -> dict[str, dict[str, Any]]:
"""
Split the flat dictionary of options into a dict of which each entry will construct complete option trees.
"""Split the flat dictionary of options into a dict of which each entry will construct complete option trees.
{
"a": { Data }
"a.b": { Data }
@@ -529,9 +461,7 @@ def option_short_name(option_name: str) -> str:
def options_to_tree(options: dict[str, Any], debug: bool = False) -> Option:
"""
Convert the options dictionary to a tree structure.
"""
"""Convert the options dictionary to a tree structure."""
# Helper function to create nested structure
def add_to_tree(path_parts: list[str], info: Any, current_node: Option) -> None:
@@ -583,22 +513,24 @@ def options_to_tree(options: dict[str, Any], debug: bool = False) -> Option:
def options_docs_from_tree(
root: Option, init_level: int = 1, prefix: list[str] | None = None
root: Option,
init_level: int = 1,
prefix: list[str] | None = None,
) -> str:
"""
eender the options from the tree structure.
"""Eender the options from the tree structure.
Args:
root (Option): The root option node.
init_level (int): The initial level of indentation.
prefix (list str): Will be printed as common prefix of all attribute names.
"""
def render_tree(option: Option, level: int = init_level) -> str:
output = ""
should_render = not option.name.startswith("<") and not option.name.startswith(
"_"
"_",
)
if should_render:
# short_name = option_short_name(option.name)
@@ -619,11 +551,10 @@ def options_docs_from_tree(
return output
md = render_tree(root)
return md
return render_tree(root)
if __name__ == "__main__": #
if __name__ == "__main__":
produce_clan_core_docs()
produce_clan_service_author_docs()

View File

@@ -1,15 +1,33 @@
# Auto-included Files
Clan automatically imports the following files from a directory and registers them.
Clan automatically imports specific files from each machine directory and registers them, reducing the need for manual configuration.
## Machine registration
## Machine Registration
Every folder `machines/{machineName}` will be registered automatically as a Clan machine.
Every folder under `machines/{machineName}` is automatically registered as a Clan machine.
!!! info "Automatically loaded files"
!!! info "Files loaded automatically for each machine"
The following files are loaded automatically for each Clan machine:
The following files are detected and imported for every Clan machine:
- [x] `machines/{machineName}/configuration.nix`
- [x] `machines/{machineName}/hardware-configuration.nix`
- [x] `machines/{machineName}/facter.json` Automatically configured, for further information see [nixos-facter](https://clan.lol/blog/nixos-facter/)
- [x] `machines/{machineName}/disko.nix` Automatically loaded, for further information see the [disko docs](https://github.com/nix-community/disko/blob/master/docs/quickstart.md).
- [x] `machines/{machineName}/configuration.nix`
Main configuration file for the machine.
- [x] `machines/{machineName}/hardware-configuration.nix`
Hardware-specific configuration generated by NixOS.
- [x] `machines/{machineName}/facter.json`
Contains system facts. Automatically generated — see [nixos-facter](https://clan.lol/blog/nixos-facter/) for details.
- [x] `machines/{machineName}/disko.nix`
Disk layout configuration. See the [disko quickstart](https://github.com/nix-community/disko/blob/master/docs/quickstart.md) for more info.
## Other Auto-included Files
* **`inventory.json`**
Managed by Clan's API.
Merges with `clan.inventory` to extend the inventory.
* **`.clan-flake`**
Sentinel file to be used to locate the root of a Clan repository.
Falls back to `.git`, `.hg`, `.svn`, or `flake.nix` if not found.

View File

@@ -1,148 +1,45 @@
# Generators
Defining a linux user's password via the nixos configuration previously required running `mkpasswd ...` and then copying the hash back into the nix configuration.
Generators are the core mechanism of the clan vars system for automating the creation and management of generated files, especially secrets, in your NixOS configurations.
In this example, we will guide you through automating that interaction using clan `vars`.
## What are Generators?
For a more general explanation of what clan vars are and how it works, see the intro of the [Reference Documentation for vars](../reference/clan.core/vars.md)
Generators solve a common problem: instead of manually running commands like `mkpasswd` to create password hashes and copying them into your configuration, generators automate this process declaratively.
This guide assumes
- Clan is set up already (see [Getting Started](../guides/getting-started/index.md))
- a machine has been added to the clan (see [Adding Machines](../guides/getting-started/add-machines.md))
A generator defines:
This section will walk you through the following steps:
- **Input prompts**: Values to request from users (passwords, names, etc.)
- **Generation script**: Logic to transform inputs into outputs
- **Output files**: Generated files that can be secrets or public data
- **Dependencies**: Other generators this one depends on
- **Runtime inputs**: Tools and packages needed by the script
1. declare a `generator` in the machine's nixos configuration
2. inspect the status via the Clan CLI
3. generate the vars
4. observe the changes
5. update the machine
6. share the root password between machines
7. change the password
## Key Benefits
## Declare a generator
- **Reproducible**: Same inputs produce same outputs across machines
- **Declarative**: Defined in your NixOS configuration alongside usage
- **Secure**: Automatic handling of secrets storage and deployment
- **Collaborative**: Shared generators work across team environments
- **Automated**: No manual copy-paste of generated values
In this example, a `vars` `generator` is used to:
## Common Use Cases
- prompt the user for the password
- run the required `mkpasswd` command to generate the hash
- store the hash in a file
- expose the file path to the nixos configuration
- **Password hashing**: Generate secure password hashes for user accounts
- **SSH keys**: Create and manage SSH host and user keys
- **Certificates**: Generate TLS certificates and certificate authorities
- **API tokens**: Create secure random tokens for services
- **Configuration files**: Generate config files that depend on secrets
Create a new nix file `root-password.nix` with the following content and import it into your `configuration.nix`
```nix
{config, pkgs, ...}: {
## Learning Path
clan.core.vars.generators.root-password = {
# prompt the user for a password
# (`password-input` being an arbitrary name)
prompts.password-input.description = "the root user's password";
prompts.password-input.type = "hidden";
# don't store the prompted password itself
prompts.password-input.persist = false;
# define an output file for storing the hash
files.password-hash.secret = false;
# define the logic for generating the hash
script = ''
cat $prompts/password-input | mkpasswd -m sha-512 > $out/password-hash
'';
# the tools required by the script
runtimeInputs = [ pkgs.mkpasswd ];
};
1. **Start here**: [Vars Getting Started Guide](../guides/vars-backend.md) - Hands-on tutorial with practical examples
2. **Understand the architecture**: [Vars Concepts Guide](../guides/vars-concepts.md) - Deep dive into design principles and patterns
3. **Explore complex scenarios**: [Advanced Examples](../guides/vars-advanced-examples.md) - Real-world patterns and best practices
4. **Troubleshoot issues**: [Troubleshooting Guide](../guides/vars-troubleshooting.md) - Common problems and solutions
# ensure users are immutable (otherwise the following config might be ignored)
users.mutableUsers = false;
# set the root password to the file containing the hash
users.users.root.hashedPasswordFile =
# clan will make sure, this path exists
config.clan.core.vars.generators.root-password.files.password-hash.path;
}
```
## API Reference
## Inspect the status
For complete configuration options and technical details, see:
Executing `clan vars list`, you should see the following:
```shellSession
$ clan vars list my_machine
root-password/password-hash: <not set>
```
...indicating that the value `password-hash` for the generator `root-password` is not set yet.
## Generate the values
This step is not strictly necessary, as deploying the machine via `clan machines update` would trigger the generator as well.
To run the generator, execute `clan vars generate` for your machine
```shellSession
$ clan vars generate my_machine
Enter the value for root-password/password-input (hidden):
```
After entering the value, the updated status is reported:
```shellSession
Updated var root-password/password-hash
old: <not set>
new: $6$RMats/YMeypFtcYX$DUi...
```
## Observe the changes
With the last step, a new file was created in your repository:
`vars/per-machine/my-machine/root-password/password-hash/value`
If the repository is a git repository, a commit was created automatically:
```shellSession
$ git log -n1
commit ... (HEAD -> master)
Author: ...
Date: ...
Update vars via generator root-password for machine grmpf-nix
```
## Update the machine
```shell
clan machines update my_machine
```
## Share root password between machines
If we just imported the `root-password.nix` from above into more machines, clan would ask for a new password for each additional machine.
If the root password instead should only be entered once and shared across all machines, the generator defined above needs to be declared as `shared`, by adding `share = true` to it:
```nix
{config, pkgs, ...}: {
clan.vars.generators.root-password = {
share = true;
# ...
}
}
```
Importing that shared generator into each machine, will ensure that the password is only asked once the first machine gets updated and then re-used for all subsequent machines.
## Change the root password
Changing the password can be done via this command.
Replace `my-machine` with your machine.
If the password is shared, just pick any machine that has the generator declared.
```shellSession
$ clan vars generate my-machine --generator root-password --regenerate
...
Enter the value for root-password/password-input (hidden):
Input received. Processing...
...
Updated var root-password/password-hash
old: $6$tb27m6EOdff.X9TM$19N...
new: $6$OyoQtDVzeemgh8EQ$zRK...
```
## Further Reading
- [Reference Documentation for `clan.core.vars` NixOS options](../reference/clan.core/vars.md)
- [Reference Documentation for the `clan vars` CLI command](../reference/cli/vars.md)
- [Vars NixOS Module Reference](../reference/clan.core/vars.md) - All configuration options
- [Vars CLI Reference](../reference/cli/vars.md) - Command-line interface

View File

@@ -21,7 +21,7 @@ The following tutorial will walk through setting up a Backup service where the t
## Services
The inventory defines `services`. Membership of `machines` is defined via `roles` exclusively.
The inventory defines `instances` of clan services. Membership of `machines` is defined via `roles` exclusively.
See each [modules documentation](../reference/clanServices/index.md) for its available roles.
@@ -31,9 +31,8 @@ A service can be added to one or multiple machines via `Roles`. Clan's `Role` in
Each service can still be customized and configured according to the modules options.
- Per instance configuration via `services.<serviceName>.<instanceName>.config`
- Per role configuration via `services.<serviceName>.<instanceName>.roles.<roleName>.config`
- Per machine configuration via `services.<serviceName>.<instanceName>.machines.<machineName>.config`
- Per role configuration via `inventory.instances.<instanceName>.roles.<roleName>.settings`
- Per machine configuration via `inventory.instances.<instanceName>.roles.<roleName>.machines.<machineName>.settings`
### Setting up the Backup Service
@@ -44,16 +43,17 @@ Each service can still be customized and configured according to the modules opt
See also: [Multiple Service Instances](#multiple-service-instances)
```{.nix hl_lines="6-7"}
clan-core.lib.clan {
inventory = {
services = {
borgbackup.instance_1 = {
# Machines can be added here.
roles.client.machines = [ "jon" ];
roles.server.machines = [ "backup_server" ];
};
```{.nix hl_lines="9-10"}
{
inventory.instances.instance_1 = {
module = {
name = "borgbackup";
input = "clan-core";
};
# Machines can be added here.
roles.client.machines."jon" {};
roles.server.machines."backup_server" = {};
};
}
```
@@ -66,8 +66,8 @@ It is possible to add services to multiple machines via tags as shown
!!! Example "Tags Example"
```{.nix hl_lines="5 8 14"}
clan-core.lib.clan {
```{.nix hl_lines="5 8 18"}
{
inventory = {
machines = {
"jon" = {
@@ -76,13 +76,16 @@ It is possible to add services to multiple machines via tags as shown
"sara" = {
tags = [ "backup" ];
};
# ...
};
services = {
borgbackup.instance_1 = {
roles.client.tags = [ "backup" ];
roles.server.machines = [ "backup_server" ];
instances.instance_1 = {
module = {
name = "borgbackup";
input = "clan-core";
};
roles.client.tags = [ "backup" ];
roles.server.machines."backup_server" = {};
};
};
}
@@ -98,22 +101,34 @@ It is possible to add services to multiple machines via tags as shown
In this example `backup_server` has role `client` and `server` in different instances.
```{.nix hl_lines="11 14"}
clan-core.lib.clan {
```{.nix hl_lines="17 26"}
{
inventory = {
machines = {
"jon" = {};
"backup_server" = {};
"backup_backup_server" = {}
"backup_backup_server" = {};
};
services = {
borgbackup.instance_1 = {
roles.client.machines = [ "jon" ];
roles.server.machines = [ "backup_server" ];
instances = {
instance_1 = {
module = {
name = "borgbackup";
input = "clan-core";
};
roles.client.machines."jon" = {};
roles.server.machines."backup_server" = {};
};
borgbackup.instance_2 = {
roles.client.machines = [ "backup_server" ];
roles.server.machines = [ "backup_backup_server" ];
instance_2 = {
module = {
name = "borgbackup";
input = "clan-core";
};
roles.client.machines."backup_server" = {};
roles.server.machines."backup_backup_server" = {};
};
};
};

View File

@@ -1,4 +1,3 @@
This guide explains how to set up and manage
[BorgBackup](https://borgbackup.readthedocs.io/) for secure, efficient backups
in a clan network. BorgBackup provides:
@@ -18,7 +17,7 @@ inventory.instances = {
borgbackup = {
module = {
name = "borgbackup";
input = "clan";
input = "clan-core";
};
roles.client.machines."jon".settings = {
destinations."storagebox" = {
@@ -177,7 +176,7 @@ storagebox::username@username.your-storagebox.de:/./borgbackup::jon-storagebox-2
### Restoring backups
For restoring a backup you have two options.
For restoring a backup you have two options.
#### Full restoration
@@ -194,6 +193,3 @@ To restore only a specific service (e.g., `linkding`):
```bash
clan backups restore --service linkding jon borgbackup storagebox::u444061@u444061.your-storagebox.de:/./borgbackup::jon-storagebox-2025-07-24T06:02:35
```

View File

@@ -1,16 +1,22 @@
# Using `clanServices`
# Using the Inventory
Clans `clanServices` system is a composable way to define and deploy services across machines.
Clan's inventory system is a composable way to define and deploy services across
machines.
This guide shows how to **instantiate** a `clanService`, explains how service definitions are structured in your inventory, and how to pick or create services from modules exposed by flakes.
This guide shows how to **instantiate** a `clanService`, explains how service
definitions are structured in your inventory, and how to pick or create services
from modules exposed by flakes.
The term **Multi-host-modules** was introduced previously in the [nixus repository](https://github.com/infinisil/nixus) and represents a similar concept.
The term **Multi-host-modules** was introduced previously in the [nixus
repository](https://github.com/infinisil/nixus) and represents a similar
concept.
---
______________________________________________________________________
## Overview
Services are used in `inventory.instances`, and then they attach to *roles* and *machines* — meaning you decide which machines run which part of the service.
Services are used in `inventory.instances`, and assigned to *roles* and
*machines* -- meaning you decide which machines run which part of the service.
For example:
@@ -18,119 +24,138 @@ For example:
inventory.instances = {
borgbackup = {
roles.client.machines."laptop" = {};
roles.client.machines."server1" = {};
roles.client.machines."workstation" = {};
roles.server.machines."backup-box" = {};
};
}
```
This says: Run borgbackup as a *client* on my *laptop* and *server1*, and as a *server* on *backup-box*.”
This says: "Run borgbackup as a *client* on my *laptop* and *workstation*, and
as a *server* on *backup-box*". `client` and `server` are roles defined by the
`borgbackup` service.
## Module source specification
Each instance includes a reference to a **module specification** this is how Clan knows which service module to use and where it came from.
Usually one would just use `imports` but we needd to make the `module source` configurable via Python API.
By default it is not required to specify the `module`, in which case it defaults to the preprovided services of clan-core.
Each instance includes a reference to a **module specification** -- this is how
Clan knows which service module to use and where it came from.
---
## Override Example
It is not required to specify the `module.input` parameter, in which case it
defaults to the pre-provided services of clan-core. In a similar fashion, the
`module.name` parameter can also be omitted, it will default to the name of the
instance.
Example of instantiating a `borgbackup` service using `clan-core`:
```nix
inventory.instances = {
# Instance Name: Different name for this 'borgbackup' instance
borgbackup = {
# Since this is instances."borgbackup" the whole `module = { ... }` below is equivalent and optional.
module = {
name = "borgbackup"; # <-- Name of the module (optional)
input = "clan-core"; # <-- The flake input where the service is defined (optional)
};
borgbackup = { # <- Instance name
# This can be partially/fully specified,
# - If the instance name is not the name of the module
# - If the input is not clan-core
# module = {
# name = "borgbackup"; # Name of the module (optional)
# input = "clan-core"; # The flake input where the service is defined (optional)
# };
# Participation of the machines is defined via roles
# Right side needs to be an attribute set. Its purpose will become clear later
roles.client.machines."machine-a" = {};
roles.server.machines."backup-host" = {};
};
}
```
If you used `clan-core` as an input attribute for your flake:
## Module Settings
Each role might expose configurable options. See clan's [clanServices
reference](../reference/clanServices/index.md) for all available options.
Settings can be set in per-machine or per-role. The latter is applied to all
machines that are assigned to that role.
```nix
# ↓ module.input = "clan-core"
inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
```
## Simplified Example
If only one instance is needed for a service and the service is a clan core service, the `module` definition can be omitted.
```nix
# Simplified way of specifying a single instance
inventory.instances = {
# instance name is `borgbackup` -> clan core module `borgbackup` will be loaded.
borgbackup = {
# Participation of the machines is defined via roles
# Right side needs to be an attribute set. Its purpose will become clear later
roles.client.machines."machine-a" = {};
roles.server.machines."backup-host" = {};
};
}
```
## Configuration Example
Each role might expose configurable options
See clan's [clanServices reference](../reference/clanServices/index.md) for available options
```nix
inventory.instances = {
borgbackup-example = {
module = {
name = "borgbackup";
input = "clan-core";
};
# Settings for 'machine-a'
roles.client.machines."machine-a" = {
# 'client' -Settings of 'machine-a'
settings = {
backupFolders = [
/home
/var
];
};
# ---------------------------
};
roles.server.machines."backup-host" = {};
# Settings for all machines of the role "server"
roles.server.settings = {
directory = "/var/lib/borgbackup";
};
};
}
```
## Tags
Multiple members can be defined using tags as follows
Tags can be used to assign multiple machines to a role at once. It can be thought of as a grouping mechanism.
For example using the `all` tag for services that you want to be configured on all
your machines is a common pattern.
The following example could be used to backup all your machines to a common
backup server
```nix
inventory.instances = {
borgbackup-example = {
module = {
name = "borgbackup";
input = "clan-core";
};
#
# The 'all' -tag targets all machines
roles.client.tags."all" = {};
# ---------------------------
borgbackup = {
# "All" machines are assigned to the borgbackup 'client' role
roles.client.tags = [ "all" ];
# But only one specific machine (backup-host) is assigned to the 'server' role
roles.server.machines."backup-host" = {};
};
}
```
## Sharing additional Nix configuration
Sometimes you need to add custom NixOS configuration alongside your clan
services. The `extraModules` option allows you to include additional NixOS
configuration that is applied for every machine assigned to that role.
There are multiple valid syntaxes for specifying modules:
```nix
inventory.instances = {
borgbackup = {
roles.client = {
# Direct module reference
extraModules = [ ../nixosModules/borgbackup.nix ];
# Or using self (needs to be json serializable)
# See next example, for a workaround.
extraModules = [ self.nixosModules.borgbackup ];
# Or inline module definition, (needs to be json compatible)
extraModules = [
{
# Your module configuration here
# ...
#
# If the module needs to contain non-serializable expressions:
imports = [ ./path/to/non-serializable.nix ];
}
];
};
};
}
```
## Picking a clanService
You can use services exposed by Clans core module library, `clan-core`.
You can use services exposed by Clan's core module library, `clan-core`.
🔗 See: [List of Available Services in clan-core](../reference/clanServices/index.md)
@@ -142,18 +167,19 @@ You can also author your own `clanService` modules.
You might expose your service module from your flake — this makes it easy for other people to also use your module in their clan.
---
______________________________________________________________________
## 💡 Tips for Working with clanServices
* You can add multiple inputs to your flake (`clan-core`, `your-org-modules`, etc.) to mix and match services.
* Each service instance is isolated by its key in `inventory.instances`, allowing you to deploy multiple versions or roles of the same service type.
* Roles can target different machines or be scoped dynamically.
- You can add multiple inputs to your flake (`clan-core`, `your-org-modules`, etc.) to mix and match services.
- Each service instance is isolated by its key in `inventory.instances`, allowing to deploy multiple versions or roles of the same service type.
- Roles can target different machines or be scoped dynamically.
---
______________________________________________________________________
## Whats Next?
## What's Next?
- [Author your own clanService →](../guides/services/community.md)
- [Migrate from clanModules →](../guides/migrations/migrate-inventory-services.md)
* [Author your own clanService →](../guides/services/community.md)
* [Migrate from clanModules →](../guides/migrations/migrate-inventory-services.md)
<!-- TODO: * [Understand the architecture →](../explanation/clan-architecture.md) -->

View File

@@ -90,13 +90,10 @@ export CLAN_DEBUG_COMMANDS=1
These options help you pinpoint the source and context of print messages and debug logs during development.
## Analyzing Performance
To understand what's causing slow performance, set the environment variable `export CLAN_CLI_PERF=1`. When you complete a clan command, you'll see a summary of various performance metrics, helping you identify what's taking up time.
## See all possible packages and tests
To quickly show all possible packages and tests execute:
@@ -155,28 +152,16 @@ To test the CLI locally in a development environment and set breakpoints for deb
## Test Locally in a Nix Sandbox
To run tests in a Nix sandbox, you have two options depending on whether your test functions have been marked as impure or not:
### Running Tests Marked as Impure
If your test functions need to execute `nix build` and have been marked as impure because you can't execute `nix build` inside a Nix sandbox, use the following command:
To run tests in a Nix sandbox:
```bash
nix run .#impure-checks -L
nix build .#checks.x86_64-linux.clan-pytest-with-core
```
This command will run the impure test functions.
### Running Pure Tests
For test functions that have not been marked as impure and don't require executing `nix build`, you can use the following command:
```bash
nix build .#checks.x86_64-linux.clan-pytest --rebuild
nix build .#checks.x86_64-linux.clan-pytest-without-core
```
This command will run all pure test functions.
### Inspecting the Nix Sandbox
If you need to inspect the Nix sandbox while running tests, follow these steps:

View File

@@ -4,6 +4,8 @@ This guide provides an example setup for a single-disk ZFS system with native en
!!! Warning
This configuration only applies to `systemd-boot` enabled systems and **requires** UEFI booting.
!!! Info "Secure Boot"
This guide is compatible with systems that have [secure boot disabled](../guides/secure-boot.md). If you encounter boot issues, check if secure boot needs to be disabled in your UEFI settings.
Replace the highlighted lines with your own disk-id.
You can find our your disk-id by executing:

View File

@@ -27,7 +27,7 @@ inputs = {
## Import the Clan flake-parts Module
After updating your flake inputs, the next step is to import the Clan flake-parts module. This will make the [Clan options](../options.md) available within `mkFlake`.
After updating your flake inputs, the next step is to import the Clan flake-parts module. This will make the [Clan options](/options) available within `mkFlake`.
```nix
{

View File

@@ -2,9 +2,9 @@
Machines can be added using the following methods
- Editing nix expressions in flake.nix (i.e. via `clan-core.lib.clan`)
- Editing machines/`machine_name`/configuration.nix (automatically included if it exists)
- `clan machines create` (imperative)
- Create a file `machines/{machine_name}/configuration.nix` (See: [File Autoincludes](../../concepts/autoincludes.md))
- Imperative via cli command: `clan machines create`
- Editing nix expressions in flake.nix See [`clan-core.lib.clan`](/options/?scope=Flake Options (clan.nix file))
See the complete [list](../../concepts/autoincludes.md) of auto-loaded files.
@@ -39,7 +39,6 @@ See the complete [list](../../concepts/autoincludes.md) of auto-loaded files.
The imperative command might create a machine folder in `machines/jon`
And might persist information in `inventory.json`
### Configuring a machine
!!! Note

View File

@@ -1,18 +1,20 @@
# Migrate existing NixOS configurations
# Convert existing NixOS configurations
This guide will help you migrate your existing NixOS configurations into Clan.
This guide will help you convert your existing NixOS configurations into a Clan.
!!! Warning
Migrating instead of starting new can be trickier and might lead to bugs or
unexpected issues. We recommend following the [Getting Started](../getting-started/index.md) guide first. Once you have a working setup, you can easily transfer your NixOS configurations over.
unexpected issues. We recommend reading the [Getting Started](./index.md) guide first.
Once you have a working setup and understand the concepts transfering your NixOS configurations over is easy.
## Back up your existing configuration
## Back up your existing configuration!
Before you start, it is strongly recommended to back up your existing
configuration in any form you see fit. If you use version control to manage
your configuration changes, it is also a good idea to follow the migration
guide in a separte branch until everything works as expected.
## Starting Point
We assume you are already using NixOS flakes to manage your configuration. If
@@ -43,10 +45,9 @@ have have two hosts: **berlin** and **cologne**.
}
```
## Add clan-core Input
## 1. Add `clan-core` to `inputs`
Add `clan-core` to your flake as input. It will provide everything we need to
manage your configurations with clan.
Add `clan-core` to your flake as input.
```nix
inputs.clan-core = {
@@ -56,7 +57,7 @@ inputs.clan-core = {
}
```
## Update Outputs
## 2. Update Outputs
To be able to access our newly added dependency, it has to be added to the
output parameters.
@@ -103,26 +104,23 @@ For the provide flake example, your flake should now look like this:
};
in
{
nixosConfigurations = clan.nixosConfigurations;
inherit (clan) clanInternals;
clan = {
inherit (clan) templates;
};
inherit (clan.config) nixosConfigurations nixosModules clanInternals;
clan = clan.config;
};
}
```
Et voilà! Your existing hosts are now part of a clan. Existing Nix tooling
Et voilà! Your existing hosts are now part of a clan.
Existing Nix tooling
should still work as normal. To check that you didn't make any errors, run `nix
flake show` and verify both hosts are still recognized as if nothing had
changed. You should also see the new `clanInternals` output.
changed. You should also see the new `clan` output.
```
nix flake show
git+file:///my-nixos-config
├───clanInternals: unknown
├───clan: unknown
└───nixosConfigurations
├───berlin: NixOS configuration
└───cologne: NixOS configuration
@@ -131,7 +129,7 @@ git+file:///my-nixos-config
Of course you can also rebuild your configuration using `nixos-rebuild` and
veryify everything still works.
## Add Clan CLI devShell
## 3. Add `clan-cli` to your `devShells`
At this point Clan is set up, but you can't use the CLI yet. To do so, it is
recommended to expose it via a `devShell` in your flake. It is also possible to
@@ -163,8 +161,8 @@ cologne
## Specify Targets
Clan needs to know where it can reach your hosts. For each of your hosts, set
`clan.core.networking.targetHost` to its adress or hostname.
Clan needs to know where it can reach your hosts. For testing purpose set
`clan.core.networking.targetHost` to the machines adress or hostname.
```nix
# machines/berlin/configuration.nix
@@ -173,6 +171,8 @@ Clan needs to know where it can reach your hosts. For each of your hosts, set
}
```
See our guide on for properly [configuring machines networking](../networking.md)
## Next Steps
You are now fully set up. Use the CLI to manage your hosts or proceed to

View File

@@ -1,12 +1,15 @@
# Update Your Machines
# Update Machines
Clan CLI enables you to remotely update your machines over SSH. This requires setting up a target address for each target machine.
The Clan command line interface enables you to update machines remotely over SSH.
In this guide we will teach you how to set a `targetHost` in Nix,
and how to define a remote builder for your machine closures.
### Setting `targetHost`
In your Nix files, set the `targetHost` to the reachable IP address of your new machine. This eliminates the need to specify `--target-host` with every command.
## Setting `targetHost`
Set the machines `targetHost` to the reachable IP address of the new machine.
This eliminates the need to specify `--target-host` in CLI commands.
```{.nix title="clan.nix" hl_lines="9"}
{
@@ -23,15 +26,42 @@ inventory.machines = {
# [...]
}
```
The use of `root@` in the target address implies SSH access as the `root` user.
Ensure that the root login is secured and only used when necessary.
## Multiple Target Hosts
### Setting a Build Host
You can now experiment with a new interface that allows you to define multiple `targetHost` addresses for different VPNs. Learn more and try it out in our [networking guide](../networking.md).
If the machine does not have enough resources to run the NixOS evaluation or build itself,
it is also possible to specify a build host instead.
During an update, the cli will ssh into the build host and run `nixos-rebuild` from there.
## Updating Machine Configurations
Execute the following command to update the specified machine:
```bash
clan machines update jon
```
All machines can be updated simultaneously by omitting the machine name:
```bash
clan machines update
```
---
## Advanced Usage
The following options are only needed for special cases, such as limited resources, mixed environments, or private flakes.
### Setting `buildHost`
If the machine does not have enough resources to run the NixOS **evaluation** or **build** itself,
it is also possible to specify a `buildHost` instead.
During an update, clan will ssh into the `buildHost` and run `nixos-rebuild` from there.
!!! Note
The `buildHost` option should be set directly within your machines Nix configuration, **not** under `inventory.machines`.
```{.nix hl_lines="5" .no-copy}
@@ -45,7 +75,11 @@ buildClan {
};
```
You can also override the build host via the command line:
### Overriding configuration with CLI flags
`buildHost` / `targetHost`, and other network settings can be temporarily overridden for a single command:
For the full list of flags refer to the [Clan CLI](../../reference/cli/index.md)
```bash
# Build on a remote host
@@ -56,23 +90,9 @@ clan machines update jon --build-host local
```
!!! Note
Make sure that the CPU architecture is the same for the buildHost as for the targetHost.
Example:
If you want to deploy to a macOS machine, your architecture is an ARM64-Darwin, that means you need a second macOS machine to build it.
Make sure the CPU architecture of the `buildHost` matches that of the `targetHost`
### Updating Machine Configurations
Execute the following command to update the specified machine:
```bash
clan machines update jon
```
You can also update all configured machines simultaneously by omitting the machine name:
```bash
clan machines update
```
For example, if deploying to a macOS machine with an ARM64-Darwin architecture, you need a second macOS machine with the same architecture to build it.
### Excluding a machine from `clan machine update`
@@ -96,14 +116,15 @@ This is useful for machines that are not always online or are not part of the re
### Uploading Flake Inputs
When updating remote machines, flake inputs are usually fetched by the build host.
However, if your flake inputs require authentication (e.g., private repositories),
you can use the `--upload-inputs` flag to upload all inputs from your local machine:
However, if flake inputs require authentication (e.g., private repositories),
Use the `--upload-inputs` flag to upload all inputs from your local machine:
```bash
clan machines update jon --upload-inputs
```
This is particularly useful when:
- Your flake references private Git repositories
- Authentication credentials are only available on your local machine
- The flake references private Git repositories
- Authentication credentials are only available on local machine
- The build host doesn't have access to certain network resources

View File

@@ -254,7 +254,7 @@ The following table shows the migration status of each deprecated clanModule:
| `data-mesher` | ✅ [Migrated](../../reference/clanServices/data-mesher.md) | |
| `deltachat` | ❌ Removed | |
| `disk-id` | ❌ Removed | |
| `dyndns` | [Being Migrated](https://git.clan.lol/clan/clan-core/pulls/4390) | |
| `dyndns` | [Migrated](../../reference/clanServices/dyndns.md) | |
| `ergochat` | ❌ Removed | |
| `garage` | ✅ [Migrated](../../reference/clanServices/garage.md) | |
| `golem-provider` | ❌ Removed | |
@@ -263,18 +263,18 @@ The following table shows the migration status of each deprecated clanModule:
| `iwd` | ❌ Removed | Use [wifi service](../../reference/clanServices/wifi.md) instead |
| `localbackup` | ✅ [Migrated](../../reference/clanServices/localbackup.md) | |
| `localsend` | ❌ Removed | |
| `machine-id` | ❌ Removed | Now an [option](../../reference/clan.core/settings.md) |
| `machine-id` | ✅ [Migrated](../../reference/clan.core/settings.md) | Now an [option](../../reference/clan.core/settings.md) |
| `matrix-synapse` | ✅ [Migrated](../../reference/clanServices/matrix-synapse.md) | |
| `moonlight` | ❌ Removed | |
| `mumble` | ❌ Removed | |
| `mycelium` | ✅ [Migrated](../../reference/clanServices/mycelium.md) | |
| `nginx` | ❌ Removed | |
| `packages` | ✅ [Migrated](../../reference/clanServices/packages.md) | |
| `postgresql` | ❌ Removed | Now an [option](../../reference/clan.core/settings.md) |
| `root-password` | ✅ [Migrated](../../reference/clanServices/users.md) | |
| `postgresql` | ✅ [Migrated](../../reference/clan.core/settings.md) | Now an [option](../../reference/clan.core/settings.md) |
| `root-password` | ✅ [Migrated](../../reference/clanServices/users.md) | See [migration guide](../../reference/clanServices/users.md#migration-from-root-password-module) |
| `single-disk` | ❌ Removed | |
| `sshd` | ✅ [Migrated](../../reference/clanServices/sshd.md) | |
| `state-version` | ✅ [Migrated](../../reference/clanServices/state-version.md) | |
| `state-version` | ✅ [Migrated](../../reference/clan.core/settings.md) | Now an [option](../../reference/clan.core/settings.md) |
| `static-hosts` | ❌ Removed | |
| `sunshine` | ❌ Removed | |
| `syncthing-static-peers` | ❌ Removed | |

View File

@@ -0,0 +1,184 @@
# Connecting to Your Machines
Clan provides automatic networking with fallback mechanisms to reliably connect to your machines.
## Option 1: Automatic Networking with Fallback (Recommended)
Clan's networking module automatically manages connections through various network technologies with intelligent fallback. When you run `clan ssh` or `clan machines update`, Clan tries each configured network by priority until one succeeds.
### Basic Setup with Internet Service
For machines with public IPs or DNS names, use the `internet` service to configure direct SSH while keeping fallback options:
```{.nix title="flake.nix" hl_lines="7-10 14-16"}
{
outputs = { self, clan-core, ... }:
let
clan = clan-core.lib.clan {
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";
};
};
# Fallback: Secure connections via Tor
tor = {
roles.server.tags.nixos = { };
};
};
};
in
{
inherit (clan.config) nixosConfigurations;
};
}
```
### Advanced Setup with Multiple Networks
```{.nix title="flake.nix" hl_lines="7-10 13-16 19-21"}
{
outputs = { self, clan-core, ... }:
let
clan = clan-core.lib.clan {
inventory.instances = {
# Priority 1: Try direct connection first
internet = {
roles.default.machines.publicserver = {
settings.host = "public.example.com";
};
};
# Priority 2: VPN for internal machines
zerotier = {
roles.controller.machines."controller" = { };
roles.peer.tags.nixos = { };
};
# Priority 3: Tor as universal fallback
tor = {
roles.server.tags.nixos = { };
};
};
};
in
{
inherit (clan.config) nixosConfigurations;
};
}
```
### How It Works
Clan automatically tries networks in order of priority:
1. Direct internet connections (if configured)
2. VPN networks (ZeroTier, Tailscale, etc.)
3. Tor hidden services
4. Any other configured networks
If one network fails, Clan automatically tries the next.
### Useful Commands
```bash
# View all configured networks and their status
clan network list
# Test connectivity through all networks
clan network ping machine1
# Show complete network topology
clan network overview
```
## Option 2: Manual targetHost (Bypasses Fallback!)
!!! warning
Setting `targetHost` directly **disables all automatic networking and fallback**. Only use this if you need complete control and don't want Clan's intelligent connection management.
### Using Inventory (For Static Addresses)
Use inventory-level `targetHost` when the address is **static** and doesn't depend on NixOS configuration:
```{.nix title="flake.nix" hl_lines="8"}
{
outputs = { self, clan-core, ... }:
let
clan = clan-core.lib.clan {
inventory.machines.server = {
# WARNING: This bypasses all networking modules!
# Use for: Static IPs, DNS names, known hostnames
deploy.targetHost = "root@192.168.1.100";
};
};
in
{
inherit (clan.config) nixosConfigurations;
};
}
```
**When to use inventory-level:**
- Static IP addresses: `"root@192.168.1.100"`
- DNS names: `"user@server.example.com"`
- Any address that doesn't change based on machine configuration
### Using NixOS Configuration (For Dynamic Addresses)
Use machine-level `targetHost` when you need to **interpolate values from the NixOS configuration**:
```{.nix title="flake.nix" hl_lines="7"}
{
outputs = { self, clan-core, ... }:
let
clan = clan-core.lib.clan {
machines.server = { config, ... }: {
# WARNING: This also bypasses all networking modules!
# REQUIRED for: Addresses that depend on NixOS config
clan.core.networking.targetHost = "root@${config.networking.hostName}.local";
};
};
in
{
inherit (clan.config) nixosConfigurations;
};
}
```
**When to use machine-level (NixOS config):**
- Using hostName from config: `"root@${config.networking.hostName}.local"`
- Building from multiple config values: `"${config.users.users.deploy.name}@${config.networking.hostName}"`
- Any address that depends on evaluated NixOS configuration
!!! info "Key Difference"
**Inventory-level** (`deploy.targetHost`) is evaluated immediately and works with static strings.
**Machine-level** (`clan.core.networking.targetHost`) is evaluated after NixOS configuration and can access `config.*` values.
## Quick Decision Guide
| Scenario | Recommended Approach | Why |
|----------|---------------------|-----|
| Public servers | `internet` service | Keeps fallback options |
| Mixed infrastructure | Multiple networks | Automatic failover |
| Machines behind NAT | ZeroTier/Tor | NAT traversal with fallback |
| Testing/debugging | Manual targetHost | Full control, no magic |
| Single static machine | Manual targetHost | Simple, no overhead |
## Command-Line Override
The `--target-host` flag bypasses ALL networking configuration:
```bash
# Emergency access - ignores all networking config
clan machines update server --target-host root@backup-ip.com
# Direct SSH - no fallback attempted
clan ssh laptop --target-host user@10.0.0.5
```
Use this for debugging or emergency access when automatic networking isn't working.

View File

@@ -255,11 +255,50 @@ outputs = inputs: flake-parts.lib.mkFlake { inherit inputs; } ({self, lib, ...}:
})
```
The benefit of this approach is that downstream users can override the value of `myClan` by using `mkForce` or other priority modifiers.
The benefit of this approach is that downstream users can override the value of
`myClan` by using `mkForce` or other priority modifiers.
## Example: A machine-type service
Users often have different types of machines. These could be any classification
you like, for example "servers" and "desktops". Having such distictions, allows
reusing parts of your configuration that should be appplied to a class of
machines. Since this is such a common pattern, here is how to write such a
service.
For this example the we have to roles: `server` and `desktop`. Additionally, we
can use the `perMachine` section to add configuration to all machines regardless
of their type.
```nix title="machine-type.nix"
{
_class = "clan.service";
manifest.name = "machine-type";
roles.server.perInstance.nixosModule = ./server.nix;
roles.desktop.perInstance.nixosModule = ./desktop.nix;
perMachine.nixosModule = {
# Configuration for all machines (any type)
};
}
```
In the inventory we the assign machines to a type, e.g. by using tags
```nix title="flake.nix"
instnaces.machine-type = {
module.input = "self";
module.name = "@pinpox/machine-type";
roles.desktop.tags.desktop = { };
roles.server.tags.server = { };
};
```
---
## Further
## Further Reading
- [Reference Documentation for Service Authors](../../reference/clanServices/clan-service-author-interface.md)
- [Migration Guide from ClanModules to ClanServices](../../guides/migrations/migrate-inventory-services.md)

View File

@@ -1,84 +0,0 @@
# How to Set `targetHost` for a Machine
The `targetHost` defines where the machine can be reached for operations like SSH or deployment. You can set it in two ways, depending on your use case.
---
## ✅ Option 1: Use the Inventory (Recommended for Static Hosts)
If the hostname is **static**, like `server.example.com`, set it in the **inventory**:
```{.nix title="flake.nix" hl_lines="8"}
{
# edlided
outputs =
{ self, clan-core, ... }:
let
# Sometimes this attribute set is defined in clan.nix
clan = clan-core.lib.clan {
inventory.machines.jon = {
deploy.targetHost = "root@server.example.com";
};
};
in
{
inherit (clan.config) nixosConfigurations nixosModules clanInternals;
# elided
};
}
```
This is fast, simple and explicit, and doesnt require evaluating the NixOS config. We can also displayed it in the clan-cli or clan-app.
---
## ✅ Option 2: Use NixOS (Only for Dynamic Hosts)
If your target host depends on a **dynamic expression** (like using the machines evaluated FQDN), set it inside the NixOS module:
```{.nix title="flake.nix" hl_lines="8"}
{
# edlided
outputs =
{ self, clan-core, ... }:
let
# Sometimes this attribute set is defined in clan.nix
clan = clan-core.lib.clan {
machines.jon = {config, ...}: {
clan.core.networking.targetHost = "jon@${config.networking.fqdn}";
};
};
in
{
inherit (clan.config) nixosConfigurations nixosModules clanInternals;
# elided
};
}
```
Use this **only if the value cannot be made static**, because its slower and won't be displayed in the clan-cli or clan-app yet.
---
## 📝 TL;DR
| Use Case | Use Inventory? | Example |
| ------------------------- | -------------- | -------------------------------- |
| Static hostname | ✅ Yes | `root@server.example.com` |
| Dynamic config expression | ❌ No | `jon@${config.networking.fqdn}` |
---
## 🚀 Coming Soon: Unified Networking Module
Were working on a new networking module that will automatically do all of this for you.
- Easier to use
- Sane defaults: Youll always be able to reach the machine — no need to worry about hostnames.
- ✨ Migration from **either method** will be supported and simple.
## Summary
- Ask: *Does this hostname dynamically change based on NixOS config?*
- If **no**, use the inventory.
- If **yes**, then use NixOS config.

View File

@@ -0,0 +1,289 @@
# Advanced Vars Examples
This guide demonstrates complex, real-world patterns for the vars system. For basic usage, see the [Getting Started guide](vars-backend.md).
## Certificate Authority with Intermediate Certificates
This example shows how to create a complete certificate authority with root and intermediate certificates using dependencies.
```nix
{
# Generate root CA (not deployed to machines)
clan.core.vars.generators.root-ca = {
files."ca.key" = {
secret = true;
deploy = false; # Keep root key offline
};
files."ca.crt".secret = false;
runtimeInputs = [ pkgs.step-cli ];
script = ''
step certificate create "My Root CA" \
$out/ca.crt $out/ca.key \
--profile root-ca \
--no-password \
--not-after 87600h
'';
};
# Generate intermediate key
clan.core.vars.generators.intermediate-key = {
files."intermediate.key" = {
secret = true;
deploy = true;
};
runtimeInputs = [ pkgs.step-cli ];
script = ''
step crypto keypair \
$out/intermediate.pub \
$out/intermediate.key \
--no-password
'';
};
# Generate intermediate certificate signed by root
clan.core.vars.generators.intermediate-cert = {
files."intermediate.crt".secret = false;
dependencies = [
"root-ca"
"intermediate-key"
];
runtimeInputs = [ pkgs.step-cli ];
script = ''
step certificate create "My Intermediate CA" \
$out/intermediate.crt \
$in/intermediate-key/intermediate.key \
--ca $in/root-ca/ca.crt \
--ca-key $in/root-ca/ca.key \
--profile intermediate-ca \
--not-after 8760h \
--no-password
'';
};
# Use the certificates in services
services.nginx.virtualHosts."example.com" = {
sslCertificate = config.clan.core.vars.generators.intermediate-cert.files."intermediate.crt".value;
sslCertificateKey = config.clan.core.vars.generators.intermediate-key.files."intermediate.key".path;
};
}
```
## Multi-Service Secret Sharing
Generate secrets that multiple services can use:
```nix
{
# Generate database credentials
clan.core.vars.generators.database = {
share = true; # Share across machines
files."password" = { };
files."connection-string" = { };
prompts.dbname = {
description = "Database name";
type = "line";
};
script = ''
# Generate password
tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32 > $out/password
# Create connection string
echo "postgresql://app:$(cat $out/password)@localhost/$prompts/dbname" \
> $out/connection-string
'';
};
# PostgreSQL uses the password
services.postgresql = {
enable = true;
initialScript = pkgs.writeText "init.sql" ''
CREATE USER app WITH PASSWORD '${
builtins.readFile config.clan.core.vars.generators.database.files."password".path
}';
'';
};
# Application uses the connection string
systemd.services.myapp = {
serviceConfig.EnvironmentFile =
config.clan.core.vars.generators.database.files."connection-string".path;
};
}
```
## SSH Host Keys with Certificates
Generate SSH host keys and sign them with a CA:
```nix
{
# SSH Certificate Authority (shared)
clan.core.vars.generators.ssh-ca = {
share = true;
files."ca" = { secret = true; deploy = false; };
files."ca.pub" = { secret = false; };
runtimeInputs = [ pkgs.openssh ];
script = ''
ssh-keygen -t ed25519 -N "" -f $out/ca
mv $out/ca.pub $out/ca.pub
'';
};
# Host-specific SSH keys
clan.core.vars.generators.ssh-host = {
files."ssh_host_ed25519_key" = {
secret = true;
owner = "root";
group = "root";
mode = "0600";
};
files."ssh_host_ed25519_key.pub" = { secret = false; };
files."ssh_host_ed25519_key-cert.pub" = { secret = false; };
dependencies = [ "ssh-ca" ];
runtimeInputs = [ pkgs.openssh ];
script = ''
# Generate host key
ssh-keygen -t ed25519 -N "" -f $out/ssh_host_ed25519_key
# Sign with CA
ssh-keygen -s $in/ssh-ca/ca \
-I "host:${config.networking.hostName}" \
-h \
-V -5m:+365d \
$out/ssh_host_ed25519_key.pub
'';
};
# Configure SSH to use the generated keys
services.openssh = {
hostKeys = [{
path = config.clan.core.vars.generators.ssh-host.files."ssh_host_ed25519_key".path;
type = "ed25519";
}];
};
}
```
## WireGuard Mesh Network
Create a WireGuard configuration with pre-shared keys:
```nix
{
# Generate WireGuard keys for this host
clan.core.vars.generators.wireguard = {
files."privatekey" = {
secret = true;
owner = "systemd-network";
mode = "0400";
};
files."publickey" = { secret = false; };
files."preshared" = { secret = true; };
runtimeInputs = [ pkgs.wireguard-tools ];
script = ''
# Generate key pair
wg genkey > $out/privatekey
wg pubkey < $out/privatekey > $out/publickey
# Generate pre-shared key
wg genpsk > $out/preshared
'';
};
# Configure WireGuard
networking.wireguard.interfaces.wg0 = {
privateKeyFile = config.clan.core.vars.generators.wireguard.files."privatekey".path;
peers = [{
publicKey = "peer-public-key-here";
presharedKeyFile = config.clan.core.vars.generators.wireguard.files."preshared".path;
allowedIPs = [ "10.0.0.2/32" ];
}];
};
}
```
## Conditional Generation Based on Machine Role
Generate different secrets based on machine configuration:
```nix
{
clan.core.vars.generators = lib.mkMerge [
# All machines get basic auth
{
basic-auth = {
files."htpasswd" = { };
prompts.username = {
description = "Username for basic auth";
type = "line";
};
prompts.password = {
description = "Password for basic auth";
type = "hidden";
};
runtimeInputs = [ pkgs.apacheHttpd ];
script = ''
htpasswd -nbB "$prompts/username" "$prompts/password" > $out/htpasswd
'';
};
}
# Only servers get API tokens
(lib.mkIf config.services.myapi.enable {
api-tokens = {
files."admin-token" = { };
files."readonly-token" = { };
runtimeInputs = [ pkgs.openssl ];
script = ''
openssl rand -hex 32 > $out/admin-token
openssl rand -hex 16 > $out/readonly-token
'';
};
})
];
}
```
## Backup Encryption Keys
Generate and manage backup encryption keys:
```nix
{
clan.core.vars.generators.backup = {
share = true; # Same key for all backup sources
files."encryption.key" = {
secret = true;
deploy = true;
};
files."encryption.pub" = { secret = false; };
runtimeInputs = [ pkgs.age ];
script = ''
# Generate age key pair
age-keygen -o $out/encryption.key 2>/dev/null
# Extract public key
grep "public key:" $out/encryption.key | cut -d: -f2 | tr -d ' ' \
> $out/encryption.pub
'';
};
# Use in backup service
services.borgbackup.jobs.system = {
encryption = {
mode = "repokey-blake2";
passCommand = "cat ${config.clan.core.vars.generators.backup.files."encryption.key".path}";
};
};
}
```
## Tips and Best Practices
1. **Use dependencies** to build complex multi-stage generations
2. **Share generators** when the same secret is needed across machines
3. **Set appropriate permissions** for service-specific secrets
4. **Use prompts** for user-specific values that shouldn't be generated
5. **Combine secret and non-secret files** in the same generator when they're related
6. **Use conditional generation** with `lib.mkIf` for role-specific secrets

View File

@@ -0,0 +1,155 @@
!!! Note
This guide demonstrates the vars system for managing secrets and generated files
Defining a linux user's password via the nixos configuration previously required running `mkpasswd ...` and then copying the hash back into the nix configuration.
In this example, we will guide you through automating that interaction using clan `vars`.
For architectural concepts and design principles, see the [Concepts guide](vars-concepts.md). For the complete API reference, see the [vars module documentation](../reference/clan.core/vars.md).
This guide assumes
- Clan is set up already (see [Getting Started](../guides/getting-started/index.md))
- a machine has been added to the clan (see [Adding Machines](getting-started/add-machines.md))
This section will walk you through the following steps:
1. declare a `generator` in the machine's nixos configuration
2. inspect the status via the Clan CLI
3. generate the vars
4. observe the changes
5. update the machine
6. share the root password between machines
7. change the password
## Declare the generator
In this example, a `vars` `generator` is used to:
- prompt the user for the password
- run the required `mkpasswd` command to generate the hash
- store the hash in a file
- expose the file path to the nixos configuration
Create a new nix file `root-password.nix` with the following content and import it into your `configuration.nix`
```nix
{config, pkgs, ...}: {
clan.core.vars.generators.root-password = {
# prompt the user for a password
# (`password-input` being an arbitrary name)
prompts.password-input.description = "the root user's password";
prompts.password-input.type = "hidden";
# don't store the prompted password itself
prompts.password-input.persist = false;
# define an output file for storing the hash
files.password-hash.secret = false;
# define the logic for generating the hash
script = ''
cat $prompts/password-input | mkpasswd -m sha-512 > $out/password-hash
'';
# the tools required by the script
runtimeInputs = [ pkgs.mkpasswd ];
};
# ensure users are immutable (otherwise the following config might be ignored)
users.mutableUsers = false;
# set the root password to the file containing the hash
users.users.root.hashedPasswordFile =
# clan will make sure, this path exists
config.clan.core.vars.generators.root-password.files.password-hash.path;
}
```
## Inspect the status
Executing `clan vars list`, you should see the following:
```shellSession
$ clan vars list my_machine
root-password/password-hash: <not set>
```
...indicating that the value `password-hash` for the generator `root-password` is not set yet.
## Generate the values
This step is not strictly necessary, as deploying the machine via `clan machines update` would trigger the generator as well.
To run the generator, execute `clan vars generate` for your machine
```shellSession
$ clan vars generate my_machine
Enter the value for root-password/password-input (hidden):
```
After entering the value, the updated status is reported:
```shellSession
Updated var root-password/password-hash
old: <not set>
new: $6$RMats/YMeypFtcYX$DUi...
```
## Observe the changes
With the last step, a new file was created in your repository:
`vars/per-machine/my-machine/root-password/password-hash/value`
If the repository is a git repository, a commit was created automatically:
```shellSession
$ git log -n1
commit ... (HEAD -> master)
Author: ...
Date: ...
Update vars via generator root-password for machine grmpf-nix
```
## Update the machine
```shell
clan machines update my_machine
```
## Share root password between machines
If we just imported the `root-password.nix` from above into more machines, clan would ask for a new password for each additional machine.
If the root password instead should only be entered once and shared across all machines, the generator defined above needs to be declared as `shared`, by adding `share = true` to it:
```nix
{config, pkgs, ...}: {
clan.core.vars.generators.root-password = {
share = true;
# ...
}
}
```
Importing that shared generator into each machine, will ensure that the password is only asked once the first machine gets updated and then re-used for all subsequent machines.
## Change the root password
Changing the password can be done via this command.
Replace `my-machine` with your machine.
If the password is shared, just pick any machine that has the generator declared.
```shellSession
$ clan vars generate my-machine --generator root-password --regenerate
...
Enter the value for root-password/password-input (hidden):
Input received. Processing...
...
Updated var root-password/password-hash
old: $6$tb27m6EOdff.X9TM$19N...
new: $6$OyoQtDVzeemgh8EQ$zRK...
```
## Further Reading
- [Understanding Vars Concepts](vars-concepts.md) - Learn about the architecture and core concepts
- [Advanced Examples](vars-advanced-examples.md) - Complex real-world examples including certificates, SSH keys, and more
- [Troubleshooting Guide](vars-troubleshooting.md) - Common issues and solutions
- [Migration Guide](migrations/migration-facts-vars.md) - Migrate from legacy facts system
- [Reference Documentation for `clan.core.vars` NixOS options](../reference/clan.core/vars.md)
- [Reference Documentation for the `clan vars` CLI command](../reference/cli/vars.md)

View File

@@ -0,0 +1,129 @@
# Understanding Clan Vars - Concepts & Architecture
This guide explains the architecture and design principles behind the vars system. For a hands-on tutorial, see the [Getting Started guide](vars-backend.md).
## Architecture Overview
The vars system provides a declarative, reproducible way to manage generated files (especially secrets) in NixOS configurations.
## Data Flow
```mermaid
graph LR
A[Generator Script] --> B[Output Files]
C[User Prompts] --> A
D[Dependencies] --> A
B --> E[Secret Storage<br/>sops/password-store]
B --> F[Nix Store<br/>public files]
E --> G[Machine Deployment]
F --> G
```
## Key Design Principles
### 1. Declarative Generation
Unlike imperative secret management, vars are declared in your NixOS configuration and generated deterministically. This ensures reproducibility across deployments.
### 2. Separation of Concerns
- **Generation logic**: Defined in generator scripts
- **Storage**: Handled by pluggable backends (sops, password-store, etc.)
- **Deployment**: Managed by NixOS activation scripts
- **Access control**: Enforced through file permissions and ownership
### 3. Composability Through Dependencies
Generators can depend on outputs from other generators, enabling complex workflows:
```nix
# Dependencies create a directed acyclic graph (DAG)
A B C
D
```
This allows building sophisticated systems like certificate authorities where intermediate certificates depend on root certificates.
### 4. Type Safety
The vars system distinguishes between:
- **Secret files**: Only accessible via `.path`, deployed to `/run/secrets/`
- **Public files**: Accessible via `.value`, stored in nix store
This prevents accidental exposure of secrets in the nix store.
## Storage Backend Architecture
The vars system uses pluggable storage backends:
- **sops** (default): Integrates with clan's existing sops encryption
- **password-store**: For users already using pass
Each backend handles encryption/decryption transparently, allowing the same generator definitions to work across different security models.
## Timing and Lifecycle
### Generation Phases
1. **Pre-deployment**: `clan vars generate` creates vars before deployment
2. **During deployment**: Missing vars are generated automatically
3. **Regeneration**: Explicit regeneration with `--regenerate` flag
### The `neededFor` Option
Control when vars are available during system activation:
```nix
files."early-secret" = {
secret = true;
neededFor = [ "users" "groups" ]; # Available early in activation
};
```
## Advanced Patterns
### Multi-Machine Coordination
The `share` option enables cross-machine secret sharing:
```mermaid
graph LR
A[Shared Generator] --> B[Machine 1]
A --> C[Machine 2]
A --> D[Machine 3]
```
This is useful for:
- Shared certificate authorities
- Mesh VPN pre-shared keys
- Cluster join tokens
### Generator Composition
Complex systems can be built by composing simple generators:
```
root-ca → intermediate-ca → service-cert
ocsp-responder
```
Each generator focuses on one task, making the system modular and testable.
## Key Advantages
Compared to manual secret management, vars provides:
- **Declarative configuration**: Define once, generate consistently
- **Dependency management**: Build complex systems with generator dependencies
- **Type safety**: Separate handling of secret and public files
- **User prompts**: Gather input when needed
- **Easy regeneration**: Update secrets with a single command
## Next Steps
- [Practical Tutorial](vars-backend.md) - Step-by-step guide
- [Advanced Examples](vars-advanced-examples.md) - Real-world patterns
- [Troubleshooting](vars-troubleshooting.md) - Common issues
- [Reference](../reference/clan.core/vars.md) - Complete API

View File

@@ -0,0 +1,169 @@
# Vars System Overview
The vars system is clan's declarative solution for managing generated files, secrets, and dynamic configuration in your NixOS deployments. It eliminates the manual steps of generating credentials, certificates, and other dynamic values by automating these processes within your infrastructure-as-code workflow.
## What Problems Does Vars Solve?
### Before Vars: Manual Secret Management
Traditional NixOS deployments require manual steps for secrets and generated files:
```bash
# Generate password hash manually
mkpasswd -m sha-512 > /tmp/root-password-hash
# Copy hash into configuration
users.users.root.hashedPasswordFile = "/tmp/root-password-hash";
```
This approach has several problems:
- **Not reproducible**: Manual steps vary between team members
- **Hard to maintain**: Updating secrets requires remembering manual commands
- **Deployment friction**: Secrets must be managed outside of your configuration
- **Team collaboration issues**: Sharing credentials securely is complex
### After Vars: Declarative Generation
With vars, the same process becomes declarative and automated:
```nix
clan.core.vars.generators.root-password = {
prompts.password.description = "Root password";
prompts.password.type = "hidden";
files.hash.secret = false;
script = "mkpasswd -m sha-512 < $prompts/password > $out/hash";
runtimeInputs = [ pkgs.mkpasswd ];
};
users.users.root.hashedPasswordFile =
config.clan.core.vars.generators.root-password.files.hash.path;
```
## Core Benefits
- **🔄 Reproducible**: Same inputs always produce the same outputs
- **📝 Declarative**: Defined alongside your NixOS configuration
- **🔐 Secure**: Automatic secret storage and encrypted deployment
- **👥 Collaborative**: Built-in sharing for team environments
- **🚀 Automated**: No manual intervention required for deployments
- **🔗 Integrated**: Works seamlessly with clan's deployment workflow
## How It Works
```mermaid
graph TB
A[Generator Declaration] --> B[clan vars generate]
B --> C{Prompts User}
C --> D[Execute Script]
D --> E[Output Files]
E --> F{Secret?}
F -->|Yes| G[Encrypted Storage]
F -->|No| H[Git Repository]
G --> I[Deploy to Machine]
H --> I
I --> J[Available in NixOS]
```
1. **Declare generators** in your NixOS configuration
2. **Generate values** using `clan vars generate` (or automatically during deployment)
3. **Store securely** in encrypted backends or version control
4. **Deploy seamlessly** to your machines where they're accessible as file paths
## Common Use Cases
| Use Case | What Gets Generated | Benefits |
|----------|-------------------|----------|
| **User passwords** | Password hashes | No plaintext in config |
| **SSH keys** | Host/user keypairs | Automated key rotation |
| **TLS certificates** | Certificates + private keys | Automated PKI |
| **Database credentials** | Passwords + connection strings | Secure service communication |
| **API tokens** | Random tokens | Service authentication |
| **Configuration files** | Complex configs with secrets | Dynamic config generation |
## Architecture Overview
The vars system has three main components:
### 1. **Generators**
Define how to create files from inputs:
- **Prompts**: Values requested from users
- **Scripts**: Generation logic
- **Dependencies**: Other generators this depends on
- **Outputs**: Files that get created
### 2. **Storage Backends**
Handle secret storage and deployment:
- **sops**: Encrypted files in git (recommended)
- **password-store**: GPG/age-based secret storage
- **vm**: For development/testing
### 3. **Integration**
Seamless NixOS integration:
- File paths available at build time
- Automatic deployment to machines
- Service restarts on changes
## Learning Path
Ready to get started? Follow this recommended path:
### 1. **🚀 Hands-On Tutorial**
[Vars Getting Started Guide](vars-backend.md)
Start here for a practical walkthrough with password generation.
### 2. **🏗️ Understand the Design**
[Vars Concepts & Architecture](vars-concepts.md)
Deep dive into design principles and advanced patterns.
### 3. **💡 Real-World Examples**
[Advanced Examples](vars-advanced-examples.md)
Complex scenarios including certificates, SSH keys, and databases.
### 4. **🔧 Troubleshooting**
[Troubleshooting Guide](vars-troubleshooting.md)
Solutions for common issues and debugging techniques.
### 5. **📚 Complete Reference**
- [NixOS Module Options](../reference/clan.core/vars.md)
- [CLI Commands](../reference/cli/vars.md)
## Quick Start Example
Here's a complete example showing password generation and usage:
```nix
# generator.nix
{ config, pkgs, ... }: {
clan.core.vars.generators.user-password = {
prompts.password = {
description = "User password";
type = "hidden";
};
files.hash = { secret = false; };
script = ''
mkpasswd -m sha-512 < $prompts/password > $out/hash
'';
runtimeInputs = [ pkgs.mkpasswd ];
};
users.users.myuser = {
hashedPasswordFile =
config.clan.core.vars.generators.user-password.files.hash.path;
};
}
```
```bash
# Generate the password
clan vars generate my-machine
# Deploy to machine
clan machines update my-machine
```
## Migration from Facts
If you're currently using the legacy facts system, see our [Migration Guide](migrations/migration-facts-vars.md) for step-by-step instructions on upgrading to vars.
---
**Ready to start?** Head to the [Getting Started Guide](vars-backend.md) for your first hands-on experience with the vars system.

View File

@@ -0,0 +1,266 @@
# Troubleshooting Vars
Quick reference for diagnosing and fixing vars issues. For basic usage, see the [Getting Started guide](vars-backend.md).
## Common Issues
### Generator Script Fails
**Symptom**: Error during `clan vars generate` or deployment
**Possible causes and solutions**:
1. **Missing runtime inputs**
```nix
# Wrong - missing required tool
runtimeInputs = [ ];
script = ''
openssl rand -hex 32 > $out/secret # openssl not found!
'';
# Correct
runtimeInputs = [ pkgs.openssl ];
```
2. **Wrong output path**
```nix
# Wrong - must use $out
script = ''
echo "secret" > ./myfile
'';
# Correct
script = ''
echo "secret" > $out/myfile
'';
```
3. **Missing declared files**
```nix
files."config" = { };
files."key" = { };
script = ''
# Wrong - only generates one file
echo "data" > $out/config
'';
# Correct - must generate all declared files
script = ''
echo "data" > $out/config
echo "key" > $out/key
'';
```
### Cannot Access Generated Files
**Symptom**: "attribute 'value' missing" or file not found
**Solutions**:
1. **Secret files don't have `.value`**
```nix
# Wrong - secret files can't use .value
files."secret" = { secret = true; };
# ...
environment.etc."app.conf".text =
config.clan.core.vars.generators.app.files."secret".value;
# Correct - use .path for secrets
environment.etc."app.conf".source =
config.clan.core.vars.generators.app.files."secret".path;
```
2. **Public files should use `.value`**
```nix
# Better for non-secrets
files."cert.pem" = { secret = false; };
# ...
sslCertificate =
config.clan.core.vars.generators.ca.files."cert.pem".value;
```
### Dependencies Not Available
**Symptom**: "No such file or directory" when accessing `$in/...`
**Solution**: Declare dependencies correctly
```nix
clan.core.vars.generators.child = {
# Wrong - missing dependency
script = ''
cat $in/parent/file > $out/newfile
'';
# Correct
dependencies = [ "parent" ];
script = ''
cat $in/parent/file > $out/newfile
'';
};
```
### Permission Denied
**Symptom**: Service cannot read generated secret file
**Solution**: Set correct ownership and permissions
```nix
files."service.key" = {
secret = true;
owner = "myservice"; # Match service user
group = "myservice";
mode = "0400"; # Read-only for owner
};
```
### Vars Not Regenerating
**Symptom**: Changes to generator script don't trigger regeneration
**Solution**: Use `--regenerate` flag
```bash
clan vars generate my-machine --generator my-generator --regenerate
```
### Prompts Not Working
**Symptom**: Script fails with "No such file or directory" for prompts
**Solution**: Access prompts correctly
```nix
# Wrong
script = ''
echo $password > $out/file
'';
# Correct
prompts.password.type = "hidden";
script = ''
cat $prompts/password > $out/file
'';
```
## Debugging Techniques
### 1. Check Generator Status
See what vars are set:
```bash
clan vars list my-machine
```
### 2. Inspect Generated Files
For shared vars:
```bash
ls -la vars/shared/my-generator/
```
For per-machine vars:
```bash
ls -la vars/per-machine/my-machine/my-generator/
```
### 3. Test Generators Locally
Create a test script to debug:
```nix
# test-generator.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.stdenv.mkDerivation {
name = "test-generator";
buildInputs = [ pkgs.openssl ]; # Your runtime inputs
buildCommand = ''
# Your generator script here
mkdir -p $out
openssl rand -hex 32 > $out/secret
ls -la $out/
'';
}
```
Run with:
```bash
nix-build test-generator.nix
```
### 4. Enable Debug Logging
Set debug mode:
```bash
clan --debug vars generate my-machine
```
### 5. Check File Permissions
Verify generated secret permissions:
```bash
# On the target machine
ls -la /run/secrets/
```
## Recovery Procedures
### Regenerate All Vars
If vars are corrupted or need refresh:
```bash
# Regenerate all for a machine
clan vars generate my-machine --regenerate
# Regenerate specific generator
clan vars generate my-machine --generator my-generator --regenerate
```
### Manual Secret Injection
For recovery or testing:
```bash
# Set a var manually (bypass generator)
echo "temporary-secret" | clan vars set my-machine my-generator/my-file
```
### Restore from Backup
Vars are stored in the repository:
```bash
# Restore previous version
git checkout HEAD~1 -- vars/
# Check and regenerate if needed
clan vars list my-machine
```
## Storage Backend Issues
### SOPS Decryption Fails
**Symptom**: "Failed to decrypt" or permission errors
**Solution**: Ensure your user/machine has the correct age keys configured. Clan manages encryption keys automatically based on the configured users and machines in your flake.
Check that:
1. Your machine is properly configured in the flake
2. Your user has access to the machine's secrets
3. The age key is available in the expected location
### Password Store Issues
**Symptom**: "pass: store not initialized"
**Solution**: Initialize password store:
```bash
export PASSWORD_STORE_DIR=/path/to/clan/vars
pass init your-gpg-key
```
## Getting Help
If these solutions don't resolve your issue:
1. Check the [clan-core issue tracker](https://git.clan.lol/clan/clan-core/issues)
2. Ask in the Clan community channels
3. Provide:
- The generator configuration
- The exact error message
- Output of `clan --debug vars generate`

View File

@@ -1,6 +0,0 @@
---
template: options.html
---
<iframe src="/options-page/" height="1000" width="100%"></iframe>

View File

@@ -4,7 +4,7 @@ This section of the site provides an overview of available options and commands
---
- [Clan Configuration Option](../options.md) - for defining a Clan
- [Clan Configuration Option](/options) - for defining a Clan
- Learn how to use the [Clan CLI](./cli/index.md)
- Explore available [services](./clanServices/index.md)
- [NixOS Configuration Options](./clan.core/index.md) - Additional options avilable on a NixOS machine.

52
flake.lock generated
View File

@@ -13,11 +13,11 @@
]
},
"locked": {
"lastModified": 1753067306,
"narHash": "sha256-jyoEbaXa8/MwVQ+PajUdT63y3gYhgD9o7snO/SLaikw=",
"rev": "18dfd42bdb2cfff510b8c74206005f733e38d8b9",
"lastModified": 1757300813,
"narHash": "sha256-JYQl+8nJYImg/inqotu9nEPcTXrRJixFN6sOfn6Tics=",
"rev": "b5f2157bcd26c73551374cd6e5b027b0119b2f3d",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/18dfd42bdb2cfff510b8c74206005f733e38d8b9.tar.gz"
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/b5f2157bcd26c73551374cd6e5b027b0119b2f3d.tar.gz"
},
"original": {
"type": "tarball",
@@ -31,11 +31,11 @@
]
},
"locked": {
"lastModified": 1754971456,
"narHash": "sha256-p04ZnIBGzerSyiY2dNGmookCldhldWAu03y0s3P8CB0=",
"lastModified": 1757255839,
"narHash": "sha256-XH33B1X888Xc/xEXhF1RPq/kzKElM0D5C9N6YdvOvIc=",
"owner": "nix-community",
"repo": "disko",
"rev": "8246829f2e675a46919718f9a64b71afe3bfb22d",
"rev": "c8a0e78d86b12ea67be6ed0f7cae7f9bfabae75a",
"type": "github"
},
"original": {
@@ -51,11 +51,11 @@
]
},
"locked": {
"lastModified": 1754487366,
"narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=",
"lastModified": 1756770412,
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18",
"rev": "4524271976b625a4a605beefd893f270620fd751",
"type": "github"
},
"original": {
@@ -71,11 +71,11 @@
]
},
"locked": {
"lastModified": 1755275010,
"narHash": "sha256-lEApCoWUEWh0Ifc3k1JdVjpMtFFXeL2gG1qvBnoRc2I=",
"lastModified": 1757430124,
"narHash": "sha256-MhDltfXesGH8VkGv3hmJ1QEKl1ChTIj9wmGAFfWj/Wk=",
"owner": "nix-darwin",
"repo": "nix-darwin",
"rev": "7220b01d679e93ede8d7b25d6f392855b81dd475",
"rev": "830b3f0b50045cf0bcfd4dab65fad05bf882e196",
"type": "github"
},
"original": {
@@ -86,11 +86,11 @@
},
"nix-select": {
"locked": {
"lastModified": 1745005516,
"narHash": "sha256-IVaoOGDIvAa/8I0sdiiZuKptDldrkDWUNf/+ezIRhyc=",
"rev": "69d8bf596194c5c35a4e90dd02c52aa530caddf8",
"lastModified": 1755887746,
"narHash": "sha256-lzWbpHKX0WAn/jJDoCijIDss3rqYIPawe46GDaE6U3g=",
"rev": "92c2574c5e113281591be01e89bb9ddb31d19156",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/nix-select/archive/69d8bf596194c5c35a4e90dd02c52aa530caddf8.tar.gz"
"url": "https://git.clan.lol/api/v1/repos/clan/nix-select/archive/92c2574c5e113281591be01e89bb9ddb31d19156.tar.gz"
},
"original": {
"type": "tarball",
@@ -99,11 +99,11 @@
},
"nixos-facter-modules": {
"locked": {
"lastModified": 1750412875,
"narHash": "sha256-uP9Xxw5XcFwjX9lNoYRpybOnIIe1BHfZu5vJnnPg3Jc=",
"lastModified": 1756491981,
"narHash": "sha256-lXyDAWPw/UngVtQfgQ8/nrubs2r+waGEYIba5UX62+k=",
"owner": "nix-community",
"repo": "nixos-facter-modules",
"rev": "14df13c84552a7d1f33c1cd18336128fbc43f920",
"rev": "c1b29520945d3e148cd96618c8a0d1f850965d8c",
"type": "github"
},
"original": {
@@ -115,10 +115,10 @@
"nixpkgs": {
"locked": {
"lastModified": 315532800,
"narHash": "sha256-moy1MfcGj+Pd+lU3PHYQUJq9OP0Evv9me8MjtmHlnRM=",
"rev": "32f313e49e42f715491e1ea7b306a87c16fe0388",
"narHash": "sha256-h8Sx4S+/0FpodZji6W9lHzwY5BcuUG85Aj3GfhvGC2o=",
"rev": "a650b5d0de99158323597f048667c4d914243224",
"type": "tarball",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre844992.32f313e49e42/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre845298.a650b5d0de99/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
@@ -181,11 +181,11 @@
]
},
"locked": {
"lastModified": 1754847726,
"narHash": "sha256-2vX8QjO5lRsDbNYvN9hVHXLU6oMl+V/PsmIiJREG4rE=",
"lastModified": 1756662192,
"narHash": "sha256-F1oFfV51AE259I85av+MAia221XwMHCOtZCMcZLK2Jk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "7d81f6fb2e19bf84f1c65135d1060d829fae2408",
"rev": "1aabc6c05ccbcbf4a635fb7a90400e44282f61c4",
"type": "github"
},
"original": {

View File

@@ -96,6 +96,7 @@
./nixosModules/flake-module.nix
./pkgs/flake-module.nix
./templates/flake-module.nix
./pkgs/clan-cli/clan_cli/tests/flake-module.nix
]
++ [
(if pathExists ./flakeModules/clan.nix then import ./flakeModules/clan.nix inputs.self else { })

View File

@@ -87,6 +87,8 @@ in
relativeDir = removePrefix "${self}/" (toString config.clan.directory);
update-vars = hostPkgs.writeShellScriptBin "update-vars" ''
set -x
export PRJ_ROOT=$(git rev-parse --show-toplevel)
${update-vars-script} $PRJ_ROOT/${relativeDir} ${testName}
'';

View File

@@ -328,7 +328,7 @@ rec {
# To get the type of a Deferred modules we need to know the interface of the place where it is evaluated.
# i.e. in case of a clan.service this is the interface of the service which dynamically changes depending on the service
# We assign "type" = []
# This means any value is valid — or like TypeScripts unknown.
# This means any value is valid — or like TypeScript's unknown.
# We can assign the type later, when we know the exact interface.
# tsType = "unknown" is a type that we preload for json2ts, such that it gets the correct type in typescript
(option.type.name == "deferredModule")

View File

@@ -245,6 +245,8 @@ in
in
{ config, ... }:
{
staticModules = clan-core.clan.modules;
distributedServices = clanLib.inventory.mapInstances {
inherit (clanConfig) inventory exportsModule;
inherit flakeInputs directory;

View File

@@ -639,7 +639,7 @@ in
Exports are used to share and expose information between instances.
Define exports in the [`perInstance`](#perInstance) or [`perMachine`](#perMachine) scope.
Define exports in the [`perInstance`](#roles.perInstance) or [`perMachine`](#perMachine) scope.
Accessing the exports:

View File

@@ -21,14 +21,14 @@ let
"secrets"
"templates"
];
clanSchema = jsonLib.parseOptions (lib.filterAttrs (n: _v: lib.elem n include) clanOpts) { };
clanSchemaNix = jsonLib.parseOptions (lib.filterAttrs (n: _v: lib.elem n include) clanOpts) { };
clan-schema-abstract = pkgs.stdenv.mkDerivation {
clanSchemaJson = pkgs.stdenv.mkDerivation {
name = "clan-schema-files";
buildInputs = [ pkgs.cue ];
src = ./.;
buildPhase = ''
export SCHEMA=${builtins.toFile "clan-schema.json" (builtins.toJSON clanSchema)}
export SCHEMA=${builtins.toFile "clan-schema.json" (builtins.toJSON clanSchemaNix)}
cp $SCHEMA schema.json
# Also generate a CUE schema version that is derived from the JSON schema
cue import -f -p compose -l '#Root:' schema.json
@@ -41,7 +41,7 @@ in
{
inherit
flakeOptions
clanSchema
clan-schema-abstract
clanSchemaNix
clanSchemaJson
;
}

View File

@@ -255,6 +255,16 @@ in
'';
};
installedAt = lib.mkOption {
type = types.nullOr types.int;
default = null;
description = ''
Indicates when the machine was first installed.
Timestamp is in unix time (seconds since epoch).
'';
};
tags = lib.mkOption {
description = ''
List of tags for the machine.

View File

@@ -27,7 +27,9 @@ in
default = { };
};
tags = lib.mkOption {
type = types.attrsOf (types.submodule { });
type = types.coercedTo (types.listOf types.str) (t: lib.genAttrs t (_: { })) (
types.attrsOf (types.submodule { })
);
default = { };
};
settings =

View File

@@ -23,6 +23,12 @@ let
};
in
{
options.staticModules = lib.mkOption {
readOnly = true;
type = lib.types.raw;
apply = moduleSet: lib.mapAttrs (inspectModule "<clan-core>") moduleSet;
};
options.modulesPerSource = lib.mkOption {
# { sourceName :: { moduleName :: {} }}
readOnly = true;

View File

@@ -1,3 +1,5 @@
"""Test driver for container-based NixOS testing."""
import argparse
import ctypes
import os
@@ -11,7 +13,7 @@ import uuid
from collections.abc import Callable
from contextlib import _GeneratorContextManager
from dataclasses import dataclass
from functools import cached_property
from functools import cache, cached_property
from pathlib import Path
from tempfile import NamedTemporaryFile, TemporaryDirectory
from typing import Any
@@ -20,23 +22,21 @@ from colorama import Fore, Style
from .logger import AbstractLogger, CompositeLogger, TerminalLogger
# Global flag to track if test environment has been initialized
_test_env_initialized = False
@cache
def init_test_environment() -> None:
"""Set up the test environment (network bridge, /etc/passwd) once."""
global _test_env_initialized
if _test_env_initialized:
return
# Set up network bridge
subprocess.run(
["ip", "link", "add", "br0", "type", "bridge"], check=True, text=True
["ip", "link", "add", "br0", "type", "bridge"],
check=True,
text=True,
)
subprocess.run(["ip", "link", "set", "br0", "up"], check=True, text=True)
subprocess.run(
["ip", "addr", "add", "192.168.1.254/24", "dev", "br0"], check=True, text=True
["ip", "addr", "add", "192.168.1.254/24", "dev", "br0"],
check=True,
text=True,
)
# Set up minimal passwd file for unprivileged operations
@@ -44,7 +44,7 @@ def init_test_environment() -> None:
passwd_content = """root:x:0:0:Root:/root:/bin/sh
nixbld:x:1000:100:Nix build user:/tmp:/bin/sh
nobody:x:65534:65534:Nobody:/:/bin/sh
"""
""" # noqa: S105 - This is not a password, it's a Unix passwd file format for testing
with NamedTemporaryFile(mode="w", delete=False, prefix="test-passwd-") as f:
f.write(passwd_content)
@@ -84,8 +84,6 @@ nogroup:x:65534:
errno = ctypes.get_errno()
raise OSError(errno, os.strerror(errno), "Failed to mount group")
_test_env_initialized = True
# Load the C library
libc = ctypes.CDLL("libc.so.6", use_errno=True)
@@ -111,8 +109,7 @@ def mount(
mountflags: int = 0,
data: str | None = None,
) -> None:
"""
A Python wrapper for the mount system call.
"""A Python wrapper for the mount system call.
:param source: The source of the file system (e.g., device name, remote filesystem).
:param target: The mount point (an existing directory).
@@ -129,7 +126,11 @@ def mount(
# Call the mount system call
result = libc.mount(
source_c, target_c, fstype_c, ctypes.c_ulong(mountflags), data_c
source_c,
target_c,
fstype_c,
ctypes.c_ulong(mountflags),
data_c,
)
if result != 0:
@@ -141,11 +142,11 @@ class Error(Exception):
pass
def prepare_machine_root(machinename: str, root: Path) -> None:
def prepare_machine_root(root: Path) -> None:
root.mkdir(parents=True, exist_ok=True)
root.joinpath("etc").mkdir(parents=True, exist_ok=True)
root.joinpath(".env").write_text(
"\n".join(f"{k}={v}" for k, v in os.environ.items())
"\n".join(f"{k}={v}" for k, v in os.environ.items()),
)
@@ -157,7 +158,6 @@ def retry(fn: Callable, timeout: int = 900) -> None:
"""Call the given function repeatedly, with 1 second intervals,
until it returns True or a timeout is reached.
"""
for _ in range(timeout):
if fn(False):
return
@@ -189,7 +189,7 @@ class Machine:
return self.get_systemd_process()
def start(self) -> None:
prepare_machine_root(self.name, self.rootdir)
prepare_machine_root(self.rootdir)
init_test_environment()
cmd = [
"systemd-nspawn",
@@ -212,8 +212,12 @@ class Machine:
self.process = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True, env=env)
def get_systemd_process(self) -> int:
assert self.process is not None, "Machine not started"
assert self.process.stdout is not None, "Machine has no stdout"
if self.process is None:
msg = "Machine not started"
raise RuntimeError(msg)
if self.process.stdout is None:
msg = "Machine has no stdout"
raise RuntimeError(msg)
for line in self.process.stdout:
print(line, end="")
@@ -230,9 +234,9 @@ class Machine:
.read_text()
.split()
)
assert len(childs) == 1, (
f"Expected exactly one child process for systemd-nspawn, got {childs}"
)
if len(childs) != 1:
msg = f"Expected exactly one child process for systemd-nspawn, got {childs}"
raise RuntimeError(msg)
try:
return int(childs[0])
except ValueError as e:
@@ -252,7 +256,9 @@ class Machine:
def tuple_from_line(line: str) -> tuple[str, str]:
match = line_pattern.match(line)
assert match is not None
if match is None:
msg = f"Failed to parse line: {line}"
raise RuntimeError(msg)
return match[1], match[2]
return dict(
@@ -262,8 +268,14 @@ class Machine:
)
def nsenter_command(self, command: str) -> list[str]:
nsenter = shutil.which("nsenter")
if not nsenter:
msg = "nsenter command not found"
raise RuntimeError(msg)
return [
"nsenter",
nsenter,
"--target",
str(self.container_pid),
"--mount",
@@ -280,12 +292,11 @@ class Machine:
def execute(
self,
command: str,
check_return: bool = True,
check_output: bool = True,
check_return: bool = True, # noqa: ARG002
check_output: bool = True, # noqa: ARG002
timeout: int | None = 900,
) -> subprocess.CompletedProcess:
"""
Execute a shell command, returning a list `(status, stdout)`.
"""Execute a shell command, returning a list `(status, stdout)`.
Commands are run with `set -euo pipefail` set:
@@ -316,21 +327,22 @@ class Machine:
`timeout` parameter, e.g., `execute(cmd, timeout=10)` or
`execute(cmd, timeout=None)`. The default is 900 seconds.
"""
# Always run command with shell opts
command = f"set -eo pipefail; source /etc/profile; set -xu; {command}"
proc = subprocess.run(
return subprocess.run(
self.nsenter_command(command),
env={},
timeout=timeout,
check=False,
stdout=subprocess.PIPE,
text=True,
)
return proc
def nested(
self, msg: str, attrs: dict[str, str] | None = None
self,
msg: str,
attrs: dict[str, str] | None = None,
) -> _GeneratorContextManager:
if attrs is None:
attrs = {}
@@ -339,8 +351,7 @@ class Machine:
return self.logger.nested(msg, my_attrs)
def systemctl(self, q: str) -> subprocess.CompletedProcess:
"""
Runs `systemctl` commands with optional support for
"""Runs `systemctl` commands with optional support for
`systemctl --user`
```py
@@ -355,8 +366,7 @@ class Machine:
return self.execute(f"systemctl {q}")
def wait_until_succeeds(self, command: str, timeout: int = 900) -> str:
"""
Repeat a shell command with 1-second intervals until it succeeds.
"""Repeat a shell command with 1-second intervals until it succeeds.
Has a default timeout of 900 seconds which can be modified, e.g.
`wait_until_succeeds(cmd, timeout=10)`. See `execute` for details on
command execution.
@@ -374,18 +384,17 @@ class Machine:
return output
def wait_for_open_port(
self, port: int, addr: str = "localhost", timeout: int = 900
self,
port: int,
addr: str = "localhost",
timeout: int = 900,
) -> None:
"""
Wait for a port to be open on the given address.
"""
"""Wait for a port to be open on the given address."""
command = f"nc -z {shlex.quote(addr)} {port}"
self.wait_until_succeeds(command, timeout=timeout)
def wait_for_file(self, filename: str, timeout: int = 30) -> None:
"""
Waits until the file exists in the machine's file system.
"""
"""Waits until the file exists in the machine's file system."""
def check_file(_last_try: bool) -> bool:
result = self.execute(f"test -e {filename}")
@@ -395,8 +404,7 @@ class Machine:
retry(check_file, timeout)
def wait_for_unit(self, unit: str, timeout: int = 900) -> None:
"""
Wait for a systemd unit to get into "active" state.
"""Wait for a systemd unit to get into "active" state.
Throws exceptions on "failed" and "inactive" states as well as after
timing out.
"""
@@ -441,9 +449,7 @@ class Machine:
return res.stdout
def shutdown(self) -> None:
"""
Shut down the machine, waiting for the VM to exit.
"""
"""Shut down the machine, waiting for the VM to exit."""
if self.process:
self.process.terminate()
self.process.wait()
@@ -557,7 +563,7 @@ class Driver:
rootdir=tempdir_path / container.name,
out_dir=self.out_dir,
logger=self.logger,
)
),
)
def start_all(self) -> None:
@@ -575,13 +581,15 @@ class Driver:
# We lauch a sleep here, so we can pgrep the process cmdline for
# the uuid
sleep = shutil.which("sleep")
assert sleep is not None, "sleep command not found"
if sleep is None:
msg = "sleep command not found"
raise RuntimeError(msg)
machine.execute(
f"systemd-run /bin/sh -c '{sleep} 999999999 && echo {nspawn_uuid}'",
)
print(
f"To attach to container {machine.name} run on the same machine that runs the test:"
f"To attach to container {machine.name} run on the same machine that runs the test:",
)
print(
" ".join(
@@ -603,8 +611,8 @@ class Driver:
"-c",
"bash",
Style.RESET_ALL,
]
)
],
),
)
def test_symbols(self) -> dict[str, Any]:
@@ -623,13 +631,13 @@ class Driver:
"additionally exposed symbols:\n "
+ ", ".join(m.name for m in self.machines)
+ ",\n "
+ ", ".join(list(general_symbols.keys()))
+ ", ".join(list(general_symbols.keys())),
)
return {**general_symbols, **machine_symbols}
def test_script(self) -> None:
"""Run the test script"""
exec(self.testscript, self.test_symbols(), None)
exec(self.testscript, self.test_symbols(), None) # noqa: S102
def run_tests(self) -> None:
"""Run the test script (for non-interactive test runs)"""

View File

@@ -25,27 +25,31 @@ class AbstractLogger(ABC):
@abstractmethod
@contextmanager
def subtest(
self, name: str, attributes: dict[str, str] | None = None
self,
name: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
pass
@abstractmethod
@contextmanager
def nested(
self, message: str, attributes: dict[str, str] | None = None
self,
message: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
pass
@abstractmethod
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def info(self, *args: Any, **kwargs: Any) -> None:
pass
@abstractmethod
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def warning(self, *args: Any, **kwargs: Any) -> None:
pass
@abstractmethod
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def error(self, *args: Any, **kwargs: Any) -> None:
pass
@abstractmethod
@@ -59,6 +63,8 @@ class AbstractLogger(ABC):
class JunitXMLLogger(AbstractLogger):
class TestCaseState:
"""State tracking for individual test cases in JUnit XML reports."""
def __init__(self) -> None:
self.stdout = ""
self.stderr = ""
@@ -66,7 +72,7 @@ class JunitXMLLogger(AbstractLogger):
def __init__(self, outfile: Path) -> None:
self.tests: dict[str, JunitXMLLogger.TestCaseState] = {
"main": self.TestCaseState()
"main": self.TestCaseState(),
}
self.currentSubtest = "main"
self.outfile: Path = outfile
@@ -74,12 +80,16 @@ class JunitXMLLogger(AbstractLogger):
atexit.register(self.close)
def log(self, message: str, attributes: dict[str, str] | None = None) -> None:
del attributes # Unused but kept for API compatibility
self.tests[self.currentSubtest].stdout += message + os.linesep
@contextmanager
def subtest(
self, name: str, attributes: dict[str, str] | None = None
self,
name: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
del attributes # Unused but kept for API compatibility
old_test = self.currentSubtest
self.tests.setdefault(name, self.TestCaseState())
self.currentSubtest = name
@@ -90,18 +100,24 @@ class JunitXMLLogger(AbstractLogger):
@contextmanager
def nested(
self, message: str, attributes: dict[str, str] | None = None
self,
message: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
del attributes # Unused but kept for API compatibility
self.log(message)
yield
def info(self, *args: Any, **kwargs: Any) -> None:
del kwargs # Unused but kept for API compatibility
self.tests[self.currentSubtest].stdout += args[0] + os.linesep
def warning(self, *args: Any, **kwargs: Any) -> None:
del kwargs # Unused but kept for API compatibility
self.tests[self.currentSubtest].stdout += args[0] + os.linesep
def error(self, *args: Any, **kwargs: Any) -> None:
del kwargs # Unused but kept for API compatibility
self.tests[self.currentSubtest].stderr += args[0] + os.linesep
self.tests[self.currentSubtest].failure = True
@@ -144,7 +160,9 @@ class CompositeLogger(AbstractLogger):
@contextmanager
def subtest(
self, name: str, attributes: dict[str, str] | None = None
self,
name: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
with ExitStack() as stack:
for logger in self.logger_list:
@@ -153,22 +171,24 @@ class CompositeLogger(AbstractLogger):
@contextmanager
def nested(
self, message: str, attributes: dict[str, str] | None = None
self,
message: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
with ExitStack() as stack:
for logger in self.logger_list:
stack.enter_context(logger.nested(message, attributes))
yield
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
for logger in self.logger_list:
logger.info(*args, **kwargs)
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
for logger in self.logger_list:
logger.warning(*args, **kwargs)
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
for logger in self.logger_list:
logger.error(*args, **kwargs)
sys.exit(1)
@@ -200,19 +220,24 @@ class TerminalLogger(AbstractLogger):
@contextmanager
def subtest(
self, name: str, attributes: dict[str, str] | None = None
self,
name: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
with self.nested("subtest: " + name, attributes):
yield
@contextmanager
def nested(
self, message: str, attributes: dict[str, str] | None = None
self,
message: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
self._eprint(
self.maybe_prefix(
Style.BRIGHT + Fore.GREEN + message + Style.RESET_ALL, attributes
)
Style.BRIGHT + Fore.GREEN + message + Style.RESET_ALL,
attributes,
),
)
tic = time.time()
@@ -220,13 +245,13 @@ class TerminalLogger(AbstractLogger):
toc = time.time()
self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)")
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
self.log(*args, **kwargs)
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
self.log(*args, **kwargs)
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
self.log(*args, **kwargs)
def print_serial_logs(self, enable: bool) -> None:
@@ -259,7 +284,9 @@ class XMLLogger(AbstractLogger):
return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C")
def maybe_prefix(
self, message: str, attributes: dict[str, str] | None = None
self,
message: str,
attributes: dict[str, str] | None = None,
) -> str:
if attributes and "machine" in attributes:
return f"{attributes['machine']}: {message}"
@@ -270,13 +297,13 @@ class XMLLogger(AbstractLogger):
self.xml.characters(message)
self.xml.endElement("line")
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def info(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
self.log(*args, **kwargs)
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def warning(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
self.log(*args, **kwargs)
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore
def error(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def]
self.log(*args, **kwargs)
def log(self, message: str, attributes: dict[str, str] | None = None) -> None:
@@ -309,14 +336,18 @@ class XMLLogger(AbstractLogger):
@contextmanager
def subtest(
self, name: str, attributes: dict[str, str] | None = None
self,
name: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
with self.nested("subtest: " + name, attributes):
yield
@contextmanager
def nested(
self, message: str, attributes: dict[str, str] | None = None
self,
message: str,
attributes: dict[str, str] | None = None,
) -> Iterator[None]:
if attributes is None:
attributes = {}

View File

@@ -8,6 +8,10 @@
{
imports = lib.optional (_class == "nixos") (
lib.mkIf config.clan.core.enableRecommendedDefaults {
# Enable automatic state-version generation.
clan.core.settings.state-version.enable = lib.mkDefault true;
# Use systemd during boot as well except:
# - systems with raids as this currently require manual configuration: https://github.com/NixOS/nixpkgs/issues/210210
# - for containers we currently rely on the `stage-2` init script that sets up our /etc
@@ -37,6 +41,7 @@
};
config = lib.mkIf config.clan.core.enableRecommendedDefaults {
# This disables the HTML manual and `nixos-help` command but leaves
# `man configuration.nix`
documentation.doc.enable = lib.mkDefault false;

View File

@@ -1,40 +1,17 @@
{ ... }:
{
perSystem =
{ ... }:
{
clan.nixosTests.machine-id = {
perSystem.clan.nixosTests.machine-id = {
name = "service-machine-id";
name = "service-machine-id";
clan = {
directory = ./.;
# Workaround until we can use nodes.server = { };
modules."@clan/importer" = ../../../../clanServices/importer;
inventory = {
machines.server = { };
instances.importer = {
module.name = "@clan/importer";
module.input = "self";
roles.default.tags.all = { };
roles.default.extraModules = [
{
# Test machine ID generation
clan.core.settings.machine-id.enable = true;
}
];
};
};
};
# TODO: Broken. Use instead of importer after fixing.
# nodes.server = { };
# This is not an actual vm test, this is a workaround to
# generate the needed vars for the eval test.
testScript = "";
clan = {
directory = ./.;
machines.server = {
clan.core.settings.machine-id.enable = true;
};
};
# This is not an actual vm test, this is a workaround to
# generate the needed vars for the eval test.
testScript = "";
};
}

View File

@@ -10,30 +10,14 @@
clan = {
directory = ./.;
# Workaround until we can use nodes.machine = { };
modules."@clan/importer" = ../../../../clanServices/importer;
inventory = {
machines.machine = { };
instances.importer = {
module.name = "@clan/importer";
module.input = "self";
roles.default.tags.all = { };
roles.default.extraModules = [
{
clan.core.postgresql.enable = true;
clan.core.postgresql.users.test = { };
clan.core.postgresql.databases.test.create.options.OWNER = "test";
clan.core.settings.directory = ./.;
}
];
};
machines.machine = {
clan.core.postgresql.enable = true;
clan.core.postgresql.users.test = { };
clan.core.postgresql.databases.test.create.options.OWNER = "test";
clan.core.settings.directory = ./.;
};
};
# TODO: Broken. Use instead of importer after fixing.
# nodes.machine = { };
testScript =
let
runpg = "runuser -u postgres -- /run/current-system/sw/bin/psql";

View File

@@ -9,28 +9,11 @@
clan = {
directory = ./.;
# Workaround until we can use nodes.server = { };
modules."@clan/importer" = ../../../../clanServices/importer;
inventory = {
machines.server = { };
instances.importer = {
module.name = "@clan/importer";
module.input = "self";
roles.default.tags.all = { };
roles.default.extraModules = [
{
clan.core.settings.state-version.enable = true;
}
];
};
machines.server = {
clan.core.settings.state-version.enable = true;
};
};
# TODO: Broken. Use instead of importer after fixing.
# nodes.server = { };
# This is not an actual vm test, this is a workaround to
# generate the needed vars for the eval test.
testScript = "";

View File

@@ -290,9 +290,11 @@ in
};
owner = mkOption {
description = "The user name or id that will own the file.";
type = str;
default = "root";
};
group = mkOption {
type = str;
description = "The group name or id that will own the file.";
default = if _class == "darwin" then "wheel" else "root";
defaultText = lib.literalExpression ''if _class == "darwin" then "wheel" else "root"'';
@@ -302,6 +304,15 @@ in
description = "The unix file mode of the file. Must be a 4-digit octal number.";
default = "0400";
};
exists = mkOption {
description = ''
Returns true if the file exists, This is used to guard against reading not set value in evaluation.
This currently only works for non secret files.
'';
type = bool;
default = if file.config.secret then throw "Cannot determine existance of secret file" else false;
defaultText = "Throws error because the existance of a secret file cannot be determined";
};
value =
mkOption {
description = ''

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