Compare commits

...

174 commits

Author SHA1 Message Date
Chris Kruining
ccef5caba0
feat: improve justfiles 2025-11-27 11:44:18 +01:00
Chris Kruining
8da8f78ea4
trying some stuff 2025-11-27 11:15:49 +01:00
Chris Kruining
2d3da197ee
lets actually commit for once...
Some checks failed
Test action / kaas (push) Failing after 1s
2025-11-20 00:05:34 +01:00
Chris Kruining
169b62e6f3
chore: update config after update 2025-11-19 11:49:09 +01:00
09e4e940bc chore: update dependencies 2025-11-19 10:27:29 +00:00
ba246b145f chore(secrets): set secret "prowlarr/apikey" for machine "ulmo" 2025-11-19 09:51:27 +00:00
d0e374c8bb chore(secrets): set secret "lidarr/apikey" for machine "ulmo" 2025-11-19 09:51:06 +00:00
6a0195587d chore(secrets): set secret "sonarr/apikey" for machine "ulmo" 2025-11-19 09:50:58 +00:00
80e61ec5d8 chore(secrets): set secret "radarr/apikey" for machine "ulmo" 2025-11-19 09:50:35 +00:00
9116361b90 chore(secrets): set secret "radarr/apikey" for machine "ulmo" 2025-11-19 09:48:56 +00:00
272f48a9ab chore(secrets): set secret "kaas" for machine "ulmo" 2025-11-13 07:50:45 +00:00
Chris Kruining
4e09252e75
feat(zitadel): add remapping of exported keys 2025-11-12 17:26:17 +01:00
Chris Kruining
fa37c3eb50
feat(zitadel): add extra users via secrets 2025-11-12 17:23:40 +01:00
Chris Kruining
df5dfa61a9
fix(justfile): escape double quotes for inputs 2025-11-12 17:20:21 +01:00
4dc24de8eb chore(secrets): set secret "zitadel/users" for machine "ulmo" 2025-11-12 16:13:37 +00:00
91d8a32239 chore(secrets): set secret "zitadel/users" for machine "ulmo" 2025-11-12 16:13:10 +00:00
9a664b2438 chore(secrets): set secret "zitadel/users" for machine "ulmo" 2025-11-12 13:40:34 +00:00
8203f653f9 chore(secrets): set secret "zitadel/users" for machine "ulmo" 2025-11-12 13:40:15 +00:00
9a3f154cab chore(secrets): removed secret "zitadel/nix/users" from machine "ulmo" 2025-11-12 13:40:07 +00:00
c5ec450517 chore(secrets): removed secret "zitadel/users" from machine "ulmo" 2025-11-12 13:36:56 +00:00
983f1aa7d8 chore(secrets): set secret "zitadel/nix/users" for machine "ulmo" 2025-11-12 13:36:42 +00:00
cebc2ec040 chore(secrets): removed secret "test" from machine "ulmo" 2025-11-12 13:31:42 +00:00
4c3adb782c chore(secrets): set secret "zitadel/users" for machine "ulmo" 2025-11-12 13:31:01 +00:00
d61e9e19ca chore(secrets): set secret "zitadel/users" for machine "ulmo" 2025-11-12 13:13:06 +00:00
95f115f04c chore(secrets): removed secret "users" from machine "ulmo" 2025-11-12 13:12:57 +00:00
d02f5fc4ee chore(secrets): set secret "users" for machine "ulmo" 2025-11-12 13:12:27 +00:00
c6f1e93f7e chore(secrets): removed secret "test/users" from machine "ulmo" 2025-11-12 13:12:15 +00:00
6fd6b74a74 chore(secrets): removed secret "test.users" from machine "ulmo" 2025-11-12 13:11:36 +00:00
61deef854f chore(secrets): set secret "test/users" for machine "ulmo" 2025-11-12 13:11:05 +00:00
5ff60d46c7 chore(secrets): set secret "test.users" for machine "ulmo" 2025-11-12 13:09:40 +00:00
Chris Kruining
e3238aa60c
chore: re-harden matrix server
Some checks failed
Test action / kaas (push) Failing after 1s
2025-11-05 09:34:08 +01:00
Chris Kruining
c64e98e0c0
chore: clean up code 2025-11-05 09:32:30 +01:00
Chris Kruining
5f92a37996
feat(Forgejo): enable mirroring 2025-11-04 15:10:02 +01:00
Chris Kruining
2e81d16f24
chore: suppress error messages
They dirty the output too much when nix fails
2025-11-04 15:09:41 +01:00
Chris Kruining
e7cedfb639
fix(Zitadel): filter out empty roles 2025-11-04 15:08:54 +01:00
Chris Kruining
fab1df76c7
chore: update commit message in just recipes 2025-11-04 13:31:15 +01:00
Chris Kruining
c98b3eefe1
feat: set up clan cli 2025-11-04 13:30:34 +01:00
Chris Kruining
2402ec0761
fix(synapse): add user mapping to fix login via sso 2025-11-04 09:46:19 +01:00
Chris Kruining
5668e1048d
chore: create temporary extra user in zitadel
Some checks failed
Test action / kaas (push) Failing after 1s
2025-11-03 16:47:09 +01:00
Chris Kruining
8104ba7e93
feat(zitadel): change the default value of the username to the key instead of the email.
This should ensure that binding to the apps goes more smoothly
2025-11-03 16:36:19 +01:00
Chris Kruining
7100d1c59c
restart synapse when secrets change 2025-11-03 16:33:08 +01:00
7125d8d375 ops(secrets): set secret "synapse/oidc_secret" for machine "ulmo" 2025-11-03 15:23:12 +00:00
13697bfc51 ops(secrets): set secret "synapse/oidc_id" for machine "ulmo" 2025-11-03 15:22:55 +00:00
Chris Kruining
9b819a2a58
feat(forgejo): update config to use secrets
Some checks failed
Test action / kaas (push) Failing after 1s
2025-11-03 15:19:41 +01:00
Chris Kruining
f33f05a5b6
feat(zitadel): implement and use even more of the zitadel API 2025-11-03 15:18:53 +01:00
01f9340cfb ops(secrets): set secret "synapse/oidc_secret" for machine "ulmo" 2025-10-30 20:58:02 +00:00
15103b16ba ops(secrets): set secret "synapse/oidc_id" for machine "ulmo" 2025-10-30 20:57:39 +00:00
Chris Kruining
138bb67ffb
feat(just): add assert utility function/recipe 2025-10-30 21:26:18 +01:00
b11ca6bd05 ops(secrets): set secret "forgejo/action_runner_token" for machine "ulmo" 2025-10-30 14:24:06 +00:00
eac33f7cef ops(secrets): set secret "forgejo/action_runner_token" for machine "ulmo" 2025-10-30 14:12:56 +00:00
7edfdf92e0 ops(secrets): set secret "forgejo/action_runner_token" for machine "ulmo" 2025-10-30 14:07:56 +00:00
7b9e07ee4b ops(secrets): set secret "forgejo/action_runner_token" for machine "ulmo" 2025-10-30 14:07:04 +00:00
5157a57f32
feat(zed): add just language server plugin
Some checks failed
Test action / kaas (push) Failing after 1s
2025-10-27 21:13:20 +01:00
Chris Kruining
84cc5ff5c4
feat(zitadel): expand terranix resources
Some checks failed
Test action / kaas (push) Failing after 1s
WOOP WOOP, it all works!
now the next, big, huge, giant, hurdle to overcome is the chicken and egg problem of needing zitadel to generate values that I need inside the nix config of synapse, forgejo, and jellyfin
2025-10-27 17:07:51 +01:00
6c9667831a ops(secrets): set secret "zitadel/masterKey" for machine "ulmo" 2025-10-27 13:11:42 +00:00
Chris Kruining
e92f2cf82c
add some commands to read secret
values
2025-10-27 11:34:11 +01:00
334c0b54cc ops(secrets): removed secret "email/info@amarth.cloud" from machine "ulmo" 2025-10-27 07:41:12 +00:00
Chris Kruining
f390d41955
WIP: trying to get smtp configured for zitadel
Some checks failed
Test action / kaas (push) Failing after 1s
2025-10-23 16:31:56 +02:00
Chris Kruining
4f0d0f7f0e
fix: various fixes to just commands 2025-10-23 16:31:19 +02:00
47df6b544a ops(secrets): set secret "email/info_amarth_cloud" for machine "ulmo" 2025-10-23 14:26:00 +00:00
34fd079fb7 ops(secrets): removed secret "email/chris@kruining.eu" from machine "ulmo" 2025-10-23 14:23:40 +00:00
5f0f986c59 ops(secrets): set secret "email/chris_kruining_eu" for machine "ulmo" 2025-10-23 14:23:22 +00:00
fe628075d9 ops(secrets): removed secret "zitadel/masterkey" from machine "ulmo" 2025-10-23 13:58:11 +00:00
dd9e79b889 ops(secrets): removed secret "je_moeder" from machine "ulmo" 2025-10-23 12:53:40 +00:00
Chris Kruining
352c057652
refactor: tidy up zitadel service module 2025-10-23 14:50:42 +02:00
Chris Kruining
e3ae7220d3
fix(stylix): add zen-browser profile 2025-10-23 14:49:47 +02:00
Chris Kruining
e9fef516ec
feat(sops): finally somewhat properly set up with sops 2025-10-23 14:47:53 +02:00
40da937ee0 ops(secrets): set secret "je_moeder/0/awesome/2" for machine "ulmo" 2025-10-23 12:45:28 +00:00
e17b144c9f ops(secrets): removed secret "je_moeder" from machine "ulmo" 2025-10-23 12:45:25 +00:00
a8dbf792e3 ops(secrets): removed secret "je_moeder/0/awesome/2" from machine "ulmo" 2025-10-23 12:44:08 +00:00
b11a33de6e ops(secrets): removed secret "je_moeder" from machine "ulmo" 2025-10-23 12:43:51 +00:00
Chris Kruining
1873bb7170
initial implementation of terranix for zitadel. SUPER HAPPY, SUPER COOL!!!
Some checks failed
Test action / kaas (push) Failing after 1s
2025-10-22 23:26:47 +02:00
Chris Kruining
81e1574023
some fixes
Some checks failed
Test action / kaas (push) Failing after 1s
2025-10-21 09:01:22 +02:00
Chris Kruining
f62fa502db
fix zitadel 2025-10-20 10:28:23 +02:00
Chris Kruining
6111ec165b move zitadel back to kruining.eu
Some checks failed
Test action / kaas (push) Failing after 1s
2025-10-16 12:54:29 +00:00
Chris Kruining
09a004ad9a fix some ulmo config 2025-10-16 12:54:29 +00:00
ac0a2d523e
.
Some checks failed
Test action / kaas (push) Failing after 0s
2025-10-15 21:18:12 +02:00
d7dc0c1428
update deps
Some checks failed
Test action / kaas (push) Failing after 1s
2025-10-14 18:33:28 +02:00
22383b005a
renamed options
Some checks failed
Test action / kaas (push) Failing after 0s
2025-10-08 20:35:16 +02:00
ce2002884e
fix updated option
Some checks are pending
Test action / kaas (push) Waiting to run
2025-10-08 20:25:39 +02:00
96dc1d47e6
update deps
Some checks are pending
Test action / kaas (push) Waiting to run
2025-10-08 20:21:38 +02:00
Chris Kruining
8c6fe96e59 kaas
Some checks are pending
Test action / kaas (push) Waiting to run
2025-10-08 18:17:50 +00:00
Chris Kruining
0fd9b0264f add static ip's 2025-10-08 18:17:50 +00:00
e55ec9c323
Update flake.lock
Some checks failed
Test action / kaas (push) Failing after 0s
2025-09-17 23:02:17 +02:00
188988f930
disable password auth for matrix
Some checks failed
Test action / kaas (push) Failing after 1s
2025-09-14 22:13:19 +02:00
6ed8bd861b
start borg backups
Some checks failed
Test action / kaas (push) Failing after 1s
2025-09-14 22:03:45 +02:00
1a4746819b
- fix matrix clients
- fix zen
- uuuugh, stupid home-manager...
2025-09-14 22:03:21 +02:00
d35165ebc0
add sso support for matrix server 2025-09-14 22:01:09 +02:00
3816942600
finally have the matrix bridges working! 2025-09-14 22:00:53 +02:00
992ddba373
rename matrix module 2025-09-11 22:09:47 +02:00
953c238a47
fix nix config
Some checks failed
Test action / kaas (push) Failing after 1s
2025-09-11 22:03:10 +02:00
Chris Kruining
d74f67e4fb
switch to synapse away from conduit
Some checks failed
Test action / kaas (push) Failing after 1s
2025-09-11 16:43:54 +02:00
Chris Kruining
d4eff47049
finally have a working matrix set up
Some checks failed
Test action / kaas (push) Failing after 1s
2025-09-11 10:53:17 +02:00
Chris Kruining
cc2f7bbea4
replace nheko with fractal 2025-09-11 10:53:10 +02:00
Chris Kruining
9ebe4fd4e7
alright, time to try it 2025-09-08 16:24:36 +02:00
Chris Kruining
2a79a4eb63
next iteration for forgejo runners 2025-09-08 16:18:02 +02:00
Chris Kruining
1d6f488ebd
.
Some checks failed
Test action / Print hello world (push) Failing after 2m46s
2025-09-08 16:14:15 +02:00
Chris Kruining
ec827c4187
update pipeline
Some checks failed
Test action / Print hello world (push) Failing after 1m51s
2025-09-08 09:03:27 +02:00
fe5cce0946
initial conduit setup
Some checks failed
Test action / Print hello world (push) Failing after 9s
2025-09-07 22:26:09 +02:00
ce7b147d04
move runner
Some checks failed
Test action / Print hello world (push) Failing after 9s
2025-09-07 20:47:45 +02:00
7f6f1166a4
add backup extension for home manager 2025-09-07 20:47:33 +02:00
288e354edf
add nheko 2025-09-07 20:06:56 +02:00
0689c338ac
solve compilation errors 2025-09-07 18:12:08 +02:00
2ca6339fe6
fix typo 2025-09-07 18:11:36 +02:00
98c9424db5
aaha, there is the code I forgot to commit...
Some checks failed
Test action / Print hello world (push) Failing after 1m52s
2025-09-07 17:30:52 +02:00
Chris Kruining
d3e7de5f5a
asdf
Some checks failed
Test action / Print hello world (push) Failing after 1m54s
2025-09-04 15:57:29 +02:00
Chris Kruining
7ac547bd81
parameterize git clone 2025-09-04 15:55:58 +02:00
Chris Kruining
f31317304e
riiight, should've seen that one coming....
Some checks failed
Test action / Print hello world (push) Failing after 1m53s
2025-09-04 15:53:35 +02:00
Chris Kruining
cd53e4c008
sdfasdfg
Some checks failed
Test action / Print hello world (push) Failing after 1m49s
2025-09-04 15:50:38 +02:00
Chris Kruining
522041cbae
waaaaaaggh
Some checks failed
Test action / Print hello world (push) Failing after 1m50s
2025-09-04 15:47:37 +02:00
Chris Kruining
8b9e1a14a8
,...
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 15:47:10 +02:00
Chris Kruining
a0e2d8db71
.
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 15:46:25 +02:00
Chris Kruining
7070382596
runAsRoot requires kvm...
Some checks failed
Test action / Print hello world (push) Failing after 1m50s
2025-09-04 15:43:18 +02:00
Chris Kruining
1cbfb6b5c0
.
Some checks failed
Test action / Print hello world (push) Failing after 27s
2025-09-04 15:34:40 +02:00
Chris Kruining
237d208e93
siiiiigh
Some checks failed
Test action / Print hello world (push) Failing after 29s
2025-09-04 15:28:59 +02:00
Chris Kruining
a114f0a7f8
.
Some checks failed
Test action / Print hello world (push) Failing after 1m47s
2025-09-04 15:26:18 +02:00
Chris Kruining
3aaad47c2b
whoops
Some checks failed
Test action / Print hello world (push) Failing after 1m49s
2025-09-04 15:23:23 +02:00
Chris Kruining
3d02de9c6c
I really don't get it anymore...
Some checks failed
Test action / Print hello world (push) Failing after 1m49s
2025-09-04 15:20:38 +02:00
Chris Kruining
a39cb0cf53
?
Some checks failed
Test action / Print hello world (push) Failing after 22s
2025-09-04 15:19:14 +02:00
Chris Kruining
898cb6c512
local builds again
Some checks failed
Test action / Print hello world (push) Failing after 17s
2025-09-04 15:17:49 +02:00
Chris Kruining
66e400e7c0
uuuuuugh
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 15:11:32 +02:00
Chris Kruining
61505943f9
add base image
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 15:09:34 +02:00
Chris Kruining
e0c37a10a5
another attempt
Some checks failed
Test action / Print hello world (push) Failing after 21s
2025-09-04 15:08:48 +02:00
Chris Kruining
2653f3fc93
sooooo lost right now....
Some checks failed
Test action / Print hello world (push) Failing after 20s
2025-09-04 15:05:40 +02:00
Chris Kruining
e0002d7254
shadowSetup than???
Some checks failed
Test action / Print hello world (push) Failing after 20s
2025-09-04 15:00:37 +02:00
Chris Kruining
22333b143b
hmmmmm
Some checks failed
Test action / Print hello world (push) Failing after 21s
2025-09-04 14:58:31 +02:00
Chris Kruining
40cd9d3745
is it podman that needs the kvm?
Some checks failed
Test action / Print hello world (push) Failing after 26s
2025-09-04 14:56:44 +02:00
Chris Kruining
101bf12909
fix warning 2025-09-04 14:55:37 +02:00
Chris Kruining
09a5df6253
fix?
Some checks failed
Test action / Print hello world (push) Failing after 30s
2025-09-04 14:53:50 +02:00
Chris Kruining
b158df262e
ugh
Some checks failed
Test action / Print hello world (push) Failing after 12s
2025-09-04 14:07:06 +02:00
Chris Kruining
716342d556
.
Some checks failed
Test action / Print hello world (push) Failing after 12s
2025-09-04 14:02:34 +02:00
Chris Kruining
e4843997ea
add credentials, but then why do I need to log in????
Some checks failed
Test action / Print hello world (push) Failing after 12s
2025-09-04 13:58:51 +02:00
Chris Kruining
9c048aca05
hmmmm
Some checks failed
Test action / Print hello world (push) Failing after 12s
2025-09-04 13:56:16 +02:00
Chris Kruining
d917f93a9f
finally some more success?????
Some checks failed
Test action / Print hello world (push) Failing after 12s
2025-09-04 13:55:13 +02:00
Chris Kruining
b8e43fedba
lets try another avenue...
Some checks failed
Test action / Print hello world (push) Failing after 13s
2025-09-04 13:47:02 +02:00
Chris Kruining
33f9a7fbd8
fix package conflict?
Some checks failed
Test action / Print hello world (push) Failing after 7s
2025-09-04 13:24:37 +02:00
Chris Kruining
7d7c3aa53a
.
Some checks failed
Test action / Print hello world (push) Failing after 16s
2025-09-04 13:22:43 +02:00
Chris Kruining
c7f3ed7cd6
.
Some checks failed
Test action / Print hello world (push) Failing after 7s
2025-09-04 13:21:05 +02:00
Chris Kruining
b2cb74657e
ahhh shit, here we go again
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 13:11:35 +02:00
Chris Kruining
25ae5ea1ac
next round
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 13:09:31 +02:00
Chris Kruining
833f4ce5e6
just fuse, got it
Some checks failed
Test action / Print hello world (push) Failing after 24s
2025-09-04 12:09:44 +02:00
Chris Kruining
55d5ea4839
is it a missing dep????
Some checks failed
Test action / Print hello world (push) Failing after 2s
2025-09-04 12:08:38 +02:00
Chris Kruining
efd98d4b44
gotta love the typos...
Some checks failed
Test action / Print hello world (push) Failing after 25s
2025-09-04 12:05:12 +02:00
Chris Kruining
9ea18b18d5
.
Some checks failed
Test action / Print hello world (push) Failing after 7s
2025-09-04 12:04:28 +02:00
Chris Kruining
68f6620383
right
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 12:03:26 +02:00
Chris Kruining
a42446985c
another attempt
Some checks failed
Test action / Print hello world (push) Failing after 7s
2025-09-04 12:02:40 +02:00
Chris Kruining
4d4f4e67e0
add registry?
Some checks failed
Test action / Print hello world (push) Failing after 7s
2025-09-04 11:23:50 +02:00
Chris Kruining
f9328cd72e
I am an idiot, as proven once more...
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 11:22:59 +02:00
Chris Kruining
b3a9ea6057
.
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 11:19:43 +02:00
Chris Kruining
8b07f55593
.
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 11:14:41 +02:00
Chris Kruining
4a26a4ad11
.
Some checks failed
Test action / Print hello world (push) Failing after 7s
2025-09-04 11:13:15 +02:00
Chris Kruining
fdf1bc34e8
.
Some checks failed
Test action / Print hello world (push) Failing after 9s
2025-09-04 11:11:06 +02:00
Chris Kruining
da1a4d42ed
woooot, more success!!!
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 11:07:58 +02:00
Chris Kruining
4762d4189e
right. obviously...
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 11:06:57 +02:00
Chris Kruining
fa0a4917a2
cool shizzle
Some checks failed
Test action / Print hello world (push) Failing after 1s
2025-09-04 11:04:13 +02:00
Chris Kruining
0d6fb5aab6
update default runner dockerfile 2025-09-04 10:39:31 +02:00
Chris Kruining
e048ada01f
whoops 2025-09-04 10:38:46 +02:00
Chris Kruining
863956c38b
oooooh, closer
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 10:17:08 +02:00
Chris Kruining
95f6b2b8d3
nixpkgs instead????
Some checks failed
Test action / Print hello world (push) Failing after 8s
2025-09-04 10:14:44 +02:00
Chris Kruining
2b887f188c
aaaaaiiii
Some checks failed
Test action / Print hello world (push) Failing after 2s
2025-09-04 10:14:06 +02:00
Chris Kruining
0b23548559
whoopsie
Some checks failed
Test action / Print hello world (push) Failing after 1s
2025-09-04 10:11:59 +02:00
Chris Kruining
9ed5cbded0
update homer
Some checks failed
Test action / Print hello world (push) Failing after 0s
2025-09-04 10:09:08 +02:00
Chris Kruining
41a4fde9f2
first attempt to push an image 2025-09-04 10:08:59 +02:00
Chris Kruining
fa81dbdcf6
even more homer
All checks were successful
Test action / Print hello world (push) Successful in 1s
2025-09-03 17:47:38 +02:00
Chris Kruining
b8b8e015c5
add pipe-operator nix feature
All checks were successful
Test action / Print hello world (push) Successful in 1s
2025-09-03 17:44:19 +02:00
Chris Kruining
a91afd3b0a
expand homer 2025-09-03 17:44:01 +02:00
Chris Kruining
6d7867b45c
update fogejo runner image
All checks were successful
Test action / Print hello world (push) Successful in 1s
2025-09-03 17:24:43 +02:00
Chris Kruining
7c75cab11b
improve podman config 2025-09-03 17:24:27 +02:00
Chris Kruining
44e7a6fa0f
harden vaultwarden
All checks were successful
Test action / Print hello world (push) Successful in 19s
2025-09-03 16:45:32 +02:00
Chris Kruining
6379b5e2de
improve zen config 2025-09-03 16:45:20 +02:00
Chris Kruining
7758806282
add homer dashboard 2025-09-03 16:44:50 +02:00
Chris Kruining
a29b757530
restructure media services 2025-09-03 15:12:30 +02:00
Chris Kruining
5ddcaf35f6
fix zen 2025-09-03 14:54:18 +02:00
39253ca080
update deps
Some checks failed
Test action / Print hello world (push) Has been cancelled
2025-08-31 17:30:45 +02:00
51 changed files with 2917 additions and 361 deletions

