Compare commits

..

134 Commits

Author SHA1 Message Date
DavHau
588eeabf39 ci performance: add check to ensure nothing depends on the whole repo
Since this project is an ever growing monorepo, having derivations depending on the whole repo leads to bad CI performance, as the cache is busted on every commit.

-> We never want any derivations depend on the whole repo

...except: the test that tests that nothing depends on the whole repo, which is added by this commit.
2025-04-30 11:55:31 +07:00
hsjobeki
2ea4bd059c Merge pull request 'refactor(clan.service): make evalClanService a standalone function to interact with standalone modules' (#3444) from hsjobeki/clan-core:clan-services-4 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3444
2025-04-29 13:38:02 +00:00
Johannes Kirschbauer
3d09c98ed3 Checks: add json-compat check wrapper to ensure all clan.modules stay json-compatible 2025-04-29 15:31:02 +02:00
Johannes Kirschbauer
a4a1363195 refactor(clan.service): make evalClanService a standalone function to interact with standalone modules 2025-04-29 15:12:44 +02:00
renovate[bot]
fd4d42c54c chore(deps): update treefmt-nix digest to 82bf32e 2025-04-29 13:00:11 +00:00
hsjobeki
670cfe6fbc Merge pull request 'Feat(clan.service): require roles.interface to be json serializable' (#3442) from hsjobeki/clan-core:clan-services-4 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3442
2025-04-29 12:51:10 +00:00
Johannes Kirschbauer
9b5f100ac6 Feat(clan.service): require roles.interface to be json serializable 2025-04-29 14:42:47 +02:00
kenji
ff71c819e1 Merge pull request 'clanModules/iwd: Migrate from facts to vars' (#3439) from kenji/clan-core:ke-iwd-migrate-to-vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3439
2025-04-29 12:03:56 +00:00
a-kenji
4bd43f297a clanModules/iwd: Migrate from facts to vars 2025-04-29 13:55:45 +02:00
Michael Hoang
78f96ec533 Merge pull request 'age plugin support' (#3322) from feat/age-plugin-support into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3322
2025-04-29 06:12:44 +00:00
Brian McGee
a438fe77a7 feat: configure age plugins for SOPS in buildClan 2025-04-29 16:02:32 +10:00
Brian McGee
d3e1c0b4e4 fix: multiple user keys in secrets
We were not loading all the user keys, only the first one.
2025-04-29 15:47:54 +10:00
Brian McGee
1694a977f1 feat: support age plugins
Extends how we parse the contents of `SOPS_AGE_KEY` / `SOPS_AGE_KEY_FILE` / `keys.txt`, allowing a user to prepend a comment before any `AGE-PLUGIN-` secret key entry to indicate its corresponding public key.

For example:

```
AGE-PLUGIN-FIDO2-HMAC-xxxxxxxxxxxxx
```

The comment can use any prefix (e.g. `# public key: age1xxxx`, `# recipient: age1xxx`) as we are looking directly for `age1xxxx` within the line.

This change is necessary to support `age` plugins as there is no unified mechanism to recover the public key from a plugin's secret key.

If a plugin secret key does not have a preceding public key comment, an error will be thrown when attempting to set a secret.
2025-04-29 15:47:54 +10:00
Michael Hoang
852fdc2846 Merge pull request 'chore(deps): lock file maintenance' (#3365) from renovate/lock-file-maintenance into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3365
2025-04-29 05:22:24 +00:00
Michael Hoang
5879c48616 container-test-driver: fix SSH not working inside container tests 2025-04-29 15:10:09 +10:00
Michael Hoang
7d46237b67 container-test-driver: add Machine.fail 2025-04-29 14:57:58 +10:00
renovate[bot]
82b3ba97b7 chore(deps): lock file maintenance 2025-04-29 02:00:26 +00:00
renovate[bot]
a79c79ffec chore(deps): update data-mesher digest to 11b5673 2025-04-29 01:40:09 +00:00
DavHau
ebada396dd build-clan: Throw better error when _class is not provided by nixpkgs 2025-04-28 15:49:14 +00:00
renovate[bot]
b709f30ef4 chore(deps): update treefmt-nix digest to 763f1ce 2025-04-28 14:30:15 +00:00
hsjobeki
7c5ed8945f Merge pull request 'ui-fixups' (#3436) from hsjobeki/clan-core:ui-fixups into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3436
2025-04-28 12:34:16 +00:00
Johannes Kirschbauer
a6f97b0a04 Fix(app/machine/create): fix css styling inconsistencies, remove ability to set tags 2025-04-28 14:25:29 +02:00
Johannes Kirschbauer
05c172466f Fix(app/sidebar): remove duplicate marker 2025-04-28 14:15:02 +02:00
Johannes Kirschbauer
b3e5b1de8a Chore(app): re-enable classname linting to be an error 2025-04-28 14:14:42 +02:00
hsjobeki
3b6657c657 Merge pull request 'Fix(app/machines): fix css styling of machine list overview' (#3435) from hsjobeki/clan-core:ui-fixups into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3435
2025-04-28 12:08:07 +00:00
Johannes Kirschbauer
6700d3d502 Fix(app/machines): fix css styling of machine list overview 2025-04-28 14:00:17 +02:00
renovate[bot]
346853c4f7 chore(deps): update treefmt-nix digest to d1863f3 2025-04-28 11:10:15 +00:00
DavHau
19e528ef54 Merge pull request 'Revert "chore(deps): update data-mesher digest to 41534a3"' (#3432) from DavHau/clan-core:revert-data-mesher into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3432
2025-04-28 11:07:34 +00:00
DavHau
ab6a73cf6b Revert "chore(deps): update data-mesher digest to 41534a3"
This reverts commit f830bf4a0e.
2025-04-28 17:55:04 +07:00
renovate[bot]
f830bf4a0e chore(deps): update data-mesher digest to 41534a3 2025-04-28 08:00:20 +00:00
renovate[bot]
d69b814fa5 chore(deps): update treefmt-nix digest to c6d3010 2025-04-28 07:40:10 +00:00
renovate[bot]
9e6fdb4aff chore(deps): update nix-darwin digest to 4515dac 2025-04-28 05:30:10 +00:00
renovate[bot]
3c5ba156b8 chore(deps): update disko digest to d0c543d 2025-04-28 04:40:10 +00:00
Michael Hoang
da7abe26a8 Merge pull request 'cli: don't depend on the entire clan-core' (#3424) from push-pzytrksvysmu into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3424
2025-04-28 03:30:01 +00:00
Michael Hoang
c73652a401 cli: don't depend on the entire clan-core 2025-04-28 13:20:07 +10:00
Michael Hoang
c347badd7f cli: fallback to bundled Nixpkgs 2025-04-28 13:10:00 +10:00
Michael Hoang
c7c3abdf04 Merge pull request 'cli: don't use select from clanLib' (#3423) from push-ywotxpmyxlwp into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3423
2025-04-28 03:01:48 +00:00
Michael Hoang
6c8ef6e9be cli: don't use select from clanLib 2025-04-28 12:52:00 +10:00
renovate[bot]
52a28488c7 chore(deps): update data-mesher digest to 8d0a67b 2025-04-28 00:30:10 +00:00
renovate[bot]
15832521e7 chore(deps): update treefmt-nix digest to b2b6c02 2025-04-27 20:30:24 +00:00
renovate[bot]
9e409cbefe chore(deps): update data-mesher digest to f05729d 2025-04-27 20:10:09 +00:00
hsjobeki
5fc1f2cdbb Merge pull request 'Chore: remove unused legacy endpoints' (#3418) from hsjobeki/clan-core:chores-remove-unused into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3418
2025-04-27 11:25:00 +00:00
Johannes Kirschbauer
b87d5a238c chore: remove unused moduleSchemas and related API endpoint for legacy modules
We didn't reach the state where we would display these schemas in the
UI.
We might need to wire this up in a similar way for the newer
clan.services
2025-04-27 13:14:09 +02:00
Johannes Kirschbauer
7007b7d62e refactor: rename clanLib.values to introspection 2025-04-27 13:10:42 +02:00
hsjobeki
033c50a5c3 Merge pull request 'Feat(clan.service): init automatic assertions for api schema checks' (#3416) from hsjobeki/clan-core:new-json-schemas into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3416
2025-04-27 11:07:12 +00:00
hsjobeki
5aa8715e9f Merge pull request 'fix: typo in auto-upgrade clanModule' (#3417) from hsjobeki/clan-core:fix-auto-upgrade into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3417
2025-04-27 10:13:22 +00:00
Johannes Kirschbauer
3e31a73ae3 fix: typo in auto-upgrade clanModule 2025-04-27 12:04:03 +02:00
Johannes Kirschbauer
6dfc324661 Feat(clan.service): init automatic assertions for api schema checks 2025-04-27 11:49:56 +02:00
hsjobeki
95e6c5ca0f Merge pull request 'Feat(clan.service): enable opt-in json-schema restriction for clan.service interface modules' (#3415) from hsjobeki/clan-core:new-json-schemas into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3415
2025-04-27 09:49:08 +00:00
Johannes Kirschbauer
8495106ec4 feat(services): init feature flags in the module manifest: 'manifest.features.API' 2025-04-27 11:07:45 +02:00
Johannes Kirschbauer
ffa8257763 chore: remove unused option 'clanSchema' from core nixos modules 2025-04-27 11:07:45 +02:00
hsjobeki
bdeba9e4bf Merge pull request 'Init 'clan_lib' namespace and migrate clan_cli.api' (#3414) from hsjobeki/clan-core:clan-lib into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3414
2025-04-26 18:29:35 +00:00
Johannes Kirschbauer
070114ae9f Fix(clan_lib.api): fix cyclic import problem for api schema export 2025-04-26 20:19:23 +02:00
Johannes Kirschbauer
acbe619883 Refactor(clan_lib): move clan_cli.api into clan_lib.api 2025-04-26 19:51:35 +02:00
Johannes Kirschbauer
3b889649ec Refactor(clan_cli): init clan_lib folder 2025-04-26 19:50:11 +02:00
Mic92
e335556767 Merge pull request 'nixpkgs source: delete existing symlink' (#3411) from nixpkgs-build into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3411
2025-04-25 14:41:23 +00:00
Jörg Thalheim
97564052ab nixpkgs source: delete existing symlink 2025-04-25 16:31:35 +02:00
Luis Hebendanz
7b6483bfad Merge pull request 'clan-cli: Expose private_key to Machine class, in the future we should merge Machine and Host class' (#3407) from Qubasa/clan-core:vpb-patches2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3407
2025-04-25 12:26:00 +00:00
Qubasa
130a5bc593 clan-cli: Improve remote destination depth validation with detailed error messaging 2025-04-25 14:00:40 +02:00
Qubasa
9d45376f95 clan-cli: Expose private_key to Machine class, in the future we should merge Machine and Host class 2025-04-25 13:38:03 +02:00
Mic92
e78bd89426 Merge pull request 'clanCore/vars: allow mode to be set' (#3404) from visualphoenix/clan-core:mode_fix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3404
2025-04-25 09:44:25 +00:00
Raymond Barbiero
222915a9ed clanCore/vars: allow mode to be set
fmt
2025-04-25 11:29:43 +02:00
Michael Hoang
d8780b8da9 Merge pull request 'lib: move select.select -> select for backwards compat with old CLIs' (#3410) from push-vxxntzmwuzzx into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3410
Reviewed-by: lassulus <clanlol@lassul.us>
2025-04-25 09:24:17 +00:00
Michael Hoang
cc4b009f06 lib: move select.select -> select for backwards compat with old CLIs 2025-04-25 17:30:06 +10:00
Michael Hoang
59e7af7830 Merge pull request 'Refactor select with new maybe selector' (#3362) from better-select into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3362
2025-04-25 07:02:22 +00:00
Michael Hoang
60ff14d6b7 cli: fix restoring backups
There was a bug in `select` that made it output attrsets instead of
lists so we fix the broken refactor done in
5ac629f549.
2025-04-25 16:52:13 +10:00
lassulus
34ac45bd13 clan-cli flake-module: get select from new lib location 2025-04-25 16:26:45 +10:00
lassulus
89adacebec templates: fix usage with new select 2025-04-25 16:26:45 +10:00
lassulus
5feccf4e57 Refactor select with new maybe selector
This is a great refactor of the select functionality in the flake class.
This now uses the same parser as the nix code, but runs it in python for
nice stacktraces.

Also we now have a maybe selector which can be used by prepending the
selector with a ?

Tests have been expanded to make sure the code is more stable and easier
to understand
2025-04-25 16:26:45 +10:00
Michael Hoang
27077817ae Merge pull request 'clan-app: improve README' (#3409) from push-ystlwosvuxvw into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3409
2025-04-25 01:20:40 +00:00
Michael Hoang
d7f0c0fc78 clan-app: improve README 2025-04-25 11:12:27 +10:00
renovate[bot]
8f37df456d Update disko digest to ca27b88 2025-04-24 13:50:10 +00:00
DavHau
dc5d10931b Merge pull request 'clan-app: add basic smoke test using OCR + nixos tests' (#3406) from DavHau/clan-core:dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3406
2025-04-24 12:02:06 +00:00
DavHau
39c13a5c38 clan-app: add basic smoke test using OCR + nixos tests 2025-04-24 18:17:09 +07:00
renovate[bot]
4be8f7d973 Update data-mesher digest to 4fdda23 2025-04-24 07:30:09 +00:00
hsjobeki
785f68b2f6 Merge pull request 'Chore(clan/clan_uri): Remove ClanURI class from clan_cli' (#3401) from hsjobeki/clan-core:remove-clan-uri into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3401
2025-04-23 15:13:32 +00:00
Johannes Kirschbauer
7076f1b0e6 Chore(clan/clan_uri): Remove ClanURI class from clan_cli 2025-04-23 16:53:11 +02:00
hsjobeki
771901f6aa Merge pull request 'Refactor: move checks/lib into lib/ to avoid duplicate lib' (#3399) from hsjobeki/clan-core:checks-lib-remove into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3399
2025-04-23 14:33:19 +00:00
Johannes Kirschbauer
a589736f9b lib/tests: fix container driver module path 2025-04-23 16:23:09 +02:00
Johannes Kirschbauer
f6e514ec6f Refactor: move checks/lib into lib/ to avoid duplicate lib
Lets avoid the mistake of nixpkgs having multiple
libs
2025-04-23 16:19:16 +02:00
DavHau
366be7c723 Merge pull request 'inventory tests: use containers by default' (#3398) from DavHau/clan-core:dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3398
2025-04-23 12:59:52 +00:00
DavHau
e2fb237c33 inventory tests: use containers by default 2025-04-23 19:49:02 +07:00
hsjobeki
c172996dbf Merge pull request 'UI: fix general layout' (#3397) from hsjobeki/clan-core:ui-3 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3397
2025-04-23 11:33:35 +00:00
Mic92
8bc58b1f8c Merge pull request 'clanModules/vaultwarden: Migrate from facts to vars' (#3394) from kenji/clan-core:ke-vaultwarden-migrate-to-vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3394
2025-04-23 11:32:52 +00:00
a-kenji
47073aed43 clanModules/vaultwarden: Migrate from facts to vars
Closes: #3389
2025-04-23 13:01:52 +02:00
kenji
55e1141eb3 Merge pull request 'clanModules/syncthing: Improve vars' (#3391) from kenji/clan-core:syncthing-improve-vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3391
2025-04-23 10:50:45 +00:00
a-kenji
62e0ca7a08 clanModules/syncthing: Improve vars 2025-04-23 10:50:45 +00:00
a-kenji
55fbac76f8 clanModules/syncthing: Group vars files 2025-04-23 10:50:45 +00:00
Johannes Kirschbauer
0289c3ddea UI: fix general layout 2025-04-23 10:25:25 +00:00
renovate[bot]
cdf3f5df4b chore(deps): update disko digest to c5140c6 2025-04-23 09:40:09 +00:00
Mic92
d987049921 Merge pull request 'temporary disabling the VM test until we have vars fixed' (#3395) from vms into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3395
2025-04-23 09:38:26 +00:00
Jörg Thalheim
c7a3f35fb1 temporary disabling the VM test until we have vars fixed
We are currently missing injecting public vars back into the vm.
To unblock the CI, we disable the test for a bit.
2025-04-23 11:26:05 +02:00
kenji
9a4a60273d Merge pull request 'syncthing: Migrate from facts to vars' (#3388) from kenji/clan-core:syncthing into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3388
2025-04-23 06:25:12 +00:00
a-kenji
5edc457fc1 chore: treefmt 2025-04-23 08:00:16 +02:00
a-kenji
8b2a92cda0 clanModules/syncthing: Fix vars usage
This fixes vars usage in the syncthing module.
Also removes some of the assumptions that were made in order for
`sysuser` to work, as we now use `userborn` for the vm functionality.
2025-04-23 07:40:44 +02:00
a-kenji
f8df19a128 checks/syncthing: Use default settings 2025-04-23 07:39:55 +02:00
a-kenji
fc5aaf5eaa checks/syncthing: Remove nixos tests 2025-04-23 07:38:36 +02:00
hsjobeki
6f2b7aa6d1 Merge pull request 'vars-fix-overeager-chache-invalidation' (#3385) from hsjobeki/clan-core:vars-fix-overeager-chache-invalidation into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3385
2025-04-22 18:28:27 +00:00
Johannes Kirschbauer
d3927f50ae Tests/fix: forbid dynamic invalidation
We cannot support dynamic hashInvalidation.
This means the invalidation can change *after* or *before* a 'vars generate'
But not during the generation itself. This causes heavy performance overhead.
Additionally this introduces a fixed-point-iteration (compare: fixed-point-iteration vs. fixed-point-function)
This iteration takes ~ 1min for two bare-bones machine with 1 generator (see: checks/data-mesher)
2025-04-22 20:19:15 +02:00
Michael Hoang
50d032f6a4 Merge pull request 'cli/machines: don't allow installing on macOS' (#3387) from push-zrqstttptroo into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3387
2025-04-22 17:22:21 +00:00
Michael Hoang
1168395336 cli/machines: don't allow installing on macOS 2025-04-23 03:13:39 +10:00
Mic92
38cbe58af4 Merge pull request 'zerotier: migrate from facts to vars' (#3383) from zerotier-vars into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3383
2025-04-22 16:48:32 +00:00
Jörg Thalheim
043077269a drop overrides of nix version 2025-04-22 18:20:35 +02:00
Jörg Thalheim
c2030eb3ba drop test_secrets_password_store
we are phasing out facts and the only fact we had left for testing, got
now dropped. We still have a sops facts test, which we might also drop
soon.
2025-04-22 18:20:35 +02:00
Jörg Thalheim
ffaa30d894 vms/run: upload vars 2025-04-22 18:20:35 +02:00
Jörg Thalheim
847e3ac4ab drop unused machine_get_fact 2025-04-22 18:20:35 +02:00
Jörg Thalheim
7392570859 use machine.{secrets,public}_{vars,fact}_store everywhere 2025-04-22 18:20:35 +02:00
Jörg Thalheim
fe6fd41a4d zerotier: migrate from facts to vars 2025-04-22 18:20:35 +02:00
Michael Hoang
b5cc250237 Merge pull request 'networking: set targetHost if FQDN is explicitly set' (#3386) from push-tylstpvrwsxv into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3386
2025-04-22 15:40:45 +00:00
Michael Hoang
e6e7f5d5de networking: set targetHost if FQDN is explicitly set 2025-04-23 01:15:13 +10:00
hsjobeki
74e64d413f Merge pull request 'Fix: remove daisyui' (#3384) from hsjobeki/clan-core:ui-2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3384
2025-04-22 14:58:53 +00:00
Johannes Kirschbauer
e417f79527 pkgs/generate-test-vars: speed up vars generation by precaching 2025-04-22 16:47:39 +02:00
Johannes Kirschbauer
b47f2b6870 vars: move overeager cache invalidation after one generator closure is regenrated.
Invalidation doesn't need to be done after each generator is executed.
We cannot interpolate values from other generators into another
generator. The generators are executed in order. The finalScript of each
generator stays constant.
After the complete closure is generated the caller of generate may
decide to invalidate the flake cache
2025-04-22 16:42:21 +02:00
Michael Hoang
5cadb0cfbc Merge pull request 'nixosModules/clanCore: support nix-darwin' (#3287) from nix-darwin into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3287
2025-04-22 13:50:38 +00:00
hsjobeki
ce55397ef7 Merge pull request 'Checks: add nixosIntegration test example to hello-service' (#3373) from hsjobeki/clan-core:checks-hello into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3373
2025-04-22 13:45:46 +00:00
Michael Hoang
20ae80ee49 vars: fix default group on macOS 2025-04-22 23:39:47 +10:00
Michael Hoang
f40ab5c379 docs: always evaluate with class of nixos 2025-04-22 23:39:47 +10:00
Michael Hoang
de12036630 cli: support updating nix-darwin machines 2025-04-22 23:39:47 +10:00
Michael Hoang
91a2739ea3 cli: fix unnecessary sudo when unspecified user defaults to root 2025-04-22 23:39:46 +10:00
Johannes Kirschbauer
7dd249863f Fix: remove daisyui
We wanted to remove daisyui a long time ago
Since renovate updates broke all of the classes somehow we use the opportunity to remove daisyui
And will fix all the breakages continously as we work on the features
2025-04-22 15:24:52 +02:00
Michael Hoang
b5901d5577 cli: only use sudo when deploying locally 2025-04-22 23:14:03 +10:00
Michael Hoang
a0117c51c1 cli: use sudo consistently when running nixos-rebuild switch 2025-04-22 23:14:03 +10:00
Michael Hoang
a575894a83 nixosModules/clanCore: support nix-darwin 2025-04-22 23:14:03 +10:00
Michael Hoang
2bbf4b168a Back out "cli: don't update macOS machines"
This backs out commit 72ed0e258a.
2025-04-22 23:14:03 +10:00
Johannes Kirschbauer
a6d7c491e4 Fix: clnixos-integration tests only work on linux 2025-04-22 14:56:09 +02:00
Mic92
1f78de953a Merge pull request 'Container-tests: add multi-container network' (#3381) from netns into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3381
2025-04-22 12:11:27 +00:00
DavHau
18493f869b container-tests: add multi-container network 2025-04-22 13:26:37 +02:00
Michael Hoang
b6ac3dbc88 Merge pull request 'Chore: restore ui lockfile from a3f6fb21c8a22977009e1055fc1d31507977e7f2' (#3380) from hsjobeki/clan-core:ui-1 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3380
2025-04-22 10:41:20 +00:00
Johannes Kirschbauer
4ead0045cb Fix: typescript problem with inventory indexing 2025-04-22 12:10:25 +02:00
renovate[bot]
3a5efdbd9f chore(deps): update sops-nix digest to 5e3e92b 2025-04-22 08:50:11 +00:00
Johannes Kirschbauer
6630e227c7 Chore: restore ui lockfile from a3f6fb21c8 2025-04-22 09:48:46 +02:00
Jörg Thalheim
508e71cace syncthing: warn that this module is currently not usuable without vms 2025-04-22 09:45:37 +02:00
Jörg Thalheim
21f69ca7c4 syncthing: migrate to new inventory system 2025-04-22 09:45:37 +02:00
Johannes Kirschbauer
999c47dbed Checks: add nixosIntegration test example to hello-service 2025-04-22 06:32:32 +00:00
259 changed files with 7312 additions and 5233 deletions

View File

@@ -0,0 +1,41 @@
{ self, pkgs, ... }:
{
name = "app-ocr-smoke-test";
enableOCR = true;
nodes = {
wayland =
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/../tests/common/wayland-cage.nix") ];
services.cage.program = "${self.packages.${pkgs.system}.clan-app}/bin/clan-app";
virtualisation.memorySize = 2047;
# TODO: get rid of this and fix debus-proxy error instead
services.cage.environment.WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS = "1";
};
xorg =
{ pkgs, modulesPath, ... }:
{
imports = [
(modulesPath + "/../tests/common/user-account.nix")
(modulesPath + "/../tests/common/x11.nix")
];
virtualisation.memorySize = 2047;
services.xserver.enable = true;
services.xserver.displayManager.sessionCommands = "${
self.packages.${pkgs.system}.clan-app
}/bin/clan-app";
test-support.displayManager.auto.user = "alice";
};
};
testScript = ''
start_all()
wayland.wait_for_unit('graphical.target')
xorg.wait_for_unit('graphical.target')
wayland.wait_for_text('Welcome to Clan')
xorg.wait_for_text('Welcome to Clan')
'';
}

View File

@@ -36,7 +36,7 @@
# Borgbackup overrides
services.borgbackup.repos.test-backups = {
path = "/var/lib/borgbackup/test-backups";
authorizedKeys = [ (builtins.readFile ../lib/ssh/pubkey) ];
authorizedKeys = [ (builtins.readFile ../assets/ssh/pubkey) ];
};
clan.borgbackup.destinations.test-backup.repo = lib.mkForce "borg@machine:.";
@@ -45,7 +45,7 @@
programs.ssh.knownHosts = {
machine.hostNames = [ "machine" ];
machine.publicKey = builtins.readFile ../lib/ssh/pubkey;
machine.publicKey = builtins.readFile ../assets/ssh/pubkey;
};
services.openssh = {
@@ -60,7 +60,7 @@
];
};
users.users.root.openssh.authorizedKeys.keyFiles = [ ../lib/ssh/pubkey ];
users.users.root.openssh.authorizedKeys.keyFiles = [ ../assets/ssh/pubkey ];
# This is needed to unlock the user for sshd
# Because we use sshd without setuid binaries
@@ -68,21 +68,21 @@
systemd.tmpfiles.settings."vmsecrets" = {
"/root/.ssh/id_ed25519" = {
C.argument = "${../lib/ssh/privkey}";
C.argument = "${../assets/ssh/privkey}";
z = {
mode = "0400";
user = "root";
};
};
"/etc/secrets/ssh.id_ed25519" = {
C.argument = "${../lib/ssh/privkey}";
C.argument = "${../assets/ssh/privkey}";
z = {
mode = "0400";
user = "root";
};
};
"/etc/secrets/borgbackup/borgbackup.ssh" = {
C.argument = "${../lib/ssh/privkey}";
C.argument = "${../assets/ssh/privkey}";
z = {
mode = "0400";
user = "root";
@@ -169,7 +169,7 @@
in
{
checks = pkgs.lib.mkIf pkgs.stdenv.isLinux {
backups = (import ../lib/container-test.nix) {
backups = self.clanLib.test.containerTest {
name = "backups";
nodes.machine = {
imports =

View File

@@ -1,4 +1,4 @@
(import ../lib/test-base.nix) (
(
{ ... }:
{
name = "borgbackup";
@@ -12,7 +12,7 @@
{
services.openssh.enable = true;
services.borgbackup.repos.testrepo = {
authorizedKeys = [ (builtins.readFile ../lib/ssh/pubkey) ];
authorizedKeys = [ (builtins.readFile ../assets/ssh/pubkey) ];
};
}
{
@@ -21,7 +21,7 @@
environment.etc.state.text = "hello world";
systemd.tmpfiles.settings."vmsecrets" = {
"/etc/secrets/borgbackup/borgbackup.ssh" = {
C.argument = "${../lib/ssh/privkey}";
C.argument = "${../assets/ssh/privkey}";
z = {
mode = "0400";
user = "root";

View File

@@ -1,19 +1,44 @@
(import ../lib/container-test.nix) (
(
{ ... }:
{
name = "container";
nodes.machine =
nodes.machine1 =
{ ... }:
{
networking.hostName = "machine";
networking.hostName = "machine1";
services.openssh.enable = true;
services.openssh.startWhenNeeded = false;
};
nodes.machine2 =
{ ... }:
{
networking.hostName = "machine2";
services.openssh.enable = true;
services.openssh.startWhenNeeded = false;
};
testScript = ''
import subprocess
start_all()
machine.succeed("systemctl status sshd")
machine.wait_for_unit("sshd")
machine1.succeed("systemctl status sshd")
machine2.succeed("systemctl status sshd")
machine1.wait_for_unit("sshd")
machine2.wait_for_unit("sshd")
p1 = subprocess.run(["ip", "a"], check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert p1.returncode == 0
bridge_output = p1.stdout.decode("utf-8")
assert "br0" in bridge_output, f"bridge not found in ip a output: {bridge_output}"
for m in [machine1, machine2]:
out = machine1.succeed("ip addr show eth1")
assert "UP" in out, f"UP not found in ip addr show output: {out}"
assert "inet" in out, f"inet not found in ip addr show output: {out}"
assert "inet6" in out, f"inet6 not found in ip addr show output: {out}"
machine1.succeed("ping -c 1 machine2")
'';
}
)

View File

@@ -14,6 +14,7 @@ in
./installation/flake-module.nix
./morph/flake-module.nix
./nixos-documentation/flake-module.nix
./sanity-checks/dont-depend-on-repo-root.nix
];
perSystem =
{
@@ -33,20 +34,25 @@ in
inherit (self) clanLib;
};
nixosTests = lib.optionalAttrs (pkgs.stdenv.isLinux) {
# import our test
secrets = import ./secrets nixosTestArgs;
container = import ./container nixosTestArgs;
# Deltachat is currently marked as broken
# deltachat = import ./deltachat nixosTestArgs;
borgbackup = import ./borgbackup nixosTestArgs;
matrix-synapse = import ./matrix-synapse nixosTestArgs;
# Base Tests
secrets = self.clanLib.test.baseTest ./secrets nixosTestArgs;
borgbackup = self.clanLib.test.baseTest ./borgbackup nixosTestArgs;
wayland-proxy-virtwl = self.clanLib.test.baseTest ./wayland-proxy-virtwl nixosTestArgs;
# Container Tests
container = self.clanLib.test.containerTest ./container nixosTestArgs;
zt-tcp-relay = self.clanLib.test.containerTest ./zt-tcp-relay nixosTestArgs;
matrix-synapse = self.clanLib.test.containerTest ./matrix-synapse nixosTestArgs;
postgresql = self.clanLib.test.containerTest ./postgresql nixosTestArgs;
# Clan Tests
mumble = import ./mumble nixosTestArgs;
dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs;
data-mesher = import ./data-mesher nixosTestArgs;
syncthing = import ./syncthing nixosTestArgs;
zt-tcp-relay = import ./zt-tcp-relay nixosTestArgs;
postgresql = import ./postgresql nixosTestArgs;
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
};
flakeOutputs =
@@ -59,7 +65,33 @@ in
self'.legacyPackages.homeConfigurations or { }
);
in
nixosTests // flakeOutputs;
nixosTests
// flakeOutputs
// {
# TODO: Automatically provide this check to downstream users to check their modules
clan-modules-json-compatible =
let
allSchemas = lib.mapAttrs (
_n: m:
let
schema =
(self.clanLib.inventory.evalClanService {
modules = [ m ];
key = "checks";
}).config.result.api.schema;
in
schema
) self.clan.modules;
in
pkgs.runCommand "combined-result"
{
schemaFile = builtins.toFile "schemas.json" (builtins.toJSON allSchemas);
}
''
mkdir -p $out
cat $schemaFile > $out/allSchemas.json
'';
};
legacyPackages = {
nixosTests =
let
@@ -74,6 +106,8 @@ in
# import our test
secrets = import ./secrets nixosTestArgs;
container = import ./container nixosTestArgs;
# Clan app tests
app-ocr = self.clanLib.test.baseTest ./app-ocr nixosTestArgs;
};
};
};

View File

@@ -56,7 +56,7 @@
in
{
checks = pkgs.lib.mkIf pkgs.stdenv.isLinux {
flash = (import ../lib/test-base.nix) {
flash = self.clanLib.test.baseTest {
name = "flash";
nodes.target = {
virtualisation.emptyDiskImages = [ 4096 ];

View File

@@ -51,7 +51,7 @@ let
};
users.users.nonrootuser = {
isNormalUser = true;
openssh.authorizedKeys.keyFiles = [ ../lib/ssh/pubkey ];
openssh.authorizedKeys.keyFiles = [ ../assets/ssh/pubkey ];
extraGroups = [ "wheel" ];
};
security.sudo.wheelNeedsPassword = false;
@@ -183,7 +183,7 @@ in
# vm-test-run-test-installation-> target: Guest root shell did not produce any data yet...
# vm-test-run-test-installation-> target: To debug, enter the VM and run 'systemctl status backdoor.service'.
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux && !pkgs.stdenv.isAarch64) {
installation = (import ../lib/test-base.nix) {
installation = self.clanLib.test.baseTest {
name = "installation";
nodes.target = {
services.openssh.enable = true;
@@ -195,7 +195,7 @@ in
testScript = ''
installer.start()
installer.succeed("${pkgs.coreutils}/bin/install -Dm 600 ${../lib/ssh/privkey} /root/.ssh/id_ed25519")
installer.succeed("${pkgs.coreutils}/bin/install -Dm 600 ${../assets/ssh/privkey} /root/.ssh/id_ed25519")
installer.wait_until_succeeds("timeout 2 ssh -o StrictHostKeyChecking=accept-new -v nonrootuser@localhost hostname")
installer.succeed("cp -r ${../..} test-flake && chmod -R +w test-flake")
@@ -210,13 +210,13 @@ in
'';
} { inherit pkgs self; };
update-hardware-configuration = (import ../lib/test-base.nix) {
update-hardware-configuration = self.clanLib.test.baseTest {
name = "update-hardware-configuration";
nodes.installer = installer;
testScript = ''
installer.start()
installer.succeed("${pkgs.coreutils}/bin/install -Dm 600 ${../lib/ssh/privkey} /root/.ssh/id_ed25519")
installer.succeed("${pkgs.coreutils}/bin/install -Dm 600 ${../assets/ssh/privkey} /root/.ssh/id_ed25519")
installer.wait_until_succeeds("timeout 2 ssh -o StrictHostKeyChecking=accept-new -v nonrootuser@localhost hostname")
installer.succeed("cp -r ${../..} test-flake && chmod -R +w test-flake")
installer.fail("test -f test-flake/machines/test-install-machine/hardware-configuration.nix")

View File

@@ -1,25 +0,0 @@
{
extraPythonPackages,
python3Packages,
buildPythonApplication,
setuptools,
util-linux,
systemd,
nix,
colorama,
junit-xml,
}:
buildPythonApplication {
pname = "test-driver";
version = "0.0.1";
propagatedBuildInputs = [
util-linux
systemd
colorama
junit-xml
nix
] ++ extraPythonPackages python3Packages;
nativeBuildInputs = [ setuptools ];
format = "pyproject";
src = ./.;
}

View File

@@ -1,52 +0,0 @@
test:
{ pkgs, self, ... }:
let
inherit (pkgs) lib;
nixos-lib = import (pkgs.path + "/nixos/lib") { };
in
(nixos-lib.runTest (
{ hostPkgs, ... }:
{
hostPkgs = pkgs;
# speed-up evaluation
defaults =
{ config, options, ... }:
{
imports = [
self.clanLib.test.minifyModule
];
config = lib.mkMerge [
(lib.optionalAttrs (options ? clan) {
clan.core.settings.machine.name = config.networking.hostName;
})
{
documentation.enable = lib.mkDefault false;
boot.isContainer = true;
# needed since nixpkgs 7fb2f407c01b017737eafc26b065d7f56434a992 removed the getty unit by default
console.enable = true;
# undo qemu stuff
system.build.initialRamdisk = "";
virtualisation.sharedDirectories = lib.mkForce { };
networking.useDHCP = false;
# we have not private networking so far
networking.interfaces = lib.mkForce { };
#networking.primaryIPAddress = lib.mkForce null;
systemd.services.backdoor.enable = false;
# we don't have permission to set cpu scheduler in our container
systemd.services.nix-daemon.serviceConfig.CPUSchedulingPolicy = lib.mkForce "";
}
];
};
# to accept external dependencies such as disko
node.specialArgs.self = self;
_module.args = { inherit self; };
imports = [
test
./container-driver/module.nix
];
}
)).config.result

View File

@@ -1,4 +1,4 @@
(import ../lib/container-test.nix) (
(
{ pkgs, ... }:
{
name = "matrix-synapse";

View File

@@ -24,7 +24,7 @@
}:
{
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux && !pkgs.stdenv.isAarch64) {
morph = (import ../lib/test-base.nix) {
morph = self.clanLib.test.baseTest {
name = "morph";
nodes = {

View File

@@ -6,6 +6,8 @@
}:
clanLib.test.makeTestClan {
inherit pkgs self;
# TODO: container driver does not support: sleep, wait_for_window, send_chars, wait_for_text
useContainers = false;
nixosTest = (
{ lib, ... }:
let

View File

@@ -1,4 +1,4 @@
(import ../lib/container-test.nix) ({
({
name = "postgresql";
nodes.machine =

View File

@@ -0,0 +1,121 @@
{
...
}:
{
perSystem =
{
system,
pkgs,
self',
lib,
...
}:
let
clanCore = self'.packages.clan-core-flake;
clanCoreHash = lib.substring 0 12 (builtins.hashString "sha256" "${clanCore}");
/*
construct a flake for the test which contains a single check which depends
on all checks of clan-core.
*/
testFlakeFile = pkgs.writeText "flake.nix" ''
{
inputs.clan-core.url = path:///to/nowhere;
outputs = {clan-core, ...}:
let
checks =
builtins.removeAttrs
clan-core.checks.${system}
[
"dont-depend-on-repo-root"
"package-clan-core-flake"
];
checksOutPaths = map (x: "''${x}") (builtins.attrValues checks);
in
{
checks.${system}.check = builtins.derivation {
name = "all-clan-core-checks";
system = "${system}";
builder = "/bin/sh";
args = ["-c" '''
of outPath in ''${toString checksOutPaths}; do
echo "$outPath" >> $out
done
'''];
};
};
}
'';
in
lib.optionalAttrs (system == "x86_64-linux") {
checks.dont-depend-on-repo-root =
pkgs.runCommand
# append repo hash to this tests name to ensure it gets invalidated on each chain
# This is needed because this test is an FOD (due to networking) and would get cached indefinitely.
"check-dont-depend-on-repo-root-${clanCoreHash}"
{
buildInputs = [
pkgs.nix
pkgs.cacert
pkgs.nix-diff
];
outputHashAlgo = "sha256";
outputHash = "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=";
}
''
mkdir clanCore testFlake store
clanCore=$(realpath clanCore)
testFlake=$(realpath testFlake)
# copy clan core flake and make writable
cp -r ${clanCore}/* clanCore/
chmod +w -R clanCore\
# copy test flake and make writable
cp ${testFlakeFile} testFlake/flake.nix
chmod +w -R testFlake
# enable flakes
export NIX_CONFIG="experimental-features = nix-command flakes"
# give nix a $HOME
export HOME=$(realpath ./store)
# override clan-core flake input to point to $clanCore\
echo "locking clan-core to $clanCore"
nix flake lock --override-input clan-core "path://$clanCore" "$testFlake" --store "$HOME"
# evaluate all tests
echo "evaluating all tests for clan core"
nix eval "$testFlake"#checks.${system}.check.drvPath --store "$HOME" --raw > drvPath1 &
# slightly modify clan core
cp -r $clanCore clanCore2
cp -r $testFlake testFlake2
export clanCore2=$(realpath clanCore2)
export testFlake2=$(realpath testFlake2)
touch clanCore2/fly-fpv
# re-evaluate all tests
echo "locking clan-core to $clanCore2"
nix flake lock --override-input clan-core "path://$clanCore2" "$testFlake2" --store "$HOME"
echo "evaluating all tests for clan core with added file"
nix eval "$testFlake2"#checks.${system}.check.drvPath --store "$HOME" --raw > drvPath2
# wait for first nix eval to return as well
while ! grep -q drv drvPath1; do sleep 1; done
# raise error if outputs are different
if [ "$(cat drvPath1)" != "$(cat drvPath2)" ]; then
echo -e "\n\nERROR: Something in clan-core depends on the whole repo" > /dev/stderr
echo -e "See details in the nix-diff below which shows the difference between two evaluations:"
echo -e " 1. Evaluation of clan-core checks without any changes"
echo -e " 1. Evaluation of clan-core checks after adding a file to the top-level of the repo"
echo "nix-diff:"
export NIX_REMOTE="$HOME"
nix-diff $(cat drvPath1) $(cat drvPath2)
exit 1
fi
touch $out
'';
};
}

View File

@@ -1,4 +1,4 @@
(import ../lib/test-base.nix) {
{
name = "secrets";
nodes.machine =

View File

@@ -1,105 +1,83 @@
(import ../lib/test-base.nix) (
# Using nixos-test, because our own test system doesn't support the necessary
# features for systemd.
{ lib, ... }:
{
name = "syncthing";
{
pkgs,
self,
clanLib,
...
}:
clanLib.test.makeTestClan {
inherit pkgs self;
# TODO: container driver does not support wait_for_file() yet
useContainers = false;
nixosTest = (
{ lib, ... }:
{
name = "syncthing";
nodes.introducer =
{ self, ... }:
{
imports = [
self.clanModules.syncthing
self.nixosModules.clanCore
{
clan.core.settings.directory = ./.;
environment.etc = {
"syncthing.pam".source = ./introducer/introducer_test_cert;
"syncthing.key".source = ./introducer/introducer_test_key;
"syncthing.api".source = ./introducer/introducer_test_api;
clan = {
directory = ./.;
inventory = {
machines = lib.genAttrs [
"introducer"
"peer1"
"peer2"
] (_: { });
services = {
syncthing.default = {
roles.peer.machines = [
"peer1"
"peer2"
];
roles.introducer.machines = [ "introducer" ];
};
clan.core.facts.services.syncthing.secret."syncthing.api".path = "/etc/syncthing.api";
services.syncthing.cert = "/etc/syncthing.pam";
services.syncthing.key = "/etc/syncthing.key";
# Doesn't test zerotier!
services.syncthing.openDefaultPorts = true;
services.syncthing.settings.folders = {
"Shared" = {
enable = true;
path = "~/Shared";
versioning = {
type = "trashcan";
params = {
cleanoutDays = "30";
};
};
};
};
};
nodes.introducer = {
# Doesn't test zerotier!
services.syncthing.openDefaultPorts = true;
services.syncthing.settings.folders = {
"Shared" = {
enable = true;
path = "~/Shared";
versioning = {
type = "trashcan";
params = {
cleanoutDays = "30";
};
};
clan.syncthing.autoAcceptDevices = true;
clan.syncthing.autoShares = [ "Shared" ];
# For faster Tests
systemd.timers.syncthing-auto-accept.timerConfig = {
OnActiveSec = 1;
OnUnitActiveSec = 1;
};
}
];
};
};
clan.syncthing.autoAcceptDevices = true;
clan.syncthing.autoShares = [ "Shared" ];
# For faster Tests
systemd.timers.syncthing-auto-accept.timerConfig = {
OnActiveSec = 1;
OnUnitActiveSec = 1;
};
};
nodes.peer1 =
{ self, ... }:
{
imports = [
self.clanModules.syncthing
self.nixosModules.clanCore
{
clan.core.settings.directory = ./.;
clan.syncthing.introducer = lib.strings.removeSuffix "\n" (
builtins.readFile ./introducer/introducer_device_id
);
environment.etc = {
"syncthing.pam".source = ./peer_1/peer_1_test_cert;
"syncthing.key".source = ./peer_1/peer_1_test_key;
};
services.syncthing.openDefaultPorts = true;
services.syncthing.cert = "/etc/syncthing.pam";
services.syncthing.key = "/etc/syncthing.key";
}
];
nodes.peer1 = {
services.syncthing.openDefaultPorts = true;
};
nodes.peer2 =
{ self, ... }:
{
imports = [
self.clanModules.syncthing
self.nixosModules.clanCore
{
clan.core.settings.directory = ./.;
clan.syncthing.introducer = lib.strings.removeSuffix "\n" (
builtins.readFile ./introducer/introducer_device_id
);
environment.etc = {
"syncthing.pam".source = ./peer_2/peer_2_test_cert;
"syncthing.key".source = ./peer_2/peer_2_test_key;
};
services.syncthing.openDefaultPorts = true;
services.syncthing.cert = "/etc/syncthing.pam";
services.syncthing.key = "/etc/syncthing.key";
}
];
nodes.peer2 = {
services.syncthing.openDefaultPorts = true;
};
testScript = ''
start_all()
introducer.wait_for_unit("syncthing")
peer1.wait_for_unit("syncthing")
peer2.wait_for_unit("syncthing")
peer1.wait_for_file("/home/user/Shared")
peer2.wait_for_file("/home/user/Shared")
introducer.shutdown()
peer1.execute("echo hello > /home/user/Shared/hello")
peer2.wait_for_file("/home/user/Shared/hello")
out = peer2.succeed("cat /home/user/Shared/hello")
print(out)
assert "hello" in out
'';
}
)
testScript = ''
start_all()
introducer.wait_for_unit("syncthing")
peer1.wait_for_unit("syncthing")
peer2.wait_for_unit("syncthing")
peer1.execute("ls -la /var/lib/syncthing")
peer2.execute("ls -la /var/lib/syncthing")
peer1.wait_for_file("/var/lib/syncthing/Shared")
peer2.wait_for_file("/var/lib/syncthing/Shared")
introducer.shutdown()
peer1.execute("echo hello > /var/lib/syncthing/Shared/hello")
peer2.wait_for_file("/var/lib/syncthing/Shared/hello")
out = peer2.succeed("cat /var/lib/syncthing/Shared/hello")
assert "hello" in out
'';
}
);
}

View File

@@ -1 +0,0 @@
RN4ZZIJ-5AOJVWT-JD5IAAZ-SWVDTHU-B4RWCXE-AEM3SRG-QBM2KC5-JTGUNQT

View File

@@ -1 +0,0 @@
fKwzSQK43LWMnjVK2TDjpTkziY364dvP

View File

@@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICHDCCAaOgAwIBAgIJAJDWPRNYN7/7MAoGCCqGSM49BAMCMEoxEjAQBgNVBAoT
CVN5bmN0aGluZzEgMB4GA1UECxMXQXV0b21hdGljYWxseSBHZW5lcmF0ZWQxEjAQ
BgNVBAMTCXN5bmN0aGluZzAeFw0yMzEyMDUwMDAwMDBaFw00MzExMzAwMDAwMDBa
MEoxEjAQBgNVBAoTCVN5bmN0aGluZzEgMB4GA1UECxMXQXV0b21hdGljYWxseSBH
ZW5lcmF0ZWQxEjAQBgNVBAMTCXN5bmN0aGluZzB2MBAGByqGSM49AgEGBSuBBAAi
A2IABEzIpSQGUVVlrSndNjiwkgZ045eH26agwT5RTN44bGRe8SJqBWC7HP3V7u1C
6ZQZALSDoDUG5Oi89wGrFnxU48mYFSJFlZAVzyZoqfxVMof3vnk3uFDPo47HA4ex
8fi6yaNVMFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCXN5bmN0aGluZzAKBggq
hkjOPQQDAgNnADBkAjB+d84wmaQuv3c94ctxV0sMh23xeTR1cPNcE8wbPQYxHmbO
HbJ3IWo5HF3di63pVgECMBUfzpmFo8dshYR2/76Ovh573Svzk2+NKEMrqRyoNVFr
JNQFhCtHbFT1rYfqYWgJBQ==
-----END CERTIFICATE-----

View File

@@ -1,6 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDBvqJxL4s7JFy0y6Ulg7C9C0m3N9VZlW328uMJrwznGuCdRHa/VD4qY
IcjtwJisdaqgBwYFK4EEACKhZANiAARMyKUkBlFVZa0p3TY4sJIGdOOXh9umoME+
UUzeOGxkXvEiagVguxz91e7tQumUGQC0g6A1BuTovPcBqxZ8VOPJmBUiRZWQFc8m
aKn8VTKH9755N7hQz6OOxwOHsfH4usk=
-----END EC PRIVATE KEY-----

View File

@@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICHTCCAaKgAwIBAgIIT2gZuvqVFP0wCgYIKoZIzj0EAwIwSjESMBAGA1UEChMJ
U3luY3RoaW5nMSAwHgYDVQQLExdBdXRvbWF0aWNhbGx5IEdlbmVyYXRlZDESMBAG
A1UEAxMJc3luY3RoaW5nMB4XDTIzMTIwNjAwMDAwMFoXDTQzMTIwMTAwMDAwMFow
SjESMBAGA1UEChMJU3luY3RoaW5nMSAwHgYDVQQLExdBdXRvbWF0aWNhbGx5IEdl
bmVyYXRlZDESMBAGA1UEAxMJc3luY3RoaW5nMHYwEAYHKoZIzj0CAQYFK4EEACID
YgAEBAr1CsciwCa0vi7eC6xxuSGijY3txbjtsyFanec/fge4oJBD3rVpaLKFETb3
TvHHsuvblzElcP483MEVq6FMUoxwuL9CzTtpJrRhtwSmAs8AHLFu8irVn8sZjgkL
sXMho1UwUzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG
AQUFBwMCMAwGA1UdEwEB/wQCMAAwFAYDVR0RBA0wC4IJc3luY3RoaW5nMAoGCCqG
SM49BAMCA2kAMGYCMQDbrtLgfcyMMIkNQn+PJe9DHYAqj8C47LQcWuIY/nekhOu0
aUfKctEAwyBtI60Y5zcCMQCEdgD/6CNBh7Qqq3z3CKPhlrpxHtCO5tNw17k0jfdH
haCwJInHZvZgclHk4EtFpTw=
-----END CERTIFICATE-----

View File

@@ -1,6 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDA14Nqo17Xs/xRLGH2KLuyzjKp4eW9iWFobVNM93RZZbECT++W3XcQc
cEc5WVtiPmWgBwYFK4EEACKhZANiAAQECvUKxyLAJrS+Lt4LrHG5IaKNje3FuO2z
IVqd5z9+B7igkEPetWlosoURNvdO8cey69uXMSVw/jzcwRWroUxSjHC4v0LNO2km
tGG3BKYCzwAcsW7yKtWfyxmOCQuxcyE=
-----END EC PRIVATE KEY-----

View File

@@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICHjCCAaOgAwIBAgIJAKbMWefkf1rVMAoGCCqGSM49BAMCMEoxEjAQBgNVBAoT
CVN5bmN0aGluZzEgMB4GA1UECxMXQXV0b21hdGljYWxseSBHZW5lcmF0ZWQxEjAQ
BgNVBAMTCXN5bmN0aGluZzAeFw0yMzEyMDYwMDAwMDBaFw00MzEyMDEwMDAwMDBa
MEoxEjAQBgNVBAoTCVN5bmN0aGluZzEgMB4GA1UECxMXQXV0b21hdGljYWxseSBH
ZW5lcmF0ZWQxEjAQBgNVBAMTCXN5bmN0aGluZzB2MBAGByqGSM49AgEGBSuBBAAi
A2IABFZTMt4RfsfBue0va7QuNdjfXMI4HfZzJCEcG+b9MtV7FlDmwMKX5fgGykD9
FBbC7yiza3+xCobdMb5bakz1qYJ7nUFCv1mwSDo2eNM+/XE+rJmlre8NwkwGmvzl
h1uhyqNVMFMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
BgEFBQcDAjAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCXN5bmN0aGluZzAKBggq
hkjOPQQDAgNpADBmAjEAwzhsroN6R4/quWeXj6dO5gt5CfSTLkLee6vrcuIP5i1U
rZvJ3OKQVmmGG6IWYe7iAjEAyuq3X2wznaqiw2YK3IDI4qVeYWpCUap0fwRNq7/x
4dC4k+BOzHcuJOwNBIY/bEuK
-----END CERTIFICATE-----

View File

@@ -1,6 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDCXHGpvumKjjDRxB6SsjZOb7duw3w+rdlGQCJTIvRThLjD6zwjnyImi
7c3PD5nWtLqgBwYFK4EEACKhZANiAARWUzLeEX7HwbntL2u0LjXY31zCOB32cyQh
HBvm/TLVexZQ5sDCl+X4BspA/RQWwu8os2t/sQqG3TG+W2pM9amCe51BQr9ZsEg6
NnjTPv1xPqyZpa3vDcJMBpr85Ydboco=
-----END EC PRIVATE KEY-----

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:f/KzvxsoWQFTSB17lPhe/MThYu4ZjJwvkCxKp7XkLyspFF9Dal4A+H+SY6vPG7yM3+dlE3ZnxjniUeivydDTwwJiWJ6E6XIhnPI=,iv:xat6pYzYV8sfyMKX4OMsr6oSOEOc09DDXGykKKoP14Y=,tag:xMxsIpYv7KrSYvpmvBvSUw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArUGdWK1BnNjdCL1l1WlNB\nUEswYm1tYlIxWXltemdlQm1OcmlNbSsvTkdrClpRUjR6TUNUcGtxWWhGdDg5SG84\nSFFiV2p6ZHJwR1VKYW4vVFBHRGFSYTgKLS0tIERJa3hRM28ySHBUME4vTUE1UUFr\nQklDdTBWdWJpdGg0cnR1ZUNWREl6K1EKbRFOr3Rhb2aGnQUHiX+3DzGgrY9C2Dvz\nVlyZ0q6lWtn4qFWPVez03T8QAtLjv2UaGtYTFnyFIWiykhhrWy2PBg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:54:54Z",
"mac": "ENC[AES256_GCM,data:LJCCaGNhBgFAKtWYMD6OcXg2FMq1DYDOySIpEY91ILXDUuJSSsuYyQqE6ZvCoThlogHd9inAajsW0GbzYpSflu/WyrqlQsNJSMFkBFBQh/FIjd18GUtZ4flHWRfHqAk/xM/g+n7iOgKMvaBrG1MG1DplLRfk/8ehcqlWX4Wxof0=,iv:PrjIiUYkePPXBRGF/Wnqi1ZgA2j4YtzL/uMC5KchfIQ=,tag:yMMrJ7vGt6urz4WfRAyaNg==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:q6mWG65NflVEvX1QUyRVFuRGOVg9wtyWDYQ8Plqw038pEyOrsVcj6Cmo6SRaRcAaxQmAUeplzYfzm2MgXMz1l/DySErH+mCyVSk=,iv:7X4mFSJXpUii+sppSAq8H7vYWGoDq3LnFJMAAjhhm7U=,tag:ep9vzbkzVtC2A8otat8vSg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5bjNlZkppR01JT0F0TklO\nSnpIcFgwb0E5dStHQlZLdGNLQ3UxRDNBdEVVCnlpdWlPVVNIdFB3ZjlpSXZURjdS\nMVlCbFV5RXI0d2t5bHJvR3U5b2NDa2MKLS0tIDJLZlE0RjhNaGhBeFVsSE93Z0NX\nVVcyUjJPL1FVTEVOUktYTEMvVFNEdlUKYkmyVjcbAf5IVb/RWBfhbmoBbuz+u8X0\n3J8a/SJsgX3vLJIpVeSQSSFTNXu0+8/QeRiXsV7GCyHu+lwL75ycmA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:54:59Z",
"mac": "ENC[AES256_GCM,data:rhi/f3r81Cm+yXJXpnPmyK7jNqJ1Pg4tU7gsOwjCv5CeJn8U6N78ZBiHndjdwzqSdp7+qwx/9gPpLQVoPzO2IhY+uRhg0l6v6N9iK9UD6tjNzsCw8zTIb/ehObRqqpzVn2BGkUte+g0Hu2/bpHFbq6qmGm8YOYnD8K7U2FoiuGQ=,iv:o7RaD5oogpjSgdfFPqb8Tfgn43ydSzA0ZTP2ayNZI9c=,tag:e/zmTPAIWX1uDQxLNznIWQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:2EaSVKRIMKVF9+qAozKl703entUWB04J61UM1QRj1omKUb5sDaOwnQKCZDZxO/CCtam/kz1jHoxCeFiJFcx+DpTyYptpSpYq1dI=,iv:syZ2HKRxQ73urS4Vwz7/3IMBYY6nk78zaooPMDkU1w4=,tag:uGaqxbU6/9DvkGY1Jq/XRw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUMnJrb2VHYVdMRHJhYjFH\nL25nN2RIZ3pVeDdYTllrUkF0TkREYmNMMVdrCkNSaGlRd3c3YXZPZmIxWExCaytu\nU3FGTmhUZ0pUUjJJNS9vcVBISmFyZHcKLS0tIHMwaFlEYkFFb2RwS3JDb2VxRFcw\nZmd6S3RXVGcwbmtHVVRmWXkwSnF1RkkKTbg6igFHIakR8EAPuf+x9yhmQHF3TPp/\nC+B1FuorpovudtxmJ1UzBmkE0r13cY6iu9Vdjh1g7tBcXUWoHZsvIA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:03Z",
"mac": "ENC[AES256_GCM,data:HuQQvWOGIjISxnNShYHLj4QinNoeOTwxpJK35swpcBnJ4JtDnA6F2JjpJI8DXIwO42eDbXIF22lJjqynRFRo6kQrrD8uhBHEFD2R+6U7zFxJ4gknWR1iF3fbM1+2VDiu8L9InpZcfb6Z8tpKPdPiYS3NGdoAJ0ClSw+8WlVsS5E=,iv:pJxsCP5Y6NTNAck0mphbLRnZ48sRRZ/YaYUobi6mGYU=,tag:ewR5QLBh3WRLkHlSGH5MsQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:UVv08bXHtWMWcMC7tBb+xy7+3JRiOfVpRPD/q/TR1/+5,iv:ZNb3GDvtuZFbXlcJyN/kzy8cRppRqWnN308mAAkOc/4=,tag:Jv5MsPQ+gTBROzG6oo0ztg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBha2t2enBPWUhHcXIveGJJ\nZklLeVNkNkhkcXFLczJjeHdFT2haSGF6UnhNCjh1MHJobSs4dmVKTVdzL1JRTXJK\nUlo2MzFOelV5UVNqVjladStHdUlqSGcKLS0tIGlqa1RZVHpva2ZmNnpSRjhseGUw\na0hmSER6VlZsZ1A2TE84OTVyQVVTRDgKoE3UzWOqYhV9Y/vayIGY6ak4MEPR+q5t\n5NY6VDkCwYiactvcSo36jiaru47jRr6ovk5Vfkq/jFO2njDND5mLqQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1wjp0vvvy4d2c0pdrth0kl505rzpz37804swf6rrny9xa208mrg2s0r5m67",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNZGZUVmVBOENtZTJmRTQz\ndUpzYXBwb1NUWmhPU1g0VWFkWUp3Y2JGQ0JVCjZPS1lxL3N0YlU5T2owSS9FSC9L\naWtScmdyclhqcTE3blFEZHRNRHhjOXMKLS0tIGR2MnhRdUpHZ2tqTzVLWFo0WVhm\neXlpWUdwc3ZHOGRXWTNlZC9UMHd2M3cKgabJLSO2rT1u+I4V/XdCt8iDXuFQw+2w\nwr2juhtq3IwBuO6VqQKwAy6hHNbEWa+e/6bPaoXiJAOdA6+LbzfSmg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:54:56Z",
"mac": "ENC[AES256_GCM,data:ajkYjU6vAqrNiknSLZOYgFYiL7A6/ut+m3bt/x22Ms7LGZv5BgsTtLDw70gbAQh9fMbQCxCngkUrHk6bvVe9afpNvdw3fPQ9hfMkXquvDjhGHMvr3bmawsBJrShuywYRZY2z++f6FA0ApGVkSG1tSFDt/Tob1wkhxbPonGnsliQ=,iv:6H2X+4RkW48+w1dHWxa4nogKbHHriGyvAOr9ODf7m68=,tag:RWv+zSyqfaKcLAjxFHhqXw==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:DdiIZhVVosBWWyQu52g9bZm4PHlYalIeNQZtiqzN6p0Q3GcIPZkrA7EUtiI/jLOY9ILRKX3yreJWlDQHiEdfjQhqR1Oneb3JVv41GASEIumhuxPU4VQyIMV3u5MNO7H+NkzsBx8JHvm0MOIar76B4Bc+7ZoaahHacNzog+rGxUplecoY8A22Cr9G71OFj4JPQJTK40DhdSxdmSaiI3FzqxyuzbYfMViVqm6X3hX/CUv5nxlNeFUw5ZKruOTq4sjgiy859dOTiTG1L4X5T2G9UNevg5eRAqGdmjB/DB8is8yMUXYloD5TSvoDXCS8rAB7DgrtcF91nv9Wxq5aYGv6ovHpG7sL/aOY507PyaWtItir1+Gy9M8ECQq50wgj308KEMSbllFIhiHaHklpqTZdJejIzVB5nxbMIrcF2537Nfw3T2awveBk7ZjuYFQ3lIZVWNe9mbVubH1JLZS6x/Fm+rY85KnT3hZHCRLuUTvb5b3My73UMmWmAN3DekSr/m7z51cxtvJQJrM9GV6Lv4PAbgzvz8BvWps/9pIQlqVPYk8fRBvKqIAtbM7V6nIH1Fx8hmoMYM+c2CIHhMKxh1b+SGTk3BYXRuF/MX/btAt0kwUh+qPQJEd+i+9qFCS2I26BzoFsjm4M9e5tp1tx0KazrsIrWRAi6faGI+i48VpYxP60BQdK0YZTczTVLw4nIZGWJ1m0cHzeViR/P3mvP0tROo4GyAloUP3QWAwC88I2btHmC008Ldg7XRmOrPtwMuj1Z38Sj1mlRSu3+5hYS7T9wbOg3J/S9o3xbGDzJFAVU5YouAhU3qWwKvmrTKn6WRPyGFafcbBxzoNyOwK1U8MtrvDEUyoevN9kP/nGbD7sfyJpStN5zrn/9NxANVAAWjje1vWVmjFlTdip9USRzmrSIbPb4PwgXjJJObF6VWXF9RTdlZNq486BTC2eE4XQ3stOJ6UJmRwsowU3TuI8xb9wNXZBFmwfkrNhvgOrpf6LTc6ouL5QfSgcj6Gg/mXvE24Y4yhRZA4lnDqbuyl7lIyzTyfiwSEmDbJTVkc=,iv:Sby7ZpP5/ThihlnmxBX485/dtdxHQBPEoHPhbRVc7hk=,tag:9azO7wAzCSkYj/Awv6X+7Q==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBreW1Cd3NQWE13NUJHR2Ur\nSmdWK3hvVHpNMzZ1cGxHbEdHd2FETm1tSkZBCkhNMHdReGRpZmVJVUJ6aDY4MW1G\nOFhHRVhpUE1FWThwZ1BDZFJxRnZqYzAKLS0tIDd6QTROa2JYLzd4RmtDODJhM2hJ\nU1NwSTE3TVQ5WEdGVzB5YVdYWWNPazQKot8O9EYCfw4r59Fn/9lYZ0xYd7SUo9lJ\nEsus6BeNg2VLFa5V5q3hlVgRHUgNM4LMqIhdDf9mkxULKt1ilmoB6A==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1wjp0vvvy4d2c0pdrth0kl505rzpz37804swf6rrny9xa208mrg2s0r5m67",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1Q213dEI0d2FMUDB2Z2F3\nOVp6anVnVVZSNTdGMktnL2Z1c3JxNEt6ZUhZCnhrRUFrcnRpRVJXbmNjSWJRQ2hO\nVnlCRVdCRUZidUwwNDQyc1UwemRWbkkKLS0tIER1WWhNNERtaEZ1NVZNOXZoczZN\nZHd3U3UrOC9PZWhPMTBCVG03ZVdRdW8KY3bksqIx78GETGEg8q63HvEp+b8GnLFM\nqE7hiC9sNN8THvXV5rZeJdIPYZ6Kan2Q09GxRzDEJBavK3ZK0DKblA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:54:57Z",
"mac": "ENC[AES256_GCM,data:SckFGU9nPJi6t3bJdRqE49i7tqzcJQB4+ZZzuzSUTnPJV+Bn+/nr6zqbf40jG4qWPPV1PJsiXoJrTOQZ5O/skLg4++c4op5U+brRZqggeJepHVdHpxe7ldVak64Of7gMJ9S5fsynyRa+96kxf/qN2qZ1f63sk0u9bImPovYOJKA=,iv:EWWRbnySYk07m8oAio71VftGhRUJWiXYKJxsnErx2ng=,tag:MS7JFdlny6OA+MjCCz3kHA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

@@ -0,0 +1 @@
Y45RCSC-Y2OENC7-OI2NQ6Y-VUU6W7X-TQDROMD-JZNYC3B-BZJA2TI-7IMW4Q4

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:DkRR6AfyQJh0rnuzIO9gOs+xSmtncpo4zQOOLMeyfRcMRYYMnfzFIDYrOg4AYEmyd/KDfX8O7r/9dfrg4t4VJIFtA78h7hVA3KFpVhyA55AMfiWKJUQZhTvZG2eRP89+S0tChu6spgTXFDXIwCXa8EwzUc5Cqd/3UHs1DFdsuwWpmcbbXY1P3k4iaSpvQse/7BC0TNn2bg2ZPd4i9ovdY9kyMyOT9/54JRr21PeJ2SJYzLEMhzc+VirU4xIWdRMvK+LJRPWQEhvDGUjxAE5B90rHYmAi8eAaEEB52wpQBthJKUdBoZHlZ/DUbk9CVF2UF4B1rBLOtnt+pN9EfBFqrq0my/6bElEQV3P5UcdC7Z/sOjWVQvjBkHc9wkJp0g6e,iv:T0qYtoUeX7FZA8omE4heI6Beeh4gmbYoJ4Ww+6ix5AY=,tag:0FpsipDR1pfQA2/Z+4ogQQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWam5QUlF2K2ZQa3RjYkxt\nZXBmbmhKcC9HeklPL2c3UFRsUGhxL212T25rCmpCYzF4MFd3REk5cWtsSSt4ZFlK\nMzlLUUg3M1J4am1ZSVg0ait3eHFtVjgKLS0tIGpzYXJzWXJ4emhIOS9oL1E1SVBR\nRXZSZlVtMENGR2RNRzRMcGxCZW8xS1UK1BuhZV2eVb545eTg7I+wk5Dth6ZUwb9R\n5KkJ8oNSahtk9J27ZmJNIuof+fEj9yNueKHbvkDGo5rUoeH9u/awsw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1wjp0vvvy4d2c0pdrth0kl505rzpz37804swf6rrny9xa208mrg2s0r5m67",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0c1FmdlRUSXBsaDcvMmlj\nUVovdlRoMzAxeGh1blh1OU1JWTh0OElhZkFZClpyZ0JpcGVFbHRJdHhqNDRnaHhY\nQVVSS3NwcXZWMm83R1BPOTAySmF6QTgKLS0tIDd1OE5VYm5qWUZtd2VvYmdob2lG\nODlpUDAzdENDT1Nvdlo2bnVHRjVRSzQKFiKoA9JY6vY6+StLnLq3Fx0SmCRDro6+\nTLy2MmJM2VjdixMBvSDJATIXdf2T5lRFqGeJIlmLftzwCSJNmar+qg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:54:57Z",
"mac": "ENC[AES256_GCM,data:xZlGmeBeMrM4bCYU0j/1rz/lh33Zm3SUKJCSHWQ9rkVzBqD6Zxok+8OLYPIXKmEUQLuD6A3Jj8BIELm7poC0ycDqTCHRP6crPR3TZ9Ha/8ws5yjpbvQA5lvYcF+GindIhTHifo0LlkXsr0Yr3ViErvHHwLifmB2RBYw++gUhxHY=,iv:DT0GgfCrKpVLaBtljUMzSMZ0vP8o24VIiUfp0etNn9Q=,tag:+4kYXei4E1AMpNAusQKcVg==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:j/cBGXgSdfB1NOuNdj6w8rdF5dVQ6ngu/pIDys7NIwoX,iv:9G2mTyHNtryKqR0hk8sceaYvQMvIMeprH2M34RphhuY=,tag:8eSMKD5PVwGB+rPS7/XBng==,type:str]",
"sops": {
"age": [
{
"recipient": "age14faw2l6rskw2gcv3rrkygmwmrp2ev9yclzq4fh8xf8sjeke8p97sw4dxuq",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4NVlLSjEyZGFoRXVkR2ZE\nSE9NeXV2V3ZDVXF0RVBUamxWdzNIL2ZYdXhjCisyVWxLak54TS9wVU1VUzVjQVEw\nZlZUaXFqSEdFd3BuMmZzNllKSkxxT28KLS0tIHNqai9wYm5oUHdjbElmRlZrRVg1\nK3BSeG9rTGJyQUpKZU95cjNQakRKajQKUBXxIEwTiz5grVKfbWlJnCC9OiHhDFCi\nG5gNsUHcj74tTWSM+nIAzjRsRWXHpz7kWk/05EQ4W0auOhQ2FaHSTw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxSkwrclJrRUVqYjZXZ2ZR\naDBMKzdocjBJNlN2U3A3T09jUmNkVDk1aDJNCkQyQVU2RWpGYzJqdVBKdVRCUHdZ\ndENMbGl2VjNCQXE5Q1lBMEVHYVp3UWsKLS0tICtaZFZGRmxpMTdodGd1a2dEMDYr\nNUowMy9MNTQ1bzVxTlJ2bDdmWjJSREUKJUZ8lQ45pQBXrOfeW25v84ywXN52Og1F\nkmtXkBNAOTr5OkJVZbUXa1lQ0CahLluleVufX0wJIyCpBfhmnjHYFQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:01Z",
"mac": "ENC[AES256_GCM,data:kUDSBhylpGSwaHDw6HK62UgtIAmG6gnAnoooFTBC5XLS/FX1KhWIg+8fmJK8mHbPVGE/Ju7Qa8cxAEEIWa12xoVlsu6UlaHOIwiOTab6gHnxAA/WL+vYjf5H4IVzh6uOJwGIl+Wc//Yovlifs5Kg2ftkiU7rlrm5aMN6GkVGS70=,iv:hRtDatGis5VgWZcyzky5MZADba4ApZhclOxjQNgDXiI=,tag:iHcjmXiHoOHTJ88kFwezdg==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:PWIDQ2EF758/YMlZ6LKB7ofyCKQJuAi0ksg70oB+Km0O5JLJ1O4nz0gpf4dk3qoHRyoyEHH2UvMHD9c7Wuxvy/2YNsIkocpDKiNLUBymYlbqA8TAbg5aZU6q5P7KT5kEujFHZlRxeDoYVgV+wtSs19nGnuZmkkqqkJ/cLWEau42YNTZ+Zu+qnahVI42eGxDK3Hz4Gynm0t5xXCHf3IQI/6eXbDxOdcTepx4hkYnE6zWIsJdS+yK+aw9dtz1NJlpaPTV9OACFZXqlEtP7H3d9XVVyGd8Gx1FbjcJZosMBEB9fG+bmxFm20gBksB1oGBaKh5sOB8OGhZEvxGqFjsJXYt1WPbm/POIvu9oDaWwAz3q9QRC60IbRSogiKLnGkeavnKqC5qYEFTcFr+9JbM9g6+pyI7PosKt5GACpqFODPx/U8iu3ooxseeI7ncDuiNbmWrDAhBcELmclWrRN879nDlfAw+Ct9EIVmP97oFYVAM6fvbxzhQ0uFe9Xrh+G0gsKnfc+XYiEhG35Ge//PdXUI1HDIaGEqcEMpH4dqzbYqkx9CKZ5+fhIcL8R0WBr4I2MI80gvD2ga9k6jpnhnlu6izAajEMNcOjCXrwc47dh5ytRi949gg/HLu38NUU8cG5JtnNP2qqHmn/hFVtTDWL7BDGGAIopC1vyJCjHY1s6pedoJkfFOEPJoKBl1bU8WCbz68GkQ5f0LrFK4026iiI0ExKXP8BApbBEU+UROqzEPcvcC24+5wUbWCnBO0O4S1k7Z4rZdfUVe9XqN2qTLFUgyaEUAnov48aB09+wsnol4xxbkkD3eihpihG58yzwBrPIhsttApOcEhMwjMwrXvbrDcV1wedglZdDCjTa7z0lPwxHaAIf4obYyddlZ36whBU8fsJEoLD2dzTzXFEmGPUKPFwtocJ4IJbNYvNBBmjeH2Eh+wcZyO0dpEuQdMY1zWeYMGWbHSuQC0LdfSvx+hCmsr2rfu8ISVqAgI7YgJc5rNro+poMl5kLpwbSFwH0TdXUJfeRuGFzi7iDgLduf5ZuUMUDsPbw7w==,iv:d6QjUKGw6zfp0Me1YjzkcEtR2fgXuKMjISB4LTbkHI0=,tag:AVyZuNbT81ER6e5/eq9WMg==,type:str]",
"sops": {
"age": [
{
"recipient": "age14faw2l6rskw2gcv3rrkygmwmrp2ev9yclzq4fh8xf8sjeke8p97sw4dxuq",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVSGxaVXN3LzFQaUFnN2Fk\nUStGY1J0a2YydFNVOXZBbjBxMmpLOUdSVVM0Ck5NWTVjNkZTSEVHT3N1UzltVDhN\ndnM3czdvV1pTVG5OV0QwN1hjRC9FYjAKLS0tIFRpS25rL0NEMGJKUHhrOG1TQVNS\nODkybmFPMnBwT3J2T2N5eUdnWlNuWk0K77EWBMrWSRcOgJz2VMTWG8b2VF3hsnfN\nlB24D6g6X+NyYqA5sr6tt2CokSelHvDmdQPp+9ctFUd8MZZOG80odg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3TTlVS0R3K0N5QlRmOXlz\nU0JFVmx5VktaYlhKTnNYRkp4YmVHa00xbkc0ClZVQ0ozQXhNRlNvbHJ3M3VpdUFy\nK01kV1hJeG1iSVZDUTFGUVlZdHF2VjgKLS0tIFRLcldTdWpmS2RFM3lkcUlIbWg4\nelNxYlowWlRQbmhlUFRON0lOTG5FdFkKFPvYOu22il6Sq2YSHmV1p5ffOafiUQVz\n19YU773ENRNtodhqigpyJJYsC53gI4lbQC70taJciICdcmdFo/OdSA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:01Z",
"mac": "ENC[AES256_GCM,data:+jHseVVdCG1Y/0D9hnO8DP7mZIV60nG1AHw11R+pGy7EHhKfLlHT7/MwCRSCbP2hwekUtfrOsuRxSCnckv29h+BMGSi3NZNPXY04tScvEmMECXia7UQWE2o0gQHHLEfSVoWYJ2dcC60cQlpXYocNY47pFx0eq0Q/u6F0SOZwEjU=,iv:GNFszYeZUVdnonQgyVNp5RPofInAOFwyk1wi506wdrI=,tag:Ix0/OieMU7KNwx6y7i8LyQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

@@ -0,0 +1 @@
BZMMAO2-WNUTFFN-GMRL6TM-QZX57TS-Q3NXHVU-V3VPNGX-QHQMBIX-LWQUQQA

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:e9zI2AphJlfeoK08uohWw+uQKdBBitrMnJCEwE5EPxD6w1qq/yoR5d94fwmEW+PzMRC+eg838I0sACEWJ0XIBb6uOECbKbhgqfqKi67GwXaobtjfQMpYe2xZvODb0LWQdZ33hJ1h23mGnbNlsafVMFySi0ydeul7rCLdNULhIBR6ph+JQHCsOO0G9BVZWSjKc1P/ItcoapMHhS0KzEhY87E6p6jkZFKrVi+bz9e1rF9uSemPF3kE/MAz3PBaqp2JbSrYHUgvDIFuQVt1AK+47rnB3Lmvk2iBD5aYXn+q6ZMRA7M5pYDxTglTlOpALikbjuUmiRZpMuJR+vCsmIEfO/MtoTah2Rawvbyn+80J/iD0C10xF4XvTgv+CAYtJhiw,iv:FZywq4cjxcMpWOYZyBKVCXHPWUNRAp01ufx3LIexfGw=,tag:Rc2iAT6CdP3UYvHf5nvDgw==,type:str]",
"sops": {
"age": [
{
"recipient": "age14faw2l6rskw2gcv3rrkygmwmrp2ev9yclzq4fh8xf8sjeke8p97sw4dxuq",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOUmNuaWlsZXMwWE9OTVZz\nVWR3MGE0TnN4eW94TzA3a3RHK000Yy9XS1MwCm8rN2xSWTFRSG02c285UUVLTFM5\nNHN0Lyt2T1c1K0tqZEdkd0VCYTVMSHMKLS0tIHpOY1hKS2xwazd3bmJIZWZvc1h6\nR2VocjBudk10bm5JVDIydVpiTnFBcnMKS5Ip6wMtZ0lfyGXLE0CJsgY6JYATPId7\nKQB3iY4YcDnW4Kz3Y8mouJcS3wGpu5l5CvBBpjbP3uUQRD1r6ex2HA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaL1QvcXh3UzZVcFkzK1Zu\ncGtkNlptWlJSZlhxSjNzUzZlM2pzUGFYRFNRCm9xdU9HZ29oT2NNM0lkTVFrWjY1\nbFNPU3BsUWVDbW9EcWlLM3NzbTNTanMKLS0tIEtJQmdwNnBXa1lveEovOC9jRkZs\nbkxOL1dkdGpCQkkvMTNrQ2FZWDF2TTAKptb/vJ5kzpULSm8LeAJqqR5Tks33Vf52\nJaVEMSbHJxcIWWR1Sf954pOOgoOyVpB3BB/DFOAf6VOeVt8RBalvBw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:01Z",
"mac": "ENC[AES256_GCM,data:WuvkahW8Nm091/eyitO/fmUJE0c8V2G2LAkfr0QdoLqppevEjV+YGNmtqtkVYFnxoQYhzysjVT54eVHVWoeZV7yUg2P9gwMIShT+skayJfXvZfJyvEaNkHWloWeGOLn5gv93P908srTKhHeufsnfGl/hkd+TuNwzzE2mS7k2gMs=,iv:9CPjqSABHJY/sXhzU3AVvtWW5tLMHDqjAV0/Hu9/Jsc=,tag:FYMbuN/BoSowzuoyoFlYxw==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:4KwVxOYKVLymyDXQ9GswpxJi6Fi5BCDJzMj4d/02nNa4,iv:9uGX3BRswPRlgPpPjdodzfwjbj7vmTqTcDNClKdGGlw=,tag:jLkefKqBfdRVy+qV073Ksg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1dutdww4x48f0e3tzmjlye9n852wx0qqhhcghsrefsq9m8c5flpfs2lxexf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTWmdQb1VNRUM4NHViYzRU\nOEkzdnhneFBQaGJ5ek1NTUxYcG5YdDhUQWhvCm1RTVc1aFRkczBYLzVZTUdhbjBz\nWXJqTDUyUXRmQVJ1R1p6cC9wSTNVbUkKLS0tIEgwSTVhMTFsdzRHdW9QcVRlZ3l3\nd2xrQkYzVFBTYldlZGtwakFnUHF2WmMKJa1A6a7umGgaFHSq8JqdwUQ6oBu65r1E\nCHSdEt7vviRXS6TRhdMdH0OiKQPTpHdspz6NRwn9KjMbrANq9Cxl6g==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsSnMxNHBJNXVyd0RKTFYw\nUW5VMGJFdDI4dTNDTTNKL0xOZ1dvQTlGN2hNCkFPbGRhc0pEUGNlN2NManV0MHRV\nOXZtTGQwbWo3cWN5d0kxd3UwcHh2NlUKLS0tIGs3NERZRTRvc0h5T0h0SFV0VzBv\nL0hCVXE1TmFKV25lWHZvOGQ5YzM0ek0K19o2HCcCHlI55kQ1khuyXMnYGf7X5YI8\nsOgm6sM//6qB2I1DC/IwrHT5+yq/3CkqKcHYfinr3ClaKNDLV4hpAw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:05Z",
"mac": "ENC[AES256_GCM,data:5S1c4kdweAoikTnowDMWYXbSOS4v97CVMTeq+OFb78FHDKVwlnk1mT43cOLVyF02i589Lxf1rMXl7T9mXyYpY6fTvWKpRBewryS58eUaI01K8NFtS/+aqdgtXoqx5jO4BHrITTlJUjQh0PfXf5Lv7cZBPiNZnu9lfwrxsNbRRPE=,iv:NQeuNVZaVjBOGydA3aCPWHTX7rlG2/I4+YhOTli+nIE=,tag:wzuOuMECuitwewGArGZMeA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:BEFeUE9tN3sjDQmLICGXziA5VPDfHNyjHaMmQlcjJj/AUmhMPOdBUAo28rPPXE+ici0vPLZmXVEcgd4ad02YpBfd1EfUMZW9vz10sv51I7ac/ClFfmbRU1q1CNDiIAHJUErDbCTghnpJMNAiz3CDg409uF8LJ/UmDo73uN8O6UVYI+jB1nxbUD8zPKpQnydRSf6MIrUSluZ3ckDNuoBe2ZcHrvBpbnzhEYHEnEwoM9C9uQQCWtEOjyrahWKr+7wCd7kgVhQfPJLeiSZDgmnnLw0q61dPWNrTyRa48DX5wMgKOOYUM0fMtPI2HGOEqTcel/smNR/4uHVyjsQBuwK/mSdwmfKxVACu6Hxb9is+qkK7pQuPYYLyyubn/nbIhflOLlH5CxbVj/4LK1wDfMbrCOueVq5Fshsj51AgNipi0b+srlDeVnWuQ1BWoCHQ4YTMdIUB5PMYPLCONWlbsb9OQoaAnD03JA3ucCUvpEEtVkqxXMVh+5VjzPX+VoenyVP6O1amiwO1FKIGh0sRd8OJRTD4ait885T4xx2e/Evi9gxZpirFmmn8enZ+oi+zL7YFLRBp+GVso/TRHHEesCHLmsqCaclt6i6BQCK4z2lLd1bXu5ATtx27ka54qdD7sTf1XhcU8Za0d+wmDNzwOCiuMMir37XDWFnR6HP1MS9cgCAVMCxmP4ETZa3FXlA0muwSWOifMlk5OZBoorMNAq543Cmffteh883NRkHUF/SAfr7hVCzUfPsDC3px7MvgqiNaUAi+bvjxlTU1NBZOMvTYtkBcpXzSyjuQ2pVGVEUKNxG8w4QS+5UoUtBBvGCF61D7iWIEHvTfJ8U6agWpcJLSMTAhNjQ8WAbYm3zMbv0J4r4qDvqe8Jn6+3lzZ5EYk4dUvd/6r/pzVJhhhzgEuGn6hfcJusb9xV92hTAVqkLocrwGzvDJ1R/kNx3shm+8H0VRiigrANoRpiTGNPF66qUynkaGU/S6K4Oo2fjCeOrpkO/XwhWsK6ZQ/24a10pO+diBLsGGoW7boqC3ff6sSxhO+Dpl4IEV9Q==,iv:Pc8ZfMZ1ZW94tRkQeVs4VZUfeXUj3WG1h4+mFW7Zafc=,tag:Q2SzduFZATYjEZJeurUMfw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1dutdww4x48f0e3tzmjlye9n852wx0qqhhcghsrefsq9m8c5flpfs2lxexf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwUDBxUm4yUXgybmdzZHBV\nZVJXcFNuN3FENU91Y2U3bDEwN2t2ZmlCQW5rCjdta1FvWWgwb042alUybVZ4WVB1\naGIrdUR3aDNmazZSd3YwSTNxb3d6b2cKLS0tIEc3dHhuRW5SaWI1YUhHQnpSR3Vr\nQ1paemJKWld6SENUbmQ3dHFmNnNoZkEKBAO21R4igmxdkZWg64tNj/wVQql4zDI/\nM6Huuoy0KqaMNGnQZyYpHOoXaA0V2Z3wRIiqBpYmpF9yPX41TWDqAw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKamJ5TDNlUHBUSm1aOW1z\nMjNEODZJWk42NlJFTW1Zdk1XWnFMU2NuZndFClJpZGVwdWtFRWgrU1EwMndxRTZK\nR0UvNzJwckZMMzdaNDBwMWZKeGppUm8KLS0tIGxsbVhqcGpZRlNGRE5JWXo4MXYy\nZGlzcVFlNHUxRmEvRkNPU3dGWlJxVXcKO/qq4BD40ctBTLKbTUb5elD/QOlFfeSL\n1a9ioyiNVehXsOWmgjg2x6POfY/1FTqB3x6PG7CxdSw5Qg31d4qcWw==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:05Z",
"mac": "ENC[AES256_GCM,data:JW1ACIn9FnOYm0a18UanYeXgdoyuGXaBzvGMBdSTUBJAF/soeN/DP41mpyzWl9JknzId+R6qooSJ3Zs9asekeUc+9ehc2ra9KdKDNEliwB1Hi5GswIYo1fYRdRrPPBV0EnWg3lLT9Sa3vDDDKQJiMUA30jnGIkN4rNOA4xD4KeE=,iv:Eyvx/ZkqM63jaamPRk5rjjeWQsA3c0rmB2Xhl28HAYc=,tag:KTzwnPsVw9uTYQU2al5mhw==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

@@ -0,0 +1 @@
TB7HCPA-CIEXTMA-KXMBEL3-V2UIPND-C2VBRVP-BJTYZP3-G62QKYA-HFF2CQ4

View File

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

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:H4xEba34JvUXuHAIxXapjcBgtScEBn++uzXqKKeCttTgHbMTHuFczAHRbNraPn6qMJj8dkgPgHuAf2xbwnIxoabnFK9C34f84DyN0QdiIUSi7WweWLK6u6HtfaL4w1yoQSwlnv3t/wYPFObMmbEivfPi7zR1ojdoZhKflCBg8piUWzh915PDiZzJ/jrdsQs1gzPD05JWPm759TgQb7vRsueXl+Cvl/sTpSQsR4TyOzJ4UveJnpGskpJiKHODkUcON5l7Dp1PJWum2Vy86bIYdsIKtm2JWysPxIbGhXHCGhrgbg5IbtTzc/XAd4P8OD2cRWeVO9zho5mUzSrHhMwdI33vmw3CvT4eLsE4i9a3NioiZP+skUm9+DIWISlaV7NS,iv:2/XetmHh4rKd3P4wjMPvmSId08u+C34g/Bo7H12G890=,tag:x9r6j87FGYex16eGhgwXVA==,type:str]",
"sops": {
"age": [
{
"recipient": "age1dutdww4x48f0e3tzmjlye9n852wx0qqhhcghsrefsq9m8c5flpfs2lxexf",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyd2J1VWJ5b1RHUS9QWVN5\nakRWNjFsVWRzWHVkQ1Jld2E5d2ovNWMyRkRjClhQY0dWN3IrWlI1L3Y0c2l0VlFY\ndWphNkRiWGFQZnB6Wlh6eWR4KzRwREUKLS0tIFVMQTk1YUpKZGJHUzQwZlRLN1hV\nTkRud2gwdE5VQlJrNVZvcmluZ2dOUVUK/TxbSStfbidfeiT6oxqXwY5xNqRQ8bbf\nRsrUR7904v41JgwawFFcTgf701SM4D0O85Nc9Sog8OkGO36jMqOEtg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWYWlJSTVCWWdOY2Yybnda\neExPU1Byb0REOGc0S3Z0MlFuWHFLdkdXbnpBClk1c1pMR2V2ZFBWckNRMmJJc3Jp\ncG9qMmU1NElVeVUxS0xpeFV4VmxqS1kKLS0tIHZYYktYaHFIZXVwWkh2bThDclcr\nQlNhcDduOXJnelI2cmNEdXVzSDhlVFkKTOXZB7SJ4vl++Du5hFi9T3nMhxPNmm8s\nkODjnmPxyKYvRMfrDzPkHtzQKaPMHRls9yzZzE2imUhwKpVlvwu2lA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-04-23T07:55:05Z",
"mac": "ENC[AES256_GCM,data:PJ0CH2G8tYNnAQV++BNTZbG2emMTp0EEY29NLXUEGxwdWfuHTZxc8QnYx1ck+4Rs28a9U7KHffnPfh4/8NwnnR9MmDcyoLN6/JMHWzUJQZhuMpGGoDxJCaxs/dFaiitlvhNdazSf1f2t8ng+OKokG6L15Mi34oXNTQ/0dyYG4Hc=,iv:YzZBO69nY4p9ut3e8NBGD1EV6Rbq/6z6z2Oh2OnM8JI=,tag:KUQqxuxJfMRSvbbRP2fLng==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.1"
}
}

View File

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

View File

@@ -1,4 +1,4 @@
import ../lib/test-base.nix (
(
{
config,
pkgs,

View File

@@ -1,4 +1,4 @@
(import ../lib/container-test.nix) (
(
{ pkgs, ... }:
{
name = "zt-tcp-relay";

View File

@@ -4,10 +4,10 @@
...
}:
let
cfg = config.clan.autoUpgrade;
cfg = config.clan.auto-upgrade;
in
{
options.clan.autoUpgrade = {
options.clan.auto-upgrade = {
flake = lib.mkOption {
type = lib.types.str;
description = "Flake reference";
@@ -15,7 +15,7 @@ in
};
config = {
system.autoUpgrade = {
inherit (cfg.clan.autoUpgrade) flake;
inherit (cfg) flake;
enable = true;
dates = "02:00";
randomizedDelaySec = "45min";

View File

@@ -13,10 +13,10 @@ let
defaultBootstrapNodes = builtins.foldl' (
urls: name:
if
builtins.pathExists "${config.clan.core.settings.directory}/machines/${name}/facts/zerotier-ip"
builtins.pathExists "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value"
then
let
ip = builtins.readFile "${config.clan.core.settings.directory}/machines/${name}/facts/zerotier-ip";
ip = builtins.readFile "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value";
in
urls ++ "${ip}:${cfg.network.port}"
else

View File

@@ -7,7 +7,7 @@
let
cfg = config.clan.iwd;
secret_path = ssid: config.clan.core.facts.services."iwd.${ssid}".secret."iwd.${ssid}".path;
secret_path = ssid: config.clan.core.vars.generators."iwd.${ssid}".files."iwd.${ssid}".path;
secret_generator = name: value: {
name = "iwd.${value.ssid}";
value =
@@ -15,17 +15,20 @@ let
secret_name = "iwd.${value.ssid}";
in
{
secret.${secret_name} = { };
generator.prompt = "Wifi password for '${value.ssid}'";
prompts.${secret_name} = {
description = "Wifi password for '${value.ssid}'";
persist = true;
};
migrateFact = secret_name;
# ref. man iwd.network
generator.script = ''
script = ''
config="
[Settings]
AutoConnect=${if value.AutoConnect then "true" else "false"}
[Security]
Passphrase=$(echo -e "$prompt_value" | ${lib.getExe pkgs.gnused} "s=\\\=\\\\\\\=g;s=\t=\\\t=g;s=\r=\\\r=g;s=^ =\\\s=")
Passphrase=$(echo -e "$prompt_value/${secret_name}" | ${lib.getExe pkgs.gnused} "s=\\\=\\\\\\\=g;s=\t=\\\t=g;s=\r=\\\r=g;s=^ =\\\s=")
"
echo "$config" > "$secrets/${secret_name}"
echo "$config" > "$out/${secret_name}"
'';
};
};
@@ -72,7 +75,7 @@ in
_: value: "C /var/lib/iwd/${value.ssid}.psk 0600 root root - ${secret_path value.ssid}"
) cfg.networks;
clan.core.facts.services = lib.mapAttrs' secret_generator cfg.networks;
clan.core.vars.generators = lib.mapAttrs' secret_generator cfg.networks;
# TODO: restart the iwd.service if something changes
})

View File

@@ -26,8 +26,8 @@
config.networking.hosts =
let
dir = config.clan.core.settings.directory;
machineDir = dir + "/machines/";
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
machineDir = "${dir}/vars/per-machine";
zerotierIpMachinePath = machine: "${machineDir}/${machine}/zerotier/zerotier-ip/value";
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
networkIpsUnchecked = builtins.map (

View File

@@ -6,10 +6,9 @@
}:
let
dir = config.clan.core.settings.directory;
machineDir = dir + "/machines/";
machineVarDir = dir + "/vars/per-machine/";
syncthingPublicKeyPath = machines: machineVarDir + machines + "/syncthing/id/value";
machinesFileSet = builtins.readDir machineDir;
machineVarDir = "${dir}/vars/per-machine/";
syncthingPublicKeyPath = machine: "${machineVarDir}/${machine}/syncthing/id/value";
machinesFileSet = builtins.readDir machineVarDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
syncthingPublicKeysUnchecked = builtins.map (
machine:
@@ -19,7 +18,7 @@ let
if builtins.pathExists fullPath then machine else null
) machines;
syncthingPublicKeyMachines = lib.filter (machine: machine != null) syncthingPublicKeysUnchecked;
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
zerotierIpMachinePath = machine: "${machineVarDir}/${machine}/zerotier/zerotier-ip/value";
networkIpsUnchecked = builtins.map (
machine:
let

View File

@@ -1,6 +1,13 @@
---
description = "A secure, file synchronization app for devices over networks, offering a private alternative to cloud services."
features = [ "inventory" ]
[constraints]
roles.introducer.min = 1
roles.introducer.max = 1
---
**Warning**: This module was written with our VM integration in mind likely won't work outside of this context. They will be generalized in future.
## Usage
We recommend configuring this module as an sync-service through the provided options. Although it provides a Web GUI through which more usage scenarios are supported.

View File

@@ -1,210 +1,6 @@
# Dont import this file
# It is only here for backwards compatibility.
# Dont author new modules with this file.
{
config,
pkgs,
lib,
...
}:
{
options.clan.syncthing = {
id = lib.mkOption {
description = ''
The ID of the machine.
It is generated automatically by default.
'';
type = lib.types.nullOr lib.types.str;
example = "BABNJY4-G2ICDLF-QQEG7DD-N3OBNGF-BCCOFK6-MV3K7QJ-2WUZHXS-7DTW4AS";
default = config.clan.core.facts.services.syncthing.public."syncthing.pub".value or null;
defaultText = "config.clan.core.facts.services.syncthing.public.\"syncthing.pub\".value";
};
introducer = lib.mkOption {
description = ''
The introducer for the machine.
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
autoAcceptDevices = lib.mkOption {
description = ''
Auto accept incoming device requests.
Should only be used on the introducer.
'';
type = lib.types.bool;
default = false;
};
autoShares = lib.mkOption {
description = ''
Auto share the following Folders by their ID's with introduced devices.
Should only be used on the introducer.
'';
type = lib.types.listOf lib.types.str;
default = [ ];
example = [
"folder1"
"folder2"
];
};
};
imports = [
{
# Syncthing ports: 8384 for remote access to GUI
# 22000 TCP and/or UDP for sync traffic
# 21027/UDP for discovery
# source: https://docs.syncthing.net/users/firewall.html
networking.firewall.interfaces."zt+".allowedTCPPorts = [
8384
22000
];
networking.firewall.allowedTCPPorts = [ 8384 ];
networking.firewall.interfaces."zt+".allowedUDPPorts = [
22000
21027
];
assertions = [
{
assertion = lib.all (
attr: builtins.hasAttr attr config.services.syncthing.settings.folders
) config.clan.syncthing.autoShares;
message = ''
Syncthing: If you want to AutoShare a folder, you need to have it configured on the sharing device.
'';
}
];
# Activates inotify compatibility on syncthing
# use mkOverride 900 here as it otherwise would collide with the default of the
# upstream nixos xserver.nix
boot.kernel.sysctl."fs.inotify.max_user_watches" = lib.mkOverride 900 524288;
services.syncthing = {
enable = true;
configDir = "/var/lib/syncthing";
overrideFolders = lib.mkDefault (
if (config.clan.syncthing.introducer == null) then true else false
);
overrideDevices = lib.mkDefault (
if (config.clan.syncthing.introducer == null) then true else false
);
dataDir = lib.mkDefault "/home/user/";
group = "syncthing";
key = lib.mkDefault config.clan.secrets.syncthing.secrets."syncthing.key".path or null;
cert = lib.mkDefault config.clan.secrets.syncthing.secrets."syncthing.cert".path or null;
settings = {
options = {
urAccepted = -1;
allowedNetworks = [ config.clan.core.networking.zerotier.subnet ];
};
devices =
{ }
// (
if (config.clan.syncthing.introducer == null) then
{ }
else
{
"${config.clan.syncthing.introducer}" = {
name = "introducer";
id = config.clan.syncthing.introducer;
introducer = true;
autoAcceptFolders = true;
};
}
);
};
};
systemd.services.syncthing-auto-accept =
let
baseAddress = "127.0.0.1:8384";
getPendingDevices = "/rest/cluster/pending/devices";
postNewDevice = "/rest/config/devices";
SharedFolderById = "/rest/config/folders/";
apiKey = config.clan.core.facts.services.syncthing.secret."syncthing.api".path or null;
in
lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Syncthing auto accept devices";
requisite = [ "syncthing.service" ];
after = [ "syncthing.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
set -x
# query pending deviceID's
APIKEY=$(cat ${apiKey})
PENDING=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${getPendingDevices})
PENDING=$(echo $PENDING | ${lib.getExe pkgs.jq} keys[])
# accept pending deviceID's
for ID in $PENDING;do
${lib.getExe pkgs.curl} -X POST -d "{\"deviceId\": $ID}" -H "Content-Type: application/json" -H "X-API-Key: $APIKEY" ${baseAddress}${postNewDevice}
# get all shared folders by their ID
for folder in ${builtins.toString config.clan.syncthing.autoShares}; do
SHARED_IDS=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder" | ${lib.getExe pkgs.jq} ."devices")
PATCHED_IDS=$(echo $SHARED_IDS | ${lib.getExe pkgs.jq} ".+= [{\"deviceID\": $ID, \"introducedBy\": \"\", \"encryptionPassword\": \"\"}]")
${lib.getExe pkgs.curl} -X PATCH -d "{\"devices\": $PATCHED_IDS}" -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder"
done
done
'';
};
systemd.timers.syncthing-auto-accept = lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Syncthing Auto Accept";
wantedBy = [ "syncthing-auto-accept.service" ];
timerConfig = {
OnActiveSec = lib.mkDefault 60;
OnUnitActiveSec = lib.mkDefault 60;
};
};
systemd.services.syncthing-init-api-key =
let
apiKey = config.clan.core.facts.services.syncthing.secret."syncthing.api".path or null;
in
lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Set the api key";
after = [ "syncthing-init.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
# set -x
set -efu pipefail
APIKEY=$(cat ${apiKey})
${lib.getExe pkgs.gnused} -i "s/<apikey>.*<\/apikey>/<apikey>$APIKEY<\/apikey>/" /var/lib/syncthing/config.xml
# sudo systemctl restart syncthing.service
systemctl restart syncthing.service
'';
serviceConfig = {
WorkingDirectory = "/var/lib/syncthing";
BindReadOnlyPaths = [ apiKey ];
Type = "oneshot";
};
};
clan.core.facts.services.syncthing = {
secret."syncthing.key" = { };
secret."syncthing.cert" = { };
secret."syncthing.api" = { };
public."syncthing.pub" = { };
generator.path = [
pkgs.coreutils
pkgs.gnugrep
pkgs.syncthing
];
generator.script = ''
syncthing generate --config "$secrets"
mv "$secrets"/key.pem "$secrets"/syncthing.key
mv "$secrets"/cert.pem "$secrets"/syncthing.cert
cat "$secrets"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$facts"/syncthing.pub
cat "$secrets"/config.xml | grep -oP '<apikey>\K[^<]+' | uniq > "$secrets"/syncthing.api
'';
};
}
];
imports = [ ./roles/peer.nix ];
}

View File

@@ -0,0 +1,6 @@
{ ... }:
{
imports = [
../shared.nix
];
}

View File

@@ -0,0 +1,20 @@
{ config, lib, ... }:
let
instanceNames = builtins.attrNames config.clan.inventory.services.syncthing;
instanceName = builtins.head instanceNames;
instance = config.clan.inventory.services.syncthing.${instanceName};
introducer = builtins.head instance.roles.introducer.machines;
introducerId = "${config.clan.core.settings.directory}/vars/per-machine/${introducer}/syncthing/id/value";
in
{
imports = [
../shared.nix
];
clan.syncthing.introducer = lib.strings.removeSuffix "\n" (
if builtins.pathExists introducerId then
builtins.readFile introducerId
else
throw "${introducerId} does not exists. Please run `clan vars generate ${introducer}` to generate the introducer device id"
);
}

View File

@@ -0,0 +1,214 @@
{
config,
pkgs,
lib,
...
}:
{
options.clan.syncthing = {
id = lib.mkOption {
description = ''
The ID of the machine.
It is generated automatically by default.
'';
type = lib.types.nullOr lib.types.str;
example = "BABNJY4-G2ICDLF-QQEG7DD-N3OBNGF-BCCOFK6-MV3K7QJ-2WUZHXS-7DTW4AS";
default = config.clan.core.vars.generators.syncthing.files."id".value;
defaultText = "config.clan.core.vars.generators.syncthing.files.\"id\".value";
};
introducer = lib.mkOption {
description = ''
The introducer for the machine.
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
autoAcceptDevices = lib.mkOption {
description = ''
Auto accept incoming device requests.
Should only be used on the introducer.
'';
type = lib.types.bool;
default = false;
};
autoShares = lib.mkOption {
description = ''
Auto share the following Folders by their ID's with introduced devices.
Should only be used on the introducer.
'';
type = lib.types.listOf lib.types.str;
default = [ ];
example = [
"folder1"
"folder2"
];
};
};
imports = [
{
# Syncthing ports: 8384 for remote access to GUI
# 22000 TCP and/or UDP for sync traffic
# 21027/UDP for discovery
# source: https://docs.syncthing.net/users/firewall.html
networking.firewall.interfaces."zt+".allowedTCPPorts = [
8384
22000
];
networking.firewall.allowedTCPPorts = [ 8384 ];
networking.firewall.interfaces."zt+".allowedUDPPorts = [
22000
21027
];
assertions = [
{
assertion = lib.all (
attr: builtins.hasAttr attr config.services.syncthing.settings.folders
) config.clan.syncthing.autoShares;
message = ''
Syncthing: If you want to AutoShare a folder, you need to have it configured on the sharing device.
'';
}
];
# Activates inotify compatibility on syncthing
# use mkOverride 900 here as it otherwise would collide with the default of the
# upstream nixos xserver.nix
boot.kernel.sysctl."fs.inotify.max_user_watches" = lib.mkOverride 900 524288;
services.syncthing = {
enable = true;
overrideFolders = lib.mkDefault (
if (config.clan.syncthing.introducer == null) then true else false
);
overrideDevices = lib.mkDefault (
if (config.clan.syncthing.introducer == null) then true else false
);
key = lib.mkDefault config.clan.core.vars.generators.syncthing.files."key".path or null;
cert = lib.mkDefault config.clan.core.vars.generators.syncthing.files."cert".path or null;
settings = {
options = {
urAccepted = -1;
allowedNetworks = [ ];
};
devices =
{ }
// (
if (config.clan.syncthing.introducer == null) then
{ }
else
{
"${config.clan.syncthing.introducer}" = {
name = "introducer";
id = config.clan.syncthing.introducer;
introducer = true;
autoAcceptFolders = true;
};
}
);
};
};
systemd.services.syncthing-auto-accept =
let
baseAddress = "127.0.0.1:8384";
getPendingDevices = "/rest/cluster/pending/devices";
postNewDevice = "/rest/config/devices";
SharedFolderById = "/rest/config/folders/";
apiKey = config.clan.core.vars.generators.syncthing.files."apikey".path;
in
lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Syncthing auto accept devices";
requisite = [ "syncthing.service" ];
after = [ "syncthing.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
set -x
# query pending deviceID's
APIKEY=$(cat ${apiKey})
PENDING=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${getPendingDevices})
PENDING=$(echo $PENDING | ${lib.getExe pkgs.jq} keys[])
# accept pending deviceID's
for ID in $PENDING;do
${lib.getExe pkgs.curl} -X POST -d "{\"deviceId\": $ID}" -H "Content-Type: application/json" -H "X-API-Key: $APIKEY" ${baseAddress}${postNewDevice}
# get all shared folders by their ID
for folder in ${builtins.toString config.clan.syncthing.autoShares}; do
SHARED_IDS=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder" | ${lib.getExe pkgs.jq} ."devices")
PATCHED_IDS=$(echo $SHARED_IDS | ${lib.getExe pkgs.jq} ".+= [{\"deviceID\": $ID, \"introducedBy\": \"\", \"encryptionPassword\": \"\"}]")
${lib.getExe pkgs.curl} -X PATCH -d "{\"devices\": $PATCHED_IDS}" -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder"
done
done
'';
};
systemd.timers.syncthing-auto-accept = lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Syncthing Auto Accept";
wantedBy = [ "syncthing-auto-accept.service" ];
timerConfig = {
OnActiveSec = lib.mkDefault 60;
OnUnitActiveSec = lib.mkDefault 60;
};
};
systemd.services.syncthing-init-api-key =
let
apiKey = config.clan.core.vars.generators.syncthing.files."apikey".path;
in
lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Set the api key";
after = [ "syncthing-init.service" ];
wantedBy = [ "multi-user.target" ];
script = ''
# set -x
set -efu pipefail
APIKEY=$(cat ${apiKey})
${lib.getExe pkgs.gnused} -i "s/<apikey>.*<\/apikey>/<apikey>$APIKEY<\/apikey>/" ${config.services.syncthing.configDir}/config.xml
# sudo systemctl restart syncthing.service
systemctl restart syncthing.service
'';
serviceConfig = {
BindReadOnlyPaths = [ apiKey ];
Type = "oneshot";
};
};
clan.core.vars.generators.syncthing = {
migrateFact = "syncthing";
files."key".group = config.services.syncthing.group;
files."key".owner = config.services.syncthing.user;
files."cert".group = config.services.syncthing.group;
files."cert".owner = config.services.syncthing.user;
files."apikey".group = config.services.syncthing.group;
files."apikey".owner = config.services.syncthing.user;
files."id".secret = false;
runtimeInputs = [
pkgs.coreutils
pkgs.gnugrep
pkgs.syncthing
];
script = ''
syncthing generate --config "$out"
mv "$out"/key.pem "$out"/key
mv "$out"/cert.pem "$out"/cert
cat "$out"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$out"/id
cat "$out"/config.xml | grep -oP '<apikey>\K[^<]+' | uniq > "$out"/apikey
'';
};
}
];
}

View File

@@ -6,9 +6,10 @@ After enabling the clan module, user accounts have to be created manually in the
This is done by visiting `vaultwarden.example.com/admin` and typing in the admin password.
You can get the admin password for vaultwarden by executing:
```bash
clan secrets get <machine-name>-vaultwarden-admin
clan vars get <machine-name> vaultwarden-admin/vaultwarden-admin
```
To see all secrets tied to vaultwarden execute:
```bash
clan secrets list | grep vaultwarden
clan vars get vaultwarden-admin/vaultwarden-admin
clan vars get vaultwarden-smtp/vaultwarden-smtp
```

View File

@@ -92,36 +92,39 @@ in
};
};
clan.core.facts.services = {
clan.core.vars.generators = {
vaultwarden-admin = {
secret."vaultwarden-admin" = { };
secret."vaultwarden-admin-hash" = { };
generator.path = with pkgs; [
migrateFact = "vaultwarden-admin";
files."vaultwarden-admin" = { };
files."vaultwarden-admin-hash" = { };
runtimeInputs = with pkgs; [
coreutils
pwgen
libargon2
openssl
];
generator.script = ''
script = ''
ADMIN_PWD=$(pwgen 16 -n1 | tr -d "\n")
ADMIN_HASH=$(echo -n "$ADMIN_PWD" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4)
config="
ADMIN_TOKEN=\"$ADMIN_HASH\"
"
echo -n "$ADMIN_PWD" > "$secrets"/vaultwarden-admin
echo -n "$config" > "$secrets"/vaultwarden-admin-hash
echo -n "$ADMIN_PWD" > "$out"/vaultwarden-admin
echo -n "$config" > "$out"/vaultwarden-admin-hash
'';
};
vaultwarden-smtp = {
secret."vaultwarden-smtp" = { };
generator.prompt = "${cfg.smtp.from} SMTP password";
generator.path = with pkgs; [ coreutils ];
generator.script = ''
migrateFact = "vaultwarden-smtp";
prompts."vaultwarden-smtp".description = "${cfg.smtp.from} SMTP password";
prompts."vaultwarden-smtp".persist = true;
runtimeInputs = with pkgs; [ coreutils ];
script = ''
prompt_value="$(cat "$prompts"/vaultwarden-smtp)"
config="
SMTP_PASSWORD=\"$prompt_value\"
"
echo -n "$config" > "$secrets"/vaultwarden-smtp
echo -n "$config" > "$out"/vaultwarden-smtp
'';
};
};
@@ -129,7 +132,7 @@ in
systemd.services."vaultwarden" = {
serviceConfig = {
EnvironmentFile = [
config.clan.core.facts.services."vaultwarden-smtp".secret."vaultwarden-smtp".path
config.clan.core.vars.generators."vaultwarden-smtp".files."vaultwarden-smtp".path
];
};
};
@@ -138,7 +141,7 @@ in
enable = true;
dbBackend = "postgresql";
environmentFile =
config.clan.core.facts.services."vaultwarden-admin".secret."vaultwarden-admin-hash".path; # TODO: Make this upstream an array
config.clan.core.vars.generators."vaultwarden-admin".files."vaultwarden-admin-hash".path; # TODO: Make this upstream an array
config = {
SMTP_SECURITY = "force_tls";
SMTP_HOST = cfg.smtp.host;

View File

@@ -6,15 +6,16 @@
}:
let
dir = config.clan.core.settings.directory;
machineDir = dir + "/machines/";
machineDir = "${dir}/vars/per-machine";
# TODO: This should use the inventory
# However we are probably going to replace this with the network module.
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
zerotierNetworkIdPath = machines: machineDir + machines + "/facts/zerotier-network-id";
networkIdsUnchecked = builtins.map (
machine:
let
fullPath = zerotierNetworkIdPath machine;
fullPath = "${machineDir}/vars/per-machine/${machine}/zerotier/zerotier-network-id/value";
in
if builtins.pathExists fullPath then builtins.readFile fullPath else null
) machines;
@@ -45,13 +46,9 @@ in
config.systemd.services.zerotier-static-peers-autoaccept =
let
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
zerotierIpFor = machine: "${machineDir}/vars/per-machine/${machine}/zerotier/zerotier-ip/value";
networkIpsUnchecked = builtins.map (
machine:
let
fullPath = zerotierIpMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
machine: if builtins.pathExists (zerotierIpFor machine) then machine else null
) machines;
networkIps = lib.filter (machine: machine != null) networkIpsUnchecked;
machinesWithIp = lib.filterAttrs (name: _: (lib.elem name networkIps)) machinesFileSet;
@@ -60,11 +57,7 @@ in
) machinesWithIp;
hosts = lib.mapAttrsToList (host: _: host) (
lib.mapAttrs' (
machine: _:
let
fullPath = zerotierIpMachinePath machine;
in
lib.nameValuePair (builtins.readFile fullPath) [ machine ]
machine: _: lib.nameValuePair (builtins.readFile (zerotierIpFor machine)) [ machine ]
) filteredMachines
);
allHostIPs = config.clan.zerotier-static-peers.networkIps ++ hosts;

View File

@@ -23,11 +23,11 @@ in
networkIps = builtins.foldl' (
ips: name:
if
builtins.pathExists "${config.clan.core.settings.directory}/machines/${name}/facts/zerotier-ip"
builtins.pathExists "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value"
then
ips
++ [
(builtins.readFile "${config.clan.core.settings.directory}/machines/${name}/facts/zerotier-ip")
(builtins.readFile "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value")
]
else
ips

View File

@@ -10,17 +10,24 @@ let
zeroTierInstance = config.clan.inventory.services.zerotier.${instanceName};
roles = zeroTierInstance.roles;
controllerMachine = builtins.head roles.controller.machines;
networkIdPath = "${config.clan.core.settings.directory}/machines/${controllerMachine}/facts/zerotier-network-id";
networkId = if builtins.pathExists networkIdPath then builtins.readFile networkIdPath else null;
networkIdPath = "${config.clan.core.settings.directory}/vars/per-machine/${controllerMachine}/zerotier/zerotier-network-id/value";
networkId =
if builtins.pathExists networkIdPath then
builtins.readFile networkIdPath
else
builtins.throw ''
No zerotier network id found for ${controllerMachine}.
Please run `clan vars generate ${controllerMachine}` first.
'';
moons = roles.moon.machines;
moonIps = builtins.foldl' (
ips: name:
if
builtins.pathExists "${config.clan.core.settings.directory}/machines/${name}/facts/zerotier-ip"
builtins.pathExists "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value"
then
ips
++ [
(builtins.readFile "${config.clan.core.settings.directory}/machines/${name}/facts/zerotier-ip")
(builtins.readFile "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value")
]
else
ips
@@ -62,7 +69,7 @@ in
clan.core.networking.zerotier.networkId = networkId;
clan.core.networking.zerotier.name = instanceName;
# TODO: in future we want to have the node id of our moons in our facts
# TODO: in future we want to have the node id of our moons in our vars
systemd.services.zerotierone.serviceConfig.ExecStartPost = lib.mkIf (moonIps != [ ]) (
lib.mkAfter [
"+${pkgs.writeScript "orbit-moons-by-ip" ''

View File

@@ -5,4 +5,19 @@
manifest.name = "clan-core/hello-word";
roles.peer = { };
perMachine =
{ machine, ... }:
{
nixosModule = {
clan.core.vars.generators.hello = {
files.hello = {
secret = false;
};
script = ''
echo "Hello world from ${machine.name}" > $out/hello
'';
};
};
};
}

View File

@@ -13,8 +13,11 @@ in
clan.inventory.modules = {
hello-world = module;
};
clan.modules = {
hello-world = module;
};
perSystem =
{ ... }:
{ pkgs, ... }:
let
# Module that contains the tests
# This module adds:
@@ -33,5 +36,22 @@ in
in
{
imports = [ unit-test-module ];
/**
1. Prepare the test vars
nix run .#generate-test-vars -- clanServices/hello-world/tests/vm hello-service
2. To run the test
nix build .#checks.x86_64-linux.hello-service
*/
checks =
# Currently we don't support nixos-integration tests on darwin
lib.optionalAttrs (pkgs.stdenv.isLinux) {
hello-service = import ./tests/vm/default.nix {
inherit module;
inherit self inputs pkgs;
clanLib = self.clanLib;
};
};
};
}

View File

@@ -0,0 +1,42 @@
{
pkgs,
self,
clanLib,
module,
...
}:
clanLib.test.makeTestClan {
inherit pkgs self;
nixosTest = (
{ ... }:
{
name = "service-hello-test";
clan = {
directory = ./.;
inventory = {
machines.peer1 = { };
instances."test" = {
module.name = "hello-service";
roles.peer.machines.peer1 = { };
};
modules = {
hello-service = module;
};
};
};
testScript =
{ nodes, ... }:
''
start_all()
# peer1 should have the 'hello' file
value = peer1.succeed("cat ${nodes.peer1.clan.core.vars.generators.hello.files.hello.path}")
assert value.strip() == "Hello world from peer1", value
'';
}
);
}

View File

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

View File

@@ -0,0 +1 @@
Hello world from peer1

View File

@@ -29,8 +29,7 @@
select-shell
pkgs.nix-unit
pkgs.tea
# Better error messages than nix 2.18
pkgs.nixVersions.latest
pkgs.nix
self'.packages.tea-create-pr
self'.packages.merge-after-ci
self'.packages.pending-reviews

View File

@@ -29,8 +29,8 @@ from dataclasses import dataclass, field
from pathlib import Path
from typing import Any
from clan_cli.api.modules import Frontmatter, extract_frontmatter, get_roles
from clan_cli.errors import ClanError
from clan_lib.api.modules import Frontmatter, extract_frontmatter, get_roles
# Get environment variables
CLAN_CORE_PATH = Path(os.environ["CLAN_CORE_PATH"])

View File

@@ -86,7 +86,7 @@ This guide shows you how to configure `zerotier` either through `NixOS Options`
configuration, substituting `<CONTROLLER>` with the controller machine name:
```nix
{ config, ... }: {
clan.core.networking.zerotier.networkId = builtins.readFile (config.clan.core.settings.directory + "/machines/<CONTROLLER>/facts/zerotier-network-id");
clan.core.networking.zerotier.networkId = builtins.readFile ../../vars/per-machine/<CONTROLLER>/zerotier/zerotier-network-id/value;
}
```
1. **Update the New Machine**: Execute:

View File

@@ -1,18 +1,19 @@
Clan enables encryption of secrets (such as passwords & keys) ensuring security and ease-of-use among users.
By default Clan utilizes the [sops](https://github.com/getsops/sops) format and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
By default, Clan uses the [sops](https://github.com/getsops/sops) format
and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
Clan can also be configured to be used with other secret store [backends](https://docs.clan.lol/reference/clan-core/vars/#clan.core.vars.settings.secretStore).
This guide will walk you through:
- **Creating a Keypair for Your User**: Learn how to generate a keypair for $USER to securely control all secrets.
- **Creating a Keypair for Your User**: Learn how to generate a keypair for `$USER` to securely control all secrets.
- **Creating Your First Secret**: Step-by-step instructions on creating your initial secret.
- **Assigning Machine Access to the Secret**: Understand how to grant a machine access to the newly created secret.
## Create Your Admin Keypair
To get started, you'll need to create **Your admin keypair**.
To get started, you'll need to create **your admin keypair**.
!!! info
Don't worry — if you've already made one before, this step won't change or overwrite it.
@@ -34,9 +35,78 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
Make sure to keep a safe backup of the private key you've just created.
If it's lost, you won't be able to get to your secrets anymore because they all need the admin key to be unlocked.
If you already have an [age] secret key and want to use that instead, you can simply edit `~/.config/sops/age/keys.txt`:
```title="~/.config/sops/age/keys.txt"
AGE-SECRET-KEY-13GWMK0KNNKXPTJ8KQ9LPSQZU7G3KU8LZDW474NX3D956GGVFAZRQTAE3F4
```
Alternatively, you can provide your [age] secret key as an environment variable `SOPS_AGE_KEY`, or in a different file
using `SOPS_AGE_KEY_FILE`.
For more information see the [SOPS] guide on [encrypting with age].
!!! note
It's safe to add any secrets created by the clan CLI and placed in your repository to version control systems like `git`.
### Using Age Plugins
If you wish to use a key generated using an [age plugin] as your admin key, extra care is needed.
You must **precede your secret key with a comment that contains its corresponding recipient**.
This is usually output as part of the generation process
and is only required because there is no unified mechanism for recovering a recipient from a plugin secret key.
Here is an example:
```title="~/.config/sops/age/keys.txt"
# public key: age1zdy49ek6z60q9r34vf5mmzkx6u43pr9haqdh5lqdg7fh5tpwlfwqea356l
AGE-PLUGIN-FIDO2-HMAC-1QQPQZRFR7ZZ2WCV...
```
!!! note
The comment that precedes the plugin secret key need only contain the recipient.
Any other text is ignored.
In the example above, you can specify `# recipient: age1zdy...`, `# public: age1zdy....` or even
just `# age1zdy....`
You will need to add an entry into your `flake.nix` to ensure that the necessary `age` plugins
are loaded when using Clan:
```nix title="flake.nix"
{
inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
inputs.nixpkgs.follows = "clan-core/nixpkgs";
outputs =
{ self, clan-core, ... }:
let
clan = clan-core.clanLib.buildClan {
inherit self;
meta.name = "myclan";
# Add Yubikey and FIDO2 HMAC plugins
# Note: the plugins listed here must be available in nixpkgs.
secrets.age.plugins = [
"age-plugin-yubikey"
"age-plugin-fido2-hmac"
];
machines = {
# elided for brevity
};
};
in
{
inherit (clan) nixosConfigurations clanInternals;
# elided for brevity
};
}
```
### Add Your Public Key(s)
```console
@@ -70,7 +140,7 @@ If you followed the quickstart tutorial all necessary secrets are initialized at
You can list keys for your user with `clan secrets users get $USER`:
```console
bin/clan secrets users get alice
clan secrets users get alice
[
{
@@ -83,17 +153,22 @@ You can list keys for your user with `clan secrets users get $USER`:
"type": "age",
"username": "alice"
}
]
]
```
To add a new key to your user:
To add a new key to your user:
```console
```console
clan secrets users add-key $USER --age-key <your_public_key>
```
To remove a key from your user:
To remove a key from your user:
```console
```console
clan secrets users remove-key $USER --age-key <your_public_key>
```
```
[age]: https://github.com/FiloSottile/age
[age plugin]: https://github.com/FiloSottile/awesome-age?tab=readme-ov-file#plugins
[sops]: https://github.com/getsops/sops
[encrypting with age]: https://github.com/getsops/sops?tab=readme-ov-file#encrypting-using-age

54
flake.lock generated
View File

@@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1745193679,
"narHash": "sha256-3sGidQ3Ze1K939cEw2hYbK1DnA8G1LCPsbvBvLoiFhI=",
"lastModified": 1745889637,
"narHash": "sha256-+BW9rppchFYIiJldD+fZA3MS2OtPNrb8l27SC3GyoSk=",
"ref": "refs/heads/main",
"rev": "817a74e34fb0e0b8012a8d2d67287c28d640b13a",
"revCount": 410,
"rev": "11b5673d9c7290a6b96c2b6c6c5be600304f310f",
"revCount": 415,
"type": "git",
"url": "https://git.clan.lol/clan/data-mesher"
},
@@ -36,11 +36,11 @@
]
},
"locked": {
"lastModified": 1745224732,
"narHash": "sha256-0OWgbEKhpMLpk3WQi3ugOwxWW4Y6JVpKiQ+o0nuNzus=",
"lastModified": 1745812220,
"narHash": "sha256-hotBG0EJ9VmAHJYF0yhWuTVZpENHvwcJ2SxvIPrXm+g=",
"owner": "nix-community",
"repo": "disko",
"rev": "1770bf1ae5da05564f86b969ef21c7228cc1a70b",
"rev": "d0c543d740fad42fe2c035b43c9d41127e073c78",
"type": "github"
},
"original": {
@@ -76,11 +76,11 @@
]
},
"locked": {
"lastModified": 1744478979,
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
"lastModified": 1745816321,
"narHash": "sha256-Gyh/fkCDqVNGM0BWvk+4UAS17w2UI6iwnbQQCmc1TDI=",
"owner": "nix-darwin",
"repo": "nix-darwin",
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
"rev": "4515dacafb0ccd42e5395aacc49fd58a43027e01",
"type": "github"
},
"original": {
@@ -89,6 +89,21 @@
"type": "github"
}
},
"nix-select": {
"locked": {
"lastModified": 1745005516,
"narHash": "sha256-IVaoOGDIvAa/8I0sdiiZuKptDldrkDWUNf/+ezIRhyc=",
"ref": "refs/heads/main",
"rev": "69d8bf596194c5c35a4e90dd02c52aa530caddf8",
"revCount": 40,
"type": "git",
"url": "https://git.clan.lol/clan/nix-select"
},
"original": {
"type": "git",
"url": "https://git.clan.lol/clan/nix-select"
}
},
"nixos-facter-modules": {
"locked": {
"lastModified": 1743671943,
@@ -107,10 +122,10 @@
"nixpkgs": {
"locked": {
"lastModified": 315532800,
"narHash": "sha256-Qbg44vc/Vw971fY3/lIzDLJVmb992RTuKXL2A69/89w=",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"narHash": "sha256-+Elxpf3FLkgKfh81xrEjVolpJEn8+fKWqEJ3ZXbAbS4=",
"rev": "29335f23bea5e34228349ea739f31ee79e267b88",
"type": "tarball",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre782598.18dd725c2960/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre791229.29335f23bea5/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
@@ -123,6 +138,7 @@
"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",
@@ -137,11 +153,11 @@
]
},
"locked": {
"lastModified": 1744669848,
"narHash": "sha256-pXyanHLUzLNd3MX9vsWG+6Z2hTU8niyphWstYEP3/GU=",
"lastModified": 1745310711,
"narHash": "sha256-ePyTpKEJTgX0gvgNQWd7tQYQ3glIkbqcW778RpHlqgA=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "61154300d945f0b147b30d24ddcafa159148026a",
"rev": "5e3e92b16d6fdf9923425a8d4df7496b2434f39c",
"type": "github"
},
"original": {
@@ -172,11 +188,11 @@
]
},
"locked": {
"lastModified": 1744961264,
"narHash": "sha256-aRmUh0AMwcbdjJHnytg1e5h5ECcaWtIFQa6d9gI85AI=",
"lastModified": 1745929750,
"narHash": "sha256-k5ELLpTwRP/OElcLpNaFWLNf8GRDq4/eHBmFy06gGko=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "8d404a69efe76146368885110f29a2ca3700bee6",
"rev": "82bf32e541b30080d94e46af13d46da0708609ea",
"type": "github"
},
"original": {

View File

@@ -23,6 +23,8 @@
treefmt-nix.url = "github:numtide/treefmt-nix";
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
nix-select.url = "git+https://git.clan.lol/clan/nix-select";
data-mesher = {
url = "git+https://git.clan.lol/clan/data-mesher";
inputs = {

View File

@@ -1,6 +1,7 @@
{ pkgs, lib }:
let
eval = lib.evalModules {
class = "nixos";
modules = [
./interface.nix
];

View File

@@ -108,6 +108,14 @@ in
default = { };
};
secrets = lib.mkOption {
type = types.submodule { imports = [ ./secrets/interface.nix ]; };
description = ''
Secrets related options such as AGE plugins required to encrypt/decrypt secrets using the CLI.
'';
default = { };
};
pkgsForSystem = lib.mkOption {
type = types.functionTo (types.nullOr types.attrs);
default = _system: null;
@@ -158,7 +166,6 @@ in
# all exported clan modules from this clan
modules = lib.mkOption { type = lib.types.raw; };
# all inventory module schemas
moduleSchemas = lib.mkOption { type = lib.types.raw; };
inventoryFile = lib.mkOption { type = lib.types.raw; };
# The machine 'imports' generated by the inventory per machine
inventoryClass = lib.mkOption { type = lib.types.raw; };
@@ -166,6 +173,7 @@ in
clanModules = lib.mkOption { type = lib.types.raw; };
source = lib.mkOption { type = lib.types.raw; };
meta = lib.mkOption { type = lib.types.raw; };
secrets = lib.mkOption { type = lib.types.raw; };
clanLib = lib.mkOption { type = lib.types.raw; };
all-machines-json = lib.mkOption { type = lib.types.raw; };
machines = lib.mkOption { type = lib.types.raw; };

View File

@@ -9,30 +9,24 @@
...
}:
{
imports = [
{
imports = builtins.filter builtins.pathExists (
[
"${directory}/machines/${name}/configuration.nix"
]
++ lib.optionals (_class == "nixos") [
"${directory}/machines/${name}/hardware-configuration.nix"
"${directory}/machines/${name}/disko.nix"
]
);
}
(lib.optionalAttrs (_class == "nixos") {
clan.core.settings = {
inherit (meta) name icon;
inherit directory;
machine = {
inherit name;
};
};
})
# TODO: move into nixos modules
({
networking.hostName = lib.mkDefault name;
})
];
imports = builtins.filter builtins.pathExists (
[
"${directory}/machines/${name}/configuration.nix"
]
++ lib.optionals (_class == "nixos") [
"${directory}/machines/${name}/hardware-configuration.nix"
"${directory}/machines/${name}/disko.nix"
]
);
clan.core.settings = {
inherit (meta) name icon;
inherit directory;
machine = {
inherit name;
};
};
# TODO: move into nixosModules
networking.hostName = lib.mkDefault name;
}

View File

@@ -122,7 +122,16 @@ in
(lib.mapAttrs (
name: v:
(
{ _class, ... }:
{ ... }@args:
let
_class =
args._class or (throw ''
Your version of nixpkgs is incompatible with the latest clan.
Please update nixpkgs input to the latest nixos-unstable or nixpkgs-unstable.
Run:
nix flake update nixpkgs
'');
in
{
imports = [
(lib.modules.importApply ./machineModules/forName.nix {
@@ -193,12 +202,6 @@ in
name: _: inventory.machines.${name}.machineClass or "nixos" == "darwin"
) (config.outputs.moduleForMachine);
moduleSchemas = clan-core.clanLib.modules.getModulesSchema {
modules = config.inventory.modules;
# TODO: make this function system agnostic
pkgs = nixpkgs.legacyPackages."x86_64-linux";
inherit clan-core;
};
inherit inventoryClass;
# TODO: unify this interface
@@ -209,29 +212,24 @@ in
inherit inventoryFile;
inventoryValuesPrios =
# Temporary workaround
builtins.removeAttrs (clan-core.clanLib.values.getPrios { options = inventory.options; })
builtins.removeAttrs (clan-core.clanLib.introspection.getPrios { options = inventory.options; })
# tags are freeformType which is not supported yet.
[ "tags" ];
templates = config.templates;
inventory = config.inventory;
meta = config.inventory.meta;
secrets = config.secrets;
source = "${clan-core}";
# machine specifics
machines = configsPerSystem;
all-machines-json =
if !lib.hasAttrByPath [ "darwinModules" "clanCore" ] clan-core then
lib.mapAttrs (
system: configs:
nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (
lib.mapAttrs (_: m: m.config.system.clan.deployment.data) (
lib.filterAttrs (_n: v: v.class == "nixos") configs
)
)
) configsPerSystem
else
throw "remove NixOS filter and support nix-darwin as well";
all-machines-json = lib.mapAttrs (
system: configs:
nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (
lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs
)
) configsPerSystem;
};
}

View File

@@ -0,0 +1,18 @@
{
lib,
...
}:
let
inherit (lib) types;
in
{
options = {
age.plugins = lib.mkOption {
type = types.listOf (types.strMatching "age-plugin-.*");
default = [ ];
description = ''
A list of age plugins which must be available in the shell when encrypting and decrypting secrets.
'';
};
};
}

View File

@@ -28,8 +28,11 @@ lib.fix (clanLib: {
test = clanLib.callLib ./test { };
# Plain imports.
values = import ./introspection { inherit lib; };
introspection = import ./introspection { inherit lib; };
jsonschema = import ./jsonschema { inherit lib; };
select = import select/default.nix;
facts = import ./facts.nix { inherit lib; };
# deprecated
# remove when https://git.clan.lol/clan/clan-core/pulls/3212 is implemented
inherit (self.inputs.nix-select.lib) select;
})

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