Compare commits
381 Commits
ke-qa-nixp
...
update-nix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c3b3ffd8e | ||
|
|
ae5712229c | ||
|
|
0ea561f998 | ||
|
|
aabbe0dfac | ||
|
|
35cb99a3a2 | ||
|
|
90e6d77e26 | ||
|
|
5fb4751bd8 | ||
|
|
03640e44a4 | ||
|
|
51fd60917e | ||
|
|
2d7e659953 | ||
|
|
c638df8ed9 | ||
|
|
ec269a48f3 | ||
|
|
fc4c9287cb | ||
|
|
fee62373a9 | ||
|
|
f075b339b5 | ||
|
|
872a622f71 | ||
|
|
4a41c4cefb | ||
|
|
a5cd36e845 | ||
|
|
0dd6c08e33 | ||
|
|
dc0b7fc3bf | ||
|
|
0d4bbbd17e | ||
|
|
90797ffa7d | ||
|
|
7f2bd809d6 | ||
|
|
da7ff9a40a | ||
|
|
410d0d0532 | ||
|
|
a25d983c87 | ||
|
|
3953fa4047 | ||
|
|
ea93cb9987 | ||
|
|
c13278f3c2 | ||
|
|
66fdf937e3 | ||
|
|
843f55f844 | ||
|
|
5a5633d779 | ||
|
|
8310433342 | ||
|
|
51141772b3 | ||
|
|
58b88e874f | ||
|
|
5fb616efb4 | ||
|
|
6c6afd6f4b | ||
|
|
4010953041 | ||
|
|
6b74c66292 | ||
|
|
fd35adbc3e | ||
|
|
f86b0ec3da | ||
|
|
5f6e0540cd | ||
|
|
c7ec9a9715 | ||
|
|
841e9135fe | ||
|
|
9299cd9666 | ||
|
|
9851993b82 | ||
|
|
55d1807f07 | ||
|
|
ee0abdc7f4 | ||
|
|
6c9ab63842 | ||
|
|
d70db5af79 | ||
|
|
eae858dec6 | ||
|
|
2ec035a1cb | ||
|
|
bd6c227bbe | ||
|
|
02f3474a58 | ||
|
|
c838e08d77 | ||
|
|
346e3d816a | ||
|
|
a15959fad2 | ||
|
|
0e0c2ead1f | ||
|
|
c42381d810 | ||
|
|
587ce7258a | ||
|
|
d0bb804843 | ||
|
|
410eecb988 | ||
|
|
98136142b4 | ||
|
|
37da9fb3e4 | ||
|
|
4566ad9789 | ||
|
|
6faacc7dde | ||
|
|
0d088cac7e | ||
|
|
3ffad3f97f | ||
|
|
3d0c281fd6 | ||
|
|
5b399fd447 | ||
|
|
bfedc93f2c | ||
|
|
c63e706fe9 | ||
|
|
dfc241c62d | ||
|
|
6fcdc05911 | ||
|
|
137f22b39e | ||
|
|
9857a395f1 | ||
|
|
4302b06715 | ||
|
|
064bc43f27 | ||
|
|
7ab1b6823f | ||
|
|
f96a487bc3 | ||
|
|
e6a1953785 | ||
|
|
4bedb380b8 | ||
|
|
3b070ae1f3 | ||
|
|
bdb0a97285 | ||
|
|
a0cce07259 | ||
|
|
1edf576702 | ||
|
|
7824ee99cb | ||
|
|
13c20242ad | ||
|
|
ba81b1ae12 | ||
|
|
7eb54b6564 | ||
|
|
5c007edd9f | ||
|
|
03ba598842 | ||
|
|
d699f0b66a | ||
|
|
65e599b92a | ||
|
|
788f8beea4 | ||
|
|
da8768c4c0 | ||
|
|
eb11054f65 | ||
|
|
5922b4617c | ||
|
|
5286994288 | ||
|
|
8ad025b462 | ||
|
|
4442cb2fe0 | ||
|
|
460c6d4fc9 | ||
|
|
893fa47a50 | ||
|
|
62d3a18783 | ||
|
|
ac1cd5114a | ||
|
|
e0b5855013 | ||
|
|
4fd057413f | ||
|
|
96fcc41b19 | ||
|
|
811b994d57 | ||
|
|
87aa62e128 | ||
|
|
612275477a | ||
|
|
046cfcb4d7 | ||
|
|
965d41b37d | ||
|
|
c36935d81a | ||
|
|
ae4197277a | ||
|
|
0cc7bd7066 | ||
|
|
31f77f7a56 | ||
|
|
d3d56e83e7 | ||
|
|
c725fc9fa3 | ||
|
|
7d6d5967dc | ||
|
|
afcc5d9e26 | ||
|
|
0e9931d749 | ||
|
|
b4d1f07ed9 | ||
|
|
0d182f4431 | ||
|
|
20a6a5684d | ||
|
|
e5967bb0de | ||
|
|
dcd7b6a8a2 | ||
|
|
a48451cc8f | ||
|
|
7580475cb6 | ||
|
|
ebe7a8ed0b | ||
|
|
c7cee905d1 | ||
|
|
5b7925c079 | ||
|
|
5e56f746ad | ||
|
|
4f5abe32f9 | ||
|
|
64a0dcb37f | ||
|
|
422f3da9df | ||
|
|
f7e20f70a8 | ||
|
|
cbabcd91ed | ||
|
|
5221d34448 | ||
|
|
5ab3c86b68 | ||
|
|
0324f68709 | ||
|
|
7cd14a5959 | ||
|
|
a6584023ae | ||
|
|
2f381bf677 | ||
|
|
a1c29f8aed | ||
|
|
42eb8e7a05 | ||
|
|
890cd47b2a | ||
|
|
cf4622052d | ||
|
|
88bf893228 | ||
|
|
0b1f711f2c | ||
|
|
39d9f44286 | ||
|
|
f91aca959f | ||
|
|
8af166b899 | ||
|
|
61a185f947 | ||
|
|
6ad2b0b124 | ||
|
|
b70c20b260 | ||
|
|
9821e39b06 | ||
|
|
2ac65b9c83 | ||
|
|
18dc042a0b | ||
|
|
7a4a940e83 | ||
|
|
df73169392 | ||
|
|
50e4b7a2f4 | ||
|
|
e836ff86b4 | ||
|
|
714bc58573 | ||
|
|
17c35c4259 | ||
|
|
727474055e | ||
|
|
892cb1baae | ||
|
|
186656999f | ||
|
|
00b7347d00 | ||
|
|
5eb6b703f0 | ||
|
|
3d436b3c6b | ||
|
|
d78dca47e2 | ||
|
|
8254d197f0 | ||
|
|
a4839f9cf2 | ||
|
|
bb4b43f5be | ||
|
|
4c7699b205 | ||
|
|
b7013dc795 | ||
|
|
617e4b0ce1 | ||
|
|
600d37682c | ||
|
|
ac4800a7df | ||
|
|
0af64dad01 | ||
|
|
a32a5151dc | ||
|
|
16d245b179 | ||
|
|
24ecdb227e | ||
|
|
867fa5140b | ||
|
|
891aac8381 | ||
|
|
2b616575e1 | ||
|
|
3f07f6ac79 | ||
|
|
c6b0b114c5 | ||
|
|
8803343ae1 | ||
|
|
4cfe866079 | ||
|
|
8609538756 | ||
|
|
5ea0e7776e | ||
|
|
a296b8a1fe | ||
|
|
ebbbdcaa59 | ||
|
|
ccf64d5951 | ||
|
|
16e20e159f | ||
|
|
43a5a5db5a | ||
|
|
c1686691fa | ||
|
|
115d0a05b7 | ||
|
|
4cfef1e21c | ||
|
|
42e3fea9e5 | ||
|
|
6b7530f27d | ||
|
|
7e00a08111 | ||
|
|
0c245f8eda | ||
|
|
9469968851 | ||
|
|
c2a71fb423 | ||
|
|
13d3bc9391 | ||
|
|
3161ab3903 | ||
|
|
6df67aee00 | ||
|
|
ed9f9c0d9d | ||
|
|
969c17e410 | ||
|
|
3c7c52e35a | ||
|
|
b0e327e0d1 | ||
|
|
550b374d20 | ||
|
|
23008d1f73 | ||
|
|
733d80d0b2 | ||
|
|
9dceddc6c2 | ||
|
|
f1747079c8 | ||
|
|
ffdcd9b41e | ||
|
|
2ef56aff70 | ||
|
|
2ca4abbfef | ||
|
|
1344466097 | ||
|
|
b1b68c514d | ||
|
|
08072b3850 | ||
|
|
67637007a2 | ||
|
|
558dd55058 | ||
|
|
63ccbd7ca7 | ||
|
|
d9f6b7e3fb | ||
|
|
254f9b9c5f | ||
|
|
44ff545436 | ||
|
|
40de60946a | ||
|
|
f25d17d9c2 | ||
|
|
70233b5e53 | ||
|
|
044d5f1c7d | ||
|
|
389c586a26 | ||
|
|
e01a79696b | ||
|
|
aade61b019 | ||
|
|
6956858d61 | ||
|
|
7e7e58eb64 | ||
|
|
46f746d09c | ||
|
|
56e03d1f25 | ||
|
|
0343e4b91a | ||
|
|
137d505c3b | ||
|
|
dd783bdf85 | ||
|
|
bf41a9ef00 | ||
|
|
d8c9508507 | ||
|
|
f313ace19a | ||
|
|
fe8f7e919e | ||
|
|
c64276b64e | ||
|
|
436da16bf9 | ||
|
|
1c3282bb63 | ||
|
|
3c4b3e180e | ||
|
|
3953715b48 | ||
|
|
7b95fa039f | ||
|
|
347668a57f | ||
|
|
63fdc13928 | ||
|
|
9b0557803e | ||
|
|
c13879ce69 | ||
|
|
f57bc30c5a | ||
|
|
38712d6fe0 | ||
|
|
1d38ffa9c2 | ||
|
|
665f036dec | ||
|
|
b74b6ff449 | ||
|
|
9c8797e770 | ||
|
|
2be6cedec4 | ||
|
|
7f49449f94 | ||
|
|
1f7bfa4e34 | ||
|
|
67fab4b11d | ||
|
|
18e3c72ef0 | ||
|
|
84d4660a8d | ||
|
|
13c3e1411a | ||
|
|
3c3a505aca | ||
|
|
f33c8e98fe | ||
|
|
869a04e5af | ||
|
|
d09fdc3528 | ||
|
|
652677d06f | ||
|
|
ec163657cd | ||
|
|
7d3aa5936d | ||
|
|
f8f8efbb88 | ||
|
|
8887e209d6 | ||
|
|
a72f74a36e | ||
|
|
0e0f8e73ec | ||
|
|
f15a113f52 | ||
|
|
1fbb4f5014 | ||
|
|
980a3c90b5 | ||
|
|
c01b14aef5 | ||
|
|
0a3e564ec0 | ||
|
|
bc09d5c886 | ||
|
|
f6b8d660d8 | ||
|
|
6014ddcd9a | ||
|
|
551f5144c7 | ||
|
|
9a664c323c | ||
|
|
7572dc8c2b | ||
|
|
e22f0d9e36 | ||
|
|
f93ae13448 | ||
|
|
749bac63f4 | ||
|
|
2bac2ec7ee | ||
|
|
f224d4b20c | ||
|
|
47aa0a3b8e | ||
|
|
dd1cab5daa | ||
|
|
32edae4ebd | ||
|
|
d829aa5838 | ||
|
|
fd6619668b | ||
|
|
50a26ece32 | ||
|
|
8f224b00a6 | ||
|
|
27d43ee21d | ||
|
|
9626e22db7 | ||
|
|
1df329fe0d | ||
|
|
9da38abc77 | ||
|
|
2814c46e68 | ||
|
|
feef0a513e | ||
|
|
9cc85b36c6 | ||
|
|
1465b18820 | ||
|
|
6fa0062573 | ||
|
|
6cd68c23f5 | ||
|
|
fdddc60676 | ||
|
|
684aa27068 | ||
|
|
35d8deb393 | ||
|
|
e2f20b5ffc | ||
|
|
fd5d7934a0 | ||
|
|
f194c31e0e | ||
|
|
061b598adf | ||
|
|
744f35e0cc | ||
|
|
4a6d46198c | ||
|
|
82d5ca9a0b | ||
|
|
28d8a91a30 | ||
|
|
18f8d69728 | ||
|
|
1feead4ce4 | ||
|
|
7f28110558 | ||
|
|
38787da891 | ||
|
|
2b587da9fe | ||
|
|
acd2c1654b | ||
|
|
2ecb1399c3 | ||
|
|
46ae6b49c1 | ||
|
|
50a8a69719 | ||
|
|
203761a99c | ||
|
|
990b4e0223 | ||
|
|
032f54cbfb | ||
|
|
47146efa0f | ||
|
|
c031abcd9e | ||
|
|
6b5dca5842 | ||
|
|
016fe3d114 | ||
|
|
9b60b4a989 | ||
|
|
3088ce025b | ||
|
|
4f1fda3de6 | ||
|
|
57f14827c2 | ||
|
|
0390d5999d | ||
|
|
58e9a28f14 | ||
|
|
b4ad5ca1bd | ||
|
|
84ecb1aae6 | ||
|
|
2b9971f538 | ||
|
|
81e15cab34 | ||
|
|
215c808071 | ||
|
|
4de052e58b | ||
|
|
a06a7a7a2c | ||
|
|
94df3855b5 | ||
|
|
a83f3c23f4 | ||
|
|
da6cd324f0 | ||
|
|
c5b96df7b0 | ||
|
|
c4feeace31 | ||
|
|
6117b664ae | ||
|
|
b8fdb48fd8 | ||
|
|
9165f7ccaf | ||
|
|
8058a7c158 | ||
|
|
fed61f49f9 | ||
|
|
f1f05c7e6b | ||
|
|
7597d1560f | ||
|
|
f739e1b66d | ||
|
|
5d3609aacd | ||
|
|
7aa51d6bd7 | ||
|
|
af91ae8c7f | ||
|
|
077bf55fd7 | ||
|
|
1f6dcb910f | ||
|
|
6363d9c99c | ||
|
|
fd30dbd1be | ||
|
|
ba4dc36ddf | ||
|
|
5abac04b15 | ||
|
|
8c84d32b13 | ||
|
|
c083548795 | ||
|
|
204f9d09e3 |
12
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
12
.gitea/PULL_REQUEST_TEMPLATE.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
## Description of the change
|
||||||
|
|
||||||
|
<!-- Brief summary of the change if not already clear from the title -->
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] Updated Documentation
|
||||||
|
- [ ] Added tests
|
||||||
|
- [ ] Doesn't affect backwards compatibility - or check the next points
|
||||||
|
- [ ] Add the breaking change and migration details to docs/release-notes.md
|
||||||
|
- !!! Review from another person is required *BEFORE* merge !!!
|
||||||
|
- [ ] Add introduction of major feature to docs/release-notes.md
|
||||||
@@ -17,4 +17,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Build clan-app for x86_64-darwin
|
- name: Build clan-app for x86_64-darwin
|
||||||
run: |
|
run: |
|
||||||
nix build .#packages.x86_64-darwin.clan-app --system x86_64-darwin --log-format bar-with-logs
|
nix build .#packages.x86_64-darwin.clan-app --log-format bar-with-logs
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
clanServices/.* @pinpox @kenji
|
clanServices/.* @pinpox @kenji
|
||||||
|
|
||||||
lib/test/container-test-driver/.* @DavHau @mic92
|
lib/test/container-test-driver/.* @DavHau @mic92
|
||||||
lib/modules/inventory/.* @hsjobeki
|
lib/inventory/.* @hsjobeki
|
||||||
lib/modules/inventoryClass/.* @hsjobeki
|
lib/inventoryClass/.* @hsjobeki
|
||||||
|
|
||||||
|
modules/.* @hsjobeki
|
||||||
|
|
||||||
pkgs/clan-app/ui/.* @hsjobeki @brianmcgee
|
pkgs/clan-app/ui/.* @hsjobeki @brianmcgee
|
||||||
pkgs/clan-app/clan_app/.* @qubasa @hsjobeki
|
pkgs/clan-app/clan_app/.* @qubasa @hsjobeki
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright 2023-2024 Clan contributors
|
Copyright 2023-2025 Clan contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
|||||||
@@ -19,20 +19,7 @@ let
|
|||||||
nixosLib = import (self.inputs.nixpkgs + "/nixos/lib") { };
|
nixosLib = import (self.inputs.nixpkgs + "/nixos/lib") { };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports =
|
imports = filter pathExists [
|
||||||
let
|
|
||||||
clanCoreModulesDir = ../nixosModules/clanCore;
|
|
||||||
getClanCoreTestModules =
|
|
||||||
let
|
|
||||||
moduleNames = attrNames (builtins.readDir clanCoreModulesDir);
|
|
||||||
testPaths = map (
|
|
||||||
moduleName: clanCoreModulesDir + "/${moduleName}/tests/flake-module.nix"
|
|
||||||
) moduleNames;
|
|
||||||
in
|
|
||||||
filter pathExists testPaths;
|
|
||||||
in
|
|
||||||
getClanCoreTestModules
|
|
||||||
++ filter pathExists [
|
|
||||||
./devshell/flake-module.nix
|
./devshell/flake-module.nix
|
||||||
./flash/flake-module.nix
|
./flash/flake-module.nix
|
||||||
./installation/flake-module.nix
|
./installation/flake-module.nix
|
||||||
@@ -40,6 +27,10 @@ in
|
|||||||
./morph/flake-module.nix
|
./morph/flake-module.nix
|
||||||
./nixos-documentation/flake-module.nix
|
./nixos-documentation/flake-module.nix
|
||||||
./dont-depend-on-repo-root.nix
|
./dont-depend-on-repo-root.nix
|
||||||
|
# clan core submodule tests
|
||||||
|
../nixosModules/clanCore/machine-id/tests/flake-module.nix
|
||||||
|
../nixosModules/clanCore/postgresql/tests/flake-module.nix
|
||||||
|
../nixosModules/clanCore/state-version/tests/flake-module.nix
|
||||||
];
|
];
|
||||||
flake.check = genAttrs [ "x86_64-linux" "aarch64-darwin" ] (
|
flake.check = genAttrs [ "x86_64-linux" "aarch64-darwin" ] (
|
||||||
system:
|
system:
|
||||||
@@ -95,11 +86,13 @@ in
|
|||||||
|
|
||||||
# Container Tests
|
# Container Tests
|
||||||
nixos-test-container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
nixos-test-container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
||||||
|
nixos-systemd-abstraction = self.clanLib.test.containerTest ./systemd-abstraction nixosTestArgs;
|
||||||
|
nixos-llm-test = self.clanLib.test.containerTest ./llm nixosTestArgs;
|
||||||
nixos-test-user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
|
nixos-test-user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
|
||||||
nixos-test-user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
|
nixos-test-user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
|
||||||
|
nixos-test-extra-python-packages = self.clanLib.test.containerTest ./test-extra-python-packages nixosTestArgs;
|
||||||
|
|
||||||
service-dummy-test = import ./service-dummy-test nixosTestArgs;
|
service-dummy-test = import ./service-dummy-test nixosTestArgs;
|
||||||
wireguard = import ./wireguard nixosTestArgs;
|
|
||||||
service-dummy-test-from-flake = import ./service-dummy-test-from-flake nixosTestArgs;
|
service-dummy-test-from-flake = import ./service-dummy-test-from-flake nixosTestArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -120,7 +113,7 @@ in
|
|||||||
) (self.darwinConfigurations or { })
|
) (self.darwinConfigurations or { })
|
||||||
// lib.mapAttrs' (n: lib.nameValuePair "package-${n}") (
|
// lib.mapAttrs' (n: lib.nameValuePair "package-${n}") (
|
||||||
if system == "aarch64-darwin" then
|
if system == "aarch64-darwin" then
|
||||||
lib.filterAttrs (n: _: n != "docs" && n != "deploy-docs" && n != "docs-options") packagesToBuild
|
lib.filterAttrs (n: _: n != "docs" && n != "deploy-docs" && n != "option-search") packagesToBuild
|
||||||
else
|
else
|
||||||
packagesToBuild
|
packagesToBuild
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ let
|
|||||||
networking.useNetworkd = true;
|
networking.useNetworkd = true;
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
services.openssh.settings.UseDns = false;
|
services.openssh.settings.UseDns = false;
|
||||||
services.openssh.settings.PasswordAuthentication = false;
|
|
||||||
system.nixos.variant_id = "installer";
|
system.nixos.variant_id = "installer";
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
pkgs.nixos-facter
|
pkgs.nixos-facter
|
||||||
|
|||||||
83
checks/llm/default.nix
Normal file
83
checks/llm/default.nix
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{ self, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
cli = self.packages.${pkgs.hostPlatform.system}.clan-cli-full;
|
||||||
|
|
||||||
|
ollama-model = pkgs.callPackage ./qwen3-4b-instruct.nix { };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "llm";
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
peer1 =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
|
||||||
|
users.users.text-user = {
|
||||||
|
isNormalUser = true;
|
||||||
|
linger = true;
|
||||||
|
uid = 1000;
|
||||||
|
extraGroups = [ "systemd-journal" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Set environment variables for user systemd
|
||||||
|
environment.extraInit = ''
|
||||||
|
if [ "$(id -u)" = "1000" ]; then
|
||||||
|
export XDG_RUNTIME_DIR="/run/user/1000"
|
||||||
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
|
||||||
|
|
||||||
|
ollama_dir="$HOME/.ollama"
|
||||||
|
mkdir -p "$ollama_dir"
|
||||||
|
ln -sf ${ollama-model}/models "$ollama_dir"/models
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Enable PAM for user systemd sessions
|
||||||
|
security.pam.services.systemd-user = {
|
||||||
|
startSession = true;
|
||||||
|
# Workaround for containers - use pam_permit to avoid helper binary issues
|
||||||
|
text = pkgs.lib.mkForce ''
|
||||||
|
account required pam_permit.so
|
||||||
|
session required pam_permit.so
|
||||||
|
session required pam_env.so conffile=/etc/pam/environment readenv=0
|
||||||
|
session required ${pkgs.systemd}/lib/security/pam_systemd.so
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
cli
|
||||||
|
pkgs.ollama
|
||||||
|
(cli.pythonRuntime.withPackages (
|
||||||
|
ps: with ps; [
|
||||||
|
pytest
|
||||||
|
pytest-xdist
|
||||||
|
(cli.pythonRuntime.pkgs.toPythonModule cli)
|
||||||
|
self.legacyPackages.${pkgs.hostPlatform.system}.nixosTestLib
|
||||||
|
]
|
||||||
|
))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript =
|
||||||
|
{ ... }:
|
||||||
|
''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
peer1.wait_for_unit("multi-user.target")
|
||||||
|
peer1.wait_for_unit("user@1000.service")
|
||||||
|
|
||||||
|
# Fix user journal permissions so text-user can read their own logs
|
||||||
|
peer1.succeed("chown text-user:systemd-journal /var/log/journal/*/user-1000.journal*")
|
||||||
|
peer1.succeed("chmod 640 /var/log/journal/*/user-1000.journal*")
|
||||||
|
# the -o adopts="" is needed to overwrite any args coming from pyproject.toml
|
||||||
|
# -p no:cacheprovider disables pytest's cacheprovider which tries to write to the nix store in this case
|
||||||
|
cmd = "su - text-user -c 'pytest -s -n0 -m service_runner -p no:cacheprovider -o addopts="" ${cli.passthru.sourceWithTests}/clan_lib/llm'"
|
||||||
|
print("Running tests with command: " + cmd)
|
||||||
|
|
||||||
|
|
||||||
|
# Run tests as text-user (environment variables are set automatically)
|
||||||
|
peer1.succeed(cmd)
|
||||||
|
'';
|
||||||
|
}
|
||||||
70
checks/llm/qwen3-4b-instruct.nix
Normal file
70
checks/llm/qwen3-4b-instruct.nix
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{ pkgs }:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Got them from https://github.com/Gholamrezadar/ollama-direct-downloader
|
||||||
|
|
||||||
|
# Download manifest
|
||||||
|
manifest = pkgs.fetchurl {
|
||||||
|
url = "https://registry.ollama.ai/v2/library/qwen3/manifests/4b-instruct";
|
||||||
|
# You'll need to calculate this hash - run the derivation once and it will tell you the correct hash
|
||||||
|
hash = "sha256-Dtze80WT6sGqK+nH0GxDLc+BlFrcpeyi8nZiwY8Wi6A=";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Download blobs
|
||||||
|
blob1 = pkgs.fetchurl {
|
||||||
|
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:b72accf9724e93698c57cbd3b1af2d3341b3d05ec2089d86d273d97964853cd2";
|
||||||
|
hash = "sha256-tyrM+XJOk2mMV8vTsa8tM0Gz0F7CCJ2G0nPZeWSFPNI=";
|
||||||
|
};
|
||||||
|
|
||||||
|
blob2 = pkgs.fetchurl {
|
||||||
|
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:85e4a5b7b8ef0e48af0e8658f5aaab9c2324c76c1641493f4d1e25fce54b18b9";
|
||||||
|
hash = "sha256-heSlt7jvDkivDoZY9aqrnCMkx2wWQUk/TR4l/OVLGLk=";
|
||||||
|
};
|
||||||
|
|
||||||
|
blob3 = pkgs.fetchurl {
|
||||||
|
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:eade0a07cac7712787bbce23d12f9306adb4781d873d1df6e16f7840fa37afec";
|
||||||
|
hash = "sha256-6t4KB8rHcSeHu84j0S+TBq20eB2HPR324W94QPo3r+w=";
|
||||||
|
};
|
||||||
|
|
||||||
|
blob4 = pkgs.fetchurl {
|
||||||
|
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:d18a5cc71b84bc4af394a31116bd3932b42241de70c77d2b76d69a314ec8aa12";
|
||||||
|
hash = "sha256-0YpcxxuEvErzlKMRFr05MrQiQd5wx30rdtaaMU7IqhI=";
|
||||||
|
};
|
||||||
|
|
||||||
|
blob5 = pkgs.fetchurl {
|
||||||
|
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:0914c7781e001948488d937994217538375b4fd8c1466c5e7a625221abd3ea7a";
|
||||||
|
hash = "sha256-CRTHeB4AGUhIjZN5lCF1ODdbT9jBRmxeemJSIavT6no=";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "ollama-qwen3-4b-instruct";
|
||||||
|
version = "1.0";
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
mkdir -p $out/models/manifests/registry.ollama.ai/library/qwen3
|
||||||
|
mkdir -p $out/models/blobs
|
||||||
|
|
||||||
|
# Copy manifest
|
||||||
|
cp ${manifest} $out/models/manifests/registry.ollama.ai/library/qwen3/4b-instruct
|
||||||
|
|
||||||
|
# Copy blobs with correct names
|
||||||
|
cp ${blob1} $out/models/blobs/sha256-b72accf9724e93698c57cbd3b1af2d3341b3d05ec2089d86d273d97964853cd2
|
||||||
|
cp ${blob2} $out/models/blobs/sha256-85e4a5b7b8ef0e48af0e8658f5aaab9c2324c76c1641493f4d1e25fce54b18b9
|
||||||
|
cp ${blob3} $out/models/blobs/sha256-eade0a07cac7712787bbce23d12f9306adb4781d873d1df6e16f7840fa37afec
|
||||||
|
cp ${blob4} $out/models/blobs/sha256-d18a5cc71b84bc4af394a31116bd3932b42241de70c77d2b76d69a314ec8aa12
|
||||||
|
cp ${blob5} $out/models/blobs/sha256-0914c7781e001948488d937994217538375b4fd8c1466c5e7a625221abd3ea7a
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
# buildPhase already created everything in $out
|
||||||
|
:
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "Qwen3 4B Instruct model for Ollama";
|
||||||
|
license = "apache-2.0";
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
modules.new-service = {
|
modules.new-service = {
|
||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "new-service";
|
manifest.name = "new-service";
|
||||||
|
manifest.readme = "Just a sample readme to not trigger the warning.";
|
||||||
roles.peer = {
|
roles.peer = {
|
||||||
description = "A peer that uses the new-service to generate some files.";
|
description = "A peer that uses the new-service to generate some files.";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ nixosLib.runTest (
|
|||||||
modules.new-service = {
|
modules.new-service = {
|
||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "new-service";
|
manifest.name = "new-service";
|
||||||
|
manifest.readme = "Just a sample readme to not trigger the warning.";
|
||||||
roles.peer = {
|
roles.peer = {
|
||||||
description = "A peer that uses the new-service to generate some files.";
|
description = "A peer that uses the new-service to generate some files.";
|
||||||
};
|
};
|
||||||
|
|||||||
67
checks/systemd-abstraction/default.nix
Normal file
67
checks/systemd-abstraction/default.nix
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
{ self, pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
cli = self.packages.${pkgs.hostPlatform.system}.clan-cli-full;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "systemd-abstraction";
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
peer1 = {
|
||||||
|
|
||||||
|
users.users.text-user = {
|
||||||
|
isNormalUser = true;
|
||||||
|
linger = true;
|
||||||
|
uid = 1000;
|
||||||
|
extraGroups = [ "systemd-journal" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Set environment variables for user systemd
|
||||||
|
environment.extraInit = ''
|
||||||
|
if [ "$(id -u)" = "1000" ]; then
|
||||||
|
export XDG_RUNTIME_DIR="/run/user/1000"
|
||||||
|
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Enable PAM for user systemd sessions
|
||||||
|
security.pam.services.systemd-user = {
|
||||||
|
startSession = true;
|
||||||
|
# Workaround for containers - use pam_permit to avoid helper binary issues
|
||||||
|
text = pkgs.lib.mkForce ''
|
||||||
|
account required pam_permit.so
|
||||||
|
session required pam_permit.so
|
||||||
|
session required pam_env.so conffile=/etc/pam/environment readenv=0
|
||||||
|
session required ${pkgs.systemd}/lib/security/pam_systemd.so
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
cli
|
||||||
|
(cli.pythonRuntime.withPackages (
|
||||||
|
ps: with ps; [
|
||||||
|
pytest
|
||||||
|
pytest-xdist
|
||||||
|
]
|
||||||
|
))
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript =
|
||||||
|
{ ... }:
|
||||||
|
''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
peer1.wait_for_unit("multi-user.target")
|
||||||
|
peer1.wait_for_unit("user@1000.service")
|
||||||
|
|
||||||
|
# Fix user journal permissions so text-user can read their own logs
|
||||||
|
peer1.succeed("chown text-user:systemd-journal /var/log/journal/*/user-1000.journal*")
|
||||||
|
peer1.succeed("chmod 640 /var/log/journal/*/user-1000.journal*")
|
||||||
|
|
||||||
|
# Run tests as text-user (environment variables are set automatically)
|
||||||
|
peer1.succeed("su - text-user -c 'pytest -p no:cacheprovider -o addopts="" -s -n0 ${cli.passthru.sourceWithTests}/clan_lib/service_runner'")
|
||||||
|
'';
|
||||||
|
}
|
||||||
26
checks/test-extra-python-packages/default.nix
Normal file
26
checks/test-extra-python-packages/default.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
(
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
name = "test-extra-python-packages";
|
||||||
|
|
||||||
|
extraPythonPackages = ps: [ ps.numpy ];
|
||||||
|
|
||||||
|
nodes.machine =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
networking.hostName = "machine";
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
start_all()
|
||||||
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
|
# Test availability of numpy
|
||||||
|
arr = np.array([1, 2, 3])
|
||||||
|
print(f"Numpy array: {arr}")
|
||||||
|
assert len(arr) == 3
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,8 +1,17 @@
|
|||||||
diff --git a/src/main.rs b/src/main.rs
|
From 46ec73cdeac58807a49b738c44d2e8d5dfbc5fc8 Mon Sep 17 00:00:00 2001
|
||||||
index 8baf5924a7db..1234567890ab 100644
|
From: pinpox <git@pablo.tools>
|
||||||
--- a/src/main.rs
|
Date: Mon, 20 Oct 2025 16:30:22 +0200
|
||||||
+++ b/src/main.rs
|
Subject: [PATCH] patch switch-to-configuration-ng for container tests
|
||||||
@@ -1295,6 +1295,12 @@ won't take effect until you reboot the system.
|
|
||||||
|
---
|
||||||
|
pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs | 6 ++++++
|
||||||
|
1 file changed, 6 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs b/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs
|
||||||
|
index f4d339ccf60e..c50863e15e32 100644
|
||||||
|
--- a/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs
|
||||||
|
+++ b/pkgs/by-name/sw/switch-to-configuration-ng/src/src/main.rs
|
||||||
|
@@ -1320,6 +1320,12 @@ won't take effect until you reboot the system.
|
||||||
|
|
||||||
for (mountpoint, current_filesystem) in current_filesystems {
|
for (mountpoint, current_filesystem) in current_filesystems {
|
||||||
// Use current version of systemctl binary before daemon is reexeced.
|
// Use current version of systemctl binary before daemon is reexeced.
|
||||||
@@ -15,3 +24,6 @@ index 8baf5924a7db..1234567890ab 100644
|
|||||||
let unit = path_to_unit_name(¤t_system_bin, &mountpoint);
|
let unit = path_to_unit_name(¤t_system_bin, &mountpoint);
|
||||||
if let Some(new_filesystem) = new_filesystems.get(&mountpoint) {
|
if let Some(new_filesystem) = new_filesystems.get(&mountpoint) {
|
||||||
if current_filesystem.fs_type != new_filesystem.fs_type
|
if current_filesystem.fs_type != new_filesystem.fs_type
|
||||||
|
--
|
||||||
|
2.51.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
nixosLib,
|
|
||||||
clan-core,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
nixosLib.runTest (
|
|
||||||
{ ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
machines = [
|
|
||||||
"controller1"
|
|
||||||
"controller2"
|
|
||||||
"peer1"
|
|
||||||
"peer2"
|
|
||||||
"peer3"
|
|
||||||
];
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
clan-core.modules.nixosTest.clanTest
|
|
||||||
];
|
|
||||||
|
|
||||||
hostPkgs = pkgs;
|
|
||||||
|
|
||||||
name = "wireguard";
|
|
||||||
|
|
||||||
clan = {
|
|
||||||
directory = ./.;
|
|
||||||
modules."@clan/wireguard" = import ../../clanServices/wireguard/default.nix;
|
|
||||||
inventory = {
|
|
||||||
|
|
||||||
machines = lib.genAttrs machines (_: { });
|
|
||||||
|
|
||||||
instances = {
|
|
||||||
|
|
||||||
/*
|
|
||||||
wg-test-one
|
|
||||||
┌───────────────────────────────┐
|
|
||||||
│ ◄───────────── │
|
|
||||||
│ controller2 controller1
|
|
||||||
│ ▲ ─────────────► ▲ ▲
|
|
||||||
│ │ │ │ │ │ │ │ │
|
|
||||||
│ │ │ │ │ │ │ │ │
|
|
||||||
│ │ │ │ │ │ │ │ │
|
|
||||||
│ │ │ │ └───────────────┐ │ │ │ │
|
|
||||||
│ │ │ └──────────────┐ │ │ │ │ │
|
|
||||||
│ ▼ │ ▼ ▼ ▼
|
|
||||||
└─► peer2 │ peer1 peer3
|
|
||||||
│ ▲
|
|
||||||
└──────────┘
|
|
||||||
*/
|
|
||||||
|
|
||||||
wg-test-one = {
|
|
||||||
|
|
||||||
module.name = "@clan/wireguard";
|
|
||||||
module.input = "self";
|
|
||||||
|
|
||||||
roles.controller.machines."controller1".settings = {
|
|
||||||
endpoint = "192.168.1.1";
|
|
||||||
};
|
|
||||||
|
|
||||||
roles.controller.machines."controller2".settings = {
|
|
||||||
endpoint = "192.168.1.2";
|
|
||||||
};
|
|
||||||
|
|
||||||
roles.peer.machines = {
|
|
||||||
peer1.settings.controller = "controller1";
|
|
||||||
peer2.settings.controller = "controller2";
|
|
||||||
peer3.settings.controller = "controller1";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: Will this actually work with conflicting ports? Can we re-use interfaces?
|
|
||||||
#wg-test-two = {
|
|
||||||
# module.name = "@clan/wireguard";
|
|
||||||
|
|
||||||
# roles.controller.machines."controller1".settings = {
|
|
||||||
# endpoint = "192.168.1.1";
|
|
||||||
# port = 51922;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# roles.peer.machines = {
|
|
||||||
# peer1 = { };
|
|
||||||
# };
|
|
||||||
#};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
|
||||||
start_all()
|
|
||||||
|
|
||||||
# Show all addresses
|
|
||||||
machines = [peer1, peer2, peer3, controller1, controller2]
|
|
||||||
for m in machines:
|
|
||||||
m.systemctl("start network-online.target")
|
|
||||||
|
|
||||||
for m in machines:
|
|
||||||
m.wait_for_unit("network-online.target")
|
|
||||||
m.wait_for_unit("systemd-networkd.service")
|
|
||||||
|
|
||||||
print("\n\n" + "="*60)
|
|
||||||
print("STARTING PING TESTS")
|
|
||||||
print("="*60)
|
|
||||||
|
|
||||||
for m1 in machines:
|
|
||||||
for m2 in machines:
|
|
||||||
if m1 != m2:
|
|
||||||
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
|
|
||||||
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
)
|
|
||||||
25
clanServices/admin/README.md
Normal file
25
clanServices/admin/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
The admin service aggregates components that allow an administrator to log in to and manage the machine.
|
||||||
|
|
||||||
|
The following configuration:
|
||||||
|
|
||||||
|
1. Enables OpenSSH with root login and adds an SSH public key named`myusersKey` to the machine's authorized_keys via the `allowedKeys` setting.
|
||||||
|
|
||||||
|
2. Automatically generates a password for the root user.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
instances = {
|
||||||
|
admin = {
|
||||||
|
roles.default.tags = {
|
||||||
|
all = { };
|
||||||
|
};
|
||||||
|
roles.default.settings = {
|
||||||
|
allowedKeys = {
|
||||||
|
myusersKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFDNnynMbFWatSFdANzbJ8iiEKL7+9ZpDaMLrWRQjyH lhebendanz@wintux";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
manifest.name = "clan-core/admin";
|
manifest.name = "clan-core/admin";
|
||||||
manifest.description = "Adds a root user with ssh access";
|
manifest.description = "Adds a root user with ssh access";
|
||||||
manifest.categories = [ "Utility" ];
|
manifest.categories = [ "Utility" ];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the admin service";
|
description = "Placeholder role to apply the admin service";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ let
|
|||||||
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
|
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
name = "service-admin";
|
name = "admin";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "service-borgbackup";
|
name = "borgbackup";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
{ ... }:
|
{
|
||||||
|
clanLib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
sharedInterface =
|
sharedInterface =
|
||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
@@ -51,15 +54,15 @@ let
|
|||||||
builtins.foldl' (
|
builtins.foldl' (
|
||||||
urls: name:
|
urls: name:
|
||||||
let
|
let
|
||||||
ipPath = "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value";
|
ip = clanLib.vars.getPublicValue {
|
||||||
|
flake = config.clan.core.settings.directory;
|
||||||
|
machine = name;
|
||||||
|
generator = "zerotier";
|
||||||
|
file = "zerotier-ip";
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
if builtins.pathExists ipPath then
|
if ip != null then urls ++ [ "[${ip}]:${builtins.toString settings.network.port}" ] else urls
|
||||||
let
|
|
||||||
ip = builtins.readFile ipPath;
|
|
||||||
in
|
|
||||||
urls ++ [ "[${ip}]:${builtins.toString settings.network.port}" ]
|
|
||||||
else
|
|
||||||
urls
|
|
||||||
) [ ] (builtins.attrNames ((roles.admin.machines or { }) // (roles.signer.machines or { })))
|
) [ ] (builtins.attrNames ((roles.admin.machines or { }) // (roles.signer.machines or { })))
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -156,9 +159,14 @@ in
|
|||||||
readHostKey =
|
readHostKey =
|
||||||
machine:
|
machine:
|
||||||
let
|
let
|
||||||
path = "${config.clan.core.settings.directory}/vars/per-machine/${machine}/data-mesher-host-key/public_key/value";
|
publicKey = clanLib.vars.getPublicValue {
|
||||||
|
flake = config.clan.core.settings.directory;
|
||||||
|
inherit machine;
|
||||||
|
generator = "data-mesher-host-key";
|
||||||
|
file = "public_key";
|
||||||
|
};
|
||||||
in
|
in
|
||||||
builtins.elemAt (lib.splitString "\n" (builtins.readFile path)) 1;
|
builtins.elemAt (lib.splitString "\n" publicKey) 1;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ in
|
|||||||
perSystem =
|
perSystem =
|
||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
clan.nixosTests.service-data-mesher = {
|
clan.nixosTests.data-mesher = {
|
||||||
imports = [ ./tests/vm/default.nix ];
|
imports = [ ./tests/vm/default.nix ];
|
||||||
clan.modules."@clan/data-mesher" = module;
|
clan.modules."@clan/data-mesher" = module;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "service-data-mesher";
|
name = "data-mesher";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "service-dyndns";
|
name = "dyndns";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
6
clanServices/dyndns/tests/vm/sops/machines/server/key.json
Executable file
6
clanServices/dyndns/tests/vm/sops/machines/server/key.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"publickey": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:seLxbv590dO0KvMJmtN7WVvUcH27VYwAc3rmyD7q6ZmwCgswOKx55LFnh0stRDKSZa8K7Dq1x7D9adhZtPAMWX8tbJswBeNMPt8=,iv:G52eugxfTi0tTzH4EN4CWmpyv6feSL34++UVSjb0aAo=,tag:6r10/a7kD2hBAmae0nz2OQ==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHVC8wZUZJYUl5MXVNa2k5\ndGV1MnFWbUNLNVdxeEtCVUc3MTd0ck9aeFFBCnFhZW40amVYc3FlN1FPRTFSWTJR\nQzhNOERKbnRnSlJVeElNSEM5ZUJsZGsKLS0tIG1uNnlNN3MweHlYczNRTW9xSytu\neThzUmxKZTJBT2lCcTdiNUI4N3paTVEKgS9j2/GVt1KBoggUj9d6UK/mIlK4niLQ\nzVq2BHt3irxQpkpGUogXH2b86zSAOEJFzsL1Rk8HM1mogTG8jqf0qA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-10-19T12:49:11Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:T/2xw2mvUi8YALyxz78qG/g/xguoUTeHNzcZfXwwSyCXMg9ircsGGLO9SOVWy/QNkibnw3Yp80tXNJyr4oJH28PhFH7RrRp8jzNdopF49ZNJb2IqJ3C7xNYRZMHfjOCd/raka+ehZq8YGilEpXUWLRk1ere9lbBMh1ycL7jJS3c=,iv:FZbY/jTNPM+p4qD41FD0K7B9zoppGuvnUY5hL/EkmYM=,tag:IF5QTyUkHXWthlAGBn9R8w==,type:str]",
|
||||||
|
"version": "3.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../sops/machines/server
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:Zu+n+DDYP7rQRTS17PJ6Apo=,iv:5WOs81Pj+S85kdC1AlOXSyPMGDfwM5UD8x7nyRZtRYQ=,tag:2JYkGnLugAni49Upv43o2g==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlR3RGQ2ZLTkR3ZWxNVCsv\naXJHRjBiVUVYZVRIY2swY2xubGhmb3pLRkNvCldhQUV2WDlqYjZ4ZUFWYXkvUEEw\nZi9XRWw0Mi9mRENDcnI0aENDR2Z4MHcKLS0tIGFQU3Q4WEErbnBjOHpNR1BSR2cr\nRFg0anE1cHExT0sySmxuUks1R05nczAKZO3R6+f9co2+YGO8HPufoq1fLqqrdTWD\n4zqemMmG2BjMRDumxtcKp8CLaZWlJoP4e/+tonfdoe42qmNF5NJcFw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzZWo4WGh1cWxKeDhDdlBm\nTVFjVFBIUU9xaGRkanNHaUVUUHN1czNRSUhNCkp5MmwzSGdycmsrZGhaRUhEbXBF\nNUhtdEF6bHZQOGJYUVhFVHlYc3FPODAKLS0tIDBRQ2VGT2IvU1F4MEVabzhYSFJq\nOWZmbGpkQmNSMnNKa0s4K2JXdGgwRlkKUQRREpG5H1mNHSc/cZrdMiSz0veJFR4N\n+W49XL/wQUZwajykwYj++G+dWDO7DQ+fpbB9w4mzbsAmCsXirseTLA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-10-19T12:49:11Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:0msda7WbQQxXQ+juT7yErgT7NADgnzqEZLTQw+4JPuAE4xcqRIYwrrAALaA0GCCM2aIWlICzJigLCuzQUfSUbIzeP79tEHiKez+NOt/xgSM9ljz7GlsmLd0vzkxdt3WSxP+sHxy0S866N2sLMUkLqPGdqeTjB+Jji5ghGhzk9ys=,iv:8UU7iA4SdR6ZlVolm708l2Iea0sQYRT+5wPBBP5tpS0=,tag:VQXslAlqLqs1QEkwW6x6qg==,type:str]",
|
||||||
|
"version": "3.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../sops/users/admin
|
||||||
12
clanServices/garage/README.md
Normal file
12
clanServices/garage/README.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Garage](https://garagehq.deuxfleurs.fr/) is an open-source, S3-compatible distributed object storage service for self-hosting.
|
||||||
|
|
||||||
|
This module provisions a single-instance S3 bucket. To customize its behavior, set `services.garage.settings` in your Nix configuration.
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
```
|
||||||
|
instances = {
|
||||||
|
garage = {
|
||||||
|
roles.default.machines."server" = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
manifest.name = "clan-core/garage";
|
manifest.name = "clan-core/garage";
|
||||||
manifest.description = "S3-compatible object store for small self-hosted geo-distributed deployments";
|
manifest.description = "S3-compatible object store for small self-hosted geo-distributed deployments";
|
||||||
manifest.categories = [ "System" ];
|
manifest.categories = [ "System" ];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the garage service";
|
description = "Placeholder role to apply the garage service";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "service-garage";
|
name = "garage";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
1
clanServices/hello-world/README.md
Normal file
1
clanServices/hello-world/README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This a test README just to appease the eval warnings if we don't have one
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "clan-core/hello-word";
|
manifest.name = "clan-core/hello-word";
|
||||||
manifest.description = "This is a test";
|
manifest.description = "This is a test";
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
# This service provides two roles: "morning" and "evening". Roles can be
|
# This service provides two roles: "morning" and "evening". Roles can be
|
||||||
# defined in this file directly (e.g. the "morning" role) or split up into a
|
# defined in this file directly (e.g. the "morning" role) or split up into a
|
||||||
@@ -34,10 +35,13 @@
|
|||||||
settings,
|
settings,
|
||||||
|
|
||||||
# The name of this instance of the service
|
# The name of this instance of the service
|
||||||
|
instanceName,
|
||||||
|
|
||||||
# The current machine
|
# The current machine
|
||||||
|
machine,
|
||||||
|
|
||||||
# All roles of this service, with their assigned machines
|
# All roles of this service, with their assigned machines
|
||||||
|
roles,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "service-hello-service";
|
name = "hello-service";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
27
clanServices/internet/README.md
Normal file
27
clanServices/internet/README.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
🚧🚧🚧 Experimental 🚧🚧🚧
|
||||||
|
|
||||||
|
Use at your own risk.
|
||||||
|
|
||||||
|
We are still refining its interfaces, instability and breakages are expected.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This module is part of Clan's [networking interface](https://docs.clan.lol/guides/networking/networking/).
|
||||||
|
|
||||||
|
Clan's networking module automatically manages connections across available network transports and falls back intelligently. When you run `clan ssh` or `clan machines update`, Clan attempts each configured network in priority order until a connection succeeds.
|
||||||
|
|
||||||
|
The example below shows how to configure a domain so server1 is reachable over the clearnet. By default, the `internet` module has the highest priority among networks.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
inventory.instances = {
|
||||||
|
# Direct SSH with fallback support
|
||||||
|
internet = {
|
||||||
|
roles.default.machines.server1 = {
|
||||||
|
settings.host = "server1.example.com";
|
||||||
|
};
|
||||||
|
roles.default.machines.server2 = {
|
||||||
|
settings.host = "192.168.1.100";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
"System"
|
"System"
|
||||||
"Network"
|
"Network"
|
||||||
];
|
];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the internet service";
|
description = "Placeholder role to apply the internet service";
|
||||||
interface =
|
interface =
|
||||||
|
|||||||
28
clanServices/kde/README.md
Normal file
28
clanServices/kde/README.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
This module sets up the [KDE Plasma](https://kde.org) Desktop environment.
|
||||||
|
|
||||||
|
!!! Note "Customisation"
|
||||||
|
This service intentionally does not provide any settings or customisation
|
||||||
|
options, as desktop preferences are highly subjective. Clan currently
|
||||||
|
supports only this default desktop configuration. Any additional
|
||||||
|
customisation can be done via the `extraModules` option. Furthermore, if you
|
||||||
|
want to use a different desktop environment or compositor (e.g. Gnome or
|
||||||
|
sway), we encourage you to to build your own
|
||||||
|
[Clan Service](https://docs.clan.lol/guides/services/community/) or have a
|
||||||
|
look at the [Community Services](https://docs.clan.lol/services/community/).
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```nix
|
||||||
|
inventory = {
|
||||||
|
instances = {
|
||||||
|
kde = {
|
||||||
|
|
||||||
|
# Deploy on all machines
|
||||||
|
roles.default.tags.all = { };
|
||||||
|
|
||||||
|
# Or individual hosts
|
||||||
|
roles.default.machines.laptop = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
19
clanServices/kde/default.nix
Normal file
19
clanServices/kde/default.nix
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
_class = "clan.service";
|
||||||
|
manifest.name = "clan-core/kde";
|
||||||
|
manifest.description = "Sets up a graphical desktop environment";
|
||||||
|
manifest.categories = [ "Desktop" ];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
|
roles.default = {
|
||||||
|
description = "KDE/Plasma (wayland): Full-featured desktop environment with modern Qt-based interface";
|
||||||
|
perInstance.nixosModule = {
|
||||||
|
services = {
|
||||||
|
displayManager.sddm.enable = true;
|
||||||
|
displayManager.sddm.wayland.enable = true;
|
||||||
|
desktopManager.plasma6.enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
24
clanServices/kde/flake-module.nix
Normal file
24
clanServices/kde/flake-module.nix
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
self,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
module = lib.modules.importApply ./default.nix {
|
||||||
|
inherit (self) packages;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
clan.modules = {
|
||||||
|
kde = module;
|
||||||
|
};
|
||||||
|
perSystem =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
clan.nixosTests.kde = {
|
||||||
|
imports = [ ./tests/vm/default.nix ];
|
||||||
|
|
||||||
|
clan.modules.kde = module;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
30
clanServices/kde/tests/vm/default.nix
Normal file
30
clanServices/kde/tests/vm/default.nix
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
name = "kde";
|
||||||
|
|
||||||
|
clan = {
|
||||||
|
directory = ./.;
|
||||||
|
inventory = {
|
||||||
|
|
||||||
|
machines.client = { };
|
||||||
|
|
||||||
|
instances = {
|
||||||
|
kde = {
|
||||||
|
module.name = "kde";
|
||||||
|
module.input = "self";
|
||||||
|
roles.default.machines."client" = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
client.systemctl("start network-online.target")
|
||||||
|
client.wait_for_unit("network-online.target")
|
||||||
|
|
||||||
|
client.wait_for_unit("graphical.target")
|
||||||
|
client.wait_for_unit("display-manager.service")
|
||||||
|
client.succeed("systemctl status display-manager.service")
|
||||||
|
'';
|
||||||
|
}
|
||||||
4
clanServices/kde/tests/vm/sops/users/admin/key.json
Normal file
4
clanServices/kde/tests/vm/sops/users/admin/key.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
name = "service-localbackup";
|
name = "localbackup";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
23
clanServices/matrix-synapse/README.md
Normal file
23
clanServices/matrix-synapse/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
This NixOS module installs and configures Synapse — a federated Matrix homeserver with end-to-end encryption — and optionally provides the Element web client.
|
||||||
|
|
||||||
|
The example below demonstrates a minimal setup that includes:
|
||||||
|
|
||||||
|
- Element web client.
|
||||||
|
- Synapse backed by PostgreSQL and nginx.
|
||||||
|
- An admin user and an additional regular user.
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
instances = {
|
||||||
|
matrix-synapse = {
|
||||||
|
roles.default.machines."jon".settings = {
|
||||||
|
acmeEmail = "admins@clan.lol";
|
||||||
|
server_tld = "clan.test";
|
||||||
|
app_domain = "matrix.clan.test";
|
||||||
|
users.admin.admin = true;
|
||||||
|
users.someuser = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
manifest.name = "clan-core/matrix-synapese";
|
manifest.name = "clan-core/matrix-synapese";
|
||||||
manifest.description = "A federated messaging server with end-to-end encryption.";
|
manifest.description = "A federated messaging server with end-to-end encryption.";
|
||||||
manifest.categories = [ "Social" ];
|
manifest.categories = [ "Social" ];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the matrix-synapse service";
|
description = "Placeholder role to apply the matrix-synapse service";
|
||||||
|
|||||||
@@ -44,8 +44,10 @@
|
|||||||
pkgs.openssl
|
pkgs.openssl
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# TODO: Implement automated certificate rotation instead of using a 100-year expiration
|
||||||
script = ''
|
script = ''
|
||||||
openssl req -x509 -nodes -newkey rsa:4096 \
|
openssl req -x509 -nodes -newkey rsa:4096 \
|
||||||
|
-days 36500 \
|
||||||
-keyout "$out"/key \
|
-keyout "$out"/key \
|
||||||
-out "$out"/crt \
|
-out "$out"/crt \
|
||||||
-subj "/C=US/ST=CA/L=San Francisco/O=Example Corp/OU=IT/CN=example.com"
|
-subj "/C=US/ST=CA/L=San Francisco/O=Example Corp/OU=IT/CN=example.com"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"publickey": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
"publickey": "age1yr5dfj6sx0lrcyegc5jentmwsf779wsc24lkd65dhrpkney0m59q5j060j",
|
||||||
"type": "age"
|
"type": "age"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
{
|
{
|
||||||
"data": "ENC[AES256_GCM,data:ACFpRJRDIgVPurZwHYW0J1MnvyuiRGnXMeQj1nb9rDAIqHbZzZk8+E0Nu1+EdXwk78ziP6tHR1GQP2ILTtpLME4lXXRVjouW5Eo=,iv:ctR1HENO3XGIq1/gzYi47nateYzsSK317EKn92ptqDI=,tag:q1yuk/ZMx3nuORkiT/XXqg==,type:str]",
|
"data": "ENC[AES256_GCM,data:ldQaNVkxK3vRIMIT28bnVL7Ls6XQowltSQAECmHC7/c9RzSPcIlHyPelZBfhgWWZpKVQiUG8juedn6W/cQ+zDZK6ViY1AWr/RYY=,iv:ZqOfwCl0YGctS/m/BGCz2XL9BBCt2IkpIaSqgxpuLaI=,tag:jcfqLJsAuH0ijlOtAyePBw==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
{
|
{
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvMUtabnp3V0dzNFFYRzk0\nd0ZJbUtDMXRPRGxpRjhYR1MyQzdJYWdJTUFrCjBNV0pPTTlIOHBBbzlEQkFzVy92\ndENxcDdIZlNDSm1oZTNveUtIeVc3MXcKLS0tIGtocENjMFNYT0s1LzhYNy92QU5G\nREVEdjErb0xPSE1yb0g5bGlackh6bEUKwxBoDteD7+JfnlFF71CHx4oEdV/TFYcF\n3JPYUbTWAIyMtUu/CLbX+Pn9Mv+McrEIqhwT7TWL/YbELKVadX/k5Q==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGUWZrL294aTRBUjY1NkdV\nUHFRWW5VdTZkVThRQmdnb1hHS3M1U1VncXpBCkM1ejMxNUh1MGNFeUdRdWpMbVE5\nRk1TcUJuaFVBc01POXlRT3BaS0w1UUkKLS0tIG5mQ2xYN0Z5ZWVWOE04YmhHUmFO\neWxMSTNOOWR5UlBiYi95ZU5TK2RTdEEK6b0uvQ9TrLNw6x41hFMBM4hynl1H1MBu\nnMTxPjQbOP7iFHd5RFbexPHfOitcHowpt3+6wIwIS1sdTFOpqTc5cw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-09-18T14:33:37Z",
|
"lastmodified": "2025-10-23T09:40:31Z",
|
||||||
"mac": "ENC[AES256_GCM,data:4631iJmioJ2vZ2PTFbdEJu7UqtyQbp43XBlgEbFAviGZdugb3weVI24rJ8m1Rdnxq8uciEeiX6YHBhURdWQY4JNm2wTGnjz7e2PwQ8FCwOmxCcIQPpdKKsziq/M4HArgD66eUxIWfTt1yJfHgBcUuuANbrbH8MirllT+hJTBhqE=,iv:rM8a/MpKbK7DlqjuR4BG77XDHLK11Q+E2rzZLDJalhk=,tag:bbGMn4anXrLHg4eLA0/CXA==,type:str]",
|
"mac": "ENC[AES256_GCM,data:rjoogj7WVVxOJYMGvZpFkrYcttme3YEZFdHiBy6FY/wbW6vJhxtMVsMlmtg3Ak/fQwxFQOKlXRVSxo9qGk1b05iYxZdZrzvdpH4wVD3xjzDWhIurDsuSHFqHyrx6TqfZzpKKijPTZESe6C/CCvV3uWo/BgBlOM0CrH3QHig4spw=,iv:mKKxmzQPcw0m3qPOTvyjFNO84phyjnALpnqhZFf/vQ0=,tag:yXSrmSLipwDrUQQs/lS+0A==,type:str]",
|
||||||
"unencrypted_suffix": "_unencrypted",
|
"version": "3.11.0"
|
||||||
"version": "3.10.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
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
|
||||||
k1PNWTkgLsXO8DNkCudxcvPElXfmaw6zwaLrZys=
|
qOLThtAMCgzwF0/KpNuP35tW8CPSQ+ORD2spDWvLbw==
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
{
|
{
|
||||||
"data": "ENC[AES256_GCM,data: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,iv:q3j8EAokyyxiszf+wyRqxEr2igaD1bX7YnFx/NbsGg8=,tag:HKKYWRJEUwW2/TxL+5dSng==,type:str]",
|
"data": "ENC[AES256_GCM,data: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,iv:cZnbdgqnDSWvbOkzjKKc/vC8xjiVSySrkpzOP+uxWKE=,tag:OA8KjOoyYJMpb2tAR8Y6OA==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
{
|
{
|
||||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaeXRjU214aWk5ajl1aW9E\naGJlb1ViaVRmMTBHdkFDQUNDZS94WFZiNUNvCllmWTJBck9hR3U3V09VWDZwQ2xI\nd3ZEQnBIUG5ZSTVIdS8rQ2FMYVhyNk0KLS0tIEE1UG8rSzFyU01sVXhGVHpoaE9i\nSis4Qi9tMGFqbTNMTDZUVk1ZdXkrM28Km4VkfaOsZ69ckjvrg+os43H/O1IoWHzC\nt4LqZRz1Tk7/d1aLWavSPPjVYrCOMZeNBqGbQpGfjjuXrafClRNQdQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMMndqMFM2b3JxZDlSMUdM\nejJyWFZLU0lHN1ZYdFJJMmp2NExuY2tnYUZFCkVLbVNjQ0hYb2tld2xvQU4rNE1J\nRzFQMjV2eHhMc3AyUzlvSGV6cUFOQ1UKLS0tIEZpWVN3WHBEZ0Vjc2lkQXdJRVRB\nd296b2VZNmVQbUt6WENWNFYzb1p0NVkK/idbBu9CRAEmY2fIx3X9GJqOkpdkmdWP\nUVeNB+SAOxNK2a6ys6d1iGsnVvRmQuZ5V4GZN6xDvnpvibWdKCGKgQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
"recipient": "age1yr5dfj6sx0lrcyegc5jentmwsf779wsc24lkd65dhrpkney0m59q5j060j",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3R1RHTGViTnRLVVkyM3J0\nbm96cGVPTlo4NXBNL0g1eEVSNG9DUkgwVFRBCmRKVTlMRmV3Tmg2RTZIclBlWlcr\ndzI5MUxhcllzbE1IMDNxa08zVkpITmsKLS0tIG01Y2dyQkY3UmRudFk2d0p6bThn\nemlaWnZoS3p4VHhMTFFwTm9VN0ttYzQKVbLFgtK6NIRIiryWHeeOPD45iwUds4QD\n7b8xYYoxlo+DETggxK6Vz3IdT/BSK5bFtgAxl864b5gW+Aw4c6AO5w==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkQkprZTU1dGNONnQ3eTIr\ncVlheXlpUUlZM2wyL3l3NlY1azNkZTI2c0RvCm0rYXBkOXBMS1ZaQVVtU2gyRXMr\nd0JuclBDVEJabld6K0VVMTJ4SCtOTVkKLS0tIC9vbTdNRlVoNHZNWlB5enUyREhj\nc21XQ1U4bU1RdzMwMithMEpWSGx4UTQKxfPIPxh3yxmzCU50l+JGzj9YKlUmeuaA\nEpphjkaUokTZh2dXE7i7XOVNylB+o2f71+mlv1ak6ftL18i/VcgADQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-09-18T14:33:37Z",
|
"lastmodified": "2025-10-23T09:40:31Z",
|
||||||
"mac": "ENC[AES256_GCM,data:XKCnd0QrAlOCECSeSvbLYHMLbmUh4fMRnLaTb5ARoP4Zc9joWGsCaRZxokc2/sG4BXA/6pkbQXHyIOudKbcBpVjjvs9E+6Mnzt53nfRoH/iOkYPbN2EO49okVZJXW0M1rlBxrxvGuiDlz2p2p6L7neKLy4EB482pYea5+dUr2Yw=,iv:oj/MkZCfkvCmAb79uzEvKwEAm1bKtWhS4rPRAWSgRgw=,tag:h5TPPILXkhJplnDT2Gqtfw==,type:str]",
|
"mac": "ENC[AES256_GCM,data:tY8mchq1LuM5j1jghjyvLeROgXEu/k+jkSf4CH3U+tnElyXYzcPt/UzbcuXVsL9xyr+n+uJz5kjtu+5sfNf2zeUgrMxaiThLk1ZnpNPq7FQKbcvysBMW4eId2hDWhi7/1T7/k9bYaGejPI9u6OFywbTW2Ic4Dw5kflw2LmXpe+E=,iv:c3bSj7TD63OtnDKaWjX/vjc0ffL8Hdxx4T5XNLa3YuI=,tag:IBXfB3ze1sSmbbkU35svxw==,type:str]",
|
||||||
"unencrypted_suffix": "_unencrypted",
|
"version": "3.11.0"
|
||||||
"version": "3.10.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
{
|
{
|
||||||
"data": "ENC[AES256_GCM,data:Q0Vn7J0nERccBYT8HZxHF0Zi5qxmMu40n0H1c+L2SCRF6vRLdURxXKDwvh8xtTU=,iv:ucExjoYDFYy19GsBbNNldJRPBSpT+L+x4PrwTG+m2K8=,tag:/Quupyy/nnUNZsDudEMmNA==,type:str]",
|
"data": "ENC[AES256_GCM,data:UAkF87pKrzkDHZIfBX4I3F7/qCvP40wC+73jGTrznhM97qG507rkNqc=,iv:U35X9C62qmFHRHFYO1UkKRR49jxxMrVKrbxORe1SZmg=,tag:hVRTMY+l+Fhszq2J9yGJhQ==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
{
|
{
|
||||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQWWo5OEJ5N1RTR0xMaDhL\nQnlUV2RrRXIzM01OemhQWjVkd3FNZjRhR2dzCi9IeE56b3VZTkNkdW9DMzVia3Zx\nbklxWmFpenRjdEIrc0ZDTGdmSTAxRTQKLS0tIHZJdjdYUzhhY0YzQjRqS0psZmpI\nVHJpUjNZNHRpc2ZWSml1TVNNejhiT28K8TTP/J+XspXZ7TVYj9YaBhEodPIXjojB\nRLqAIgJXRaK4NCLukC6l0IMii6w5J/512RnO2ZBTGhKfbdLfyLOFqg==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBR2pTN1Z2czJOelM1SjQ4\nQ1BxK09iT0JlNjBEMThoRnRXTXBRejk3ZVVRClJMeVlHTklwTzRubldvdmdmUzRJ\ndDR1M3pEMHROUktyckxoODBxTXozMUUKLS0tIHBUTFFseTJSaSsyWU5PdThNQ2hG\nTXpjZlhIaG1CM2E3R2JmdWlndTZzZHcKYbFqPfQ5s157FBj2Xs8Q5lXgi+FUX9aZ\ne6nOnOHvmgq6MdDK2z6WjtqP4HM/WU9iFSrGSQCvhPFweY1ILmU9tQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
"recipient": "age1yr5dfj6sx0lrcyegc5jentmwsf779wsc24lkd65dhrpkney0m59q5j060j",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrZVc5b0FhbzNXcG1zUDlD\neEVWcWpSRkRCMkxBTHdBM3dCbjVpR3FBa0VjCitlTmx4eUJOMHlaU0dFZEhpK3ZD\nZzlMQXVuZWpnaUNmQW9kOGtOaGVDMU0KLS0tIFNlUi9LSzF0UEJCSVBiRlRSNFQz\nNHhMbmNlRXd4ZEJQWVcvTWdCRWEzMUkKls7RbmNOdPDx8z15F+7qay9qIWx6jNsN\nTahT+GgbG29t1aGQCb0yEzKuUyAp39maxxSWToPsfCgJSYJ8RYiUng==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2dGVGd1A5dkt6QzAyL2Ja\nSUNoSEc0K0NQc04zREZSN3JORUdMRlpCdkI4CktSSS9NTjhKTUt1YUhTZERmK1Fi\nSjhmTG1CckNTYVNnL1MrR3d1VnRLMkkKLS0tIFNBS2Z0N3BFWjRUcGRDMm5mM2FR\nNlp3VkRYN1dtMGdRSFVjNXVZb2pjbXcKYaWNCnqIe85ldUWh5RWcbxA28k/1EJV9\ntoD5y6Qu0qZqm7vhgHPSZ8fCmuiafQTUj77XhjJbfw1exac1wP0m8w==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-09-18T14:33:39Z",
|
"lastmodified": "2025-10-23T09:40:34Z",
|
||||||
"mac": "ENC[AES256_GCM,data:g+9/fRiqom2+W28ZpiF+oBj9V6ieq5Xz3sRz3GyzvHoLr6yw51JvpG2QuYNYANW0WCiUjFDkU0qPj/9gLHcuX52nc+gNaTzznb1QGPg7WCGSQI7xaMzyYsPxHpg/BOdj5CL8GyLiOWstD1ch0kc3bJmyu68sJUs04uGtHAADzsE=,iv:oASrYaZarEPDu0R3hd/jMazLgwG5r//hIdMyU/tN15o=,tag:o1fgf5oy+rlWXg88FN5Nfw==,type:str]",
|
"mac": "ENC[AES256_GCM,data:y4bNxCWif4JL/AfkfV2wQb22xooHQUgr6//ajzgyBJ5Z9xB8WboVhyTn0nKnA6G+1PpJmoaXUWFQcv0kq6RPFw3teATw5pdKK29NS9rxqnIht5v7mrqP0CnVoFQVDz1yGtY0rotGd7hUNAXsrjb6Ewfs6N3k8QPwpTX4V7STT48=,iv:+BMrr/Vjnd8DT7aC1/ckp5LZ7UuQkffsMeGbBFxjhGA=,tag:vuUWd2UjJaVY/20QrIzC+g==,type:str]",
|
||||||
"unencrypted_suffix": "_unencrypted",
|
"version": "3.11.0"
|
||||||
"version": "3.10.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
{
|
{
|
||||||
"data": "ENC[AES256_GCM,data:4NIUEK05kEQAKjR8F9mU3M/XvtZXw+X6CejVI0usMcb4WzagNz7XTVDhLWXZ9St5Ev0Y,iv:bD2+rDLMoWSqUAIZRJof0wRrJVya1xwZUTIJBdCs98I=,tag:g2s4byFHTzwU3ikcBGMElA==,type:str]",
|
"data": "ENC[AES256_GCM,data:6iT6HrBnOhKWfDKRzI73kobk2a1XsVUZhQpBK8kK9BQa8mv+tIc45gP5GwcD,iv:K5tWZHyLznul21de/RgXloJ/7g87N/bq3EGKSOOe1HY=,tag:q9Xm92SpgKcCI8W95E509A==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
{
|
{
|
||||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQeVh2M2tqSGlOVkpzNlhU\nd0pMd1R0c0tQWnZzdXViWmtxcjl1Wk1Ka0FNCnBUUWJVbjlyR1hSNGpXNWlPRHJB\nNnMzN3BMQ2NDamFBMlhHbVdJUEZ6cjQKLS0tIEJjWmI0ZDl1NXgrSW9uc0R0LzAr\neEwwOC9DdDg2RTJHQ0M3QTFlcVBaSE0K2Du4NguefdEyY1gS6OuVdO3gHga4omcR\n8B+K1wUfIQbArxZLawPxrj7WNDoW5d4mF9fA3MeV1DFyc4KwtYZmUw==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQb3hNVW5BK05tRllUTFRR\nUzM3aFJYamVzZEZELzRieDMwNzBtMTY2ZnpBCjdFU25uSllRYjloTjV2Zjc3RjAz\nTTl4M1pRL0g0QklhUlNjK2oveHZQWVUKLS0tIGlLdHFWMHZ6QXltdEF1YmlicXgy\ndzZVUGRmQ1JKUFN6WEhIbEMvZy9xUU0KurnoOMO9YEbsqg8zYw7vqL1hjKGnq65B\nxI+uV0aGVS79zu6Sqtm62XmgRNdySdz+seYxtISZviGRvhKsvHWi0g==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
"recipient": "age1yr5dfj6sx0lrcyegc5jentmwsf779wsc24lkd65dhrpkney0m59q5j060j",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvWkdBakVrMVR4RU8xdDlF\nRDkvL0Mrb3ltazhIMjRLZDVlSTVlaFY2ODBBCnlQM2s0SGEvZjFDN3dGWDhIN0dK\nenhQbjZ1ZS9QZzg5SE5XazZXS3dFSkkKLS0tIHJhKzhadGpjTXd4L3hOQkhpR0Fy\nYzhTN2dxVSt3OE5uZFpuWmVlYW4vd1kKwHOxP0C5mLcm4oIT/sGQtUsdsmu3LSN0\nSola5+N+IrAZ+HKnuZlDLZ5JmJSc5j/YhGNn7KR1xhkhfGSS1e3UZw==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPSEJWanVSNEdkTDd1T3ho\nUFE2UklxRmp4L0M4MHlnM3o3Q0FkR00rRjNBCkk2SEVpQjdCeUpxN21mbG5LdUZh\nUXhwRkpwVDZuTzhUb2g3WmFnR3c4NWMKLS0tIGcrbkIrYVYyVVlBN0NyYlI4cGx1\nTitVR083K3pwL1Zlc1I3VVdVakJCVkUKCcDSfeu4Md5iPcZOcCktDvwXh0G3wdFb\nGr73xyIY9lcP2+NupMBgKTBxck4beRcJxxyFhYf9ZSkmIK3e4pFQNg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-09-18T14:33:39Z",
|
"lastmodified": "2025-10-23T09:40:34Z",
|
||||||
"mac": "ENC[AES256_GCM,data:ehbrYqTJcsBKGHUB25JHFnKXrJ6z3LkcElZ89xVr4XxLet+odbhsjIoP2FCcxex7PlXcegMduhHBpXwNGUbX+IUNAXTxlWA9CLDmYhWuS2WLiEVXrS11NE03/zUyHdVx/C38dbIPrWD9iaYSrAiuOyfqDTh9k/Bn7vehLTtadoE=,iv:Nk2WVuJydi5tfsb1Mib4A6NocBCDp9QoIbSadq3bIDI=,tag:IaoyfCv3SkmtemXMR9XnkA==,type:str]",
|
"mac": "ENC[AES256_GCM,data:Qh2VQ43UqUhQtMBEhjBfky2hUjTNxJcKrIm6zGteJ/X+z0FxZ9LoUew48ml+HPHvPN+vLRtgVeOkP2d3x0kq/ag4RDNFuK7IgkzrVt8vzT0IpDHJmyw1ehGYy/MhMaDR5zv0ADZV/GrXrn9O+Wj74cgGqYg15TQJ3I/a68ViYhk=,iv:aJZCcd25xaOhmrfkJZuGUAdAGb7lFrP3D5kZtZnP/v4=,tag:se43YOxOEZHawE1SnnvTzA==,type:str]",
|
||||||
"unencrypted_suffix": "_unencrypted",
|
"version": "3.11.0"
|
||||||
"version": "3.10.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
{
|
{
|
||||||
"data": "ENC[AES256_GCM,data:0BmP+NwG/NGe6R5yU55/MdPEQ8E5u+VXWtvstHc4GpDtmBY=,iv:vo8XBcN7KcYjiyKvvp+XDOdP9yR9B7wJi0XlaiCdVbk=,tag:brK9ntAPSuOvw/C+oDo51g==,type:str]",
|
"data": "ENC[AES256_GCM,data:BxHELvbSQkvKnKLFXTAuRFYSO0lD2WuZLFah9S0=,iv:Lt8kE85YZcwfD5t5bEQWTOHoD66D77u/1CqimEI7DW0=,tag:LD8oeZ+imsh9pV75+3YzkQ==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
{
|
{
|
||||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4Tk1INGtybUVlejlNNlZE\nVms3TkdRVVF1T0E4TmV3NmxvYWVEL2U3WVhNCjJIaHhBcWVlMEYxRjg5bzJpTWdJ\neUhaRTNRTmtlTW0zUXQxTVZEMkQ2MFEKLS0tIFNGWDI4b2FXTE8xQ2xqb0cyK3FI\ncktHWnE5c1ZSVFpmQU1HZmU2VVB1QmcK/s1fVmwpMMg4BYkkAJzSY7hVQWae1F7g\nmfH8EGlr74mifWUNEbd49/K13nl8atQx6bcau83JIEQR+yyihuY4Jw==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDRmExdUNwWGRnQ2FLWXpU\nWW40V09mNTJwMEk1d0xGRjRLZ2NGRk9uQVg4CmE5cWpZVE81TzJxZm04ZWowVW1y\naUVldkc4MHJsbW1vOTh6KzFNM3lGUncKLS0tIDlDdW90dzlJTVRwN2JlYWFTZHpC\nV1pnOStuanV3MmJwWXJVbitqV0dUK28KEp0VUW7F1kRB2VqINUu1yXLbDwvvLzJn\noFd9WnA6HXxfyZvwk45DSwnb6VskuQryy9cqNYgvfiVOAaPuK0rsHg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
"recipient": "age1yr5dfj6sx0lrcyegc5jentmwsf779wsc24lkd65dhrpkney0m59q5j060j",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsL2FXVytUUVZnVU90bG5L\nYURiYjgwN3RuTldWMGl4clpUWmxkeUsrVzM0CkhKZFgwWHl4dWhNSWRQRXVPNDR6\na3hHNmp2RG9YNDhNM2MyV2FuOGY2UlUKLS0tIFpNU2tNOHdhRDRTdHhYWVh2NGZa\nU3J3S0hpclZzWGIwTlFyczdNZkZSZTAKXCZrLaIOVq90ejoKMaRiK0xNw8WOPcnm\nz2uxProEYvQhY8k29mhCFX5HCN0tGn1XTtHeDL7uHuKuFsnSG/fgYQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiWnhRMTkxd3l5VWVLMCty\nQ1JYRGlYZ25LeXVNL0Z1bHl1UzVpeEdFYm1RCit4ZFc3YmdGeC9FTENWOGVJaUJo\nOGFPZWZHSWhlcU54WGJ6U3RNWE9PUlEKLS0tIGd0cWpBSzBWcXZWS2R3Y254bFdC\nVnRMeGJCbHNNWE5JVWVXTVZFTDgxSVUKavBd6tPVqlkZGMo1dlYOZ3U3hkRa7IuP\ni/MoRY2J6IdDVoOq1bYJzZ30apG/ADXYUNCVnqDftyD9t5Ws04SkMg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-09-18T14:33:39Z",
|
"lastmodified": "2025-10-23T09:40:34Z",
|
||||||
"mac": "ENC[AES256_GCM,data:QkGJKj/H+MI9Mr9Up5NDUToSddY5eTz47egc2+IatfxR8RebKJ2/mYaeLV26vPdmY60bIac4N/nZkoa6IVBhkHHMvsEHsx3nD6Lro9Wf/pWP8Zddzr90LF5p2+wusq25JutKQiPKOb2gmrcagmSsH/7V/UqI/my3PMeKmw6irhw=,iv:hOtHF/cDFdNfvqCKRhJsOwAHEiQmCPjENzsg23sKG+Q=,tag:K7qG9b4fQD0VbAV8OYp3vw==,type:str]",
|
"mac": "ENC[AES256_GCM,data:k60YIgs+HdcrGkaW4XI3iu2O6JMwlX0ToV8o/Eix27M1xJ2ipcnJI7gghWGBG3GWlzuVHAl9QlkFPu4SRv6KtP62iGzbnzXlbIe+Z1eQgkn+GGaM39SZpsMlW8T1OtV3mW6oe+NRCP7zmPgc2Yr3U08wYSooDOn4XOze5qZNbGk=,iv:q8siSK4a8CHkXcJxO4QTsX12zZxKTwHdw6qirF8j/v0=,tag:aWrxb1x+7BJQ9vIrttc+Hw==,type:str]",
|
||||||
"unencrypted_suffix": "_unencrypted",
|
"version": "3.11.0"
|
||||||
"version": "3.10.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
clanServices/mycelium/README.md
Normal file
20
clanServices/mycelium/README.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
[Mycelium](https://github.com/threefoldtech/mycelium) is an end-to-end encrypted IPv6 overlay network that spans the globe.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Locality-aware routing: finds the shortest path between nodes.
|
||||||
|
- All traffic is end-to-end encrypted.
|
||||||
|
- Can route traffic via friend nodes and is location-aware.
|
||||||
|
- Automatic rerouting if a physical link goes down.
|
||||||
|
- IPv6 addresses are derived from private keys.
|
||||||
|
- A simple, reliable message bus is implemented on top of Mycelium.
|
||||||
|
- Supports multiple transports (QUIC, TCP, …). Hole punching for QUIC is in progress to enable true P2P connectivity behind NATs.
|
||||||
|
- Designed for planetary-scale scalability; previous overlay networks reached practical limits, and Mycelium focuses on scaling.
|
||||||
|
- Can run without a TUN device and be used solely as a reliable message bus.
|
||||||
|
|
||||||
|
Example configuration below connects all your machines to the Mycelium network:
|
||||||
|
```nix
|
||||||
|
mycelium = {
|
||||||
|
roles.peer.tags.all = {};
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
"System"
|
"System"
|
||||||
"Network"
|
"Network"
|
||||||
];
|
];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
roles.peer = {
|
roles.peer = {
|
||||||
description = "A peer in the mycelium network";
|
description = "A peer in the mycelium network";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "service-mycelium";
|
name = "mycelium";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
test.useContainers = false;
|
test.useContainers = false;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
11
clanServices/packages/README.md
Normal file
11
clanServices/packages/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
This service is meant to be consumed by the UI / API, and exposes a JSON serializable interface to add packages to a machine over the inventory.
|
||||||
|
|
||||||
|
The example below demonstrates installing the "cbonsai" application to a machine named "server.
|
||||||
|
|
||||||
|
```
|
||||||
|
instances.packages = {
|
||||||
|
roles.default.machines."server".settings = {
|
||||||
|
packages = [ "cbonsai" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
manifest.categories = [
|
manifest.categories = [
|
||||||
"System"
|
"System"
|
||||||
];
|
];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the packages service";
|
description = "Placeholder role to apply the packages service";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "service-packages";
|
name = "packages";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
# Clan service: sshd
|
|
||||||
What it does
|
## What it does
|
||||||
- Generates and persists SSH host keys via `vars`.
|
- Generates and persists SSH host keys via `vars`.
|
||||||
- Optionally issues CA‑signed host certificates for servers.
|
- Optionally issues CA-signed host certificates for servers.
|
||||||
- Installs the `server` CA public key into `clients` `known_hosts` for TOFU‑less verification.
|
- Installs the `server` CA public key into `clients` `known_hosts` for TOFU-less verification.
|
||||||
|
|
||||||
|
|
||||||
When to use it
|
## When to use it
|
||||||
- Zero‑TOFU SSH for dynamic fleets: admins/CI can connect to frequently rebuilt hosts (e.g., server-1.example.com) without prompts or per‑host `known_hosts` churn.
|
- Zero-TOFU SSH for dynamic fleets: admins/CI can connect to frequently rebuilt hosts (e.g., server-1.example.com) without prompts or per-host `known_hosts` churn.
|
||||||
|
|
||||||
Roles
|
### Roles
|
||||||
- Server: runs sshd, presents a CA‑signed host certificate for `<machine>.<domain>`.
|
- Server: runs sshd, presents a CA-signed host certificate for `<machine>.<domain>`.
|
||||||
- Client: trusts the CA for the given domains to verify servers’ certificates.
|
- Client: trusts the CA for the given domains to verify servers' certificates.
|
||||||
Tip: assign both roles to a machine if it should both present a cert and verify others.
|
Tip: assign both roles to a machine if it should both present a cert and verify others.
|
||||||
|
|
||||||
Quick start (with host certificates)
|
Quick start (with host certificates)
|
||||||
@@ -80,12 +80,13 @@ Admins should trust only production; CI should trust prod and staging. Servers a
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- Admin -> server1.prod.example.com: zero‑TOFU (verified via cert).
|
### Explanation
|
||||||
|
- Admin -> server1.prod.example.com: zero-TOFU (verified via cert).
|
||||||
- Admin -> server1.staging.example.com: falls back to TOFU (or is blocked by policy).
|
- Admin -> server1.staging.example.com: falls back to TOFU (or is blocked by policy).
|
||||||
- CI -> either prod or staging: zero‑TOFU for both.
|
- CI -> either prod or staging: zero-TOFU for both.
|
||||||
Note: server and client searchDomains don’t have to be identical; they only need to overlap for the hostnames you actually use.
|
Note: server and client searchDomains don't have to be identical; they only need to overlap for the hostnames you actually use.
|
||||||
|
|
||||||
Notes
|
### Notes
|
||||||
- Connect using a name that matches a cert principal (e.g., `server1.example.com`); wildcards are not allowed inside the certificate.
|
- Connect using a name that matches a cert principal (e.g., `server1.example.com`); wildcards are not allowed inside the certificate.
|
||||||
- CA private key stays in `vars` (not deployed); only the CA public key is distributed.
|
- CA private key stays in `vars` (not deployed); only the CA public key is distributed.
|
||||||
- Logins still require your user SSH keys on the server (passwords are disabled).
|
- Logins still require your user SSH keys on the server (passwords are disabled).
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "clan-core/sshd";
|
manifest.name = "clan-core/sshd";
|
||||||
manifest.description = "Enables secure remote access to the machine over SSH";
|
manifest.description = "Enables secure remote access to the machine over SSH with automatic host key management and optional CA-signed host certificates.";
|
||||||
manifest.categories = [
|
manifest.categories = [
|
||||||
"System"
|
"System"
|
||||||
"Network"
|
"Network"
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
perInstance =
|
perInstance =
|
||||||
{ settings, ... }:
|
{ settings, roles, ... }:
|
||||||
{
|
{
|
||||||
nixosModule =
|
nixosModule =
|
||||||
{
|
{
|
||||||
@@ -38,8 +38,19 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
uniqueStrings = list: builtins.attrNames (builtins.groupBy lib.id list);
|
||||||
|
# Collect searchDomains from all servers in this instance
|
||||||
|
allServerSearchDomains = lib.flatten (
|
||||||
|
lib.mapAttrsToList (_name: machineConfig: machineConfig.settings.certificate.searchDomains or [ ]) (
|
||||||
|
roles.server.machines or { }
|
||||||
|
)
|
||||||
|
);
|
||||||
|
# Merge client's searchDomains with all servers' searchDomains
|
||||||
|
searchDomains = uniqueStrings (settings.certificate.searchDomains ++ allServerSearchDomains);
|
||||||
|
in
|
||||||
{
|
{
|
||||||
clan.core.vars.generators.openssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) {
|
clan.core.vars.generators.openssh-ca = lib.mkIf (searchDomains != [ ]) {
|
||||||
share = true;
|
share = true;
|
||||||
files.id_ed25519.deploy = false;
|
files.id_ed25519.deploy = false;
|
||||||
files."id_ed25519.pub" = {
|
files."id_ed25519.pub" = {
|
||||||
@@ -54,9 +65,9 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.ssh.knownHosts.ssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) {
|
programs.ssh.knownHosts.ssh-ca = lib.mkIf (searchDomains != [ ]) {
|
||||||
certAuthority = true;
|
certAuthority = true;
|
||||||
extraHostNames = builtins.map (domain: "*.${domain}") settings.certificate.searchDomains;
|
extraHostNames = builtins.map (domain: "*.${domain}") searchDomains;
|
||||||
publicKey = config.clan.core.vars.generators.openssh-ca.files."id_ed25519.pub".value;
|
publicKey = config.clan.core.vars.generators.openssh-ca.files."id_ed25519.pub".value;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -180,7 +191,9 @@
|
|||||||
settings.PasswordAuthentication = false;
|
settings.PasswordAuthentication = false;
|
||||||
|
|
||||||
settings.HostCertificate = lib.mkIf (
|
settings.HostCertificate = lib.mkIf (
|
||||||
|
# this check needs to go first, as otherwise generators.openssh-cert does not exist
|
||||||
settings.certificate.searchDomains != [ ]
|
settings.certificate.searchDomains != [ ]
|
||||||
|
&& config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".exists
|
||||||
) config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".path;
|
) config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".path;
|
||||||
|
|
||||||
hostKeys = [
|
hostKeys = [
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ in
|
|||||||
clan.nixosTests.sshd = {
|
clan.nixosTests.sshd = {
|
||||||
imports = [ ./tests/vm/default.nix ];
|
imports = [ ./tests/vm/default.nix ];
|
||||||
|
|
||||||
|
clan.modules."@clan/sshd" = module;
|
||||||
|
};
|
||||||
|
clan.nixosTests.sshd-no-search-domains = {
|
||||||
|
imports = [ ./tests/vm/no-search-domains.nix ];
|
||||||
|
|
||||||
clan.modules."@clan/sshd" = module;
|
clan.modules."@clan/sshd" = module;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "service-sshd";
|
name = "sshd";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
45
clanServices/sshd/tests/vm/no-search-domains.nix
Normal file
45
clanServices/sshd/tests/vm/no-search-domains.nix
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
This is a regression test for the following error:
|
||||||
|
error: attribute 'openssh-cert' missing
|
||||||
|
at /nix/store/y1k4bqwjql6bhlry456cs4marpamiqlr-source/clanServices/sshd/default.nix:184:17:
|
||||||
|
183| # this check needs to go first, as otherwise generators.openssh-cert does not exist
|
||||||
|
184| config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".exists
|
||||||
|
| ^
|
||||||
|
185| && settings.certificate.searchDomains != [ ]
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
name = "sshd";
|
||||||
|
|
||||||
|
clan = {
|
||||||
|
directory = ./.;
|
||||||
|
inventory = {
|
||||||
|
machines.server = { };
|
||||||
|
machines.client = { };
|
||||||
|
|
||||||
|
instances = {
|
||||||
|
sshd-test = {
|
||||||
|
module.name = "@clan/sshd";
|
||||||
|
module.input = "self";
|
||||||
|
roles.server.machines."server".settings = {
|
||||||
|
hostKeys.rsa.enable = true;
|
||||||
|
};
|
||||||
|
roles.client.machines."client".settings = {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
server = { };
|
||||||
|
client = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
# don't do anything, just evaluate the machines
|
||||||
|
exit(0)
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../sops/machines/client
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../sops/machines/server
|
||||||
@@ -2,9 +2,17 @@
|
|||||||
"data": "ENC[AES256_GCM,data:Qje3bXRHcAiFCslFfAeUTcOn2woc06e1sLAoH16x1sZ7N0i07rHqwsBjn7nKvMee6tktIjLMGTPOQL9TLgYI+wDgU5MHqlZlVBnYLk+VXYEKhymDlS3RAg5pbrmJzkucl/Vw5VBlDK+n8qnrgFG2pgpiC6Lzb5f4I7pxUl4zcz9jCf0Stj10lVQgkbvnr8UMUvcb1vUF/EAhF6WhhhgrhpbYrK+PkNW6EXmxIXdUdXvSqVWvJby2NgBaGOM1lwnWv4LOOiJ1BNXnOnLE0a8+8SjqahzqroeFvUCtoFxJ45/LqFTtgS9cQ44FaqrMRSWlOgsNR2BkeT449fKUCwYfEW1g/R47I9hAm/bcKrOBpHdAji/hpcDy73Qb9ZKrY6/0kRXl/ECI3YVX8nrHIjEJpoZ7a/dxJu7z8OOdb7gP2mVPTiWcbpD/KwpefDWLKnYhBrXUNaqSajf95Ahln2Vn6sALbbjcUzs/x5OqchYe1/kYy7MaGbEFNPeINnGid73c7xfUoyI90Ho4azLW8Q/n,iv:9heXX8g1P8/4gGT3+RYYmz6rJ5EnIDr5w1OAbGybL+I=,tag:p6mHZ8+EaJ+Nyn59n2TQ4g==,type:str]",
|
"data": "ENC[AES256_GCM,data:Qje3bXRHcAiFCslFfAeUTcOn2woc06e1sLAoH16x1sZ7N0i07rHqwsBjn7nKvMee6tktIjLMGTPOQL9TLgYI+wDgU5MHqlZlVBnYLk+VXYEKhymDlS3RAg5pbrmJzkucl/Vw5VBlDK+n8qnrgFG2pgpiC6Lzb5f4I7pxUl4zcz9jCf0Stj10lVQgkbvnr8UMUvcb1vUF/EAhF6WhhhgrhpbYrK+PkNW6EXmxIXdUdXvSqVWvJby2NgBaGOM1lwnWv4LOOiJ1BNXnOnLE0a8+8SjqahzqroeFvUCtoFxJ45/LqFTtgS9cQ44FaqrMRSWlOgsNR2BkeT449fKUCwYfEW1g/R47I9hAm/bcKrOBpHdAji/hpcDy73Qb9ZKrY6/0kRXl/ECI3YVX8nrHIjEJpoZ7a/dxJu7z8OOdb7gP2mVPTiWcbpD/KwpefDWLKnYhBrXUNaqSajf95Ahln2Vn6sALbbjcUzs/x5OqchYe1/kYy7MaGbEFNPeINnGid73c7xfUoyI90Ho4azLW8Q/n,iv:9heXX8g1P8/4gGT3+RYYmz6rJ5EnIDr5w1OAbGybL+I=,tag:p6mHZ8+EaJ+Nyn59n2TQ4g==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age124l8cfswl97ck0e0qw8l47usf375srn69e4mhxr3gr40erxw7pesftxshx",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5b0Y3aldQWXJyZzU3aGZU\naWpOK1VXdUVlSUVvZzJqSDVCekQ0Z2JxblRvCmFWd0c1SC9jckMweTIrNmg0VnN3\ncTNwMkVTL0ZyT3RGeUs2NnlNb21GWTQKLS0tIEpGM2FacUNoakJ0dlJwMWZMNU0x\nVWhmV1pDOTRFNExpVHBTRUx2L2ZaMVUK+ka9oqcvoLjwwUqIol0rU1VsJHhs4S1P\nWpKKPetUPEF4xxWj0OdeMc40XCTjl6CBdbtcrslH3tuZHjeSWQ6QCg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkNlpCNGR0SHVtVzJ2K0hM\ncng1ZWlTSGQzWndXVWhlbEZMN25TUklXV1I4Cm9PZkJ3Zi81YXoxdzVPTFI3dE1a\nUnJnUmJPbi9CYmdFL2ltaTRSQ1MreFUKLS0tIDE4Y05IamJjL0huY2l2YU4zbDJs\ndTl1b0wzaTM4MndlcFZYVThqbWtVeFUKuSZLJpUrccuusJPU2xWHw19wTN8mKZW3\n1GJJjlb79rZp/RbSMxFxkyVHgu+F9kbpRgViICJSWkeR495786oArA==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLM3lNL1UyUjhRdFBvenlv\naXBTYXJva0hCTS8vK1hCYmdQdlpBNGFNTkNrCmVTbFROTWVWRzZyc2E0SjVDT1hs\nMm9qT0plcHNJaWczcWJTd0llYldGMVkKLS0tIGh6M04yQ3RiMGVYbTNYMEdCVTNK\nUDhaS3FSVWl4ZGlPYTRodW80VElsZ1UKxi48UZpxuu7gkRtQrCi4//suOpuFY6sl\n8b1xcN/tMn2MWW9hvx4K4qJLXTWOm+9GiZqJ51JBb0hihRh7fC3SfA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1f39qxz84yv272wk636el0kdyagzudcs99ucpkjarsj2rey6yvccse9lwet",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGK2Z5OGFsVjBJcGFITENH\nL205TDBaNkRvQ3ZBbGVDU0wrWnl5QkJaSFZNCjhNSXpMTTd1ejlqbVNBUDZ2TlFn\neUhNdEh4M1RhQnFabHpaMVd5eG11THcKLS0tIE9PS3JlVFVPNG5sM3hpWG95V1ho\nSXBySU1SUExkVHNHZElmQWExTVN3cHMKvzdlCWP8/9xviu/9AMxw/4ZyXo4O3AE9\n84IQBDO4GYrqnXvOroxjsNCDrCBDH0WPuYAphctJvyI5SSAtL4uHhQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-06-09T19:51:28Z",
|
"lastmodified": "2025-06-09T19:51:28Z",
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
## Usage
|
This service configures Syncthing to continuously synchronize a folder peer-to-peer across your machines.
|
||||||
|
|
||||||
|
Example configuration:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
@@ -6,15 +8,17 @@
|
|||||||
roles.peer.tags.all = { };
|
roles.peer.tags.all = { };
|
||||||
roles.peer.settings.folders = {
|
roles.peer.settings.folders = {
|
||||||
documents = {
|
documents = {
|
||||||
path = "~/syncthing/documents";
|
path = "/home/youruser/syncthing/documents";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Now the folder `~/syncthing/documents` will be shared and kept in sync with all your machines.
|
Notes:
|
||||||
|
- Each key under `folders` is a folder ID (an arbitrary identifier for Syncthing).
|
||||||
|
- Prefer absolute paths (example shown). `~` may work in some environments but can be ambiguous in service contexts.
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
Extensive documentation is available on the [Syncthing](https://docs.syncthing.net/) website.
|
See the official Syncthing docs: https://docs.syncthing.net/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "service-syncthing-service";
|
name = "syncthing-service";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
22
clanServices/tor/README.md
Normal file
22
clanServices/tor/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
🚧🚧🚧 Experimental 🚧🚧🚧
|
||||||
|
|
||||||
|
Use at your own risk.
|
||||||
|
|
||||||
|
We are still refining its interfaces, instability and breakages are expected.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This module is part of Clan's [networking interface](https://docs.clan.lol/guides/networking/networking/).
|
||||||
|
|
||||||
|
Clan's networking module automatically manages connections across available network transports and falls back intelligently. When you run `clan ssh` or `clan machines update`, Clan attempts each configured network in priority order until a connection succeeds.
|
||||||
|
|
||||||
|
The example below configures all your nixos machines to be reachable over the Tor network. By default, the `tor` module has the lowest priority among networks, as it's the slowest.
|
||||||
|
|
||||||
|
```nix
|
||||||
|
inventory.instances = {
|
||||||
|
# Fallback: Secure connections via Tor
|
||||||
|
tor = {
|
||||||
|
roles.server.tags.nixos = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
"System"
|
"System"
|
||||||
"Network"
|
"Network"
|
||||||
];
|
];
|
||||||
|
manifest.readme = builtins.readFile ./README.md;
|
||||||
|
|
||||||
roles.client = {
|
roles.client = {
|
||||||
description = ''
|
description = ''
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "service-trusted-nix-caches";
|
name = "trusted-nix-caches";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "service-users";
|
name = "users";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "service-wifi";
|
name = "wifi";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
6
clanServices/wifi/tests/vm/sops/machines/second/key.json
Executable file
6
clanServices/wifi/tests/vm/sops/machines/second/key.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"publickey": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:xAQ6TcwttQNb1BXlq2j+xZX+vGbqV5XKZyZMBAnQ00hWLu6Ba6pN2qR4HItKQ1KWza8WGhzgGdcwZv6Qobgmp9wAcwWlAubS7FU=,iv:KalRsDqWxqscJOeZcnQfFkP7QTBVZpP8XAdPHvikfaM=,tag:EAndFTqRYRcCgD5/ixniBA==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjZnpWd0grazhjak0ra3NK\nSEpVTWVEaXEzc3ZIeloySXBqVk01SVNsVmtzCk5weWJCSGNlb2FRM0RWVEYwTHlC\nTVFBd1cvYlZrNlQ4TFRydFNzWXNicE0KLS0tIFZ5WllRNEI0Q3hQaVU2WjhGNDFr\nLy9pSXU5Y2FINy9LbXg4dzdHREQveE0KyxWDDyRpo0eTIXj0lHQtOunLtAP/Q+70\n+GvfjW7WXHXvXyg6CXzpCy6F6UWie4LHO9VrJM2mTjoh+q4l5DT6CA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-10-19T12:53:35Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:P6Wcm7daPMe6laceFIiIzhcGa9k37Fo5ZnBFhdVmkATuR2oqMZp9Ke5r73SbC5B95QoPnWVNNnrxkn/oiVQmSiiDaf718isLAfU+7zGkV0BZCtfCrqe82JzH2iQ0tKSxsVJqklCijAfUBGpt/EYN6c4QnM2IFulbiWs2kqWMi4I=,iv:mRuTg2RblZCNX3yQNFKCtuwjwIptZ5VGpSyLV6Ah5NI=,tag:Xl8/jrtIhxfAi+FrnwKh7Q==,type:str]",
|
||||||
|
"version": "3.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
25.11
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../sops/machines/second
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:B08uqk2DxB8QJ93QBM71,iv:XawCB0nwWxso5+yC8az33cFnt/qKzITOwUP0ZFI20Ho=,tag:mZg5U4t9beHch+Oic2VsVw==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age1afr59kwlpuapv2g9m0sa4k9yc22ulj7zcway538z7nnsgvf2re5qd7k03a",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLWEV0STNnMlRreElVSk1y\nRTB6cCtWc0tkNUEycklSU0x5cHZwN3FIQkcwCkJQemRZOWZFSit3QmZ2a3RrOGFh\nUEhLSEZLRW9lWkN2b1VKK2EybUYvcTQKLS0tIGt6VWFmVHpNc2c0T3E0TjBYeWp1\ncjFCcEd3MTlYVGRsRlpXWWRsWlU0dkEKe5NUijC+GVxzj8bMEY6v+qHw9iylpwQz\nFLKneLikKVcRYoTYecimaQdUbYCiEwUB7KCpENcNmjZx6eVmTvGeMQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6T1hheHNaZ2h6Mlc5WEJq\nUk8zTC82N2ZHUUJQK0VLdXBkNEFnNlRHamh3CitrWGpVVGQreDRZdTF5L2VXNENn\neThUd0tjUWpCNW01QklZakx6NnNoT28KLS0tIGVOLytqUGtsaWhFbi9mU2ttMmow\nOFhwVmkyVDdZK09ramZOYktFdkV5R1EKWGseGbOtLS45gb6fb8LFzlfdsRGC7x9B\ncn03oAcfC2Yo/kqoT4tjQF/COn408SBkytwZ3GbL8Bnul/RyjcHJNQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-10-19T12:53:38Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:MneMlobCnJZVn5QEwxL1os48TOJhrfETry39G2Si1kT5OKq6SlNB2mtVOshmGv21Cue/JNZWr9kwO0SS4egs4CsWaW8MMoR+84KIGIu9uol3vieEayd8nOjJfCKp0fRQKi1ElJRUtjLApA1KQ05WjG+vlb2JxNl67NWRqtykA44=,iv:f91eVJiSfmvM9ym8a3VYlijNZW5SoGUCUqAgFEax6Bo=,tag:ciANv3ov6p0gCJTIQwBoJg==,type:str]",
|
||||||
|
"version": "3.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../sops/users/admin
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user