2
.envrc Normal file
View file

@ -0,0 +1,2 @@
# shellcheck shell=bash
use flake

View file

@ -7,10 +7,9 @@ on:
- main
jobs:
hello:
name: Print hello world
runs-on: default
kaas:
runs-on: nix
steps:
- name: Echo
run: |
echo "Hello, world!"
nix --version

8
.gitignore vendored
View file

@ -1,2 +1,8 @@
# ---> Nix
# Ignore build outputs from performing a nix-build or `nix build` command
result
*.qcow2
result-*
# Ignore automatically generated direnv output
.direnv

14
.just/machine.just Normal file
View file

@ -0,0 +1,14 @@
set unstable := true
set quiet := true
_default: list
[doc('List machines')]
list:
ls -1 ../systems/x86_64-linux/
[doc('Update the target machine')]
[no-exit-message]
update machine:
just assert '-d "../systems/x86_64-linux/{{ machine }}"' "Machine {{ machine }} does not exist, must be one of: $(ls ../systems/x86_64-linux/ | tr '\n' ' ')"
nixos-rebuild switch --use-remote-sudo --target-host {{ machine }} --flake ..#{{ machine }}

33
.just/vars.just Normal file
View file

@ -0,0 +1,33 @@
set unstable := true
set quiet := true
base_path := invocation_directory() / "systems/x86_64-linux"
_default:
just --list
[doc('list all vars of the target machine')]
list machine:
sops decrypt {{ base_path }}/{{ machine }}/secrets.yml
edit machine:
sops edit {{ base_path }}/{{ machine }}/secrets.yml
@set machine key value:
sops set {{ base_path }}/{{ machine }}/secrets.yml "$(printf '%s\n' '["{{ key }}"]' | sed -E 's#/#"]["#g; s/\["([0-9]+)"\]/[\1]/g')" "\"$(echo '{{ value }}' | sed 's/\"/\\\"/g')\""
git add {{ base_path }}/{{ machine }}/secrets.yml
git commit -m 'chore(secrets): set secret "{{ key }}" for machine "{{ machine }}"' -- {{ base_path }}/{{ machine }}/secrets.yml > /dev/null
echo "Done"
get machine key:
sops decrypt {{ base_path }}/{{ machine }}/secrets.yml | yq ".$(echo "{{ key }}" | sed -E 's/\//./g')"
remove machine key:
sops unset {{ base_path }}/{{ machine }}/secrets.yml "$(printf '%s\n' '["{{ key }}"]' | sed -E 's#/#"]["#g; s/\["([0-9]+)"\]/[\1]/g')"
git add {{ base_path }}/{{ machine }}/secrets.yml
git commit -m 'chore(secrets): removed secret "{{ key }}" from machine "{{ machine }}"' -- {{ base_path }}/{{ machine }}/secrets.yml > /dev/null
echo "Done"

40
.justfile Normal file
View file

@ -0,0 +1,40 @@
_default:
just --list --list-submodules
set unstable
set quiet
mod vars '.just/vars.just'
mod machine '.just/machine.just'
[doc('Show information about project')]
show:
echo "show"
[doc('update the flake dependencies')]
update:
nix flake update
git commit -m 'chore: update dependencies' -- ./flake.lock > /dev/null
echo "Done"
[doc('Rebase branch on main')]
rebase:
git stash -q \
&& git fetch \
&& git rebase origin/main \
&& git stash pop -q
echo "Done"
[doc('Introspection on flake output')]
select key:
nix eval --json .#{{ key }} | jq .
#===============================================================================================
# Utils
# ===============================================================================================
[no-cd]
[no-exit-message]
[private]
assert condition message:
[ {{ condition }} ] || { echo -e 1>&2 "\n\x1b[1;41m Error \x1b[0m {{ message }}\n"; exit 1; }

11
.sops.yaml Normal file
View file

@ -0,0 +1,11 @@
keys:
- &ulmo_1 age19qfpf980tadguqq44zf6xwvjvl428dyrj46ha3n6aeqddwhtnuqqml7etq
- &ulmo_2 age1ewes0f5snqx3sh5ul6fa6qtxzhd25829v6mf5rx2wnheat6fefps5rme2x
creation_rules:
# All Machine secrets
- path_regex: systems/[^/]+/[^/]+/[^/]+\.(yml|yaml)$
key_groups:
- age:
- *ulmo_1
- *ulmo_2

View file

@ -1,8 +0,0 @@
keys:
- &primary age10c5hmykkduvy75yvqfnchm5lcesr5puarhkwp4l7xdwpykdm397q6xdxuy
creation_rules:
- path_regex: secrets/secrets.yml$
key_groups:
- age:
- *primary

View file

@ -1,30 +0,0 @@
#ENC[AES256_GCM,data:jozDiJTPaF427kVL4MDV8VOVhft52sOS9YIfj0n8WUJmQzVoiNY=,iv:8kyaDw0l82KZfYKkfKDj0wvcIkY6zas5e8puubEr1mA=,tag:LvuVGvU195BihU8TbPN1xg==,type:comment]
example_key: ENC[AES256_GCM,data:9jefDfjJLP8Ha135Lg==,iv:9SUpjO1t65gA3LiwYN6nMj7icwInxTCQz7JsNEfQ2XA=,tag:Y8BBSLwUQem8wSXAlvnEXg==,type:str]
#ENC[AES256_GCM,data:IU1T4k/+44s8qFnjnreDMihjQRmMd5qSTtfA/ung5/1f1JmBXGP7EwYJBFF9BSBkBqBfv24A9Ok=,iv:tHzL3pW/qsNdWGT3c+ni0uTlkBMWOu/SsraymCuAkqs=,tag:nWZgWdPNiKQ0j/t9Z/5l5g==,type:comment]
#ENC[AES256_GCM,data:BhUTbsJB5voz4m1w8u1Y/MI8kR5lpRW8RpZO65IyGg232uNSoBLXB2QSl1GseyTC8bZHPiCF2gnttPD+76kqVlfzhhDu4EKU,iv:Ic8ZpR2QBBGhF2++S/TR/DRutkTghpMiby+yvNy0CSE=,tag:Z1JEtowycGDNWuznlkId8A==,type:comment]
example:
my_subdir:
my_secret: ENC[AES256_GCM,data:hccfc6uU4tGT,iv:HYjmo9kAVCcXSpDKWGku3vaJVvZHzYB3l079xXw5OEQ=,tag:c2b8BSqlL1LTcDf1nSPfVA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age10c5hmykkduvy75yvqfnchm5lcesr5puarhkwp4l7xdwpykdm397q6xdxuy
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpeHZXWkZ2andYSytmYWpR
ckttNVJZaWxDK2ZwME1iY2wrWFNwR0hzWUNFCjVSaWpmTHkzdHpPNjhueTQ5ZUEz
YW1BcnIwU1hsb2lodk1QcHJvTUdrVVUKLS0tIFNpWlBqb2pOWDVLV0FvU1FUODJB
dTg0QXZuSkJXV3ZRSUlKcktDNElia28KKZ62gTVpeiz1CfK7awURrPZ7zAYx9vfR
Ajxk0cw1gleE6EU2iIlLOWtmyZbcNk1X32a+otXijlH8fDGtoxA97Q==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-03-09T11:37:49Z"
mac: ENC[AES256_GCM,data:ZEqJc6slPb3YMR9kn/jFImjkQQIT3KyUK3qE3JMty+IAAr9GT8r+rHOwku4TOwL6YzON6L5vkUQFFKnOz9GiJuGkStc6AbML4SfOlRDsaFU4kwO+27UvDBYRqi6iHtJ2pu/uD4wELVhdbElxHvFlCjtgqBWaWmlXw3ATjkiZnik=,iv:zJNM/TqNfBO/mr8ZK/I/FfXwknyn9YpJ0eo4EpHSJvQ=,tag:G4FLx/Hwknq5hYEb8SWQLg==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.9.4
zitadel:
masterKey: thisWillBeAnEncryptedValueInTheFuture

569
flake.lock generated
View file

@ -5,11 +5,11 @@
"fromYaml": "fromYaml"
},
"locked": {
"lastModified": 1746562888,
"narHash": "sha256-YgNJQyB5dQiwavdDFBMNKk1wyS77AtdgDk/VtU6wEaI=",
"lastModified": 1755819240,
"narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=",
"owner": "SenchoPens",
"repo": "base16.nix",
"rev": "806a1777a5db2a1ef9d5d6f493ef2381047f2b89",
"rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6",
"type": "github"
},
"original": {
@ -21,16 +21,17 @@
"base16-fish": {
"flake": false,
"locked": {
"lastModified": 1622559957,
"narHash": "sha256-PebymhVYbL8trDVVXxCvZgc0S5VxI7I1Hv4RMSquTpA=",
"lastModified": 1754405784,
"narHash": "sha256-l9xHIy+85FN+bEo6yquq2IjD1rSg9fjfjpyGP1W8YXo=",
"owner": "tomyun",
"repo": "base16-fish",
"rev": "2f6dd973a9075dabccd26f1cded09508180bf5fe",
"rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561",
"type": "github"
},
"original": {
"owner": "tomyun",
"repo": "base16-fish",
"rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561",
"type": "github"
}
},
@ -67,17 +68,92 @@
"type": "github"
}
},
"clan-core": {
"inputs": {
"data-mesher": "data-mesher",
"disko": "disko",
"flake-parts": "flake-parts",
"nix-darwin": "nix-darwin",
"nix-select": "nix-select",
"nixos-facter-modules": "nixos-facter-modules",
"nixpkgs": [
"nixpkgs"
],
"sops-nix": "sops-nix",
"systems": "systems",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1763547157,
"narHash": "sha256-lJcMap2uT+x1R8WUUKKQ6ndynysJ/JOkrMThMGz6DP0=",
"rev": "2cb2134a6ee32d427097077c4fb4c416b52ae988",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/2cb2134a6ee32d427097077c4fb4c416b52ae988.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.clan.lol/clan/clan-core/archive/main.tar.gz"
}
},
"data-mesher": {
"inputs": {
"flake-parts": [
"clan-core",
"flake-parts"
],
"nixpkgs": [
"clan-core",
"nixpkgs"
],
"treefmt-nix": [
"clan-core",
"treefmt-nix"
]
},
"locked": {
"lastModified": 1762942435,
"narHash": "sha256-zIWGs5FIytTtJN+dhDb8Yx+q4TQI/yczuL539yVcyPE=",
"rev": "0ee328404b12c65e8106bde9e9fab8abf4ecada4",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/0ee328404b12c65e8106bde9e9fab8abf4ecada4.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.clan.lol/clan/data-mesher/archive/main.tar.gz"
}
},
"disko": {
"inputs": {
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762276996,
"narHash": "sha256-TtcPgPmp2f0FAnc+DMEw4ardEgv1SGNR3/WFGH0N19M=",
"owner": "nix-community",
"repo": "disko",
"rev": "af087d076d3860760b3323f6b583f4d828c1ac17",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"erosanix": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1755108317,
"narHash": "sha256-j7RGK7nyoHuJzQjVFBngpsVowIn4DAtprn66UyAFNRQ=",
"lastModified": 1762360792,
"narHash": "sha256-YR7vqk+XEvFUQ/miuBAD3+p+97QUN86ya9Aw0K5feJE=",
"owner": "emmanuelrosa",
"repo": "erosanix",
"rev": "5aa322a6e586a2b46af65ab6c9a3d6042a95ff2e",
"rev": "9075dff5685d3e7269284e53ca496da0beb24596",
"type": "github"
},
"original": {
@ -94,11 +170,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1755153894,
"narHash": "sha256-DEKeIg3MQy5GMFiFRUzcx1hGGBN2ypUPTo0jrMAdmH4=",
"lastModified": 1763534658,
"narHash": "sha256-i/51/Zi/1pM9hZxxSuA3nVPpyqlGoWwJwajyA/loOpo=",
"owner": "nix-community",
"repo": "fenix",
"rev": "f6874c6e512bc69d881d979a45379b988b80a338",
"rev": "69e40ddf45698d0115a62a7a15d8412f35dd4c09",
"type": "github"
},
"original": {
@ -114,11 +190,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1755083788,
"narHash": "sha256-CXiS6gfw0NH+luSpNhtRZjy4NqVFrmsYpoetu3N/fMk=",
"lastModified": 1763504432,
"narHash": "sha256-kpmPI67TdoTxiK7LsmgmkKW3iHoyvZJwZeiJhpwPfmw=",
"owner": "nix-community",
"repo": "flake-firefox-nightly",
"rev": "523078b104590da5850a61dfe291650a6b49809c",
"rev": "49d5d8d42a7650e5353f8467c813839290cb7c9f",
"type": "github"
},
"original": {
@ -130,11 +206,11 @@
"firefox-gnome-theme": {
"flake": false,
"locked": {
"lastModified": 1748383148,
"narHash": "sha256-pGvD/RGuuPf/4oogsfeRaeMm6ipUIznI2QSILKjKzeA=",
"lastModified": 1758112371,
"narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=",
"owner": "rafaelmardojai",
"repo": "firefox-gnome-theme",
"rev": "4eb2714fbed2b80e234312611a947d6cb7d70caf",
"rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d",
"type": "github"
},
"original": {
@ -161,11 +237,11 @@
},
"flake-compat_2": {
"locked": {
"lastModified": 1746162366,
"narHash": "sha256-5SSSZ/oQkwfcAz/o/6TlejlVGqeK08wyREBQ5qFFPhM=",
"lastModified": 1761640442,
"narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=",
"owner": "nix-community",
"repo": "flake-compat",
"rev": "0f158086a2ecdbb138cd0429410e44994f1b7e4b",
"rev": "4a56054d8ffc173222d09dad23adf4ba946c8884",
"type": "github"
},
"original": {
@ -225,16 +301,16 @@
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"nvf",
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1754487366,
"narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=",
"lastModified": 1762980239,
"narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18",
"rev": "52a2caecc898d0b46b2b905f058ccc5081f842da",
"type": "github"
},
"original": {
@ -244,6 +320,27 @@
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": [
"nvf",
"nixpkgs"
]
},
"locked": {
"lastModified": 1760948891,
"narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_3": {
"inputs": {
"nixpkgs-lib": [
"stylix",
@ -251,11 +348,32 @@
]
},
"locked": {
"lastModified": 1751413152,
"narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=",
"lastModified": 1756770412,
"narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "77826244401ea9de6e3bac47c2db46005e1f30b5",
"rev": "4524271976b625a4a605beefd893f270620fd751",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_4": {
"inputs": {
"nixpkgs-lib": [
"terranix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1736143030,
"narHash": "sha256-+hu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "b905f6fc23a9051a6e1b741e1438dbfc0634c6de",
"type": "github"
},
"original": {
@ -266,7 +384,7 @@
},
"flake-utils": {
"inputs": {
"systems": "systems"
"systems": "systems_2"
},
"locked": {
"lastModified": 1731533236,
@ -303,7 +421,7 @@
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
"systems": "systems_3"
},
"locked": {
"lastModified": 1731533236,
@ -321,7 +439,7 @@
},
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
"systems": "systems_4"
},
"locked": {
"lastModified": 1731533236,
@ -339,7 +457,7 @@
},
"flake-utils_4": {
"inputs": {
"systems": "systems_5"
"systems": "systems_6"
},
"locked": {
"lastModified": 1694529238,
@ -392,18 +510,20 @@
"gnome-shell": {
"flake": false,
"locked": {
"lastModified": 1748186689,
"narHash": "sha256-UaD7Y9f8iuLBMGHXeJlRu6U1Ggw5B9JnkFs3enZlap0=",
"host": "gitlab.gnome.org",
"lastModified": 1762869044,
"narHash": "sha256-nwm/GJ2Syigf7VccLAZ66mFC8mZJFqpJmIxSGKl7+Ds=",
"owner": "GNOME",
"repo": "gnome-shell",
"rev": "8c88f917db0f1f0d80fa55206c863d3746fa18d0",
"type": "github"
"rev": "680e3d195a92203f28d4bf8c6e8bb537cc3ed4ad",
"type": "gitlab"
},
"original": {
"host": "gitlab.gnome.org",
"owner": "GNOME",
"ref": "48.2",
"ref": "gnome-49",
"repo": "gnome-shell",
"type": "github"
"type": "gitlab"
}
},
"grub2-themes": {
@ -411,11 +531,11 @@
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1755072091,
"narHash": "sha256-FCkbELHIFXlVREaopW13QFMzwLPr/otjucmyNLQQXeg=",
"lastModified": 1757136219,
"narHash": "sha256-tKU+vq34KHu/A2wD7WdgP5A4/RCmSD8hB0TyQAUlixA=",
"owner": "vinceliuice",
"repo": "grub2-themes",
"rev": "03d8c9cf0d1bcf67765ac5fa35263f1b08c584fa",
"rev": "80dd04ddf3ba7b284a7b1a5df2b1e95ee2aad606",
"type": "github"
},
"original": {
@ -429,14 +549,15 @@
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
],
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1754593854,
"narHash": "sha256-fiWzQKZP92+2nm9wGBa/UYuEdVJkshHqNpCFfklas8k=",
"lastModified": 1763486183,
"narHash": "sha256-10EvBTF9ELezWg+KoKZJ3bxrPzT1Xz95ifurC6HixLY=",
"owner": "himmelblau-idm",
"repo": "himmelblau",
"rev": "e0b9a3efdcf0c6c59ed3352ffb2b003ab6aa2fed",
"rev": "fb27f4bee812e4b4df9df9f78bd5280f0aa2193c",
"type": "github"
},
"original": {
@ -452,11 +573,32 @@
]
},
"locked": {
"lastModified": 1755121891,
"narHash": "sha256-UtYkukiGnPRJ5rpd4W/wFVrLMh8fqtNkqHTPgHEtrqU=",
"lastModified": 1763416652,
"narHash": "sha256-8EBEEvtzQ11LCxpQHMNEBQAGtQiCu/pqP9zSovDSbNM=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "279ca5addcdcfa31ac852b3ecb39fc372684f426",
"rev": "ea164b7c9ccdc2321379c2ff78fd4317b4c41312",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"home-manager_2": {
"inputs": {
"nixpkgs": [
"zen-browser",
"nixpkgs"
]
},
"locked": {
"lastModified": 1762964643,
"narHash": "sha256-RYHN8O/Aja59XDji6WSJZPkJpYVUfpSkyH+PEupBJqM=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "827f2a23373a774a8805f84ca5344654c31f354b",
"type": "github"
},
"original": {
@ -473,11 +615,11 @@
]
},
"locked": {
"lastModified": 1755151620,
"narHash": "sha256-fVMalQZ+tRXR8oue2SdWu4CdlsS2NII+++rI40XQ8rU=",
"lastModified": 1763453666,
"narHash": "sha256-Hu8lDUlbMFvcYX30LBXX7Gq5FbU35bERH0pSX5qHf/Q=",
"owner": "Jovian-Experiments",
"repo": "Jovian-NixOS",
"rev": "16e12d22754d97064867006acae6e16da7a142a6",
"rev": "b843b551415c7aecc97c8b3ab3fff26fd0cd8bbf",
"type": "github"
},
"original": {
@ -507,11 +649,11 @@
},
"mnw": {
"locked": {
"lastModified": 1748710831,
"narHash": "sha256-eZu2yH3Y2eA9DD3naKWy/sTxYS5rPK2hO7vj8tvUCSU=",
"lastModified": 1758834834,
"narHash": "sha256-Y7IvY4F8vajZyp3WGf+KaiIVwondEkMFkt92Cr9NZmg=",
"owner": "Gerg-L",
"repo": "mnw",
"rev": "cff958a4e050f8d917a6ff3a5624bc4681c6187d",
"rev": "cfbc7d1cc832e318d0863a5fc91d940a96034001",
"type": "github"
},
"original": {
@ -520,6 +662,27 @@
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1763136804,
"narHash": "sha256-6p2ljK42s0S8zS0UU59EsEqupz0GVCaBYRylpUadeBM=",
"owner": "nix-darwin",
"repo": "nix-darwin",
"rev": "973db96394513fd90270ea5a1211a82a4a0ba47f",
"type": "github"
},
"original": {
"owner": "nix-darwin",
"repo": "nix-darwin",
"type": "github"
}
},
"nix-github-actions": {
"inputs": {
"nixpkgs": [
@ -549,11 +712,11 @@
"nixpkgs": "nixpkgs_5"
},
"locked": {
"lastModified": 1755137329,
"narHash": "sha256-9MxuOLH7jk58IVUUDWwLeqk9U4ATE6X37955Ld+4/zw=",
"lastModified": 1763171892,
"narHash": "sha256-6cg9zSiqKA89yJzVtYhBaBptqq6bX4pr4g7WLAHOD4Y=",
"owner": "Infinidoge",
"repo": "nix-minecraft",
"rev": "d9330bc35048238597880e89fb173799de9db5e9",
"rev": "316858c27d278b20e776cd4dd8f787812f587ba2",
"type": "github"
},
"original": {
@ -562,6 +725,19 @@
"type": "github"
}
},
"nix-select": {
"locked": {
"lastModified": 1763303120,
"narHash": "sha256-yxcNOha7Cfv2nhVpz9ZXSNKk0R7wt4AiBklJ8D24rVg=",
"rev": "3d1e3860bef36857a01a2ddecba7cdb0a14c35a9",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/nix-select/archive/3d1e3860bef36857a01a2ddecba7cdb0a14c35a9.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.clan.lol/clan/nix-select/archive/main.tar.gz"
}
},
"nixlib": {
"locked": {
"lastModified": 1736643958,
@ -592,6 +768,21 @@
"type": "github"
}
},
"nixos-facter-modules": {
"locked": {
"lastModified": 1762264948,
"narHash": "sha256-iaRf6n0KPl9hndnIft3blm1YTAyxSREV1oX0MFZ6Tk4=",
"owner": "nix-community",
"repo": "nixos-facter-modules",
"rev": "fa695bff9ec37fd5bbd7ee3181dbeb5f97f53c96",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixos-facter-modules",
"type": "github"
}
},
"nixos-generators": {
"inputs": {
"nixlib": "nixlib",
@ -621,11 +812,11 @@
]
},
"locked": {
"lastModified": 1755171343,
"narHash": "sha256-h6bbfhqWcHlx9tcyYa7dhaEiNpusLCcFYkJ/AnltLW8=",
"lastModified": 1763537456,
"narHash": "sha256-/WRqcqeE9C+mxxWgI7jy5blMrvg2lHFSlTFjC8pRWos=",
"owner": "nix-community",
"repo": "nixos-wsl",
"rev": "e37cfef071466a9ca649f6899aff05226ce17e9e",
"rev": "cd9eb5225fc91eb67629966844d2ff371824abb1",
"type": "github"
},
"original": {
@ -636,11 +827,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1754002724,
"narHash": "sha256-1NBby4k2UU9FR7a9ioXtCOpv8jYO0tZAGarMsxN8sz8=",
"lastModified": 1761828793,
"narHash": "sha256-xjdPwMD4wVuDD85U+3KST62VzFkJueI6oBwIzpzUHLY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8271ed4b2e366339dd622f329151e45745ade121",
"rev": "843859a08e114403f44aaf5b996b44c38094aa46",
"type": "github"
},
"original": {
@ -665,29 +856,13 @@
"type": "github"
}
},
"nixpkgs_10": {
"locked": {
"lastModified": 1727348695,
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1755061300,
"narHash": "sha256-eov82CkCrpiECJa3dyQ2da1sPGnAP3HK0UEra5eupaM=",
"lastModified": 1763469780,
"narHash": "sha256-IW67Db/wBNQwJ5e0fF9Yk4SmdivMcecrUVDs7QJoC/s=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "d4df8d6cc1ccfd3e4349a1d54e4fb1171e7ec1f5",
"rev": "a70b03ca5dc9d46294740f165abdef9f9bea5632",
"type": "github"
},
"original": {
@ -715,11 +890,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1755178357,
"narHash": "sha256-rzgUmlO5/pt7uPAlY6E70clNjg9JmrgBxalEj2zKq08=",
"lastModified": 1763547551,
"narHash": "sha256-YOdXVAqEGmrPUgs71r8ziuu9qqpn3jJEiIxsIls+VQA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6eac4364f979ef460fb6ebd17ca65b8dae03cba4",
"rev": "06aa4d5f488875b6af46e10b45b8000ed0906860",
"type": "github"
},
"original": {
@ -747,11 +922,11 @@
},
"nixpkgs_6": {
"locked": {
"lastModified": 1755027561,
"narHash": "sha256-IVft239Bc8p8Dtvf7UAACMG5P3ZV+3/aO28gXpGtMXI=",
"lastModified": 1763421233,
"narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "005433b926e16227259a1843015b5b2b7f7d1fc3",
"rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648",
"type": "github"
},
"original": {
@ -763,11 +938,11 @@
},
"nixpkgs_7": {
"locked": {
"lastModified": 1755049066,
"narHash": "sha256-ANrc15FSoOAdNbfKHxqEJjZLftIwIsenJGRb/04K41s=",
"lastModified": 1761880412,
"narHash": "sha256-QoJjGd4NstnyOG4mm4KXF+weBzA2AH/7gn1Pmpfcb0A=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "e45f8f193029378d0aaee5431ba098dc80054e9a",
"rev": "a7fc11be66bdfb5cdde611ee5ce381c183da8386",
"type": "github"
},
"original": {
@ -779,11 +954,11 @@
},
"nixpkgs_8": {
"locked": {
"lastModified": 1744868846,
"narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=",
"lastModified": 1763191728,
"narHash": "sha256-esRhOS0APE6k40Hs/jjReXg+rx+J5LkWw7cuWFKlwYA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c",
"rev": "1d4c88323ac36805d09657d13a5273aea1b34f0c",
"type": "github"
},
"original": {
@ -795,11 +970,11 @@
},
"nixpkgs_9": {
"locked": {
"lastModified": 1751792365,
"narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=",
"lastModified": 1762977756,
"narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1fd8bada0b6117e6c7eb54aad5813023eed37ccb",
"rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55",
"type": "github"
},
"original": {
@ -821,11 +996,11 @@
]
},
"locked": {
"lastModified": 1751906969,
"narHash": "sha256-BSQAOdPnzdpOuCdAGSJmefSDlqmStFNScEnrWzSqKPw=",
"lastModified": 1758998580,
"narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=",
"owner": "nix-community",
"repo": "NUR",
"rev": "ddb679f4131e819efe3bbc6457ba19d7ad116f25",
"rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728",
"type": "github"
},
"original": {
@ -837,17 +1012,17 @@
"nvf": {
"inputs": {
"flake-compat": "flake-compat_4",
"flake-parts": "flake-parts",
"flake-parts": "flake-parts_2",
"mnw": "mnw",
"nixpkgs": "nixpkgs_7",
"systems": "systems_4"
"systems": "systems_5"
},
"locked": {
"lastModified": 1755115677,
"narHash": "sha256-98Ad2F5w1xW94KymQiBohNBYpFqMa0K28v9S1SzyTY8=",
"lastModified": 1762622004,
"narHash": "sha256-NpzzgaoMK8aRHnndHWbYNKLcZN0r1y6icCoJvGoBsoE=",
"owner": "notashelf",
"repo": "nvf",
"rev": "c5dc7192496a1fad38134e54f8b4fca8ac51a9fe",
"rev": "09470524a214ed26633ddc2b6ec0c9bf31a8b909",
"type": "github"
},
"original": {
@ -866,11 +1041,11 @@
]
},
"locked": {
"lastModified": 1754501628,
"narHash": "sha256-FExJ54tVB5iu7Dh2tLcyCSWpaV+lmUzzWKZUkemwXvo=",
"lastModified": 1762784320,
"narHash": "sha256-odsk96Erywk5hs0dhArF38zb7Oe0q6LZ70gXbxAPKno=",
"owner": "nix-community",
"repo": "plasma-manager",
"rev": "cca090f8115c4172b9aef6c5299ae784bdd5e133",
"rev": "7911a0f8a44c7e8b29d031be3149ee8943144321",
"type": "github"
},
"original": {
@ -881,6 +1056,7 @@
},
"root": {
"inputs": {
"clan-core": "clan-core",
"erosanix": "erosanix",
"fenix": "fenix",
"firefox": "firefox",
@ -897,19 +1073,20 @@
"nvf": "nvf",
"plasma-manager": "plasma-manager",
"snowfall-lib": "snowfall-lib",
"sops-nix": "sops-nix",
"sops-nix": "sops-nix_2",
"stylix": "stylix",
"terranix": "terranix",
"zen-browser": "zen-browser"
}
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1755004716,
"narHash": "sha256-TbhPR5Fqw5LjAeI3/FOPhNNFQCF3cieKCJWWupeZmiA=",
"lastModified": 1762860488,
"narHash": "sha256-rMfWMCOo/pPefM2We0iMBLi2kLBAnYoB9thi4qS7uk4=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "b2a58b8c6eff3c3a2c8b5c70dbf69ead78284194",
"rev": "2efc80078029894eec0699f62ec8d5c1a56af763",
"type": "github"
},
"original": {
@ -919,6 +1096,27 @@
"type": "github"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"himmelblau",
"nixpkgs"
]
},
"locked": {
"lastModified": 1759977258,
"narHash": "sha256-hOxEFSEBoqDmJb7BGX1CzT1gvUPK6r+Qs+n3IxBgfTs=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "1d0c6173f57d07db7957b50e799240d4f2d7520f",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"snowfall-lib": {
"inputs": {
"flake-compat": "flake-compat_5",
@ -942,15 +1140,36 @@
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1763264763,
"narHash": "sha256-N0BEoJIlJ+M6sWZJ8nnfAjGY9VLvM6MXMitRenmhBkY=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "882e56c8293e44d57d882b800a82f8b2ee7a858f",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"sops-nix_2": {
"inputs": {
"nixpkgs": "nixpkgs_8"
},
"locked": {
"lastModified": 1754988908,
"narHash": "sha256-t+voe2961vCgrzPFtZxha0/kmFSHFobzF00sT8p9h0U=",
"lastModified": 1763509310,
"narHash": "sha256-s2WzTAD3vJtPACBCZXezNUMTG/wC6SFsU9DxazB9wDI=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "3223c7a92724b5d804e9988c6b447a0d09017d48",
"rev": "3ee33c0ed7c5aa61b4e10484d2ebdbdc98afb03e",
"type": "github"
},
"original": {
@ -966,11 +1185,11 @@
"base16-helix": "base16-helix",
"base16-vim": "base16-vim",
"firefox-gnome-theme": "firefox-gnome-theme",
"flake-parts": "flake-parts_2",
"flake-parts": "flake-parts_3",
"gnome-shell": "gnome-shell",
"nixpkgs": "nixpkgs_9",
"nur": "nur",
"systems": "systems_6",
"systems": "systems_7",
"tinted-foot": "tinted-foot",
"tinted-kitty": "tinted-kitty",
"tinted-schemes": "tinted-schemes",
@ -978,11 +1197,11 @@
"tinted-zed": "tinted-zed"
},
"locked": {
"lastModified": 1755027820,
"narHash": "sha256-hBSU7BEhd05y/pC9tliYjkFp8AblkbNEkPei229+0Pg=",
"lastModified": 1763497248,
"narHash": "sha256-OGP6MYc+lVkLVQOTS6ORszDcCnZm7kDOGpFBdDoLd0k=",
"owner": "nix-community",
"repo": "stylix",
"rev": "c592717e9f713bbae5f718c784013d541346363d",
"rev": "f19ac46f6aa26188b2020ed40066a5b832be9c53",
"type": "github"
},
"original": {
@ -1081,6 +1300,58 @@
"type": "github"
}
},
"systems_7": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_8": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"terranix": {
"inputs": {
"flake-parts": "flake-parts_4",
"nixpkgs": [
"nixpkgs"
],
"systems": "systems_8"
},
"locked": {
"lastModified": 1762472226,
"narHash": "sha256-iVS4sxVgGn+T74rGJjEJbzx+kjsuaP3wdQVXBNJ79A0=",
"owner": "terranix",
"repo": "terranix",
"rev": "3b5947a48da5694094b301a3b1ef7b22ec8b19fc",
"type": "github"
},
"original": {
"owner": "terranix",
"repo": "terranix",
"type": "github"
}
},
"tinted-foot": {
"flake": false,
"locked": {
@ -1117,11 +1388,11 @@
"tinted-schemes": {
"flake": false,
"locked": {
"lastModified": 1750770351,
"narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=",
"lastModified": 1757716333,
"narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=",
"owner": "tinted-theming",
"repo": "schemes",
"rev": "5a775c6ffd6e6125947b393872cde95867d85a2a",
"rev": "317a5e10c35825a6c905d912e480dfe8e71c7559",
"type": "github"
},
"original": {
@ -1133,11 +1404,11 @@
"tinted-tmux": {
"flake": false,
"locked": {
"lastModified": 1751159871,
"narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=",
"lastModified": 1757811970,
"narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=",
"owner": "tinted-theming",
"repo": "tinted-tmux",
"rev": "bded5e24407cec9d01bd47a317d15b9223a1546c",
"rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e",
"type": "github"
},
"original": {
@ -1149,11 +1420,11 @@
"tinted-zed": {
"flake": false,
"locked": {
"lastModified": 1751158968,
"narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=",
"lastModified": 1757811247,
"narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=",
"owner": "tinted-theming",
"repo": "base16-zed",
"rev": "86a470d94204f7652b906ab0d378e4231a5b3384",
"rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e",
"type": "github"
},
"original": {
@ -1162,20 +1433,44 @@
"type": "github"
}
},
"zen-browser": {
"treefmt-nix": {
"inputs": {
"nixpkgs": "nixpkgs_10"
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1727721329,
"narHash": "sha256-QYlWZwUSwrM7BuO+dXclZIwoPvBIuJr6GpFKv9XKFPI=",
"owner": "MarceColl",
"repo": "zen-browser-flake",
"rev": "e6ab73f405e9a2896cce5956c549a9cc359e5fcc",
"lastModified": 1762938485,
"narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
"type": "github"
},
"original": {
"owner": "MarceColl",
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"zen-browser": {
"inputs": {
"home-manager": "home-manager_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1763521945,
"narHash": "sha256-Zcrafbe4niRJMbzaVOwg7+iedJhwBFttre2DpyCC6qA=",
"owner": "0xc000022070",
"repo": "zen-browser-flake",
"rev": "24d7381b9231c23daceec5d372cc28e877f7785d",
"type": "github"
},
"original": {
"owner": "0xc000022070",
"repo": "zen-browser-flake",
"type": "github"
}

View file

@ -41,7 +41,10 @@
inputs.nixpkgs.follows = "nixpkgs";
};
zen-browser.url = "github:MarceColl/zen-browser-flake";
zen-browser = {
url = "github:0xc000022070/zen-browser-flake";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-minecraft.url = "github:Infinidoge/nix-minecraft";
@ -63,11 +66,11 @@
url = "github:Jovian-Experiments/Jovian-NixOS";
inputs.nixpkgs.follows = "nixpkgs";
};
grub2-themes = {
url = "github:vinceliuice/grub2-themes";
};
nixos-wsl = {
url = "github:nix-community/nixos-wsl";
inputs = {
@ -75,6 +78,16 @@
flake-compat.follows = "";
};
};
terranix = {
url = "github:terranix/terranix";
inputs.nixpkgs.follows = "nixpkgs";
};
clan-core = {
url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs: inputs.snowfall-lib.mkFlake {
@ -93,8 +106,15 @@
channels-config = {
allowUnfree = true;
permittedInsecurePackages = [
# Due to *arr stack
"dotnet-sdk-6.0.428"
"aspnetcore-runtime-6.0.36"
# I think this is because of zen
"qtwebengine-5.15.19"
# For Nheko, the matrix client
"olm-3.2.16"
];
};
@ -104,9 +124,13 @@
flux.overlays.default
];
systems.modules = with inputs; [
clan-core.nixosModules.default
];
homes.modules = with inputs; [
stylix.homeModules.stylix
plasma-manager.homeManagerModules.plasma-manager
plasma-manager.homeModules.plasma-manager
];
};
}

View file

@ -35,6 +35,7 @@
bitwarden.enable = true;
discord.enable = true;
ladybird.enable = true;
matrix.enable = true;
obs.enable = true;
onlyoffice.enable = true;
signal.enable = true;

38
lib/options/default.nix Normal file
View file

@ -0,0 +1,38 @@
{ lib, ...}:
let
inherit (builtins) isString typeOf;
inherit (lib) mkOption types throwIfNot concatStringsSep splitStringBy toLower map;
in
{
options = {
mkUrlOptions =
defaults:
{
host = mkOption {
type = types.str;
example = "host.tld";
description = ''
Hostname
'';
} // (defaults.host or {});
port = mkOption {
type = types.port;
default = 1234;
example = "1234";
description = ''
Port
'';
} // (defaults.port or {});
protocol = mkOption {
type = types.str;
default = "https";
example = "https";
description = ''
Which protocol to use when creating a url string
'';
} // (defaults.protocol or {});
};
};
}

39
lib/strings/default.nix Normal file
View file

@ -0,0 +1,39 @@
{ lib, ...}:
let
inherit (builtins) isString typeOf match toString head;
inherit (lib) throwIfNot concatStringsSep splitStringBy toLower map concatMapAttrsStringSep;
in
{
strings = {
#========================================================================================
# Converts a string to snake case
#
# simply replaces any uppercase letter to its lowercase variant preceeded by an underscore
#========================================================================================
toSnakeCase =
str:
throwIfNot (isString str) "toSnakeCase only accepts string values, but got ${typeOf str}" (
str
|> splitStringBy (prev: curr: builtins.match "[a-z]" prev != null && builtins.match "[A-Z]" curr != null) true
|> map (p: toLower p)
|> concatStringsSep "_"
);
#========================================================================================
# Converts a set of url parts to a string
#========================================================================================
toUrl =
{ protocol ? null, host, port ? null, path ? null, query ? null, hash ? null }:
let
trim_slashes = str: str |> match "^\/*(.+?)\/*$" |> head;
encode_to_str = set: concatMapAttrsStringSep "&" (n: v: "${n}=${v}") set;
_protocol = if protocol != null then "${protocol}://" else "";
_port = if port != null then ":${toString port}" else "";
_path = if path != null then "/${path |> trim_slashes}" else "";
_query = if query != null then "?${query |> encode_to_str}" else "";
_hash = if hash != null then "#${hash |> encode_to_str}" else "";
in
"${_protocol}${host}${_port}${_path}${_query}${_hash}";
};
}

View file

@ -0,0 +1,19 @@
{ config, lib, pkgs, namespace, osConfig ? {}, ... }:
let
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.application.matrix;
in
{
options.${namespace}.application.matrix = {
enable = mkEnableOption "enable Matrix client (Fractal)";
};
config = mkIf cfg.enable {
home.packages = with pkgs; [ fractal element-desktop ];
programs.element-desktop = {
enable = true;
};
};
}

View file

@ -5,35 +5,61 @@ let
cfg = config.${namespace}.application.zen;
in
{
imports = [
inputs.zen-browser.homeModules.default
];
options.${namespace}.application.zen = {
enable = mkEnableOption "enable zen";
};
config = mkIf cfg.enable {
home.packages = [ inputs.zen-browser.packages.${pkgs.system}.specific ];
home.sessionVariables = {
MOZ_ENABLE_WAYLAND = "1";
};
programs.zen-browser = {
enable = true;
policies = {
AutofillAddressEnabled = true;
AutofillCreditCardEnabled = false;
AppAutoUpdate = false;
DisableAppUpdate = true;
ManualAppUpdateOnly = true;
DisableFeedbackCommands = true;
DisableFirefoxStudies = true;
DisablePocket = true;
DisableTelemetry = true;
# DontCheckDefaultBrowser = false;
DontCheckDefaultBrowser = false;
NoDefaultBookmarks = true;
# OfferToSaveLogins = false;
OfferToSaveLogins = false;
EnableTrackingProtection = {
Value = true;
Locked = true;
Cryptomining = true;
Fingerprinting = true;
};
HttpAllowlist = [
"http://ulmo"
];
};
policies.ExtensionSettings = let
mkExtension = id: {
install_url = "https://addons.mozilla.org/firefox/downloads/latest/${builtins.toString id}/latest.xpi";
installation_mode = "force_installed";
};
in
{
ublock_origin = 4531307;
ghostry = 4562168;
bitwarden = 4562769;
sponsorblock = 4541835;
};
};
};

View file

@ -64,7 +64,7 @@ in
};
kwalletrc = {
Wallet.Enabled = false;
Wallet.Enabled = true;
};
plasmarc = {

View file

@ -15,7 +15,7 @@ in {
programs.zed-editor = {
enable = true;
extensions = [ "nix" "toml" "html" ];
extensions = [ "nix" "toml" "html" "just-ls" ];
userSettings = {
assistant.enabled = false;

View file

@ -4,7 +4,9 @@ let
in
{
systemd.user.startServices = "sd-switch";
programs.home-manager.enable = true;
programs.home-manager = {
enable = true;
};
home.stateVersion = mkDefault (osConfig.system.stateVersion or "25.05");
}
}

View file

@ -17,6 +17,7 @@ in
eza.enable = true;
fzf.enable = true;
git.enable = true;
just.enable = true;
starship.enable = true;
tmux.enable = true;
yazi.enable = true;

View file

@ -31,9 +31,11 @@ in
package = pkgs.gitFull;
difftastic = {
enable = true;
background = "dark";
color = "always";
display = "inline";
options = {
background = "dark";
color = "always";
display = "inline";
};
};
ignores = [

View file

@ -0,0 +1,15 @@
{ config, lib, pkgs, namespace, ... }:
let
inherit (lib) mkEnableOption mkIf;
cfg = config.${namespace}.shell.toolset.just;
in
{
options.${namespace}.shell.toolset.just = {
enable = mkEnableOption "version-control system";
};
config = mkIf cfg.enable {
home.packages = with pkgs; [ just gum ];
};
}

View file

@ -31,7 +31,9 @@ in {
base16Scheme = "${pkgs.base16-schemes}/share/themes/${cfg.theme}.yaml";
image = ./${cfg.theme}.jpg;
polarity = cfg.polarity;
targets.qt.platform = mkDefault "kde6";
# targets.qt.platform = mkDefault "kde";
targets.zen-browser.profileNames = [ "Chris" ];
fonts = {
serif = {
@ -50,7 +52,7 @@ in {
};
emoji = {
package = pkgs.noto-fonts-emoji;
package = pkgs.noto-fonts-color-emoji;
name = "Noto Color Emoji";
};
};

View file

@ -12,7 +12,18 @@ in
};
config = mkIf cfg.enable {
environment.plasma6.excludePackages = with pkgs.kdePackages; [ konsole kate ghostwriter oxygen ];
environment.plasma6.excludePackages = with pkgs.kdePackages; [
elisa
kmahjongg
kmines
konversation
kpat
ksudoku
konsole
kate
ghostwriter
oxygen
];
environment.sessionVariables.NIXOS_OZONE_WL = "1";
services = {

View file

@ -17,11 +17,6 @@ in
};
amdgpu = {
amdvlk = {
enable = true;
support32Bit.enable = true;
};
initrd.enable = true;
};
};

View file

@ -0,0 +1,6 @@
{ ... }:
{
config = {
home-manager.backupFileExtension = "homeManagerBackup";
};
}

View file

@ -1,24 +1,20 @@
{ pkgs, lib, namespace, config, ... }:
let
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.nix;
in
{
options.${namespace}.nix = {
enable = mkEnableOption "Enable nix command";
};
options.${namespace}.nix = {};
config = mkIf cfg.enable {
config = {
programs.git.enable = true;
nix = {
package = pkgs.nixVersions.latest;
extraOptions = "experimental-features = nix-command flakes";
extraOptions = "experimental-features = nix-command flakes pipe-operators";
settings = {
experimental-features = [ "nix-command" "flakes" ];
experimental-features = [ "nix-command" "flakes" "pipe-operators" ];
allowed-users = [ "@wheel" ];
trusted-users = [ "@wheel" ];

View file

@ -1,33 +1,595 @@
{ config, lib, pkgs, namespace, ... }:
{ config, lib, pkgs, namespace, system, inputs, ... }:
let
inherit (lib) mkIf mkEnableOption mkForce;
inherit (lib) mkIf mkEnableOption mkOption types toUpper toSentenceCase nameValuePair mapAttrs mapAttrs' concatMapAttrs concatMapStringsSep filterAttrsRecursive listToAttrs imap0 head drop length literalExpression attrNames;
inherit (lib.${namespace}.strings) toSnakeCase;
cfg = config.${namespace}.services.authentication.zitadel;
db_name = "zitadel";
db_user = "zitadel";
database = "zitadel";
in
{
options.${namespace}.services.authentication.zitadel = {
enable = mkEnableOption "Zitadel";
organization = mkOption {
type = types.attrsOf (types.submodule ({ name, ... }: {
options =
let
org = name;
in
{
isDefault = mkOption {
type = types.bool;
default = false;
example = "true";
description = ''
True sets the org as default org for the instance. Only one org can be default org.
Nothing happens if you set it to false until you set another org as default org.
'';
};
project = mkOption {
default = {};
type = types.attrsOf (types.submodule {
options = {
hasProjectCheck = mkOption {
type = types.bool;
default = false;
example = "true";
description = ''
ZITADEL checks if the org of the user has permission to this project.
'';
};
privateLabelingSetting = mkOption {
type = types.nullOr (types.enum [ "unspecified" "enforceProjectResourceOwnerPolicy" "allowLoginUserResourceOwnerPolicy" ]);
default = null;
example = "enforceProjectResourceOwnerPolicy";
description = ''
Defines from where the private labeling should be triggered,
supported values:
- unspecified
- enforceProjectResourceOwnerPolicy
- allowLoginUserResourceOwnerPolicy
'';
};
projectRoleAssertion = mkOption {
type = types.bool;
default = false;
example = "true";
description = ''
Describes if roles of user should be added in token.
'';
};
projectRoleCheck = mkOption {
type = types.bool;
default = false;
example = "true";
description = ''
ZITADEL checks if the user has at least one on this project.
'';
};
role = mkOption {
default = {};
type = types.attrsOf (types.submodule ({ name, ... }: {
options =
let
roleName = name;
in
{
displayName = mkOption {
type = types.str;
default = toSentenceCase name;
example = "RoleName";
description = ''
Name used for project role.
'';
};
group = mkOption {
type = types.nullOr types.str;
default = null;
example = "some_group";
description = ''
Group used for project role.
'';
};
};
}));
};
assign = mkOption {
default = {};
type = types.attrsOf (types.listOf types.str);
};
application = mkOption {
default = {};
type = types.attrsOf (types.submodule {
options = {
redirectUris = mkOption {
type = types.nonEmptyListOf types.str;
example = ''
[ "https://example.com/redirect/url" ]
'';
description = ''
.
'';
};
grantTypes = mkOption {
type = types.nonEmptyListOf (types.enum [ "authorizationCode" "implicit" "refreshToken" "deviceCode" "tokenExchange" ]);
example = ''
[ "authorizationCode" ]
'';
description = ''
.
'';
};
responseTypes = mkOption {
type = types.nonEmptyListOf (types.enum [ "code" "idToken" "idTokenToken" ]);
example = ''
[ "code" ]
'';
description = ''
.
'';
};
exportMap =
let
strOpt = mkOption { type = types.nullOr types.str; default = null; };
in
mkOption {
type = types.submodule { options = { client_id = strOpt; client_secret = strOpt; }; };
default = {};
example = literalExpression ''
{
client_id = "SSO_CLIENT_ID";
client_secret = "SSO_CLIENT_SECRET";
}
'';
description = ''
Remap the outputted variables to another key.
'';
};
};
});
};
};
});
};
user = mkOption {
default = {};
type = types.attrsOf (types.submodule ({ name, ... }: {
options =
let
username = name;
in
{
email = mkOption {
type = types.str;
example = "someone@some.domain";
description = ''
Username.
'';
};
userName = mkOption {
type = types.nullOr types.str;
default = username;
example = "some_user_name";
description = ''
Username. Default value is the key of the config object you created, you can overwrite that by setting this option
'';
};
firstName = mkOption {
type = types.str;
example = "John";
description = ''
First name of the user.
'';
};
lastName = mkOption {
type = types.str;
example = "Doe";
description = ''
Last name of the user.
'';
};
roles = mkOption {
type = types.listOf types.str;
default = [];
example = "[ \"ORG_OWNER\" ]";
description = ''
List of roles granted to organisation.
'';
};
instanceRoles = mkOption {
type = types.listOf types.str;
default = [];
example = "[ \"IAM_OWNER\" ]";
description = ''
List of roles granted to instance.
'';
};
};
}));
};
action = mkOption {
default = {};
type = types.attrsOf (types.submodule ({ name, ... }: {
options = {
script = mkOption {
type = types.str;
example = ''
(ctx, api) => {
api.v1.claims.setClaim('some_claim', 'some_value');
};
'';
description = ''
The script to run. This must be a function that receives 2 parameters, and returns void. During the creation of the action's script this module simly does `const {{name}} = {{script}}`.
'';
};
timeout = mkOption {
type = (types.ints.between 0 20);
default = 10;
example = "10";
description = ''
After which time the action will be terminated if not finished.
'';
};
allowedToFail = mkOption {
type = types.bool;
default = true;
example = "true";
description = ''
Allowed to fail.
'';
};
};
}));
};
triggers = mkOption {
default = [];
type = types.listOf (types.submodule {
options = {
flowType = mkOption {
type = types.enum [ "authentication" "customiseToken" "internalAuthentication" "samlResponse" ];
example = "customiseToken";
description = ''
Type of the flow to which the action triggers belong.
'';
};
triggerType = mkOption {
type = types.enum [ "postAuthentication" "preCreation" "postCreation" "preUserinfoCreation" "preAccessTokenCreation" "preSamlResponse" ];
example = "postAuthentication";
description = ''
Trigger type on when the actions get triggered.
'';
};
actions = mkOption {
type = types.nonEmptyListOf types.str;
example = ''[ "action_name" ]'';
description = ''
Names of actions to trigger
'';
};
};
});
};
};
}));
};
};
config = mkIf cfg.enable {
config = let
_refTypeMap = {
org = { type = "org"; };
project = { type = "project"; };
user = { type = "user"; tfType = "human_user"; };
};
mapRef' = { type, tfType ? type }: name: { "${type}Id" = "\${ resource.zitadel_${tfType}.${toSnakeCase name}.id }"; };
mapRef = type: name: mapRef' (_refTypeMap.${type}) name;
mapEnum = prefix: value: "${prefix}_${value |> toSnakeCase |> toUpper}";
mapValue = type: value: ({
appType = mapEnum "OIDC_APP_TYPE" value;
grantTypes = map (t: mapEnum "OIDC_GRANT_TYPE" t) value;
responseTypes = map (t: mapEnum "OIDC_RESPONSE_TYPE" t) value;
authMethodType = mapEnum "OIDC_AUTH_METHOD_TYPE" value;
flowType = mapEnum "FLOW_TYPE" value;
triggerType = mapEnum "TRIGGER_TYPE" value;
accessTokenType = mapEnum "OIDC_TOKEN_TYPE" value;
}."${type}" or value);
toResource = name: value: nameValuePair
(toSnakeCase name)
(lib.mapAttrs' (k: v: nameValuePair (toSnakeCase k) (mapValue k v)) value);
withRef = type: name: attrs: attrs // (mapRef type name);
select = keys: callback: set:
if (length keys) == 0 then
mapAttrs' callback set
else let key = head keys; in
concatMapAttrs (k: v: select (drop 1 keys) (callback k) (v.${key} or {})) set
;
append = attrList: set: set // (listToAttrs attrList);
forEach = src: key: set:
let
_key = concatMapStringsSep "_" (k: "\${item.${k}}") key;
in
{
forEach = "{ for item in ${src} : \"${_key}\" => item }";
}
// set;
config' = config;
# this is a nix package, the generated json file to be exact
terraformConfiguration = inputs.terranix.lib.terranixConfiguration {
inherit system;
modules = [
({ config, lib, ... }: {
config = {
terraform.required_providers.zitadel = {
source = "zitadel/zitadel";
version = "2.2.0";
};
provider.zitadel = {
domain = "auth.kruining.eu";
insecure = "false";
jwt_profile_file = "/var/lib/zitadel/machine-key.json";
};
locals = {
extra_users = lib.tfRef "
flatten([ for org, users in jsondecode(file(\"${config'.sops.secrets."zitadel/users".path}\")): [
for name, details in users: {
org = org
name = name
email = details.email
firstName = details.firstName
lastName = details.lastName
}
] ])
";
orgs = cfg.organization |> mapAttrs (org: _: lib.tfRef "resource.zitadel_org.${org}.id");
};
resource = {
# Organizations
zitadel_org = cfg.organization |> select [] (name: { isDefault, ... }:
{ inherit name isDefault; }
|> toResource name
);
# Projects per organization
zitadel_project = cfg.organization |> select [ "project" ] (org: name: { hasProjectCheck, privateLabelingSetting, projectRoleAssertion, projectRoleCheck, ... }:
{
inherit name hasProjectCheck privateLabelingSetting projectRoleAssertion projectRoleCheck;
}
|> withRef "org" org
|> toResource "${org}_${name}"
);
# Each OIDC app per project
zitadel_application_oidc = cfg.organization |> select [ "project" "application" ] (org: project: name: { redirectUris, grantTypes, responseTypes, ...}:
{
inherit name redirectUris grantTypes responseTypes;
accessTokenRoleAssertion = true;
idTokenRoleAssertion = true;
accessTokenType = "JWT";
}
|> withRef "org" org
|> withRef "project" "${org}_${project}"
|> toResource "${org}_${project}_${name}"
);
# Each project role
zitadel_project_role = cfg.organization |> select [ "project" "role" ] (org: project: name: value:
{ inherit (value) displayName group; roleKey = name; }
|> withRef "org" org
|> withRef "project" "${org}_${project}"
|> toResource "${org}_${project}_${name}"
);
# Each project role assignment
zitadel_user_grant = cfg.organization |> select [ "project" "assign" ] (org: project: user: roles:
{ roleKeys = roles; }
|> withRef "org" org
|> withRef "project" "${org}_${project}"
|> withRef "user" "${org}_${user}"
|> toResource "${org}_${project}_${user}"
);
# Users
zitadel_human_user =
cfg.organization
|> select [ "user" ] (org: name: { email, userName, firstName, lastName, ... }:
{
inherit email userName firstName lastName;
isEmailVerified = true;
}
|> withRef "org" org
|> toResource "${org}_${name}"
)
|> append
[
(forEach "local.extra_users" [ "org" "name" ] {
orgId = lib.tfRef "local.orgs[each.value.org]";
userName = lib.tfRef "each.value.name";
email = lib.tfRef "each.value.email";
firstName = lib.tfRef "each.value.firstName";
lastName = lib.tfRef "each.value.lastName";
isEmailVerified = true;
}
|> toResource "extraUsers")
]
;
# Global user roles
zitadel_instance_member =
cfg.organization
|> filterAttrsRecursive (n: v: !(v ? "instanceRoles" && (length v.instanceRoles) == 0))
|> select [ "user" ] (org: name: { instanceRoles, ... }:
{ roles = instanceRoles; }
|> withRef "user" "${org}_${name}"
|> toResource "${org}_${name}"
);
# Organazation specific roles
zitadel_org_member =
cfg.organization
|> filterAttrsRecursive (n: v: !(v ? "roles" && (length v.roles) == 0))
|> select [ "user" ] (org: name: { roles, ... }:
{ inherit roles; }
|> withRef "org" org
|> withRef "user" "${org}_${name}"
|> toResource "${org}_${name}"
);
# Organazation's actions
zitadel_action = cfg.organization |> select [ "action" ] (org: name: { timeout, allowedToFail, script, ...}:
{
inherit allowedToFail name;
timeout = "${toString timeout}s";
script = "const ${name} = ${script}";
}
|> withRef "org" org
|> toResource "${org}_${name}"
);
# Organazation's action assignments
zitadel_trigger_actions =
cfg.organization
|> concatMapAttrs (org: { triggers, ... }:
triggers
|> imap0 (i: { flowType, triggerType, actions, ... }: (let name = "trigger_${toString i}"; in
{
inherit flowType triggerType;
actionIds =
actions
|> map (action: (lib.tfRef "zitadel_action.${org}_${toSnakeCase action}.id"));
}
|> withRef "org" org
|> toResource "${org}_${name}"
))
|> listToAttrs
);
# SMTP config
zitadel_smtp_config.default = {
sender_address = "chris@kruining.eu";
sender_name = "no-reply (Zitadel)";
tls = true;
host = "black-mail.nl:587";
user = "chris@kruining.eu";
password = lib.tfRef "file(\"${config'.sops.secrets."zitadel/email".path}\")";
set_active = true;
};
# Client credentials per app
local_sensitive_file = cfg.organization |> select [ "project" "application" ] (org: project: name: { exportMap, ... }:
nameValuePair "${org}_${project}_${name}" {
content = ''
${if exportMap.client_id != null then exportMap.client_id else "CLIENT_ID"}=${lib.tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_id"}
${if exportMap.client_secret != null then exportMap.client_secret else "CLIENT_SECRET"}=${lib.tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_secret"}
'';
filename = "/var/lib/zitadel/clients/${org}_${project}_${name}";
}
);
};
};
})
];
};
in
mkIf cfg.enable {
${namespace}.services.persistance.postgresql.enable = true;
environment.systemPackages = with pkgs; [
zitadel
];
systemd.tmpfiles.rules = [
"d /tmp/zitadelApplyTerraform 0755 zitadel zitadel -"
"d /var/lib/zitadel/clients 0755 zitadel zitadel -"
];
systemd.services.zitadelApplyTerraform = {
description = "Zitadel terraform apply";
wantedBy = [ "multi-user.target" ];
wants = [ "zitadel.service" ];
script = ''
#!/usr/bin/env bash
if [ "$(systemctl is-active zitadel)" != "active" ]; then
echo "Zitadel is not running"
exit 1
fi
# Print the path to the source for easier debugging
echo "config location: ${terraformConfiguration}"
# Copy infra code into workspace
cp -f ${terraformConfiguration} config.tf.json
# Initialize OpenTofu
${lib.getExe pkgs.opentofu} init
# Run the infrastructure code
# ${lib.getExe pkgs.opentofu} plan
${lib.getExe pkgs.opentofu} apply -auto-approve
'';
serviceConfig = {
Type = "oneshot";
User = "zitadel";
Group = "zitadel";
WorkingDirectory = "/tmp/zitadelApplyTerraform";
};
};
services = {
zitadel = {
enable = true;
openFirewall = true;
# masterKeyFile = config.sops.secrets."zitadel/masterKey".path;
masterKeyFile = "/var/lib/zitadel/master_key";
masterKeyFile = config.sops.secrets."zitadel/masterKey".path;
tlsMode = "external";
settings = {
Port = 9092;
ExternalDomain = "auth.amarth.cloud";
ExternalDomain = "auth.kruining.eu";
ExternalPort = 443;
ExternalSecure = true;
@ -40,39 +602,13 @@ in
SecretHasher.Hasher.Algorithm = "argon2id";
};
DefaultInstance = {
PasswordComplexityPolicy = {
MinLength = 20;
HasLowercase = false;
HasUppercase = false;
HasNumber = false;
HasSymbol = false;
};
LoginPolicy = {
AllowRegister = false;
ForceMFA = true;
};
LockoutPolicy = {
MaxPasswordAttempts = 5;
MaxOTPAttempts = 10;
};
SMTPConfiguration = {
SMTP = {
Host = "black-mail.nl:587";
User = "info@amarth.cloud";
Password = "__TODO_USE_SOPS__";
};
FromName = "Amarth Zitadel";
};
};
Database.postgres = {
Host = "localhost";
# Zitadel will report error if port is not set
Port = 5432;
Database = db_name;
Database = database;
User = {
Username = db_user;
Username = database;
SSL.Mode = "disable";
};
Admin = {
@ -83,9 +619,16 @@ in
};
steps = {
FirstInstance = {
InstanceName = "auth.amarth.cloud";
# Not sure, this option seems to be mostly irrelevant
InstanceName = "eu";
MachineKeyPath = "/var/lib/zitadel/machine-key.json";
# PatPath = "/var/lib/zitadel/machine-key.pat";
# LoginClientPatPath = "/var/lib/zitadel/machine-key.json";
Org = {
Name = "Amarth";
Name = "kruining";
Human = {
UserName = "chris";
FirstName = "Chris";
@ -96,39 +639,49 @@ in
};
Password = "KaasIsAwesome1!";
};
Machine = {
Machine = {
Username = "terraform-service-user";
Name = "Terraform";
};
MachineKey = { ExpirationDate = "2026-01-01T00:00:00Z"; Type = 1; };
# Pat = { ExpirationDate = "2026-01-01T00:00:00Z"; };
};
# LoginClient.Machine = {
# Username = "terraform-service-user";
# Name = "Terraform";
# };
};
};
};
# extraStepsPaths = [
# config.sops.templates."secrets.yaml".path
# ];
};
postgresql = {
enable = true;
ensureDatabases = [ db_name ];
ensureDatabases = [ database ];
ensureUsers = [
{
name = db_user;
name = database;
ensureDBOwnership = true;
}
];
authentication = mkForce ''
# Generated file, do not edit!
# TYPE DATABASE USER ADDRESS METHOD
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
'';
};
caddy = {
enable = true;
virtualHosts = {
"auth.amarth.cloud".extraConfig = ''
reverse_proxy h2c://127.0.0.1:9092
"auth.kruining.eu".extraConfig = ''
reverse_proxy h2c://::1:9092
'';
};
extraConfig = ''
(auth-z) {
forward_auth h2c://127.0.0.1:9092 {
(auth) {
forward_auth h2c://::1:9092 {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
}
@ -136,12 +689,37 @@ in
'';
};
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
# Secrets
sops.secrets."zitadel/masterKey" = {
owner = "zitadel";
group = "zitadel";
restartUnits = [ "zitadel.service" ];
sops = {
secrets = {
"zitadel/masterKey" = {
owner = "zitadel";
group = "zitadel";
restartUnits = [ "zitadel.service" ]; #EMGDB#6O$8qpGoLI1XjhUhnng1san@0
};
"zitadel/email" = {
owner = "zitadel";
group = "zitadel";
key = "email/chris_kruining_eu";
restartUnits = [ "zitadel.service" ];
};
"zitadel/users" = {
owner = "zitadel";
group = "zitadel";
restartUnits = [ "zitadelApplyTerraform.service" ];
};
};
templates = {
"users.yml" = {
};
};
};
};
}

View file

@ -0,0 +1,35 @@
{ config, lib, pkgs, namespace, ... }:
let
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.services.backup.borg;
in
{
options.${namespace}.services.backup.borg = {
enable = mkEnableOption "Borg Backup";
};
config = mkIf cfg.enable {
programs.ssh.extraConfig = ''
Host beheer.hazelhof.nl
Port 222
User chris
AddressFamily inet
IdentityFile /home/chris/.ssh/id_ed25519
'';
services = {
borgbackup.jobs = {
media = {
paths = "/var/media/test";
encryption.mode = "none";
# environment.BORG_SSH = "ssh -4 -i /home/chris/.ssh/id_ed25519";
environment.BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = "yes";
repo = "ssh://beheer.hazelhof.nl//media";
compression = "auto,zstd";
startAt = "daily";
};
};
};
};
}

View file

@ -0,0 +1,200 @@
{ config, lib, pkgs, namespace, ... }:
let
inherit (builtins) toString toJSON;
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.services.communication.matrix;
domain = "kruining.eu";
fqn = "matrix.${domain}";
port = 4001;
database = "synapse";
in
{
options.${namespace}.services.communication.matrix = {
enable = mkEnableOption "Matrix server (Synapse)";
};
config = mkIf cfg.enable {
${namespace}.services = {
persistance.postgresql.enable = true;
# virtualisation.podman.enable = true;
};
networking.firewall.allowedTCPPorts = [ 4001 ];
services = {
matrix-synapse = {
enable = true;
extras = [ "oidc" ];
extraConfigFiles = [
config.sops.templates."synapse-oidc.yaml".path
];
settings = {
server_name = domain;
public_baseurl = "https://${fqn}";
enable_metrics = true;
registration_shared_secret = "tZtBnlhEmLbMwF0lQ112VH1Rl5MkZzYH9suI4pEoPXzk6nWUB8FJF4eEnwLkbstz";
url_preview_enabled = true;
precence.enabled = true;
# Since we'll be using OIDC for auth disable all local options
enable_registration = false;
enable_registration_without_verification = false;
password_config.enabled = false;
backchannel_logout_enabled = true;
sso = {
client_whitelist = [ "http://[::1]:9092" ];
update_profile_information = true;
};
database = {
# this is postgresql (also the default, but I prefer to be explicit)
name = "psycopg2";
args = {
database = database;
user = database;
};
};
listeners = [
{
bind_addresses = ["::"];
port = port;
type = "http";
tls = false;
x_forwarded = true;
resources = [
{
names = [ "client" "federation" "openid" "metrics" "media" "health" ];
compress = true;
}
];
}
];
};
};
mautrix-signal = {
enable = true;
registerToSynapse = true;
settings = {
appservice = {
provisioning.enabled = false;
# port = 40011;
};
homeserver = {
address = "http://[::1]:${toString port}";
domain = domain;
};
bridge = {
permissions = {
"@chris:${domain}" = "admin";
};
};
};
};
mautrix-whatsapp = {
enable = true;
registerToSynapse = true;
settings = {
appservice = {
provisioning.enabled = false;
# port = 40012;
};
homeserver = {
address = "http://[::1]:${toString port}";
domain = domain;
};
bridge = {
permissions = {
"@chris:${domain}" = "admin";
};
};
};
};
postgresql = {
enable = true;
ensureDatabases = [ database ];
ensureUsers = [
{
name = database;
ensureDBOwnership = true;
}
];
};
caddy = {
enable = true;
virtualHosts = let
server = {
"m.server" = "${fqn}:443";
};
client = {
"m.homeserver".base_url = "https://${fqn}";
"m.identity_server".base_url = "https://auth.kruining.eu";
};
in {
"${domain}".extraConfig = ''
header /.well-known/matrix/* Content-Type application/json
header /.well-known/matrix/* Access-Control-Allow-Origin *
respond /.well-known/matrix/server `${toJSON server}`
respond /.well-known/matrix/client `${toJSON client}`
'';
"${fqn}".extraConfig = ''
reverse_proxy /_matrix/* http://::1:4001
reverse_proxy /_synapse/client/* http://::1:4001
'';
};
};
};
sops = {
secrets = {
"synapse/oidc_id" = {};
"synapse/oidc_secret" = {};
};
templates = {
"synapse-oidc.yaml" = {
owner = "matrix-synapse";
content = ''
oidc_providers:
- discover: true
idp_id: zitadel
idp_name: Zitadel
issuer: "https://auth.kruining.eu"
scopes:
- openid
- profile
client_id: '${config.sops.placeholder."synapse/oidc_id"}'
client_secret: '${config.sops.placeholder."synapse/oidc_secret"}'
backchannel_logout_enabled: true
user_mapping_provider:
config:
localpart_template: "{{ user.preferred_username }}"
display_name_template: "{{ user.name }}"
'';
restartUnits = [ "matrix-synapse.service" ];
};
};
};
};
}

View file

@ -1,6 +1,7 @@
{ config, lib, pkgs, namespace, ... }:
let
inherit (lib) mkIf mkEnableOption;
inherit (builtins) toString;
inherit (lib) mkIf mkEnableOption mkOption;
cfg = config.${namespace}.services.development.forgejo;
domain = "git.amarth.cloud";
@ -8,10 +9,22 @@ in
{
options.${namespace}.services.development.forgejo = {
enable = mkEnableOption "Forgejo";
port = mkOption {
type = lib.types.port;
default = 5002;
example = "1234";
description = ''
Which port to bind forgejo to
'';
};
};
config = mkIf cfg.enable {
${namespace}.services.virtualisation.podman.enable = true;
${namespace}.services = {
persistance.postgresql.enable = true;
virtualisation.podman.enable = true;
};
environment.systemPackages = with pkgs; [ forgejo ];
@ -30,7 +43,7 @@ in
server = {
DOMAIN = domain;
ROOT_URL = "https://${domain}/";
HTTP_PORT = 5002;
HTTP_PORT = cfg.port;
LANDING_PAGE = "explore";
};
@ -80,7 +93,7 @@ in
openid = {
ENABLE_OPENID_SIGNIN = true;
ENABLE_OPENID_SIGNUP = true;
WHITELISTED_URIS = "https://auth.amarth.cloud";
WHITELISTED_URIS = "https://auth.kruining.eu";
};
oauth2_client = {
@ -91,6 +104,7 @@ in
actions = {
ENABLED = true;
# DEFAULT_ACTIONS_URL = "https://data.forgejo.org";
};
other = {
@ -98,12 +112,16 @@ in
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false;
};
metrics = {
ENABLED = true;
};
api = {
ENABLE_SWAGGER = false;
};
mirror = {
ENABLED = false;
ENABLED = true;
};
session = {
@ -116,9 +134,9 @@ in
PROTOCOL = "smtp+starttls";
SMTP_ADDR = "black-mail.nl";
SMTP_PORT = 587;
FROM = "info@amarth.cloud";
USER = "info@amarth.cloud";
PASSWD = "__TODO_USE_SOPS__";
FROM = "chris@kruining.eu";
USER = "chris@kruining.eu";
PASSWD_URI = "file:${config.sops.secrets."forgejo/email".path}";
};
};
};
@ -126,20 +144,22 @@ in
openssh.settings.AllowUsers = [ "forgejo" ];
gitea-actions-runner = {
package = pkgs.forgejo-actions-runner;
package = pkgs.forgejo-runner;
instances.default = {
enable = true;
name = "default";
url = "https://git.amarth.cloud";
# Obtaining the path to the runner token file may differ
# tokenFile should be in format TOKEN=<secret>, since it's EnvironmentFile for systemd
# tokenFile = config.age.secrets.forgejo-runner-token.path;
token = "ZBetud1F0IQ9VjVFpZ9bu0FXgx9zcsy1x25yvjhw";
tokenFile = config.sops.secrets."forgejo/action_runner_token".path;
# token = "ZBetud1F0IQ9VjVFpZ9bu0FXgx9zcsy1x25yvjhw";
labels = [
"default:docker://node:22-bullseye"
"default:docker://nixos/nix:latest"
"ubuntu:docker://ubuntu:24-bookworm"
"nix:docker://git.amarth.cloud/amarth/runners/default:latest"
];
settings = {
log.level = "info";
};
};
};
@ -147,17 +167,32 @@ in
caddy = {
enable = true;
virtualHosts = {
${domain}.extraConfig = ''
# import auth-z
"${domain}".extraConfig = ''
# import auth
# stupid dumb way to prevent the login page and go to zitadel instead
# be aware that this does not disable local login at all!
rewrite /user/login /user/oauth2/Zitadel
# rewrite /user/login /user/oauth2/Zitadel
reverse_proxy http://127.0.0.1:5002
reverse_proxy http://127.0.0.1:${toString cfg.port}
'';
};
};
};
sops.secrets = {
"forgejo/action_runner_token" = {
owner = "gitea-runner";
group = "gitea-runner";
restartUnits = [ "gitea-runner-default.service" ];
};
"forgejo/email" = {
owner = "forgejo";
group = "forgejo";
key = "email/chris_kruining_eu";
restartUnits = [ "forgejo.service" ];
};
};
};
}

View file

@ -1,9 +1,11 @@
{ pkgs, lib, namespace, config, ... }:
{ pkgs, lib, namespace, config, inputs, system, ... }:
let
inherit (lib) mkIf mkEnableOption mkOption;
inherit (lib.types) str;
cfg = config.${namespace}.services.media;
arr = ["radarr" ];
in
{
options.${namespace}.services.media = {
@ -60,44 +62,74 @@ in
"d '${cfg.path}/reiverr/config' 0700 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/downloads/incomplete' 0700 ${cfg.user} ${cfg.group} - -"
"d '${cfg.path}/downloads/done' 0700 ${cfg.user} ${cfg.group} - -"
"d /var/lib/radarrApplyTerraform 0755 ${cfg.user} ${cfg.group} -"
];
#=========================================================================
# Services
#=========================================================================
services = let
serviceConf = {
arr-services =
arr
|> lib.imap (i: service: {
name = service;
value = {
enable = true;
openFirewall = true;
environmentFiles = [
config.sops.templates."${service}/config.env".path
];
settings = {
auth.authenticationMethod = "External";
server = {
bindaddress = "0.0.0.0";
port = 2000 + i;
};
postgres = {
host = "localhost";
port = "5432";
user = service;
maindb = service;
logdb = service;
};
};
}
// (if service != "prowlarr" then { user = cfg.user; group = cfg.group; } else {});
})
|> lib.listToAttrs
;
in
arr-services // {
bazarr = {
enable = true;
openFirewall = true;
user = cfg.user;
group = cfg.group;
listenPort = 2005;
};
# port is harcoded in nixpkgs module
jellyfin = {
enable = true;
openFirewall = true;
user = cfg.user;
group = cfg.group;
};
in {
jellyfin = serviceConf;
radarr = serviceConf;
sonarr = serviceConf;
bazarr = serviceConf;
lidarr = serviceConf;
flaresolverr = {
enable = true;
openFirewall = true;
};
jellyseerr = {
enable = true;
openFirewall = true;
};
prowlarr = {
enable = true;
openFirewall = true;
port = 2007;
};
qbittorrent = {
enable = true;
openFirewall = true;
webuiPort = 5000;
webuiPort = 2008;
serverConfig = {
LegalNotice.Accepted = true;
@ -107,6 +139,7 @@ in
group = cfg.group;
};
# port is harcoded in nixpkgs module
sabnzbd = {
enable = true;
openFirewall = true;
@ -116,46 +149,159 @@ in
group = cfg.group;
};
postgresql =
let
databases = arr |> lib.concatMap (s: [ s "${s}-log" ]);
in
{
enable = true;
ensureDatabases = arr;
ensureUsers = arr |> lib.map (service: {
name = service;
ensureDBOwnership = true;
});
};
caddy = {
enable = true;
virtualHosts = {
"media.kruining.eu".extraConfig = ''
import auth
reverse_proxy http://127.0.0.1:9494
'';
"jellyfin.kruining.eu".extraConfig = ''
reverse_proxy http://127.0.0.1:8096
reverse_proxy http://[::1]:8096
'';
};
};
};
systemd.services.radarrApplyTerraform =
let
# this is a nix package, the generated json file to be exact
terraformConfiguration = inputs.terranix.lib.terranixConfiguration {
inherit system;
modules = [
({ config, lib, ... }: {
config = {
variable = {
api_key = {
type = "string";
description = "Radarr api key";
};
};
terraform.required_providers.radarr = {
source = "devopsarr/radarr";
version = "2.2.0";
};
provider.radarr = {
url = "http://127.0.0.1:2001";
api_key = lib.tfRef "var.api_key";
};
resource = {
radarr_root_folder.local = {
path = "/var/media/movies";
};
};
};
})
];
};
in
{
description = "Radarr terraform apply";
wantedBy = [ "multi-user.target" ];
wants = [ "radarr.service" ];
script = ''
#!/usr/bin/env bash
if [ "$(systemctl is-active radarr)" != "active" ]; then
echo "Radarr is not running"
exit 1
fi
# Sleep for a bit to give radarr the chance to start up
sleep 5s
# Print the path to the source for easier debugging
echo "config location: ${terraformConfiguration}"
# Copy infra code into workspace
cp -f ${terraformConfiguration} config.tf.json
# Initialize OpenTofu
${lib.getExe pkgs.opentofu} init
# Run the infrastructure code
# ${lib.getExe pkgs.opentofu} plan -var-file='${config.sops.templates."radarr/config.tfvars".path}'
${lib.getExe pkgs.opentofu} apply -auto-approve -var-file='${config.sops.templates."radarr/config.tfvars".path}'
'';
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
WorkingDirectory = "/var/lib/radarrApplyTerraform";
EnvironmentFile = [
config.sops.templates."radarr/config.env".path
];
};
};
systemd.services.jellyfin.serviceConfig.killSignal = lib.mkForce "SIGKILL";
${namespace}.services.virtualisation.podman.enable = true;
virtualisation = {
oci-containers = {
backend = "podman";
containers = {
# flaresolverr = {
# image = "flaresolverr/flaresolverr";
# autoStart = true;
# ports = [ "127.0.0.1:8191:8191" ];
# };
reiverr = {
image = "ghcr.io/aleksilassila/reiverr:v2.2.0";
autoStart = true;
ports = [ "127.0.0.1:9494:9494" ];
volumes = [ "${cfg.path}/reiverr/config:/config" ];
sops = {
secrets =
arr
|> lib.map (service: {
name = "${service}/apikey";
value = {
owner = cfg.user;
group = cfg.group;
restartUnits = [ "${service}.service" ];
};
};
};
};
})
|> lib.listToAttrs
;
networking.firewall.allowedTCPPorts = [ 80 443 6969 ];
templates =
let
apikeys =
arr
|> lib.map (service: {
name = "${service}/config.env";
value = {
owner = cfg.user;
group = cfg.group;
restartUnits = [ "${service}.service" ];
content = ''
${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}"
'';
};
})
|> lib.listToAttrs;
tfvars =
arr
|> lib.map(service: {
name = "${service}/config.tfvars";
value = {
owner = cfg.user;
group = cfg.group;
restartUnits = [ "${service}ApplyTerraform.service" ];
content = ''
api_key = "${config.sops.placeholder."${service}/apikey"}"
'';
};
})
|> lib.listToAttrs;
in
apikeys // tfvars
;
};
};
}

View file

@ -0,0 +1,161 @@
{ config, lib, namespace, ... }:
let
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.services.media.homer;
in
{
options.${namespace}.services.media.homer = {
enable = mkEnableOption "Enable homer";
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 2000 ];
services = {
homer = {
enable = true;
virtualHost = {
caddy.enable = true;
domain = "http://:2000";
};
settings = {
title = "Ulmo dashboard";
columns = 4;
connectivityCheck = true;
links = [];
services = [
{
name = "Services";
items = [
{
name = "Zitadel";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/zitadel.svg";
tag = "app";
url = "https://auth.kruining.eu";
target = "_blank";
}
{
name = "Forgejo";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/forgejo.svg";
tag = "app";
type = "Gitea";
url = "https://git.amarth.cloud";
target = "_blank";
}
{
name = "Vaultwarden";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/vaultwarden.svg";
type = "Vaultwarden";
tag = "app";
url = "https://vault.kruining.eu";
target = "_blank";
}
];
}
{
name = "Observability";
items = [
{
name = "Grafana";
type = "Grafana";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/grafana.svg";
tag = "app";
url = "http://${config.networking.hostName}:${builtins.toString config.services.grafana.settings.server.http_port}";
target = "_blank";
}
{
name = "Prometheus";
type = "Prometheus";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/prometheus.svg";
tag = "app";
url = "http://${config.networking.hostName}:${builtins.toString config.services.prometheus.port}";
target = "_blank";
}
];
}
{
name = "Media";
items = [
{
name = "Jellyfin (Movies)";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/jellyfin.svg";
tag = "app";
type = "Emby";
url = "http://${config.networking.hostName}:8096";
apikey = "e3ceed943eeb409ba8342738db7cc1f5";
libraryType = "movies";
target = "_blank";
}
{
name = "Radarr";
type = "Radarr";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/radarr.svg";
tag = "app";
url = "http://${config.networking.hostName}:2001";
target = "_blank";
}
{
name = "Sonarr";
type = "Sonarr";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/sonarr.svg";
tag = "app";
url = "http://${config.networking.hostName}:2002";
target = "_blank";
}
{
name = "Lidarr";
type = "Lidarr";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/lidarr.svg";
tag = "app";
url = "http://${config.networking.hostName}:2003";
target = "_blank";
}
{
name = "Prowlarr";
type = "Prowlarr";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/prowlarr.svg";
tag = "app";
url = "http://${config.networking.hostName}:2004";
target = "_blank";
}
{
name = "qBittorrent";
type = "qBittorrent";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/qbittorrent.svg";
tag = "app";
url = "http://${config.networking.hostName}:${builtins.toString config.services.qbittorrent.webuiPort}";
target = "_blank";
}
{
name = "SABnzbd";
type = "SABnzbd";
logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/sabnzdb-light.svg";
tag = "app";
url = "http://${config.networking.hostName}:8080";
target = "_blank";
}
];
}
];
};
};
};
};
}

View file

@ -0,0 +1,214 @@
{ pkgs, config, lib, namespace, inputs, system, ... }:
let
inherit (builtins) toString;
inherit (lib) mkIf mkEnableOption mkOption types;
cfg = config.${namespace}.services.media.servarr;
in
{
options.${namespace}.services.media = {
servarr = mkOption {
type = types.attrsOf (types.submodule ({ name, ... }: {
options = {
enable = mkEnableOption "Enable ${name}";
debug = mkEnableOption "Use tofu plan instead of tofu apply for ${name} ";
port = mkOption {
type = types.port;
};
rootFolders = mkOption {
type = types.listOf types.str;
default = [];
};
};
}));
default = {};
};
};
config = {
services =
cfg
|> lib.mapAttrsToList (service: { enable, port, ... }: (mkIf enable {
"${service}" = {
enable = true;
openFirewall = true;
environmentFiles = [
config.sops.templates."${service}/config.env".path
];
settings = {
auth.authenticationMethod = "External";
server = {
bindaddress = "0.0.0.0";
port = port;
};
postgres = {
host = "localhost";
port = "5432";
user = service;
maindb = service;
logdb = service;
};
};
};
}))
|> lib.mergeAttrsList
|> (set: set // {
postgres = {
ensureDatabases = cfg |> lib.attrNames;
ensureUsers = cfg |> lib.attrNames |> lib.map (service: {
name = service;
ensureDBOwnership = true;
});
};
})
;
systemd =
cfg
|> lib.mapAttrsToList (service: { enable, debug, port, rootFolders, ... }: (mkIf enable {
tmpfiles.rules = [
"d /var/lib/${service}ApplyTerraform 0755 ${service} ${service} -"
];
services."${service}ApplyTerraform" =
let
terraformConfiguration = inputs.terranix.lib.terranixConfiguration {
inherit system;
modules = [
({ config, lib, ... }: {
config = {
variable = {
api_key = {
type = "string";
description = "${service} api key";
};
};
terraform.required_providers.${service} = {
source = "devopsarr/${service}";
version = "2.2.0";
};
provider.${service} = {
url = "http://127.0.0.1:${toString port}";
api_key = lib.tfRef "var.api_key";
};
resource = {
"${service}_root_folder" =
rootFolders
|> lib.imap (i: f: lib.nameValuePair "local${toString i}" { path = f; })
|> lib.listToAttrs
;
};
};
})
];
};
in
{
description = "${service} terraform apply";
wantedBy = [ "multi-user.target" ];
wants = [ "${service}.service" ];
script = ''
#!/usr/bin/env bash
# Sleep for a bit to give the service a chance to start up
sleep 5s
if [ "$(systemctl is-active ${service})" != "active" ]; then
echo "${service} is not running"
exit 1
fi
# Print the path to the source for easier debugging
echo "config location: ${terraformConfiguration}"
# Copy infra code into workspace
cp -f ${terraformConfiguration} config.tf.json
# Initialize OpenTofu
${lib.getExe pkgs.opentofu} init
# Run the infrastructure code
${lib.getExe pkgs.opentofu} \
${if debug then "plan" else "apply -auto-approve"} \
-var-file='${config.sops.templates."${service}/config.tfvars".path}'
'';
serviceConfig = {
Type = "oneshot";
User = service;
Group = service;
WorkingDirectory = "/var/lib/${service}ApplyTerraform";
EnvironmentFile = [
config.sops.templates."${service}/config.env".path
];
};
};
}))
|> lib.mergeAttrsList
;
users.users =
cfg
|> lib.mapAttrsToList (service: { enable, ... }: (mkIf enable {
"${service}".extraGroups = [ "media" ];
}))
|> lib.mergeAttrsList
;
sops =
cfg
|> lib.mapAttrsToList (service: { enable, ... }: (mkIf enable {
secrets."${service}/apikey" = {
owner = service;
group = service;
restartUnits = [ "${service}.service" ];
};
templates = {
"${service}/config.env" = {
owner = service;
group = service;
restartUnits = [ "${service}.service" ];
content = ''
${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}"
'';
};
"${service}/config.tfvars" = {
owner = service;
group = service;
restartUnits = [ "${service}.service" ];
content = ''
api_key = "${config.sops.placeholder."${service}/apikey"}"
'';
};
};
}))
|> lib.mergeAttrsList
;
};
# cfg
# |> lib.mapAttrsToList (service: { enable, debug, port, rootFolders, ... }: (mkIf enable {
# # sops = {
# # };
# }))
# |> lib.mergeAttrsList
# ;
}

View file

@ -42,9 +42,9 @@ in
login_attribute_path = "username";
name_attribute_path = "full_name";
role_attribute_path = "contains(urn:zitadel:iam:org:project:roles[*], 'owner') && 'GrafanaAdmin' || contains(urn:zitadel:iam:org:project:roles[*], 'contributer') && 'Editor' || 'Viewer'";
auth_url = "https://auth.amarth.cloud/oauth/v2/authorize";
token_url = "https://auth.amarth.cloud/oauth/v2/token";
api_url = "https://auth.amarth.cloud/oidc/v1/userinfo";
auth_url = "https://auth.kruining.eu/oauth/v2/authorize";
token_url = "https://auth.kruining.eu/oauth/v2/token";
api_url = "https://auth.kruining.eu/oidc/v1/userinfo";
allow_sign_up = true;
auto_login = true;
use_pkce = true;

View file

@ -23,7 +23,7 @@ in
common = {
ring = {
instance_addr = "127.0.0.1";
kvstore.store = "inmmemory";
kvstore.store = "inmemory";
};
replication_factor = 1;
path_prefix = "/tmp/loki";

View file

@ -29,9 +29,11 @@ in
filename = "filename";
};
clients = {
url = "http://127.0.0.1:3100/loki/api/v1/push";
};
clients = [
{
url = "http://::1:9003/loki/api/v1/push";
}
];
scrape_configs = [
{

View file

@ -0,0 +1,25 @@
{ pkgs, config, lib, namespace, ... }:
let
inherit (builtins) toString;
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.services.observability.uptime-kuma;
in
{
options.${namespace}.services.observability.uptime-kuma = {
enable = mkEnableOption "enable uptime kuma";
};
config = mkIf cfg.enable {
services.uptime-kuma = {
enable = true;
settings = {
PORT = toString 9006;
HOST = "0.0.0.0";
};
};
networking.firewall.allowedTCPPorts = [ 9006 ];
};
}

View file

@ -0,0 +1,21 @@
{ config, pkgs, lib, namespace, ... }:
let
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.services.persistance.convex;
in
{
imports = [ ./source.nix ];
options.${namespace}.services.persistance.convex = {
enable = mkEnableOption "enable Convex";
};
config = mkIf cfg.enable {
services.convex = {
enable = true;
package = pkgs.${namespace}.convex;
secret = "ThisIsMyAwesomeSecret";
};
};
}

View file

@ -0,0 +1,149 @@
{ config, pkgs, lib, namespace, ... }:
let
inherit (lib) mkIf mkEnableOption mkPackageOption mkOption optional types;
cfg = config.services.convex;
default_user = "convex";
default_group = "convex";
in
{
options.services.convex = {
enable = mkEnableOption "enable Convex (backend only for now)";
package = mkPackageOption pkgs "convex" {};
name = lib.mkOption {
type = types.str;
default = "convex";
description = ''
Name for the instance.
'';
};
secret = lib.mkOption {
type = types.str;
default = "";
description = ''
Secret for the instance.
'';
};
apiPort = mkOption {
type = types.port;
default = 3210;
description = ''
The TCP port to use for the API.
'';
};
actionsPort = mkOption {
type = types.port;
default = 3211;
description = ''
The TCP port to use for the HTTP actions.
'';
};
dashboardPort = mkOption {
type = types.port;
default = 6791;
description = ''
The TCP port to use for the Dashboard.
'';
};
openFirewall = lib.mkOption {
type = types.bool;
default = false;
description = ''
Whether to open ports in the firewall for the server.
'';
};
user = lib.mkOption {
type = types.str;
default = default_user;
description = ''
As which user to run the service.
'';
};
group = lib.mkOption {
type = types.str;
default = default_group;
description = ''
As which group to run the service.
'';
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.secret != "";
message = ''
No secret provided for convex
'';
}
];
users = {
users.${cfg.user} = {
description = "System user for convex service";
isSystemUser = true;
group = cfg.group;
};
groups.${cfg.group} = {};
};
networking.firewall.allowedTCPPorts = optional cfg.openFirewall [ cfg.apiPort cfg.actionsPort cfg.dashboardPort ];
environment.systemPackages = [ cfg.package ];
systemd.services.convex = {
description = "Convex Backend server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = "${cfg.package}/bin --instance-name ${cfg.name} --instance-secret ${cfg.secret}";
Type = "notify";
User = cfg.user;
Group = cfg.group;
RuntimeDirectory = "convex";
RuntimeDirectoryMode = "0775";
StateDirectory = "convex";
StateDirectoryMode = "0775";
Umask = "0077";
CapabilityBoundingSet = "";
NoNewPrivileges = true;
# Sandboxing
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectClock = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
LockPersonality = true;
};
};
};
}

View file

@ -0,0 +1,26 @@
{ config, lib, pkgs, namespace, ... }:
let
inherit (lib) mkIf mkEnableOption;
cfg = config.${namespace}.services.persistance.postgresql;
in
{
options.${namespace}.services.persistance.postgresql = {
enable = mkEnableOption "Postgresql";
};
config = mkIf cfg.enable {
services = {
postgresql = {
enable = true;
authentication = ''
# Generated file, do not edit!
# TYPE DATABASE USER ADDRESS METHOD
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
'';
};
};
};
}

View file

@ -1,13 +1,87 @@
{ pkgs, config, lib, namespace, ... }:
let
inherit (builtins) toString;
inherit (lib) mkIf mkEnableOption;
inherit (lib) mkIf mkEnableOption mkOption types getAttrs toUpper concatMapAttrsStringSep;
cfg = config.${namespace}.services.security.vaultwarden;
databaseProviderSqlite = types.submodule ({ ... }: {
options = {
type = mkOption {
type = types.enum [ "sqlite" ];
};
file = mkOption {
type = types.str;
description = '''';
};
};
});
databaseProviderPostgresql = types.submodule ({ ... }:
let
urlOptions = lib.${namespace}.options.mkUrlOptions {
host = {
description = ''
Hostname of the postgresql server
'';
};
port = {
default = 5432;
example = "5432";
description = ''
Port of the postgresql server
'';
};
protocol = mkOption {
default = "postgres";
example = "postgres";
};
};
in
{
options = {
type = mkOption {
type = types.enum [ "postgresql" ];
};
sslMode = mkOption {
type = types.enum [ "verify-ca" "verify-full" "require" "prefer" "allow" "disabled" ];
default = "verify-full";
example = "verify-ca";
description = ''
How to verify the server's ssl
| mode | eavesdropping protection | MITM protection | Statement |
|-------------|--------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| disable | No | No | I don't care about security, and I don't want to pay the overhead of encryption. |
| allow | Maybe | No | I don't care about security, but I will pay the overhead of encryption if the server insists on it. |
| prefer | Maybe | No | I don't care about encryption, but I wish to pay the overhead of encryption if the server supports it. |
| require | Yes | No | I want my data to be encrypted, and I accept the overhead. I trust that the network will make sure I always connect to the server I want. |
| verify-ca | Yes | Depends on CA policy | I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server that I trust. |
| verify-full | Yes | Yes | I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server I trust, and that it's the one I specify. |
[Source](https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS)
'';
};
} // (urlOptions |> getAttrs [ "protocol" "host" "port" ]);
});
in
{
options.${namespace}.services.security.vaultwarden = {
enable = mkEnableOption "enable vaultwarden";
database = mkOption {
type = types.oneOf [
(types.addCheck databaseProviderSqlite (x: x ? type && x.type == "sqlite"))
(types.addCheck databaseProviderPostgresql (x: x ? type && x.type == "postgresql"))
null
];
default = null;
description = '''';
};
};
config = mkIf cfg.enable {
@ -15,6 +89,8 @@ in
"d '/var/lib/vaultwarden' 0700 vaultwarden vaultwarden - -"
];
# systemd.services.vaultwarden.wants = [ "zitadelApplyTerraform.service" ];
services = {
vaultwarden = {
enable = true;
@ -26,8 +102,6 @@ in
SIGNUPS_ALLOWED = false;
DOMAIN = "https://vault.kruining.eu";
ADMIN_TOKEN = "";
DATABASE_URL = "postgres://localhost:5432/vaultwarden?sslmode=disable";
WEB_VAULT_ENABLED = true;
@ -39,11 +113,8 @@ in
SSO_ROLES_ENABLED = true;
SSO_ORGANIZATIONS_ENABLED = true;
SSO_ORGANIZATIONS_REVOCATION = true;
SSO_AUTHORITY = "https://auth.amarth.cloud/";
SSO_AUTHORITY = "https://auth.kruining.eu/";
SSO_SCOPES = "email profile offline_access";
SSO_AUDIENCE_TRUSTED = "^333297815511892227$";
SSO_CLIENT_ID = "335178854421299459";
SSO_CLIENT_SECRET = "";
ROCKET_ADDRESS = "::1";
ROCKET_PORT = 8222;
@ -52,11 +123,15 @@ in
SMTP_HOST = "black-mail.nl";
SMTP_PORT = 587;
SMTP_SECURITY = "starttls";
SMTP_USERNAME = "info@amarth.cloud";
SMTP_PASSWORD = "";
SMTP_FROM = "info@amarth.cloud";
SMTP_USERNAME = "chris@kruining.eu";
SMTP_FROM = "chris@kruining.eu";
SMTP_FROM_NAME = "Chris' Vaultwarden";
};
environmentFile = [
"/var/lib/zitadel/clients/nix_ulmo_vaultwarden"
config.sops.templates."vaultwarden/config.env".path
];
};
postgresql = {
@ -76,6 +151,12 @@ in
"vault.kruining.eu".extraConfig = ''
encode zstd gzip
handle_path /admin {
respond 401 {
close
}
}
reverse_proxy http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT} {
header_up X-Real-IP {remote_host}
}
@ -83,5 +164,54 @@ in
};
};
};
sops = {
secrets = {
"vaultwarden/email" = {
owner = config.users.users.vaultwarden.name;
group = config.users.users.vaultwarden.name;
key = "email/chris_kruining_eu";
restartUnits = [ "vaultwarden.service" ];
};
};
templates = {
"vaultwarden/config.env" = {
content = ''
SMTP_PASSWORD='${config.sops.placeholder."vaultwarden/email"}';
'';
owner = config.users.users.vaultwarden.name;
group = config.users.groups.vaultwarden.name;
};
temp-db-output.content =
let
config =
cfg.database
|> ({ type, ... }@db:
if type == "sqlite" then
{ inherit (db) type file; }
else if type == "postgresql" then
{
inherit (db) type;
url = lib.${namespace}.strings.toUrl {
inherit (db) protocol host port;
path = "vaultwarden";
query = {
sslmode = db.sslMode;
};
};
}
else
{}
)
|> concatMapAttrsStringSep "\n" (n: v: "${toUpper n}=${v}")
;
in
''
# GENERATED VALUES
${config}
'';
};
};
};
}

View file

@ -12,6 +12,7 @@ in
config = mkIf cfg.enable {
virtualisation = {
containers.enable = true;
oci-containers.backend = "podman";
podman = {
enable = true;

View file

@ -1,4 +1,4 @@
{ pkgs, config, namespace, inputs, ... }:
{ pkgs, config, namespace, inputs, system, ... }:
let
cfg = config.${namespace}.system.security.sops;
in
@ -13,10 +13,14 @@ in
environment.systemPackages = with pkgs; [ sops ];
sops = {
defaultSopsFile = ../../../../../_secrets/secrets.yaml;
defaultSopsFormat = "yaml";
defaultSopsFile = inputs.self + "/systems/${system}/${config.networking.hostName}/secrets.yml";
age.keyFile = "/home/";
age = {
# keyFile = "~/.config/sops/age/keys.txt";
# sshKeyPaths = [ "~/.ssh/id_ed25519" ];
# generateKey = true;
};
};
};
}

View file

@ -0,0 +1,59 @@
{
lib,
stdenv,
rustPlatform,
fetchFromGitHub,
# dependencies
openssl,
pkg-config,
cmake,
llvmPackages,
postgresql,
sqlite,
#options
dbBackend ? "postgresql",
...
}:
rustPlatform.buildRustPackage rec {
pname = "convex";
version = "2025-08-20-c9b561e";
src = fetchFromGitHub {
owner = "get-convex";
repo = "convex-backend";
rev = "c9b561e1b365c85ef28af35d742cb7dd174b5555";
hash = "sha256-4h4AQt+rQ+nTw6eTbbB5vqFt9MFjKYw3Z7bGXdXijJ0=";
};
cargoHash = "sha256-pcDNWGrk9D0qcF479QAglPLFDZp27f8RueP5/lq9jho=";
cargoBuildFlags = [
"-p" "local_backend"
"--bin" "convex-local-backend"
];
env = {
LIBCLANG_PATH = "${llvmPackages.libclang}/lib";
};
strictDeps = true;
# Build-time dependencies
nativeBuildInputs = [ pkg-config cmake rustPlatform.bindgenHook ];
# Run-time dependencies
buildInputs =
[ openssl ]
++ lib.optional (dbBackend == "sqlite") sqlite
++ lib.optional (dbBackend == "postgresql") postgresql;
buildFeatures = "";
meta = with lib; {
license = licenses.fsl11Asl20;
mainProgram = "convex";
};
}

View file

@ -0,0 +1,12 @@
{ mkShell, inputs, pkgs, ... }:
mkShell {
packages = with pkgs; [
bash
sops
just
yq
pwgen
inputs.clan-core.packages.x86_64-linux.clan-cli
];
}

View file

@ -5,6 +5,8 @@
./hardware.nix
];
system.activationScripts.remove-gtkrc.text = "rm -f /home/chris/.gtkrc-2.0";
sneeuwvlok = {
hardware.has = {
gpu.amd = true;

View file

@ -8,7 +8,7 @@ in
swapDevices = [];
boot.supportedFilesystems = [ "nfs" ];
fileSystems = {
"/" = {
device = "/dev/disk/by-label/nixos";
@ -26,9 +26,9 @@ in
fsType = "nfs";
};
"/home/chris/mandos" = {
device = "mandos:/";
fsType = "nfs";
};
# "/home/chris/mandos" = {
# device = "mandos:/";
# fsType = "nfs";
# };
};
}

View file

@ -5,26 +5,200 @@
./hardware.nix
];
networking = {
interfaces.enp2s0 = {
ipv6.addresses = [
{ address = "2a0d:6e00:1dc9:0::dead:beef"; prefixLength = 64; }
];
useDHCP = true;
};
defaultGateway = {
address = "192.168.1.1";
interface = "enp2s0";
};
defaultGateway6 = {
address = "fe80::1";
interface = "enp2s0";
};
};
# Expose amarht cloud stuff like this until I have a proper solution
services.caddy.virtualHosts = {
"auth.amarth.cloud".extraConfig = ''
reverse_proxy http://192.168.1.223:9092
'';
"amarth.cloud".extraConfig = ''
reverse_proxy http://192.168.1.223:8080
'';
};
sneeuwvlok = {
services = {
authentication.authelia.enable = true;
authentication.zitadel.enable = true;
backup.borg.enable = true;
authentication.zitadel = {
enable = true;
organization = {
nix = {
user = {
chris = {
email = "chris@kruining.eu";
firstName = "Chris";
lastName = "Kruining";
roles = [ "ORG_OWNER" ];
instanceRoles = [ "IAM_OWNER" ];
};
kaas = {
email = "chris+kaas@kruining.eu";
firstName = "Kaas";
lastName = "Kruining";
};
};
project = {
ulmo = {
projectRoleCheck = true;
projectRoleAssertion = true;
hasProjectCheck = true;
role = {
jellyfin = {
group = "jellyfin";
};
jellyfin_admin = {
group = "jellyfin";
};
};
assign = {
chris = [ "jellyfin" "jellyfin_admin" ];
kaas = [ "jellyfin" ];
};
application = {
jellyfin = {
redirectUris = [ "https://jellyfin.kruining.eu/sso/OID/redirect/zitadel" ];
grantTypes = [ "authorizationCode" ];
responseTypes = [ "code" ];
};
forgejo = {
redirectUris = [ "https://git.amarth.cloud/user/oauth2/zitadel/callback" ];
grantTypes = [ "authorizationCode" ];
responseTypes = [ "code" ];
};
vaultwarden = {
redirectUris = [ "https://vault.kruining.eu/identity/connect/oidc-signin" ];
grantTypes = [ "authorizationCode" ];
responseTypes = [ "code" ];
exportMap = {
client_id = "SSO_CLIENT_ID";
client_secret = "SSO_CLIENT_SECRET";
};
};
matrix = {
redirectUris = [ "https://matrix.kruining.eu/_synapse/client/oidc/callback" ];
grantTypes = [ "authorizationCode" ];
responseTypes = [ "code" ];
};
};
};
};
action = {
flattenRoles = {
script = ''
(ctx, api) => {
if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
return;
}
const roles = ctx.v1.user.grants.grants.flatMap(({ roles, projectId }) => roles.map(role => projectId + ':' + role));
api.v1.claims.setClaim('nix:zitadel:custom', JSON.stringify({ roles }));
};
'';
};
};
triggers = [
{ flowType = "customiseToken"; triggerType = "preUserinfoCreation"; actions = [ "flattenRoles" ]; }
{ flowType = "customiseToken"; triggerType = "preAccessTokenCreation"; actions = [ "flattenRoles" ]; }
];
};
};
};
communication.matrix.enable = true;
development.forgejo.enable = true;
networking.ssh.enable = true;
media.enable = true;
media.homer.enable = true;
media.nfs.enable = true;
media.servarr = {
# radarr = {
# port = 2001;
# };
sonarr = {
enable = true;
# debug = true;
port = 2002;
rootFolders = [
"/var/media/series"
];
};
lidarr = {
enable = true;
debug = true;
port = 2003;
rootFolders = [
"/var/media/music"
];
};
prowlarr = {
enable = true;
debug = true;
port = 2004;
};
};
observability = {
grafana.enable = true;
prometheus.enable = true;
loki.enable = true;
promtail.enable = true;
# uptime-kuma.enable = true;
};
security.vaultwarden.enable = true;
persistance.convex.enable = true;
security.vaultwarden = {
enable = true;
database = {
# type = "sqlite";
# file = "/var/lib/vaultwarden/state.db";
type = "postgresql";
host = "localhost";
port = 5432;
sslMode = "disabled";
};
};
};
editor = {

View file

@ -5,9 +5,7 @@ in
{
# TODO :: Implement disko at some point
swapDevices = [
{ device = "/dev/disk/by-uuid/0ddf001a-5679-482e-b254-04a1b9094794"; }
];
swapDevices = [];
boot.supportedFilesystems = [ "nfs" ];

View file

@ -0,0 +1,45 @@
email:
chris_kruining_eu: ENC[AES256_GCM,data:/JS+dQ6ABlkdjRZP+sGeUY3js30swS4=,iv:d5CcoY6DD3DJ/e3t0OU/KUULccJpTN0uBQPQzl/3R0s=,tag:aTN7RdzXkIpci9tEBjevSA==,type:str]
info_amarth_cloud: ENC[AES256_GCM,data:/x7aAFAxXYYf79tB08VQmmuTIy2TvdSTFfAzIWdIr+I=,iv:plNxS6oOin+oEql+1xsePOsUfLJkf+ZPBviPRTbIghE=,tag:hjtK3rysd2NNBA2mWdv8cw==,type:str]
zitadel:
masterKey: ENC[AES256_GCM,data:4MPvBo407qrS7NF4oUTf84tZoPkSRmiHdD7qpkYeHME=,iv:H2NIAN0xBUDqnyco9gA3zYAsKtSeA/JpqYrPhc1eqc0=,tag:6OFGDfsucG5gDerImgpuXA==,type:str]
nix: {}
users: ENC[AES256_GCM,data:xkjm0+PBt6gmZyfi3n3OIEe5b+d4OtN0Y3UfmdcbcJHbJZuiz+60oUjlAN0vjtsi0muufoAqtGJTIpm9nDZzzN7b7LK43TAhcuSlIm5LpbZFp1U3H4laRbTwauAT6wA0aDCfAkwTozxAuEUk1jAu+65ktJNJb7b0PR7s/I/wf7IgW2+K4Jv3LIOZIipUwfuvXuTzsxCElYRvGZXmIuXrYq1EaymksHHggemrKeMWLAae7mzz5v3aBbwxiVjQNkQkS4ApsO/5nZUat0oqXA==,iv:fptZn4NmX3iYKSEPLJAOFpt+KQ6TR1w9KaY9IF4p/Wk=,tag:UKvMOSIT5/mhfZA3usbLhQ==,type:str]
forgejo:
action_runner_token: ENC[AES256_GCM,data:yJ6OnRq5kinbuhvH06K5o3l86EafuBoojMwg/qhP+cgeH+BwPeE+Ng==,iv:IeXJahPxgLNIUFmkgp495tLVh8UyQBmJ2SnVEUhlhHs=,tag:XYQi613CxSp8AQeilJMrsg==,type:str]
synapse:
oidc_id: ENC[AES256_GCM,data:XbCpyGq0LeRJWq8dv/5Dipvp,iv:YDhgl26z1NBbIQLoLdGVz0+ze6o1ZcmgVHPfwoRj57I=,tag:y2vUuqnDmtTvVQmZCAlnLg==,type:str]
oidc_secret: ENC[AES256_GCM,data:nVFi5EFbNMZ0mvrDHVYC0NiwJlo2eEw44D+Fcv9SKSb2oO00lGEDkP/oXDj5YgDq6RLQSe3f/SUOn77ntwnZYg==,iv:awe7VNUYOn9ofl1QlQTrEN5d0i5WkVM35qndruL4VXo=,tag:8Yoc9lFF9aWbtAa5fzQGEA==,type:str]
kaas: ENC[AES256_GCM,data:3yI6lH0rw+f2OFJ94Z7zb0pYwy4FDFs9rJi2wpd9VVWghmey5g4O788ypXa34XqKCQDDHDgTxwyDs6KpvCQQaLV1PDhXd4Po0SSlIOkUtCWhOf6Tp3PM2ASoE+AAAzJLJUc6AZdBJRyYU9V+UvO9jW+WmlpZpsg5crnVMzZo7f2AF0ep9A/A5BL1Y2UhYQE4LDVkLC9AL3hl8IhF5xSdZdO0ugrP0x7CKVUxA7fJyOjx7/IKVwvgKD4xlhIgv9lYPTvE2vUs+w==,iv:e6b98ZnBqf7hh3SSKGdTl63OpQm1oK95lHXdwTiLft8=,tag:IS/lDgvJvSd7OmDLP+uG1g==,type:str]
radarr:
apikey: ENC[AES256_GCM,data:G141GW4PyS5pbAV39HcVscMw3s30txOgTZzWaL7o+ccZfnfDLv796O6xKXdqGZ8saLsveghLw9Z6a5luusHyQ3Q5ESL6W7SVeZVTuSqSC3i/4jl75FJxhnsgVsfrnYxzLGpKiw==,iv:sZl/XLh6y3WgSAn6nH3sFB6atBifZdghm+QsCNDbcjY=,tag:Tw+R80nrF0T0yDti0Uf+ig==,type:str]
sonarr:
apikey: ENC[AES256_GCM,data:s8bgDJ+LpIH1Mt3KSiIKB8LnxztOkHdc8J6+50o+HoDUAfIIsZkA2oX/m7UecrTSRi6ay8D9yjhe6ZwSNXhJh6wQqTS7gZWn8f6QfrfI+8DKdc9enh91suQxjkz8Q+wnKK0zBg==,iv:LmAe6v+6ItVnHB6gko6mhiGOuVBksBYP4dXfbxpAIPE=,tag:DZ8kwOwaWwWTGWEGu5S0Kg==,type:str]
lidarr:
apikey: ENC[AES256_GCM,data:I2eKaxidmxem7C7ukmyIfwASNqrkS4vEOiCcU5kSNY6DR0pXsYg0PBdgu8vzK6llbXODLdG5t55BordIWvVRJGAauo0FMvtp59NSNpza7cK68tdKGvNefD6bqhUIR06BY11niQ==,iv:48AD7cd17TlWY5yAagepLOIVwgxhD/d13Pnup6GsWDA=,tag:teOVtW8opE99hqAXQwvlrA==,type:str]
prowlarr:
apikey: ENC[AES256_GCM,data:pyZ2WGEs/PlIdhDsQq2TPGJbplkd5fLF0ZkBjITqIJlnAzYHb+rl+KOM4rHqQcI6yAJM8X1Y3ymGrD7vG7GiRxB7yoEG13SKhZIWOddTnxIhbkz81RfrL2fUJIydOaP6sS//9Q==,iv:Tr6MWoC6nC7rdVTOjT1T2itT+lVL4GnUiAr5/+IHAs0=,tag:keIJNuGeVht8+xSN3FnBGA==,type:str]
sops:
age:
- recipient: age19qfpf980tadguqq44zf6xwvjvl428dyrj46ha3n6aeqddwhtnuqqml7etq
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwdDZyZkxvNU4zM3NHb2gx
ZlhLZk5JWUFGMWZGeUVHNkFFU1NtZlBQVVhjCmZGai9NdmdUeU5VcW9ROVZKTW5q
cmZaQ2JlaldaTWduQklocUZLT2FUcGcKLS0tIHlqVU0wdXJ0dTE4dlZSVEczd2Yv
RVFxVHFxbkVNbEZsaVcwYXZCdUc5R1kKQdAN6LEKmGLCSkKhNuEr0YK2zl9Aw1kK
6C25lN532mG55zIRectZda1Fmi1GMZ/2v3b5qz7x+TDMA9m/47OjmA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ewes0f5snqx3sh5ul6fa6qtxzhd25829v6mf5rx2wnheat6fefps5rme2x
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoK3lqRDhEMXEvaUp3OWdV
eFlZSGpJcGs0RTdRbllWdmdZTzl3RTlDNlIwCm92R290NjNyK2NNbWpINTBhazNS
NTJYWEw0SGc1TUtrd0NZSmowakMvSlEKLS0tIG5uUEIrZGVORkRNVnBVOHgyMXZG
TTRWaHhpNWlkVDFmMFN4ZTNHMUxyNVkKV693pzTKRkZboQCMPr9IyMGSgxfuHXcb
Y6BNcp6Qg6PWtX5QI7wRkPNINAK1TEbRBba+b8h6gMmVU4DliQyFiQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-11-19T09:51:26Z"
mac: ENC[AES256_GCM,data:pMMkxHPochpI8si/oHhU7MHqC1JjNhMP7HCRNQQEkwBQI489xiC02t+qUwpmG4oIheqi8lEcZPpL4t9HzRN9sZImaI2LrJn3cHFojHzXzo7FPfvfUilZe1+JXLfm+wn+bflAEutIcfDiZc/MjiKOxRHwZy5Pr41Mj6uPIUr62zk=,iv:GwvMVgJ6m1DQcRZMVzshbuMK/Kx8vE8Ym83KbxuvYRg=,tag:wVSol9LDRzoFjQppB8J9gA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0