diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..0f94eed --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +# shellcheck shell=bash +use flake diff --git a/.forgejo/workflows/action.yml b/.forgejo/workflows/action.yml index 4aac00e..684cfad 100644 --- a/.forgejo/workflows/action.yml +++ b/.forgejo/workflows/action.yml @@ -7,10 +7,9 @@ on: - main jobs: - hello: - name: Print hello world - runs-on: default + kaas: + runs-on: nix steps: - name: Echo run: | - echo "Hello, world!" \ No newline at end of file + nix --version \ No newline at end of file diff --git a/.gitignore b/.gitignore index 87a3018..3cb44c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ +# ---> Nix +# Ignore build outputs from performing a nix-build or `nix build` command result -*.qcow2 +result-* + +# Ignore automatically generated direnv output +.direnv + diff --git a/.just/machine.just b/.just/machine.just new file mode 100644 index 0000000..3e3ba14 --- /dev/null +++ b/.just/machine.just @@ -0,0 +1,14 @@ +set unstable := true +set quiet := true + +_default: list + +[doc('List machines')] +list: + ls -1 ../systems/x86_64-linux/ + +[doc('Update the target machine')] +[no-exit-message] +update machine: + just assert '-d "../systems/x86_64-linux/{{ machine }}"' "Machine {{ machine }} does not exist, must be one of: $(ls ../systems/x86_64-linux/ | tr '\n' ' ')" + nixos-rebuild switch --use-remote-sudo --target-host {{ machine }} --flake ..#{{ machine }} diff --git a/.just/vars.just b/.just/vars.just new file mode 100644 index 0000000..230f00c --- /dev/null +++ b/.just/vars.just @@ -0,0 +1,33 @@ +set unstable := true +set quiet := true + +base_path := invocation_directory() / "systems/x86_64-linux" + +_default: + just --list + +[doc('list all vars of the target machine')] +list machine: + sops decrypt {{ base_path }}/{{ machine }}/secrets.yml + +edit machine: + sops edit {{ base_path }}/{{ machine }}/secrets.yml + +@set machine key value: + sops set {{ base_path }}/{{ machine }}/secrets.yml "$(printf '%s\n' '["{{ key }}"]' | sed -E 's#/#"]["#g; s/\["([0-9]+)"\]/[\1]/g')" "\"$(echo '{{ value }}' | sed 's/\"/\\\"/g')\"" + + git add {{ base_path }}/{{ machine }}/secrets.yml + git commit -m 'chore(secrets): set secret "{{ key }}" for machine "{{ machine }}"' -- {{ base_path }}/{{ machine }}/secrets.yml > /dev/null + + echo "Done" + +get machine key: + sops decrypt {{ base_path }}/{{ machine }}/secrets.yml | yq ".$(echo "{{ key }}" | sed -E 's/\//./g')" + +remove machine key: + sops unset {{ base_path }}/{{ machine }}/secrets.yml "$(printf '%s\n' '["{{ key }}"]' | sed -E 's#/#"]["#g; s/\["([0-9]+)"\]/[\1]/g')" + + git add {{ base_path }}/{{ machine }}/secrets.yml + git commit -m 'chore(secrets): removed secret "{{ key }}" from machine "{{ machine }}"' -- {{ base_path }}/{{ machine }}/secrets.yml > /dev/null + + echo "Done" diff --git a/.justfile b/.justfile new file mode 100644 index 0000000..1937f04 --- /dev/null +++ b/.justfile @@ -0,0 +1,40 @@ +_default: + just --list --list-submodules + +set unstable +set quiet + +mod vars '.just/vars.just' +mod machine '.just/machine.just' + +[doc('Show information about project')] +show: + echo "show" + +[doc('update the flake dependencies')] +update: + nix flake update + git commit -m 'chore: update dependencies' -- ./flake.lock > /dev/null + echo "Done" + +[doc('Rebase branch on main')] +rebase: + git stash -q \ + && git fetch \ + && git rebase origin/main \ + && git stash pop -q + + echo "Done" + +[doc('Introspection on flake output')] +select key: + nix eval --json .#{{ key }} | jq . + +#=============================================================================================== +# Utils +# =============================================================================================== +[no-cd] +[no-exit-message] +[private] +assert condition message: + [ {{ condition }} ] || { echo -e 1>&2 "\n\x1b[1;41m Error \x1b[0m {{ message }}\n"; exit 1; } diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..9e7956c --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,11 @@ +keys: + - &ulmo_1 age19qfpf980tadguqq44zf6xwvjvl428dyrj46ha3n6aeqddwhtnuqqml7etq + - &ulmo_2 age1ewes0f5snqx3sh5ul6fa6qtxzhd25829v6mf5rx2wnheat6fefps5rme2x + +creation_rules: + # All Machine secrets + - path_regex: systems/[^/]+/[^/]+/[^/]+\.(yml|yaml)$ + key_groups: + - age: + - *ulmo_1 + - *ulmo_2 \ No newline at end of file diff --git a/.sops.yml b/.sops.yml deleted file mode 100644 index 96e09c3..0000000 --- a/.sops.yml +++ /dev/null @@ -1,8 +0,0 @@ -keys: - - &primary age10c5hmykkduvy75yvqfnchm5lcesr5puarhkwp4l7xdwpykdm397q6xdxuy - -creation_rules: - - path_regex: secrets/secrets.yml$ - key_groups: - - age: - - *primary diff --git a/_secrets/secrets.yaml b/_secrets/secrets.yaml deleted file mode 100644 index 78b1a8c..0000000 --- a/_secrets/secrets.yaml +++ /dev/null @@ -1,30 +0,0 @@ -#ENC[AES256_GCM,data:jozDiJTPaF427kVL4MDV8VOVhft52sOS9YIfj0n8WUJmQzVoiNY=,iv:8kyaDw0l82KZfYKkfKDj0wvcIkY6zas5e8puubEr1mA=,tag:LvuVGvU195BihU8TbPN1xg==,type:comment] -example_key: ENC[AES256_GCM,data:9jefDfjJLP8Ha135Lg==,iv:9SUpjO1t65gA3LiwYN6nMj7icwInxTCQz7JsNEfQ2XA=,tag:Y8BBSLwUQem8wSXAlvnEXg==,type:str] -#ENC[AES256_GCM,data:IU1T4k/+44s8qFnjnreDMihjQRmMd5qSTtfA/ung5/1f1JmBXGP7EwYJBFF9BSBkBqBfv24A9Ok=,iv:tHzL3pW/qsNdWGT3c+ni0uTlkBMWOu/SsraymCuAkqs=,tag:nWZgWdPNiKQ0j/t9Z/5l5g==,type:comment] -#ENC[AES256_GCM,data:BhUTbsJB5voz4m1w8u1Y/MI8kR5lpRW8RpZO65IyGg232uNSoBLXB2QSl1GseyTC8bZHPiCF2gnttPD+76kqVlfzhhDu4EKU,iv:Ic8ZpR2QBBGhF2++S/TR/DRutkTghpMiby+yvNy0CSE=,tag:Z1JEtowycGDNWuznlkId8A==,type:comment] -example: - my_subdir: - my_secret: ENC[AES256_GCM,data:hccfc6uU4tGT,iv:HYjmo9kAVCcXSpDKWGku3vaJVvZHzYB3l079xXw5OEQ=,tag:c2b8BSqlL1LTcDf1nSPfVA==,type:str] -sops: - kms: [] - gcp_kms: [] - azure_kv: [] - hc_vault: [] - age: - - recipient: age10c5hmykkduvy75yvqfnchm5lcesr5puarhkwp4l7xdwpykdm397q6xdxuy - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpeHZXWkZ2andYSytmYWpR - ckttNVJZaWxDK2ZwME1iY2wrWFNwR0hzWUNFCjVSaWpmTHkzdHpPNjhueTQ5ZUEz - YW1BcnIwU1hsb2lodk1QcHJvTUdrVVUKLS0tIFNpWlBqb2pOWDVLV0FvU1FUODJB - dTg0QXZuSkJXV3ZRSUlKcktDNElia28KKZ62gTVpeiz1CfK7awURrPZ7zAYx9vfR - Ajxk0cw1gleE6EU2iIlLOWtmyZbcNk1X32a+otXijlH8fDGtoxA97Q== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-03-09T11:37:49Z" - mac: ENC[AES256_GCM,data:ZEqJc6slPb3YMR9kn/jFImjkQQIT3KyUK3qE3JMty+IAAr9GT8r+rHOwku4TOwL6YzON6L5vkUQFFKnOz9GiJuGkStc6AbML4SfOlRDsaFU4kwO+27UvDBYRqi6iHtJ2pu/uD4wELVhdbElxHvFlCjtgqBWaWmlXw3ATjkiZnik=,iv:zJNM/TqNfBO/mr8ZK/I/FfXwknyn9YpJ0eo4EpHSJvQ=,tag:G4FLx/Hwknq5hYEb8SWQLg==,type:str] - pgp: [] - unencrypted_suffix: _unencrypted - version: 3.9.4 - -zitadel: - masterKey: thisWillBeAnEncryptedValueInTheFuture diff --git a/flake.lock b/flake.lock index 27521bd..9d38839 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "fromYaml": "fromYaml" }, "locked": { - "lastModified": 1746562888, - "narHash": "sha256-YgNJQyB5dQiwavdDFBMNKk1wyS77AtdgDk/VtU6wEaI=", + "lastModified": 1755819240, + "narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=", "owner": "SenchoPens", "repo": "base16.nix", - "rev": "806a1777a5db2a1ef9d5d6f493ef2381047f2b89", + "rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6", "type": "github" }, "original": { @@ -21,16 +21,17 @@ "base16-fish": { "flake": false, "locked": { - "lastModified": 1622559957, - "narHash": "sha256-PebymhVYbL8trDVVXxCvZgc0S5VxI7I1Hv4RMSquTpA=", + "lastModified": 1754405784, + "narHash": "sha256-l9xHIy+85FN+bEo6yquq2IjD1rSg9fjfjpyGP1W8YXo=", "owner": "tomyun", "repo": "base16-fish", - "rev": "2f6dd973a9075dabccd26f1cded09508180bf5fe", + "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561", "type": "github" }, "original": { "owner": "tomyun", "repo": "base16-fish", + "rev": "23ae20a0093dca0d7b39d76ba2401af0ccf9c561", "type": "github" } }, @@ -67,17 +68,92 @@ "type": "github" } }, + "clan-core": { + "inputs": { + "data-mesher": "data-mesher", + "disko": "disko", + "flake-parts": "flake-parts", + "nix-darwin": "nix-darwin", + "nix-select": "nix-select", + "nixos-facter-modules": "nixos-facter-modules", + "nixpkgs": [ + "nixpkgs" + ], + "sops-nix": "sops-nix", + "systems": "systems", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1763547157, + "narHash": "sha256-lJcMap2uT+x1R8WUUKKQ6ndynysJ/JOkrMThMGz6DP0=", + "rev": "2cb2134a6ee32d427097077c4fb4c416b52ae988", + "type": "tarball", + "url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/2cb2134a6ee32d427097077c4fb4c416b52ae988.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://git.clan.lol/clan/clan-core/archive/main.tar.gz" + } + }, + "data-mesher": { + "inputs": { + "flake-parts": [ + "clan-core", + "flake-parts" + ], + "nixpkgs": [ + "clan-core", + "nixpkgs" + ], + "treefmt-nix": [ + "clan-core", + "treefmt-nix" + ] + }, + "locked": { + "lastModified": 1762942435, + "narHash": "sha256-zIWGs5FIytTtJN+dhDb8Yx+q4TQI/yczuL539yVcyPE=", + "rev": "0ee328404b12c65e8106bde9e9fab8abf4ecada4", + "type": "tarball", + "url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/0ee328404b12c65e8106bde9e9fab8abf4ecada4.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://git.clan.lol/clan/data-mesher/archive/main.tar.gz" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "clan-core", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762276996, + "narHash": "sha256-TtcPgPmp2f0FAnc+DMEw4ardEgv1SGNR3/WFGH0N19M=", + "owner": "nix-community", + "repo": "disko", + "rev": "af087d076d3860760b3323f6b583f4d828c1ac17", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, "erosanix": { "inputs": { "flake-compat": "flake-compat", "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1755108317, - "narHash": "sha256-j7RGK7nyoHuJzQjVFBngpsVowIn4DAtprn66UyAFNRQ=", + "lastModified": 1762360792, + "narHash": "sha256-YR7vqk+XEvFUQ/miuBAD3+p+97QUN86ya9Aw0K5feJE=", "owner": "emmanuelrosa", "repo": "erosanix", - "rev": "5aa322a6e586a2b46af65ab6c9a3d6042a95ff2e", + "rev": "9075dff5685d3e7269284e53ca496da0beb24596", "type": "github" }, "original": { @@ -94,11 +170,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1755153894, - "narHash": "sha256-DEKeIg3MQy5GMFiFRUzcx1hGGBN2ypUPTo0jrMAdmH4=", + "lastModified": 1763534658, + "narHash": "sha256-i/51/Zi/1pM9hZxxSuA3nVPpyqlGoWwJwajyA/loOpo=", "owner": "nix-community", "repo": "fenix", - "rev": "f6874c6e512bc69d881d979a45379b988b80a338", + "rev": "69e40ddf45698d0115a62a7a15d8412f35dd4c09", "type": "github" }, "original": { @@ -114,11 +190,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1755083788, - "narHash": "sha256-CXiS6gfw0NH+luSpNhtRZjy4NqVFrmsYpoetu3N/fMk=", + "lastModified": 1763504432, + "narHash": "sha256-kpmPI67TdoTxiK7LsmgmkKW3iHoyvZJwZeiJhpwPfmw=", "owner": "nix-community", "repo": "flake-firefox-nightly", - "rev": "523078b104590da5850a61dfe291650a6b49809c", + "rev": "49d5d8d42a7650e5353f8467c813839290cb7c9f", "type": "github" }, "original": { @@ -130,11 +206,11 @@ "firefox-gnome-theme": { "flake": false, "locked": { - "lastModified": 1748383148, - "narHash": "sha256-pGvD/RGuuPf/4oogsfeRaeMm6ipUIznI2QSILKjKzeA=", + "lastModified": 1758112371, + "narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=", "owner": "rafaelmardojai", "repo": "firefox-gnome-theme", - "rev": "4eb2714fbed2b80e234312611a947d6cb7d70caf", + "rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d", "type": "github" }, "original": { @@ -161,11 +237,11 @@ }, "flake-compat_2": { "locked": { - "lastModified": 1746162366, - "narHash": "sha256-5SSSZ/oQkwfcAz/o/6TlejlVGqeK08wyREBQ5qFFPhM=", + "lastModified": 1761640442, + "narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=", "owner": "nix-community", "repo": "flake-compat", - "rev": "0f158086a2ecdbb138cd0429410e44994f1b7e4b", + "rev": "4a56054d8ffc173222d09dad23adf4ba946c8884", "type": "github" }, "original": { @@ -225,16 +301,16 @@ "flake-parts": { "inputs": { "nixpkgs-lib": [ - "nvf", + "clan-core", "nixpkgs" ] }, "locked": { - "lastModified": 1754487366, - "narHash": "sha256-pHYj8gUBapuUzKV/kN/tR3Zvqc7o6gdFB9XKXIp1SQ8=", + "lastModified": 1762980239, + "narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "af66ad14b28a127c5c0f3bbb298218fc63528a18", + "rev": "52a2caecc898d0b46b2b905f058ccc5081f842da", "type": "github" }, "original": { @@ -244,6 +320,27 @@ } }, "flake-parts_2": { + "inputs": { + "nixpkgs-lib": [ + "nvf", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760948891, + "narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_3": { "inputs": { "nixpkgs-lib": [ "stylix", @@ -251,11 +348,32 @@ ] }, "locked": { - "lastModified": 1751413152, - "narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=", + "lastModified": 1756770412, + "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "77826244401ea9de6e3bac47c2db46005e1f30b5", + "rev": "4524271976b625a4a605beefd893f270620fd751", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_4": { + "inputs": { + "nixpkgs-lib": [ + "terranix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1736143030, + "narHash": "sha256-+hu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "b905f6fc23a9051a6e1b741e1438dbfc0634c6de", "type": "github" }, "original": { @@ -266,7 +384,7 @@ }, "flake-utils": { "inputs": { - "systems": "systems" + "systems": "systems_2" }, "locked": { "lastModified": 1731533236, @@ -303,7 +421,7 @@ }, "flake-utils_2": { "inputs": { - "systems": "systems_2" + "systems": "systems_3" }, "locked": { "lastModified": 1731533236, @@ -321,7 +439,7 @@ }, "flake-utils_3": { "inputs": { - "systems": "systems_3" + "systems": "systems_4" }, "locked": { "lastModified": 1731533236, @@ -339,7 +457,7 @@ }, "flake-utils_4": { "inputs": { - "systems": "systems_5" + "systems": "systems_6" }, "locked": { "lastModified": 1694529238, @@ -392,18 +510,20 @@ "gnome-shell": { "flake": false, "locked": { - "lastModified": 1748186689, - "narHash": "sha256-UaD7Y9f8iuLBMGHXeJlRu6U1Ggw5B9JnkFs3enZlap0=", + "host": "gitlab.gnome.org", + "lastModified": 1762869044, + "narHash": "sha256-nwm/GJ2Syigf7VccLAZ66mFC8mZJFqpJmIxSGKl7+Ds=", "owner": "GNOME", "repo": "gnome-shell", - "rev": "8c88f917db0f1f0d80fa55206c863d3746fa18d0", - "type": "github" + "rev": "680e3d195a92203f28d4bf8c6e8bb537cc3ed4ad", + "type": "gitlab" }, "original": { + "host": "gitlab.gnome.org", "owner": "GNOME", - "ref": "48.2", + "ref": "gnome-49", "repo": "gnome-shell", - "type": "github" + "type": "gitlab" } }, "grub2-themes": { @@ -411,11 +531,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1755072091, - "narHash": "sha256-FCkbELHIFXlVREaopW13QFMzwLPr/otjucmyNLQQXeg=", + "lastModified": 1757136219, + "narHash": "sha256-tKU+vq34KHu/A2wD7WdgP5A4/RCmSD8hB0TyQAUlixA=", "owner": "vinceliuice", "repo": "grub2-themes", - "rev": "03d8c9cf0d1bcf67765ac5fa35263f1b08c584fa", + "rev": "80dd04ddf3ba7b284a7b1a5df2b1e95ee2aad606", "type": "github" }, "original": { @@ -429,14 +549,15 @@ "flake-utils": "flake-utils_2", "nixpkgs": [ "nixpkgs" - ] + ], + "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1754593854, - "narHash": "sha256-fiWzQKZP92+2nm9wGBa/UYuEdVJkshHqNpCFfklas8k=", + "lastModified": 1763486183, + "narHash": "sha256-10EvBTF9ELezWg+KoKZJ3bxrPzT1Xz95ifurC6HixLY=", "owner": "himmelblau-idm", "repo": "himmelblau", - "rev": "e0b9a3efdcf0c6c59ed3352ffb2b003ab6aa2fed", + "rev": "fb27f4bee812e4b4df9df9f78bd5280f0aa2193c", "type": "github" }, "original": { @@ -452,11 +573,32 @@ ] }, "locked": { - "lastModified": 1755121891, - "narHash": "sha256-UtYkukiGnPRJ5rpd4W/wFVrLMh8fqtNkqHTPgHEtrqU=", + "lastModified": 1763416652, + "narHash": "sha256-8EBEEvtzQ11LCxpQHMNEBQAGtQiCu/pqP9zSovDSbNM=", "owner": "nix-community", "repo": "home-manager", - "rev": "279ca5addcdcfa31ac852b3ecb39fc372684f426", + "rev": "ea164b7c9ccdc2321379c2ff78fd4317b4c41312", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "zen-browser", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762964643, + "narHash": "sha256-RYHN8O/Aja59XDji6WSJZPkJpYVUfpSkyH+PEupBJqM=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "827f2a23373a774a8805f84ca5344654c31f354b", "type": "github" }, "original": { @@ -473,11 +615,11 @@ ] }, "locked": { - "lastModified": 1755151620, - "narHash": "sha256-fVMalQZ+tRXR8oue2SdWu4CdlsS2NII+++rI40XQ8rU=", + "lastModified": 1763453666, + "narHash": "sha256-Hu8lDUlbMFvcYX30LBXX7Gq5FbU35bERH0pSX5qHf/Q=", "owner": "Jovian-Experiments", "repo": "Jovian-NixOS", - "rev": "16e12d22754d97064867006acae6e16da7a142a6", + "rev": "b843b551415c7aecc97c8b3ab3fff26fd0cd8bbf", "type": "github" }, "original": { @@ -507,11 +649,11 @@ }, "mnw": { "locked": { - "lastModified": 1748710831, - "narHash": "sha256-eZu2yH3Y2eA9DD3naKWy/sTxYS5rPK2hO7vj8tvUCSU=", + "lastModified": 1758834834, + "narHash": "sha256-Y7IvY4F8vajZyp3WGf+KaiIVwondEkMFkt92Cr9NZmg=", "owner": "Gerg-L", "repo": "mnw", - "rev": "cff958a4e050f8d917a6ff3a5624bc4681c6187d", + "rev": "cfbc7d1cc832e318d0863a5fc91d940a96034001", "type": "github" }, "original": { @@ -520,6 +662,27 @@ "type": "github" } }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "clan-core", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763136804, + "narHash": "sha256-6p2ljK42s0S8zS0UU59EsEqupz0GVCaBYRylpUadeBM=", + "owner": "nix-darwin", + "repo": "nix-darwin", + "rev": "973db96394513fd90270ea5a1211a82a4a0ba47f", + "type": "github" + }, + "original": { + "owner": "nix-darwin", + "repo": "nix-darwin", + "type": "github" + } + }, "nix-github-actions": { "inputs": { "nixpkgs": [ @@ -549,11 +712,11 @@ "nixpkgs": "nixpkgs_5" }, "locked": { - "lastModified": 1755137329, - "narHash": "sha256-9MxuOLH7jk58IVUUDWwLeqk9U4ATE6X37955Ld+4/zw=", + "lastModified": 1763171892, + "narHash": "sha256-6cg9zSiqKA89yJzVtYhBaBptqq6bX4pr4g7WLAHOD4Y=", "owner": "Infinidoge", "repo": "nix-minecraft", - "rev": "d9330bc35048238597880e89fb173799de9db5e9", + "rev": "316858c27d278b20e776cd4dd8f787812f587ba2", "type": "github" }, "original": { @@ -562,6 +725,19 @@ "type": "github" } }, + "nix-select": { + "locked": { + "lastModified": 1763303120, + "narHash": "sha256-yxcNOha7Cfv2nhVpz9ZXSNKk0R7wt4AiBklJ8D24rVg=", + "rev": "3d1e3860bef36857a01a2ddecba7cdb0a14c35a9", + "type": "tarball", + "url": "https://git.clan.lol/api/v1/repos/clan/nix-select/archive/3d1e3860bef36857a01a2ddecba7cdb0a14c35a9.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://git.clan.lol/clan/nix-select/archive/main.tar.gz" + } + }, "nixlib": { "locked": { "lastModified": 1736643958, @@ -592,6 +768,21 @@ "type": "github" } }, + "nixos-facter-modules": { + "locked": { + "lastModified": 1762264948, + "narHash": "sha256-iaRf6n0KPl9hndnIft3blm1YTAyxSREV1oX0MFZ6Tk4=", + "owner": "nix-community", + "repo": "nixos-facter-modules", + "rev": "fa695bff9ec37fd5bbd7ee3181dbeb5f97f53c96", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-facter-modules", + "type": "github" + } + }, "nixos-generators": { "inputs": { "nixlib": "nixlib", @@ -621,11 +812,11 @@ ] }, "locked": { - "lastModified": 1755171343, - "narHash": "sha256-h6bbfhqWcHlx9tcyYa7dhaEiNpusLCcFYkJ/AnltLW8=", + "lastModified": 1763537456, + "narHash": "sha256-/WRqcqeE9C+mxxWgI7jy5blMrvg2lHFSlTFjC8pRWos=", "owner": "nix-community", "repo": "nixos-wsl", - "rev": "e37cfef071466a9ca649f6899aff05226ce17e9e", + "rev": "cd9eb5225fc91eb67629966844d2ff371824abb1", "type": "github" }, "original": { @@ -636,11 +827,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1754002724, - "narHash": "sha256-1NBby4k2UU9FR7a9ioXtCOpv8jYO0tZAGarMsxN8sz8=", + "lastModified": 1761828793, + "narHash": "sha256-xjdPwMD4wVuDD85U+3KST62VzFkJueI6oBwIzpzUHLY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8271ed4b2e366339dd622f329151e45745ade121", + "rev": "843859a08e114403f44aaf5b996b44c38094aa46", "type": "github" }, "original": { @@ -665,29 +856,13 @@ "type": "github" } }, - "nixpkgs_10": { - "locked": { - "lastModified": 1727348695, - "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs_2": { "locked": { - "lastModified": 1755061300, - "narHash": "sha256-eov82CkCrpiECJa3dyQ2da1sPGnAP3HK0UEra5eupaM=", + "lastModified": 1763469780, + "narHash": "sha256-IW67Db/wBNQwJ5e0fF9Yk4SmdivMcecrUVDs7QJoC/s=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d4df8d6cc1ccfd3e4349a1d54e4fb1171e7ec1f5", + "rev": "a70b03ca5dc9d46294740f165abdef9f9bea5632", "type": "github" }, "original": { @@ -715,11 +890,11 @@ }, "nixpkgs_4": { "locked": { - "lastModified": 1755178357, - "narHash": "sha256-rzgUmlO5/pt7uPAlY6E70clNjg9JmrgBxalEj2zKq08=", + "lastModified": 1763547551, + "narHash": "sha256-YOdXVAqEGmrPUgs71r8ziuu9qqpn3jJEiIxsIls+VQA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6eac4364f979ef460fb6ebd17ca65b8dae03cba4", + "rev": "06aa4d5f488875b6af46e10b45b8000ed0906860", "type": "github" }, "original": { @@ -747,11 +922,11 @@ }, "nixpkgs_6": { "locked": { - "lastModified": 1755027561, - "narHash": "sha256-IVft239Bc8p8Dtvf7UAACMG5P3ZV+3/aO28gXpGtMXI=", + "lastModified": 1763421233, + "narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "005433b926e16227259a1843015b5b2b7f7d1fc3", + "rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648", "type": "github" }, "original": { @@ -763,11 +938,11 @@ }, "nixpkgs_7": { "locked": { - "lastModified": 1755049066, - "narHash": "sha256-ANrc15FSoOAdNbfKHxqEJjZLftIwIsenJGRb/04K41s=", + "lastModified": 1761880412, + "narHash": "sha256-QoJjGd4NstnyOG4mm4KXF+weBzA2AH/7gn1Pmpfcb0A=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e45f8f193029378d0aaee5431ba098dc80054e9a", + "rev": "a7fc11be66bdfb5cdde611ee5ce381c183da8386", "type": "github" }, "original": { @@ -779,11 +954,11 @@ }, "nixpkgs_8": { "locked": { - "lastModified": 1744868846, - "narHash": "sha256-5RJTdUHDmj12Qsv7XOhuospjAjATNiTMElplWnJE9Hs=", + "lastModified": 1763191728, + "narHash": "sha256-esRhOS0APE6k40Hs/jjReXg+rx+J5LkWw7cuWFKlwYA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ebe4301cbd8f81c4f8d3244b3632338bbeb6d49c", + "rev": "1d4c88323ac36805d09657d13a5273aea1b34f0c", "type": "github" }, "original": { @@ -795,11 +970,11 @@ }, "nixpkgs_9": { "locked": { - "lastModified": 1751792365, - "narHash": "sha256-J1kI6oAj25IG4EdVlg2hQz8NZTBNYvIS0l4wpr9KcUo=", + "lastModified": 1762977756, + "narHash": "sha256-4PqRErxfe+2toFJFgcRKZ0UI9NSIOJa+7RXVtBhy4KE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1fd8bada0b6117e6c7eb54aad5813023eed37ccb", + "rev": "c5ae371f1a6a7fd27823bc500d9390b38c05fa55", "type": "github" }, "original": { @@ -821,11 +996,11 @@ ] }, "locked": { - "lastModified": 1751906969, - "narHash": "sha256-BSQAOdPnzdpOuCdAGSJmefSDlqmStFNScEnrWzSqKPw=", + "lastModified": 1758998580, + "narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=", "owner": "nix-community", "repo": "NUR", - "rev": "ddb679f4131e819efe3bbc6457ba19d7ad116f25", + "rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728", "type": "github" }, "original": { @@ -837,17 +1012,17 @@ "nvf": { "inputs": { "flake-compat": "flake-compat_4", - "flake-parts": "flake-parts", + "flake-parts": "flake-parts_2", "mnw": "mnw", "nixpkgs": "nixpkgs_7", - "systems": "systems_4" + "systems": "systems_5" }, "locked": { - "lastModified": 1755115677, - "narHash": "sha256-98Ad2F5w1xW94KymQiBohNBYpFqMa0K28v9S1SzyTY8=", + "lastModified": 1762622004, + "narHash": "sha256-NpzzgaoMK8aRHnndHWbYNKLcZN0r1y6icCoJvGoBsoE=", "owner": "notashelf", "repo": "nvf", - "rev": "c5dc7192496a1fad38134e54f8b4fca8ac51a9fe", + "rev": "09470524a214ed26633ddc2b6ec0c9bf31a8b909", "type": "github" }, "original": { @@ -866,11 +1041,11 @@ ] }, "locked": { - "lastModified": 1754501628, - "narHash": "sha256-FExJ54tVB5iu7Dh2tLcyCSWpaV+lmUzzWKZUkemwXvo=", + "lastModified": 1762784320, + "narHash": "sha256-odsk96Erywk5hs0dhArF38zb7Oe0q6LZ70gXbxAPKno=", "owner": "nix-community", "repo": "plasma-manager", - "rev": "cca090f8115c4172b9aef6c5299ae784bdd5e133", + "rev": "7911a0f8a44c7e8b29d031be3149ee8943144321", "type": "github" }, "original": { @@ -881,6 +1056,7 @@ }, "root": { "inputs": { + "clan-core": "clan-core", "erosanix": "erosanix", "fenix": "fenix", "firefox": "firefox", @@ -897,19 +1073,20 @@ "nvf": "nvf", "plasma-manager": "plasma-manager", "snowfall-lib": "snowfall-lib", - "sops-nix": "sops-nix", + "sops-nix": "sops-nix_2", "stylix": "stylix", + "terranix": "terranix", "zen-browser": "zen-browser" } }, "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1755004716, - "narHash": "sha256-TbhPR5Fqw5LjAeI3/FOPhNNFQCF3cieKCJWWupeZmiA=", + "lastModified": 1762860488, + "narHash": "sha256-rMfWMCOo/pPefM2We0iMBLi2kLBAnYoB9thi4qS7uk4=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "b2a58b8c6eff3c3a2c8b5c70dbf69ead78284194", + "rev": "2efc80078029894eec0699f62ec8d5c1a56af763", "type": "github" }, "original": { @@ -919,6 +1096,27 @@ "type": "github" } }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "himmelblau", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1759977258, + "narHash": "sha256-hOxEFSEBoqDmJb7BGX1CzT1gvUPK6r+Qs+n3IxBgfTs=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "1d0c6173f57d07db7957b50e799240d4f2d7520f", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, "snowfall-lib": { "inputs": { "flake-compat": "flake-compat_5", @@ -942,15 +1140,36 @@ } }, "sops-nix": { + "inputs": { + "nixpkgs": [ + "clan-core", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763264763, + "narHash": "sha256-N0BEoJIlJ+M6sWZJ8nnfAjGY9VLvM6MXMitRenmhBkY=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "882e56c8293e44d57d882b800a82f8b2ee7a858f", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "sops-nix_2": { "inputs": { "nixpkgs": "nixpkgs_8" }, "locked": { - "lastModified": 1754988908, - "narHash": "sha256-t+voe2961vCgrzPFtZxha0/kmFSHFobzF00sT8p9h0U=", + "lastModified": 1763509310, + "narHash": "sha256-s2WzTAD3vJtPACBCZXezNUMTG/wC6SFsU9DxazB9wDI=", "owner": "Mic92", "repo": "sops-nix", - "rev": "3223c7a92724b5d804e9988c6b447a0d09017d48", + "rev": "3ee33c0ed7c5aa61b4e10484d2ebdbdc98afb03e", "type": "github" }, "original": { @@ -966,11 +1185,11 @@ "base16-helix": "base16-helix", "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", - "flake-parts": "flake-parts_2", + "flake-parts": "flake-parts_3", "gnome-shell": "gnome-shell", "nixpkgs": "nixpkgs_9", "nur": "nur", - "systems": "systems_6", + "systems": "systems_7", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", "tinted-schemes": "tinted-schemes", @@ -978,11 +1197,11 @@ "tinted-zed": "tinted-zed" }, "locked": { - "lastModified": 1755027820, - "narHash": "sha256-hBSU7BEhd05y/pC9tliYjkFp8AblkbNEkPei229+0Pg=", + "lastModified": 1763497248, + "narHash": "sha256-OGP6MYc+lVkLVQOTS6ORszDcCnZm7kDOGpFBdDoLd0k=", "owner": "nix-community", "repo": "stylix", - "rev": "c592717e9f713bbae5f718c784013d541346363d", + "rev": "f19ac46f6aa26188b2020ed40066a5b832be9c53", "type": "github" }, "original": { @@ -1081,6 +1300,58 @@ "type": "github" } }, + "systems_7": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "terranix": { + "inputs": { + "flake-parts": "flake-parts_4", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_8" + }, + "locked": { + "lastModified": 1762472226, + "narHash": "sha256-iVS4sxVgGn+T74rGJjEJbzx+kjsuaP3wdQVXBNJ79A0=", + "owner": "terranix", + "repo": "terranix", + "rev": "3b5947a48da5694094b301a3b1ef7b22ec8b19fc", + "type": "github" + }, + "original": { + "owner": "terranix", + "repo": "terranix", + "type": "github" + } + }, "tinted-foot": { "flake": false, "locked": { @@ -1117,11 +1388,11 @@ "tinted-schemes": { "flake": false, "locked": { - "lastModified": 1750770351, - "narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=", + "lastModified": 1757716333, + "narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=", "owner": "tinted-theming", "repo": "schemes", - "rev": "5a775c6ffd6e6125947b393872cde95867d85a2a", + "rev": "317a5e10c35825a6c905d912e480dfe8e71c7559", "type": "github" }, "original": { @@ -1133,11 +1404,11 @@ "tinted-tmux": { "flake": false, "locked": { - "lastModified": 1751159871, - "narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=", + "lastModified": 1757811970, + "narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=", "owner": "tinted-theming", "repo": "tinted-tmux", - "rev": "bded5e24407cec9d01bd47a317d15b9223a1546c", + "rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e", "type": "github" }, "original": { @@ -1149,11 +1420,11 @@ "tinted-zed": { "flake": false, "locked": { - "lastModified": 1751158968, - "narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=", + "lastModified": 1757811247, + "narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=", "owner": "tinted-theming", "repo": "base16-zed", - "rev": "86a470d94204f7652b906ab0d378e4231a5b3384", + "rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e", "type": "github" }, "original": { @@ -1162,20 +1433,44 @@ "type": "github" } }, - "zen-browser": { + "treefmt-nix": { "inputs": { - "nixpkgs": "nixpkgs_10" + "nixpkgs": [ + "clan-core", + "nixpkgs" + ] }, "locked": { - "lastModified": 1727721329, - "narHash": "sha256-QYlWZwUSwrM7BuO+dXclZIwoPvBIuJr6GpFKv9XKFPI=", - "owner": "MarceColl", - "repo": "zen-browser-flake", - "rev": "e6ab73f405e9a2896cce5956c549a9cc359e5fcc", + "lastModified": 1762938485, + "narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4", "type": "github" }, "original": { - "owner": "MarceColl", + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "zen-browser": { + "inputs": { + "home-manager": "home-manager_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1763521945, + "narHash": "sha256-Zcrafbe4niRJMbzaVOwg7+iedJhwBFttre2DpyCC6qA=", + "owner": "0xc000022070", + "repo": "zen-browser-flake", + "rev": "24d7381b9231c23daceec5d372cc28e877f7785d", + "type": "github" + }, + "original": { + "owner": "0xc000022070", "repo": "zen-browser-flake", "type": "github" } diff --git a/flake.nix b/flake.nix index d696f4b..d7a7508 100644 --- a/flake.nix +++ b/flake.nix @@ -41,7 +41,10 @@ inputs.nixpkgs.follows = "nixpkgs"; }; - zen-browser.url = "github:MarceColl/zen-browser-flake"; + zen-browser = { + url = "github:0xc000022070/zen-browser-flake"; + inputs.nixpkgs.follows = "nixpkgs"; + }; nix-minecraft.url = "github:Infinidoge/nix-minecraft"; @@ -63,11 +66,11 @@ url = "github:Jovian-Experiments/Jovian-NixOS"; inputs.nixpkgs.follows = "nixpkgs"; }; - + grub2-themes = { url = "github:vinceliuice/grub2-themes"; }; - + nixos-wsl = { url = "github:nix-community/nixos-wsl"; inputs = { @@ -75,6 +78,16 @@ flake-compat.follows = ""; }; }; + + terranix = { + url = "github:terranix/terranix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + clan-core = { + url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs: inputs.snowfall-lib.mkFlake { @@ -93,8 +106,15 @@ channels-config = { allowUnfree = true; permittedInsecurePackages = [ + # Due to *arr stack "dotnet-sdk-6.0.428" "aspnetcore-runtime-6.0.36" + + # I think this is because of zen + "qtwebengine-5.15.19" + + # For Nheko, the matrix client + "olm-3.2.16" ]; }; @@ -104,9 +124,13 @@ flux.overlays.default ]; + systems.modules = with inputs; [ + clan-core.nixosModules.default + ]; + homes.modules = with inputs; [ stylix.homeModules.stylix - plasma-manager.homeManagerModules.plasma-manager + plasma-manager.homeModules.plasma-manager ]; }; } diff --git a/homes/x86_64-linux/chris@manwe/default.nix b/homes/x86_64-linux/chris@manwe/default.nix index cd6fa1a..9abe613 100644 --- a/homes/x86_64-linux/chris@manwe/default.nix +++ b/homes/x86_64-linux/chris@manwe/default.nix @@ -35,6 +35,7 @@ bitwarden.enable = true; discord.enable = true; ladybird.enable = true; + matrix.enable = true; obs.enable = true; onlyoffice.enable = true; signal.enable = true; diff --git a/lib/options/default.nix b/lib/options/default.nix new file mode 100644 index 0000000..72e8621 --- /dev/null +++ b/lib/options/default.nix @@ -0,0 +1,38 @@ +{ lib, ...}: +let + inherit (builtins) isString typeOf; + inherit (lib) mkOption types throwIfNot concatStringsSep splitStringBy toLower map; +in +{ + options = { + mkUrlOptions = + defaults: + { + host = mkOption { + type = types.str; + example = "host.tld"; + description = '' + Hostname + ''; + } // (defaults.host or {}); + + port = mkOption { + type = types.port; + default = 1234; + example = "1234"; + description = '' + Port + ''; + } // (defaults.port or {}); + + protocol = mkOption { + type = types.str; + default = "https"; + example = "https"; + description = '' + Which protocol to use when creating a url string + ''; + } // (defaults.protocol or {}); + }; + }; +} \ No newline at end of file diff --git a/lib/strings/default.nix b/lib/strings/default.nix new file mode 100644 index 0000000..0c15699 --- /dev/null +++ b/lib/strings/default.nix @@ -0,0 +1,39 @@ +{ lib, ...}: +let + inherit (builtins) isString typeOf match toString head; + inherit (lib) throwIfNot concatStringsSep splitStringBy toLower map concatMapAttrsStringSep; +in +{ + strings = { + #======================================================================================== + # Converts a string to snake case + # + # simply replaces any uppercase letter to its lowercase variant preceeded by an underscore + #======================================================================================== + toSnakeCase = + str: + throwIfNot (isString str) "toSnakeCase only accepts string values, but got ${typeOf str}" ( + str + |> splitStringBy (prev: curr: builtins.match "[a-z]" prev != null && builtins.match "[A-Z]" curr != null) true + |> map (p: toLower p) + |> concatStringsSep "_" + ); + + #======================================================================================== + # Converts a set of url parts to a string + #======================================================================================== + toUrl = + { protocol ? null, host, port ? null, path ? null, query ? null, hash ? null }: + let + trim_slashes = str: str |> match "^\/*(.+?)\/*$" |> head; + encode_to_str = set: concatMapAttrsStringSep "&" (n: v: "${n}=${v}") set; + + _protocol = if protocol != null then "${protocol}://" else ""; + _port = if port != null then ":${toString port}" else ""; + _path = if path != null then "/${path |> trim_slashes}" else ""; + _query = if query != null then "?${query |> encode_to_str}" else ""; + _hash = if hash != null then "#${hash |> encode_to_str}" else ""; + in + "${_protocol}${host}${_port}${_path}${_query}${_hash}"; + }; +} \ No newline at end of file diff --git a/modules/home/application/matrix/default.nix b/modules/home/application/matrix/default.nix new file mode 100644 index 0000000..867a94f --- /dev/null +++ b/modules/home/application/matrix/default.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, namespace, osConfig ? {}, ... }: +let + inherit (lib) mkIf mkEnableOption; + + cfg = config.${namespace}.application.matrix; +in +{ + options.${namespace}.application.matrix = { + enable = mkEnableOption "enable Matrix client (Fractal)"; + }; + + config = mkIf cfg.enable { + home.packages = with pkgs; [ fractal element-desktop ]; + + programs.element-desktop = { + enable = true; + }; + }; +} diff --git a/modules/home/application/zen/default.nix b/modules/home/application/zen/default.nix index ad4cb92..b7cec03 100644 --- a/modules/home/application/zen/default.nix +++ b/modules/home/application/zen/default.nix @@ -5,35 +5,61 @@ let cfg = config.${namespace}.application.zen; in { + imports = [ + inputs.zen-browser.homeModules.default + ]; + options.${namespace}.application.zen = { enable = mkEnableOption "enable zen"; }; config = mkIf cfg.enable { - home.packages = [ inputs.zen-browser.packages.${pkgs.system}.specific ]; - home.sessionVariables = { MOZ_ENABLE_WAYLAND = "1"; }; programs.zen-browser = { + enable = true; + policies = { AutofillAddressEnabled = true; AutofillCreditCardEnabled = false; + + AppAutoUpdate = false; DisableAppUpdate = true; + ManualAppUpdateOnly = true; + DisableFeedbackCommands = true; DisableFirefoxStudies = true; DisablePocket = true; DisableTelemetry = true; - # DontCheckDefaultBrowser = false; + + DontCheckDefaultBrowser = false; NoDefaultBookmarks = true; - # OfferToSaveLogins = false; + OfferToSaveLogins = false; EnableTrackingProtection = { Value = true; Locked = true; Cryptomining = true; Fingerprinting = true; }; + + HttpAllowlist = [ + "http://ulmo" + ]; + }; + + policies.ExtensionSettings = let + mkExtension = id: { + install_url = "https://addons.mozilla.org/firefox/downloads/latest/${builtins.toString id}/latest.xpi"; + installation_mode = "force_installed"; + }; + in + { + ublock_origin = 4531307; + ghostry = 4562168; + bitwarden = 4562769; + sponsorblock = 4541835; }; }; }; diff --git a/modules/home/desktop/plasma/default.nix b/modules/home/desktop/plasma/default.nix index 13476fb..0b679a0 100644 --- a/modules/home/desktop/plasma/default.nix +++ b/modules/home/desktop/plasma/default.nix @@ -64,7 +64,7 @@ in }; kwalletrc = { - Wallet.Enabled = false; + Wallet.Enabled = true; }; plasmarc = { diff --git a/modules/home/editor/zed/default.nix b/modules/home/editor/zed/default.nix index b35acba..f0fe7fa 100644 --- a/modules/home/editor/zed/default.nix +++ b/modules/home/editor/zed/default.nix @@ -15,7 +15,7 @@ in { programs.zed-editor = { enable = true; - extensions = [ "nix" "toml" "html" ]; + extensions = [ "nix" "toml" "html" "just-ls" ]; userSettings = { assistant.enabled = false; diff --git a/modules/home/home-manager/default.nix b/modules/home/home-manager/default.nix index 93bae2e..5f3be03 100644 --- a/modules/home/home-manager/default.nix +++ b/modules/home/home-manager/default.nix @@ -4,7 +4,9 @@ let in { systemd.user.startServices = "sd-switch"; - programs.home-manager.enable = true; + programs.home-manager = { + enable = true; + }; home.stateVersion = mkDefault (osConfig.system.stateVersion or "25.05"); -} \ No newline at end of file +} diff --git a/modules/home/shell/default.nix b/modules/home/shell/default.nix index d1df4cb..9968e54 100644 --- a/modules/home/shell/default.nix +++ b/modules/home/shell/default.nix @@ -17,6 +17,7 @@ in eza.enable = true; fzf.enable = true; git.enable = true; + just.enable = true; starship.enable = true; tmux.enable = true; yazi.enable = true; diff --git a/modules/home/shell/toolset/git/default.nix b/modules/home/shell/toolset/git/default.nix index 3edfb60..299b2a6 100644 --- a/modules/home/shell/toolset/git/default.nix +++ b/modules/home/shell/toolset/git/default.nix @@ -31,9 +31,11 @@ in package = pkgs.gitFull; difftastic = { enable = true; - background = "dark"; - color = "always"; - display = "inline"; + options = { + background = "dark"; + color = "always"; + display = "inline"; + }; }; ignores = [ diff --git a/modules/home/shell/toolset/just/default.nix b/modules/home/shell/toolset/just/default.nix new file mode 100644 index 0000000..e956b2a --- /dev/null +++ b/modules/home/shell/toolset/just/default.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, namespace, ... }: +let + inherit (lib) mkEnableOption mkIf; + + cfg = config.${namespace}.shell.toolset.just; +in +{ + options.${namespace}.shell.toolset.just = { + enable = mkEnableOption "version-control system"; + }; + + config = mkIf cfg.enable { + home.packages = with pkgs; [ just gum ]; + }; +} diff --git a/modules/home/themes/default.nix b/modules/home/themes/default.nix index 276e850..3fb8f15 100644 --- a/modules/home/themes/default.nix +++ b/modules/home/themes/default.nix @@ -31,7 +31,9 @@ in { base16Scheme = "${pkgs.base16-schemes}/share/themes/${cfg.theme}.yaml"; image = ./${cfg.theme}.jpg; polarity = cfg.polarity; - targets.qt.platform = mkDefault "kde6"; + +# targets.qt.platform = mkDefault "kde"; + targets.zen-browser.profileNames = [ "Chris" ]; fonts = { serif = { @@ -50,7 +52,7 @@ in { }; emoji = { - package = pkgs.noto-fonts-emoji; + package = pkgs.noto-fonts-color-emoji; name = "Noto Color Emoji"; }; }; diff --git a/modules/nixos/desktop/plasma/default.nix b/modules/nixos/desktop/plasma/default.nix index 11c0cd9..d1e2a28 100644 --- a/modules/nixos/desktop/plasma/default.nix +++ b/modules/nixos/desktop/plasma/default.nix @@ -12,7 +12,18 @@ in }; config = mkIf cfg.enable { - environment.plasma6.excludePackages = with pkgs.kdePackages; [ konsole kate ghostwriter oxygen ]; + environment.plasma6.excludePackages = with pkgs.kdePackages; [ + elisa + kmahjongg + kmines + konversation + kpat + ksudoku + konsole + kate + ghostwriter + oxygen + ]; environment.sessionVariables.NIXOS_OZONE_WL = "1"; services = { diff --git a/modules/nixos/hardware/gpu/amd/default.nix b/modules/nixos/hardware/gpu/amd/default.nix index 68db574..cdc9d1e 100644 --- a/modules/nixos/hardware/gpu/amd/default.nix +++ b/modules/nixos/hardware/gpu/amd/default.nix @@ -17,11 +17,6 @@ in }; amdgpu = { - amdvlk = { - enable = true; - support32Bit.enable = true; - }; - initrd.enable = true; }; }; diff --git a/modules/nixos/home-manager/default.nix b/modules/nixos/home-manager/default.nix new file mode 100644 index 0000000..d147d46 --- /dev/null +++ b/modules/nixos/home-manager/default.nix @@ -0,0 +1,6 @@ +{ ... }: +{ + config = { + home-manager.backupFileExtension = "homeManagerBackup"; + }; +} diff --git a/modules/nixos/nix/default.nix b/modules/nixos/nix/default.nix index 7d1f069..bf96f59 100644 --- a/modules/nixos/nix/default.nix +++ b/modules/nixos/nix/default.nix @@ -1,24 +1,20 @@ { pkgs, lib, namespace, config, ... }: let - inherit (lib) mkIf mkEnableOption; - cfg = config.${namespace}.nix; in { - options.${namespace}.nix = { - enable = mkEnableOption "Enable nix command"; - }; + options.${namespace}.nix = {}; - config = mkIf cfg.enable { + config = { programs.git.enable = true; nix = { package = pkgs.nixVersions.latest; - extraOptions = "experimental-features = nix-command flakes"; + extraOptions = "experimental-features = nix-command flakes pipe-operators"; settings = { - experimental-features = [ "nix-command" "flakes" ]; + experimental-features = [ "nix-command" "flakes" "pipe-operators" ]; allowed-users = [ "@wheel" ]; trusted-users = [ "@wheel" ]; diff --git a/modules/nixos/services/authentication/zitadel/default.nix b/modules/nixos/services/authentication/zitadel/default.nix index a95d849..9a02f01 100644 --- a/modules/nixos/services/authentication/zitadel/default.nix +++ b/modules/nixos/services/authentication/zitadel/default.nix @@ -1,33 +1,595 @@ -{ config, lib, pkgs, namespace, ... }: +{ config, lib, pkgs, namespace, system, inputs, ... }: let - inherit (lib) mkIf mkEnableOption mkForce; + inherit (lib) mkIf mkEnableOption mkOption types toUpper toSentenceCase nameValuePair mapAttrs mapAttrs' concatMapAttrs concatMapStringsSep filterAttrsRecursive listToAttrs imap0 head drop length literalExpression attrNames; + inherit (lib.${namespace}.strings) toSnakeCase; cfg = config.${namespace}.services.authentication.zitadel; - db_name = "zitadel"; - db_user = "zitadel"; + database = "zitadel"; in { options.${namespace}.services.authentication.zitadel = { enable = mkEnableOption "Zitadel"; + + organization = mkOption { + type = types.attrsOf (types.submodule ({ name, ... }: { + options = + let + org = name; + in + { + isDefault = mkOption { + type = types.bool; + default = false; + example = "true"; + description = '' + True sets the org as default org for the instance. Only one org can be default org. + Nothing happens if you set it to false until you set another org as default org. + ''; + }; + + project = mkOption { + default = {}; + type = types.attrsOf (types.submodule { + options = { + hasProjectCheck = mkOption { + type = types.bool; + default = false; + example = "true"; + description = '' + ZITADEL checks if the org of the user has permission to this project. + ''; + }; + + privateLabelingSetting = mkOption { + type = types.nullOr (types.enum [ "unspecified" "enforceProjectResourceOwnerPolicy" "allowLoginUserResourceOwnerPolicy" ]); + default = null; + example = "enforceProjectResourceOwnerPolicy"; + description = '' + Defines from where the private labeling should be triggered, + + supported values: + - unspecified + - enforceProjectResourceOwnerPolicy + - allowLoginUserResourceOwnerPolicy + ''; + }; + + projectRoleAssertion = mkOption { + type = types.bool; + default = false; + example = "true"; + description = '' + Describes if roles of user should be added in token. + ''; + }; + + projectRoleCheck = mkOption { + type = types.bool; + default = false; + example = "true"; + description = '' + ZITADEL checks if the user has at least one on this project. + ''; + }; + + role = mkOption { + default = {}; + type = types.attrsOf (types.submodule ({ name, ... }: { + options = + let + roleName = name; + in + { + displayName = mkOption { + type = types.str; + default = toSentenceCase name; + example = "RoleName"; + description = '' + Name used for project role. + ''; + }; + + group = mkOption { + type = types.nullOr types.str; + default = null; + example = "some_group"; + description = '' + Group used for project role. + ''; + }; + }; + })); + }; + + assign = mkOption { + default = {}; + type = types.attrsOf (types.listOf types.str); + }; + + application = mkOption { + default = {}; + type = types.attrsOf (types.submodule { + options = { + redirectUris = mkOption { + type = types.nonEmptyListOf types.str; + example = '' + [ "https://example.com/redirect/url" ] + ''; + description = '' + . + ''; + }; + + grantTypes = mkOption { + type = types.nonEmptyListOf (types.enum [ "authorizationCode" "implicit" "refreshToken" "deviceCode" "tokenExchange" ]); + example = '' + [ "authorizationCode" ] + ''; + description = '' + . + ''; + }; + + responseTypes = mkOption { + type = types.nonEmptyListOf (types.enum [ "code" "idToken" "idTokenToken" ]); + example = '' + [ "code" ] + ''; + description = '' + . + ''; + }; + + exportMap = + let + strOpt = mkOption { type = types.nullOr types.str; default = null; }; + in + mkOption { + type = types.submodule { options = { client_id = strOpt; client_secret = strOpt; }; }; + default = {}; + example = literalExpression '' + { + client_id = "SSO_CLIENT_ID"; + client_secret = "SSO_CLIENT_SECRET"; + } + ''; + description = '' + Remap the outputted variables to another key. + ''; + }; + }; + }); + }; + }; + }); + }; + + user = mkOption { + default = {}; + type = types.attrsOf (types.submodule ({ name, ... }: { + options = + let + username = name; + in + { + email = mkOption { + type = types.str; + example = "someone@some.domain"; + description = '' + Username. + ''; + }; + + userName = mkOption { + type = types.nullOr types.str; + default = username; + example = "some_user_name"; + description = '' + Username. Default value is the key of the config object you created, you can overwrite that by setting this option + ''; + }; + + firstName = mkOption { + type = types.str; + example = "John"; + description = '' + First name of the user. + ''; + }; + + lastName = mkOption { + type = types.str; + example = "Doe"; + description = '' + Last name of the user. + ''; + }; + + roles = mkOption { + type = types.listOf types.str; + default = []; + example = "[ \"ORG_OWNER\" ]"; + description = '' + List of roles granted to organisation. + ''; + }; + + instanceRoles = mkOption { + type = types.listOf types.str; + default = []; + example = "[ \"IAM_OWNER\" ]"; + description = '' + List of roles granted to instance. + ''; + }; + }; + })); + }; + + action = mkOption { + default = {}; + type = types.attrsOf (types.submodule ({ name, ... }: { + options = { + script = mkOption { + type = types.str; + example = '' + (ctx, api) => { + api.v1.claims.setClaim('some_claim', 'some_value'); + }; + ''; + description = '' + The script to run. This must be a function that receives 2 parameters, and returns void. During the creation of the action's script this module simly does `const {{name}} = {{script}}`. + ''; + }; + + timeout = mkOption { + type = (types.ints.between 0 20); + default = 10; + example = "10"; + description = '' + After which time the action will be terminated if not finished. + ''; + }; + + allowedToFail = mkOption { + type = types.bool; + default = true; + example = "true"; + description = '' + Allowed to fail. + ''; + }; + }; + })); + }; + + triggers = mkOption { + default = []; + type = types.listOf (types.submodule { + options = { + flowType = mkOption { + type = types.enum [ "authentication" "customiseToken" "internalAuthentication" "samlResponse" ]; + example = "customiseToken"; + description = '' + Type of the flow to which the action triggers belong. + ''; + }; + + triggerType = mkOption { + type = types.enum [ "postAuthentication" "preCreation" "postCreation" "preUserinfoCreation" "preAccessTokenCreation" "preSamlResponse" ]; + example = "postAuthentication"; + description = '' + Trigger type on when the actions get triggered. + ''; + }; + + actions = mkOption { + type = types.nonEmptyListOf types.str; + example = ''[ "action_name" ]''; + description = '' + Names of actions to trigger + ''; + }; + }; + }); + }; + }; + })); + }; }; - config = mkIf cfg.enable { + config = let + _refTypeMap = { + org = { type = "org"; }; + project = { type = "project"; }; + user = { type = "user"; tfType = "human_user"; }; + }; + + mapRef' = { type, tfType ? type }: name: { "${type}Id" = "\${ resource.zitadel_${tfType}.${toSnakeCase name}.id }"; }; + mapRef = type: name: mapRef' (_refTypeMap.${type}) name; + mapEnum = prefix: value: "${prefix}_${value |> toSnakeCase |> toUpper}"; + + mapValue = type: value: ({ + appType = mapEnum "OIDC_APP_TYPE" value; + grantTypes = map (t: mapEnum "OIDC_GRANT_TYPE" t) value; + responseTypes = map (t: mapEnum "OIDC_RESPONSE_TYPE" t) value; + authMethodType = mapEnum "OIDC_AUTH_METHOD_TYPE" value; + + flowType = mapEnum "FLOW_TYPE" value; + triggerType = mapEnum "TRIGGER_TYPE" value; + accessTokenType = mapEnum "OIDC_TOKEN_TYPE" value; + }."${type}" or value); + + toResource = name: value: nameValuePair + (toSnakeCase name) + (lib.mapAttrs' (k: v: nameValuePair (toSnakeCase k) (mapValue k v)) value); + + withRef = type: name: attrs: attrs // (mapRef type name); + + select = keys: callback: set: + if (length keys) == 0 then + mapAttrs' callback set + else let key = head keys; in + concatMapAttrs (k: v: select (drop 1 keys) (callback k) (v.${key} or {})) set + ; + + append = attrList: set: set // (listToAttrs attrList); + forEach = src: key: set: + let + _key = concatMapStringsSep "_" (k: "\${item.${k}}") key; + in + { + forEach = "{ for item in ${src} : \"${_key}\" => item }"; + } + // set; + + config' = config; + + # this is a nix package, the generated json file to be exact + terraformConfiguration = inputs.terranix.lib.terranixConfiguration { + inherit system; + + modules = [ + ({ config, lib, ... }: { + config = { + terraform.required_providers.zitadel = { + source = "zitadel/zitadel"; + version = "2.2.0"; + }; + + provider.zitadel = { + domain = "auth.kruining.eu"; + insecure = "false"; + jwt_profile_file = "/var/lib/zitadel/machine-key.json"; + }; + + locals = { + extra_users = lib.tfRef " + flatten([ for org, users in jsondecode(file(\"${config'.sops.secrets."zitadel/users".path}\")): [ + for name, details in users: { + org = org + name = name + email = details.email + firstName = details.firstName + lastName = details.lastName + } + ] ]) + "; + orgs = cfg.organization |> mapAttrs (org: _: lib.tfRef "resource.zitadel_org.${org}.id"); + }; + + resource = { + # Organizations + zitadel_org = cfg.organization |> select [] (name: { isDefault, ... }: + { inherit name isDefault; } + |> toResource name + ); + + # Projects per organization + zitadel_project = cfg.organization |> select [ "project" ] (org: name: { hasProjectCheck, privateLabelingSetting, projectRoleAssertion, projectRoleCheck, ... }: + { + inherit name hasProjectCheck privateLabelingSetting projectRoleAssertion projectRoleCheck; + } + |> withRef "org" org + |> toResource "${org}_${name}" + ); + + # Each OIDC app per project + zitadel_application_oidc = cfg.organization |> select [ "project" "application" ] (org: project: name: { redirectUris, grantTypes, responseTypes, ...}: + { + inherit name redirectUris grantTypes responseTypes; + + accessTokenRoleAssertion = true; + idTokenRoleAssertion = true; + accessTokenType = "JWT"; + } + |> withRef "org" org + |> withRef "project" "${org}_${project}" + |> toResource "${org}_${project}_${name}" + ); + + # Each project role + zitadel_project_role = cfg.organization |> select [ "project" "role" ] (org: project: name: value: + { inherit (value) displayName group; roleKey = name; } + |> withRef "org" org + |> withRef "project" "${org}_${project}" + |> toResource "${org}_${project}_${name}" + ); + + # Each project role assignment + zitadel_user_grant = cfg.organization |> select [ "project" "assign" ] (org: project: user: roles: + { roleKeys = roles; } + |> withRef "org" org + |> withRef "project" "${org}_${project}" + |> withRef "user" "${org}_${user}" + |> toResource "${org}_${project}_${user}" + ); + + # Users + zitadel_human_user = + cfg.organization + |> select [ "user" ] (org: name: { email, userName, firstName, lastName, ... }: + { + inherit email userName firstName lastName; + + isEmailVerified = true; + } + |> withRef "org" org + |> toResource "${org}_${name}" + ) + |> append + [ + (forEach "local.extra_users" [ "org" "name" ] { + orgId = lib.tfRef "local.orgs[each.value.org]"; + userName = lib.tfRef "each.value.name"; + email = lib.tfRef "each.value.email"; + firstName = lib.tfRef "each.value.firstName"; + lastName = lib.tfRef "each.value.lastName"; + + isEmailVerified = true; + } + |> toResource "extraUsers") + ] + ; + + # Global user roles + zitadel_instance_member = + cfg.organization + |> filterAttrsRecursive (n: v: !(v ? "instanceRoles" && (length v.instanceRoles) == 0)) + |> select [ "user" ] (org: name: { instanceRoles, ... }: + { roles = instanceRoles; } + |> withRef "user" "${org}_${name}" + |> toResource "${org}_${name}" + ); + + # Organazation specific roles + zitadel_org_member = + cfg.organization + |> filterAttrsRecursive (n: v: !(v ? "roles" && (length v.roles) == 0)) + |> select [ "user" ] (org: name: { roles, ... }: + { inherit roles; } + |> withRef "org" org + |> withRef "user" "${org}_${name}" + |> toResource "${org}_${name}" + ); + + # Organazation's actions + zitadel_action = cfg.organization |> select [ "action" ] (org: name: { timeout, allowedToFail, script, ...}: + { + inherit allowedToFail name; + timeout = "${toString timeout}s"; + script = "const ${name} = ${script}"; + } + |> withRef "org" org + |> toResource "${org}_${name}" + ); + + # Organazation's action assignments + zitadel_trigger_actions = + cfg.organization + |> concatMapAttrs (org: { triggers, ... }: + triggers + |> imap0 (i: { flowType, triggerType, actions, ... }: (let name = "trigger_${toString i}"; in + { + inherit flowType triggerType; + + actionIds = + actions + |> map (action: (lib.tfRef "zitadel_action.${org}_${toSnakeCase action}.id")); + } + |> withRef "org" org + |> toResource "${org}_${name}" + )) + |> listToAttrs + ); + + # SMTP config + zitadel_smtp_config.default = { + sender_address = "chris@kruining.eu"; + sender_name = "no-reply (Zitadel)"; + tls = true; + host = "black-mail.nl:587"; + user = "chris@kruining.eu"; + password = lib.tfRef "file(\"${config'.sops.secrets."zitadel/email".path}\")"; + set_active = true; + }; + + # Client credentials per app + local_sensitive_file = cfg.organization |> select [ "project" "application" ] (org: project: name: { exportMap, ... }: + nameValuePair "${org}_${project}_${name}" { + content = '' + ${if exportMap.client_id != null then exportMap.client_id else "CLIENT_ID"}=${lib.tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_id"} + ${if exportMap.client_secret != null then exportMap.client_secret else "CLIENT_SECRET"}=${lib.tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_secret"} + ''; + filename = "/var/lib/zitadel/clients/${org}_${project}_${name}"; + } + ); + }; + }; + }) + ]; + }; + in + mkIf cfg.enable { + ${namespace}.services.persistance.postgresql.enable = true; + environment.systemPackages = with pkgs; [ zitadel ]; + systemd.tmpfiles.rules = [ + "d /tmp/zitadelApplyTerraform 0755 zitadel zitadel -" + "d /var/lib/zitadel/clients 0755 zitadel zitadel -" + ]; + + systemd.services.zitadelApplyTerraform = { + description = "Zitadel terraform apply"; + + wantedBy = [ "multi-user.target" ]; + wants = [ "zitadel.service" ]; + + script = '' + #!/usr/bin/env bash + + if [ "$(systemctl is-active zitadel)" != "active" ]; then + echo "Zitadel is not running" + exit 1 + fi + + # Print the path to the source for easier debugging + echo "config location: ${terraformConfiguration}" + + # Copy infra code into workspace + cp -f ${terraformConfiguration} config.tf.json + + # Initialize OpenTofu + ${lib.getExe pkgs.opentofu} init + + # Run the infrastructure code + # ${lib.getExe pkgs.opentofu} plan + ${lib.getExe pkgs.opentofu} apply -auto-approve + ''; + + serviceConfig = { + Type = "oneshot"; + User = "zitadel"; + Group = "zitadel"; + + WorkingDirectory = "/tmp/zitadelApplyTerraform"; + }; + }; + services = { zitadel = { enable = true; openFirewall = true; - # masterKeyFile = config.sops.secrets."zitadel/masterKey".path; - masterKeyFile = "/var/lib/zitadel/master_key"; + masterKeyFile = config.sops.secrets."zitadel/masterKey".path; tlsMode = "external"; settings = { Port = 9092; - ExternalDomain = "auth.amarth.cloud"; + ExternalDomain = "auth.kruining.eu"; ExternalPort = 443; ExternalSecure = true; @@ -40,39 +602,13 @@ in SecretHasher.Hasher.Algorithm = "argon2id"; }; - DefaultInstance = { - PasswordComplexityPolicy = { - MinLength = 20; - HasLowercase = false; - HasUppercase = false; - HasNumber = false; - HasSymbol = false; - }; - LoginPolicy = { - AllowRegister = false; - ForceMFA = true; - }; - LockoutPolicy = { - MaxPasswordAttempts = 5; - MaxOTPAttempts = 10; - }; - SMTPConfiguration = { - SMTP = { - Host = "black-mail.nl:587"; - User = "info@amarth.cloud"; - Password = "__TODO_USE_SOPS__"; - }; - FromName = "Amarth Zitadel"; - }; - }; - Database.postgres = { Host = "localhost"; # Zitadel will report error if port is not set Port = 5432; - Database = db_name; + Database = database; User = { - Username = db_user; + Username = database; SSL.Mode = "disable"; }; Admin = { @@ -83,9 +619,16 @@ in }; steps = { FirstInstance = { - InstanceName = "auth.amarth.cloud"; + # Not sure, this option seems to be mostly irrelevant + InstanceName = "eu"; + + MachineKeyPath = "/var/lib/zitadel/machine-key.json"; + # PatPath = "/var/lib/zitadel/machine-key.pat"; + # LoginClientPatPath = "/var/lib/zitadel/machine-key.json"; + Org = { - Name = "Amarth"; + Name = "kruining"; + Human = { UserName = "chris"; FirstName = "Chris"; @@ -96,39 +639,49 @@ in }; Password = "KaasIsAwesome1!"; }; + + Machine = { + Machine = { + Username = "terraform-service-user"; + Name = "Terraform"; + }; + MachineKey = { ExpirationDate = "2026-01-01T00:00:00Z"; Type = 1; }; + # Pat = { ExpirationDate = "2026-01-01T00:00:00Z"; }; + }; + + # LoginClient.Machine = { + # Username = "terraform-service-user"; + # Name = "Terraform"; + # }; }; }; }; + # extraStepsPaths = [ + # config.sops.templates."secrets.yaml".path + # ]; }; postgresql = { enable = true; - ensureDatabases = [ db_name ]; + ensureDatabases = [ database ]; ensureUsers = [ { - name = db_user; + name = database; ensureDBOwnership = true; } ]; - authentication = mkForce '' - # Generated file, do not edit! - # TYPE DATABASE USER ADDRESS METHOD - local all all trust - host all all 127.0.0.1/32 trust - host all all ::1/128 trust - ''; }; caddy = { enable = true; virtualHosts = { - "auth.amarth.cloud".extraConfig = '' - reverse_proxy h2c://127.0.0.1:9092 + "auth.kruining.eu".extraConfig = '' + reverse_proxy h2c://::1:9092 ''; }; extraConfig = '' - (auth-z) { - forward_auth h2c://127.0.0.1:9092 { + (auth) { + forward_auth h2c://::1:9092 { uri /api/authz/forward-auth copy_headers Remote-User Remote-Groups Remote-Email Remote-Name } @@ -136,12 +689,37 @@ in ''; }; }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; # Secrets - sops.secrets."zitadel/masterKey" = { - owner = "zitadel"; - group = "zitadel"; - restartUnits = [ "zitadel.service" ]; + sops = { + secrets = { + "zitadel/masterKey" = { + owner = "zitadel"; + group = "zitadel"; + restartUnits = [ "zitadel.service" ]; #EMGDB#6O$8qpGoLI1XjhUhnng1san@0 + }; + + "zitadel/email" = { + owner = "zitadel"; + group = "zitadel"; + key = "email/chris_kruining_eu"; + restartUnits = [ "zitadel.service" ]; + }; + + "zitadel/users" = { + owner = "zitadel"; + group = "zitadel"; + restartUnits = [ "zitadelApplyTerraform.service" ]; + }; + }; + + templates = { + "users.yml" = { + + }; + }; }; }; } diff --git a/modules/nixos/services/backup/borg/default.nix b/modules/nixos/services/backup/borg/default.nix new file mode 100644 index 0000000..9cbbea0 --- /dev/null +++ b/modules/nixos/services/backup/borg/default.nix @@ -0,0 +1,35 @@ +{ config, lib, pkgs, namespace, ... }: +let + inherit (lib) mkIf mkEnableOption; + + cfg = config.${namespace}.services.backup.borg; +in +{ + options.${namespace}.services.backup.borg = { + enable = mkEnableOption "Borg Backup"; + }; + + config = mkIf cfg.enable { + programs.ssh.extraConfig = '' + Host beheer.hazelhof.nl + Port 222 + User chris + AddressFamily inet + IdentityFile /home/chris/.ssh/id_ed25519 + ''; + + services = { + borgbackup.jobs = { + media = { + paths = "/var/media/test"; + encryption.mode = "none"; + # environment.BORG_SSH = "ssh -4 -i /home/chris/.ssh/id_ed25519"; + environment.BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK = "yes"; + repo = "ssh://beheer.hazelhof.nl//media"; + compression = "auto,zstd"; + startAt = "daily"; + }; + }; + }; + }; +} diff --git a/modules/nixos/services/communication/matrix/default.nix b/modules/nixos/services/communication/matrix/default.nix new file mode 100644 index 0000000..ce92df4 --- /dev/null +++ b/modules/nixos/services/communication/matrix/default.nix @@ -0,0 +1,200 @@ +{ config, lib, pkgs, namespace, ... }: +let + inherit (builtins) toString toJSON; + inherit (lib) mkIf mkEnableOption; + + cfg = config.${namespace}.services.communication.matrix; + + domain = "kruining.eu"; + fqn = "matrix.${domain}"; + port = 4001; + + database = "synapse"; +in +{ + options.${namespace}.services.communication.matrix = { + enable = mkEnableOption "Matrix server (Synapse)"; + }; + + config = mkIf cfg.enable { + ${namespace}.services = { + persistance.postgresql.enable = true; + # virtualisation.podman.enable = true; + }; + + networking.firewall.allowedTCPPorts = [ 4001 ]; + + services = { + matrix-synapse = { + enable = true; + + extras = [ "oidc" ]; + + extraConfigFiles = [ + config.sops.templates."synapse-oidc.yaml".path + ]; + + settings = { + server_name = domain; + public_baseurl = "https://${fqn}"; + + enable_metrics = true; + + registration_shared_secret = "tZtBnlhEmLbMwF0lQ112VH1Rl5MkZzYH9suI4pEoPXzk6nWUB8FJF4eEnwLkbstz"; + + url_preview_enabled = true; + precence.enabled = true; + + # Since we'll be using OIDC for auth disable all local options + enable_registration = false; + enable_registration_without_verification = false; + password_config.enabled = false; + backchannel_logout_enabled = true; + + sso = { + client_whitelist = [ "http://[::1]:9092" ]; + update_profile_information = true; + }; + + database = { + # this is postgresql (also the default, but I prefer to be explicit) + name = "psycopg2"; + args = { + database = database; + user = database; + }; + }; + + listeners = [ + { + bind_addresses = ["::"]; + port = port; + type = "http"; + tls = false; + x_forwarded = true; + + resources = [ + { + names = [ "client" "federation" "openid" "metrics" "media" "health" ]; + compress = true; + } + ]; + } + ]; + }; + }; + + mautrix-signal = { + enable = true; + registerToSynapse = true; + + settings = { + appservice = { + provisioning.enabled = false; + # port = 40011; + }; + + homeserver = { + address = "http://[::1]:${toString port}"; + domain = domain; + }; + + bridge = { + permissions = { + "@chris:${domain}" = "admin"; + }; + }; + }; + }; + + mautrix-whatsapp = { + enable = true; + registerToSynapse = true; + + settings = { + appservice = { + provisioning.enabled = false; + # port = 40012; + }; + + homeserver = { + address = "http://[::1]:${toString port}"; + domain = domain; + }; + + bridge = { + permissions = { + "@chris:${domain}" = "admin"; + }; + }; + }; + }; + + postgresql = { + enable = true; + ensureDatabases = [ database ]; + ensureUsers = [ + { + name = database; + ensureDBOwnership = true; + } + ]; + }; + + caddy = { + enable = true; + virtualHosts = let + server = { + "m.server" = "${fqn}:443"; + }; + client = { + "m.homeserver".base_url = "https://${fqn}"; + "m.identity_server".base_url = "https://auth.kruining.eu"; + }; + in { + "${domain}".extraConfig = '' + header /.well-known/matrix/* Content-Type application/json + header /.well-known/matrix/* Access-Control-Allow-Origin * + respond /.well-known/matrix/server `${toJSON server}` + respond /.well-known/matrix/client `${toJSON client}` + ''; + "${fqn}".extraConfig = '' + reverse_proxy /_matrix/* http://::1:4001 + reverse_proxy /_synapse/client/* http://::1:4001 + ''; + }; + }; + }; + + sops = { + secrets = { + "synapse/oidc_id" = {}; + "synapse/oidc_secret" = {}; + }; + + templates = { + "synapse-oidc.yaml" = { + owner = "matrix-synapse"; + content = '' + oidc_providers: + - discover: true + idp_id: zitadel + idp_name: Zitadel + issuer: "https://auth.kruining.eu" + scopes: + - openid + - profile + client_id: '${config.sops.placeholder."synapse/oidc_id"}' + client_secret: '${config.sops.placeholder."synapse/oidc_secret"}' + backchannel_logout_enabled: true + user_mapping_provider: + config: + localpart_template: "{{ user.preferred_username }}" + display_name_template: "{{ user.name }}" + ''; + restartUnits = [ "matrix-synapse.service" ]; + }; + }; + }; + }; +} diff --git a/modules/nixos/services/development/forgejo/default.nix b/modules/nixos/services/development/forgejo/default.nix index bdabbd6..52f026f 100644 --- a/modules/nixos/services/development/forgejo/default.nix +++ b/modules/nixos/services/development/forgejo/default.nix @@ -1,6 +1,7 @@ { config, lib, pkgs, namespace, ... }: let - inherit (lib) mkIf mkEnableOption; + inherit (builtins) toString; + inherit (lib) mkIf mkEnableOption mkOption; cfg = config.${namespace}.services.development.forgejo; domain = "git.amarth.cloud"; @@ -8,10 +9,22 @@ in { options.${namespace}.services.development.forgejo = { enable = mkEnableOption "Forgejo"; + + port = mkOption { + type = lib.types.port; + default = 5002; + example = "1234"; + description = '' + Which port to bind forgejo to + ''; + }; }; config = mkIf cfg.enable { - ${namespace}.services.virtualisation.podman.enable = true; + ${namespace}.services = { + persistance.postgresql.enable = true; + virtualisation.podman.enable = true; + }; environment.systemPackages = with pkgs; [ forgejo ]; @@ -30,7 +43,7 @@ in server = { DOMAIN = domain; ROOT_URL = "https://${domain}/"; - HTTP_PORT = 5002; + HTTP_PORT = cfg.port; LANDING_PAGE = "explore"; }; @@ -80,7 +93,7 @@ in openid = { ENABLE_OPENID_SIGNIN = true; ENABLE_OPENID_SIGNUP = true; - WHITELISTED_URIS = "https://auth.amarth.cloud"; + WHITELISTED_URIS = "https://auth.kruining.eu"; }; oauth2_client = { @@ -91,6 +104,7 @@ in actions = { ENABLED = true; + # DEFAULT_ACTIONS_URL = "https://data.forgejo.org"; }; other = { @@ -98,12 +112,16 @@ in SHOW_FOOTER_TEMPLATE_LOAD_TIME = false; }; + metrics = { + ENABLED = true; + }; + api = { ENABLE_SWAGGER = false; }; mirror = { - ENABLED = false; + ENABLED = true; }; session = { @@ -116,9 +134,9 @@ in PROTOCOL = "smtp+starttls"; SMTP_ADDR = "black-mail.nl"; SMTP_PORT = 587; - FROM = "info@amarth.cloud"; - USER = "info@amarth.cloud"; - PASSWD = "__TODO_USE_SOPS__"; + FROM = "chris@kruining.eu"; + USER = "chris@kruining.eu"; + PASSWD_URI = "file:${config.sops.secrets."forgejo/email".path}"; }; }; }; @@ -126,20 +144,22 @@ in openssh.settings.AllowUsers = [ "forgejo" ]; gitea-actions-runner = { - package = pkgs.forgejo-actions-runner; + package = pkgs.forgejo-runner; instances.default = { enable = true; name = "default"; url = "https://git.amarth.cloud"; # Obtaining the path to the runner token file may differ # tokenFile should be in format TOKEN=, since it's EnvironmentFile for systemd - # tokenFile = config.age.secrets.forgejo-runner-token.path; - token = "ZBetud1F0IQ9VjVFpZ9bu0FXgx9zcsy1x25yvjhw"; + tokenFile = config.sops.secrets."forgejo/action_runner_token".path; + # token = "ZBetud1F0IQ9VjVFpZ9bu0FXgx9zcsy1x25yvjhw"; labels = [ - "default:docker://node:22-bullseye" + "default:docker://nixos/nix:latest" + "ubuntu:docker://ubuntu:24-bookworm" + "nix:docker://git.amarth.cloud/amarth/runners/default:latest" ]; settings = { - + log.level = "info"; }; }; }; @@ -147,17 +167,32 @@ in caddy = { enable = true; virtualHosts = { - ${domain}.extraConfig = '' - # import auth-z + "${domain}".extraConfig = '' + # import auth # stupid dumb way to prevent the login page and go to zitadel instead # be aware that this does not disable local login at all! - rewrite /user/login /user/oauth2/Zitadel + # rewrite /user/login /user/oauth2/Zitadel - reverse_proxy http://127.0.0.1:5002 + reverse_proxy http://127.0.0.1:${toString cfg.port} ''; }; }; }; + + sops.secrets = { + "forgejo/action_runner_token" = { + owner = "gitea-runner"; + group = "gitea-runner"; + restartUnits = [ "gitea-runner-default.service" ]; + }; + + "forgejo/email" = { + owner = "forgejo"; + group = "forgejo"; + key = "email/chris_kruining_eu"; + restartUnits = [ "forgejo.service" ]; + }; + }; }; } diff --git a/modules/nixos/services/media/default.nix b/modules/nixos/services/media/default.nix index f76e4ae..1950bf0 100644 --- a/modules/nixos/services/media/default.nix +++ b/modules/nixos/services/media/default.nix @@ -1,9 +1,11 @@ -{ pkgs, lib, namespace, config, ... }: +{ pkgs, lib, namespace, config, inputs, system, ... }: let inherit (lib) mkIf mkEnableOption mkOption; inherit (lib.types) str; cfg = config.${namespace}.services.media; + + arr = ["radarr" ]; in { options.${namespace}.services.media = { @@ -60,44 +62,74 @@ in "d '${cfg.path}/reiverr/config' 0700 ${cfg.user} ${cfg.group} - -" "d '${cfg.path}/downloads/incomplete' 0700 ${cfg.user} ${cfg.group} - -" "d '${cfg.path}/downloads/done' 0700 ${cfg.user} ${cfg.group} - -" + "d /var/lib/radarrApplyTerraform 0755 ${cfg.user} ${cfg.group} -" ]; #========================================================================= # Services #========================================================================= services = let - serviceConf = { + arr-services = + arr + |> lib.imap (i: service: { + name = service; + value = { + enable = true; + openFirewall = true; + + environmentFiles = [ + config.sops.templates."${service}/config.env".path + ]; + + settings = { + auth.authenticationMethod = "External"; + + server = { + bindaddress = "0.0.0.0"; + port = 2000 + i; + }; + + postgres = { + host = "localhost"; + port = "5432"; + user = service; + maindb = service; + logdb = service; + }; + }; + } + // (if service != "prowlarr" then { user = cfg.user; group = cfg.group; } else {}); + }) + |> lib.listToAttrs + ; + in + arr-services // { + bazarr = { + enable = true; + openFirewall = true; + user = cfg.user; + group = cfg.group; + listenPort = 2005; + }; + + # port is harcoded in nixpkgs module + jellyfin = { enable = true; openFirewall = true; user = cfg.user; group = cfg.group; }; - in { - jellyfin = serviceConf; - radarr = serviceConf; - sonarr = serviceConf; - bazarr = serviceConf; - lidarr = serviceConf; flaresolverr = { enable = true; openFirewall = true; - }; - - jellyseerr = { - enable = true; - openFirewall = true; - }; - - prowlarr = { - enable = true; - openFirewall = true; + port = 2007; }; qbittorrent = { enable = true; openFirewall = true; - webuiPort = 5000; + webuiPort = 2008; serverConfig = { LegalNotice.Accepted = true; @@ -107,6 +139,7 @@ in group = cfg.group; }; + # port is harcoded in nixpkgs module sabnzbd = { enable = true; openFirewall = true; @@ -116,46 +149,159 @@ in group = cfg.group; }; + postgresql = + let + databases = arr |> lib.concatMap (s: [ s "${s}-log" ]); + in + { + enable = true; + ensureDatabases = arr; + ensureUsers = arr |> lib.map (service: { + name = service; + ensureDBOwnership = true; + }); + }; + caddy = { enable = true; virtualHosts = { - "media.kruining.eu".extraConfig = '' - import auth - - reverse_proxy http://127.0.0.1:9494 - ''; "jellyfin.kruining.eu".extraConfig = '' - reverse_proxy http://127.0.0.1:8096 + reverse_proxy http://[::1]:8096 ''; }; }; }; + systemd.services.radarrApplyTerraform = + let + # this is a nix package, the generated json file to be exact + terraformConfiguration = inputs.terranix.lib.terranixConfiguration { + inherit system; + + modules = [ + ({ config, lib, ... }: { + config = { + variable = { + api_key = { + type = "string"; + description = "Radarr api key"; + }; + }; + + terraform.required_providers.radarr = { + source = "devopsarr/radarr"; + version = "2.2.0"; + }; + + provider.radarr = { + url = "http://127.0.0.1:2001"; + api_key = lib.tfRef "var.api_key"; + }; + + resource = { + radarr_root_folder.local = { + path = "/var/media/movies"; + }; + }; + }; + }) + ]; + }; + in + { + description = "Radarr terraform apply"; + + wantedBy = [ "multi-user.target" ]; + wants = [ "radarr.service" ]; + + script = '' + #!/usr/bin/env bash + + if [ "$(systemctl is-active radarr)" != "active" ]; then + echo "Radarr is not running" + exit 1 + fi + + # Sleep for a bit to give radarr the chance to start up + sleep 5s + + # Print the path to the source for easier debugging + echo "config location: ${terraformConfiguration}" + + # Copy infra code into workspace + cp -f ${terraformConfiguration} config.tf.json + + # Initialize OpenTofu + ${lib.getExe pkgs.opentofu} init + + # Run the infrastructure code + # ${lib.getExe pkgs.opentofu} plan -var-file='${config.sops.templates."radarr/config.tfvars".path}' + ${lib.getExe pkgs.opentofu} apply -auto-approve -var-file='${config.sops.templates."radarr/config.tfvars".path}' + ''; + + serviceConfig = { + Type = "oneshot"; + User = cfg.user; + Group = cfg.group; + + WorkingDirectory = "/var/lib/radarrApplyTerraform"; + + EnvironmentFile = [ + config.sops.templates."radarr/config.env".path + ]; + }; + }; + systemd.services.jellyfin.serviceConfig.killSignal = lib.mkForce "SIGKILL"; - ${namespace}.services.virtualisation.podman.enable = true; - - virtualisation = { - oci-containers = { - backend = "podman"; - - containers = { - # flaresolverr = { - # image = "flaresolverr/flaresolverr"; - # autoStart = true; - # ports = [ "127.0.0.1:8191:8191" ]; - # }; - - reiverr = { - image = "ghcr.io/aleksilassila/reiverr:v2.2.0"; - autoStart = true; - ports = [ "127.0.0.1:9494:9494" ]; - volumes = [ "${cfg.path}/reiverr/config:/config" ]; + sops = { + secrets = + arr + |> lib.map (service: { + name = "${service}/apikey"; + value = { + owner = cfg.user; + group = cfg.group; + restartUnits = [ "${service}.service" ]; }; - }; - }; - }; + }) + |> lib.listToAttrs + ; - networking.firewall.allowedTCPPorts = [ 80 443 6969 ]; + templates = + let + apikeys = + arr + |> lib.map (service: { + name = "${service}/config.env"; + value = { + owner = cfg.user; + group = cfg.group; + restartUnits = [ "${service}.service" ]; + content = '' + ${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}" + ''; + }; + }) + |> lib.listToAttrs; + + tfvars = + arr + |> lib.map(service: { + name = "${service}/config.tfvars"; + value = { + owner = cfg.user; + group = cfg.group; + restartUnits = [ "${service}ApplyTerraform.service" ]; + content = '' + api_key = "${config.sops.placeholder."${service}/apikey"}" + ''; + }; + }) + |> lib.listToAttrs; + in + apikeys // tfvars + ; + }; }; } diff --git a/modules/nixos/services/media/homer/default.nix b/modules/nixos/services/media/homer/default.nix new file mode 100644 index 0000000..79633ab --- /dev/null +++ b/modules/nixos/services/media/homer/default.nix @@ -0,0 +1,161 @@ +{ config, lib, namespace, ... }: +let + inherit (lib) mkIf mkEnableOption; + + cfg = config.${namespace}.services.media.homer; +in +{ + options.${namespace}.services.media.homer = { + enable = mkEnableOption "Enable homer"; + }; + + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ 2000 ]; + + services = { + homer = { + enable = true; + + virtualHost = { + caddy.enable = true; + domain = "http://:2000"; + }; + + settings = { + title = "Ulmo dashboard"; + + columns = 4; + connectivityCheck = true; + + links = []; + + services = [ + { + name = "Services"; + items = [ + { + name = "Zitadel"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/zitadel.svg"; + tag = "app"; + url = "https://auth.kruining.eu"; + target = "_blank"; + } + + { + name = "Forgejo"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/forgejo.svg"; + tag = "app"; + type = "Gitea"; + url = "https://git.amarth.cloud"; + target = "_blank"; + } + + { + name = "Vaultwarden"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/vaultwarden.svg"; + type = "Vaultwarden"; + tag = "app"; + url = "https://vault.kruining.eu"; + target = "_blank"; + } + ]; + } + + { + name = "Observability"; + items = [ + { + name = "Grafana"; + type = "Grafana"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/grafana.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:${builtins.toString config.services.grafana.settings.server.http_port}"; + target = "_blank"; + } + + { + name = "Prometheus"; + type = "Prometheus"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/prometheus.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:${builtins.toString config.services.prometheus.port}"; + target = "_blank"; + } + ]; + } + + { + name = "Media"; + items = [ + { + name = "Jellyfin (Movies)"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/jellyfin.svg"; + tag = "app"; + type = "Emby"; + url = "http://${config.networking.hostName}:8096"; + apikey = "e3ceed943eeb409ba8342738db7cc1f5"; + libraryType = "movies"; + target = "_blank"; + } + + { + name = "Radarr"; + type = "Radarr"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/radarr.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:2001"; + target = "_blank"; + } + + { + name = "Sonarr"; + type = "Sonarr"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/sonarr.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:2002"; + target = "_blank"; + } + + { + name = "Lidarr"; + type = "Lidarr"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/lidarr.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:2003"; + target = "_blank"; + } + + { + name = "Prowlarr"; + type = "Prowlarr"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/prowlarr.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:2004"; + target = "_blank"; + } + + { + name = "qBittorrent"; + type = "qBittorrent"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/qbittorrent.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:${builtins.toString config.services.qbittorrent.webuiPort}"; + target = "_blank"; + } + + { + name = "SABnzbd"; + type = "SABnzbd"; + logo = "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/sabnzdb-light.svg"; + tag = "app"; + url = "http://${config.networking.hostName}:8080"; + target = "_blank"; + } + ]; + } + ]; + }; + }; + }; + }; +} diff --git a/modules/nixos/services/media/servarr/default.nix b/modules/nixos/services/media/servarr/default.nix new file mode 100644 index 0000000..097a36b --- /dev/null +++ b/modules/nixos/services/media/servarr/default.nix @@ -0,0 +1,214 @@ +{ pkgs, config, lib, namespace, inputs, system, ... }: +let + inherit (builtins) toString; + inherit (lib) mkIf mkEnableOption mkOption types; + + cfg = config.${namespace}.services.media.servarr; +in +{ + options.${namespace}.services.media = { + servarr = mkOption { + type = types.attrsOf (types.submodule ({ name, ... }: { + options = { + enable = mkEnableOption "Enable ${name}"; + debug = mkEnableOption "Use tofu plan instead of tofu apply for ${name} "; + + port = mkOption { + type = types.port; + }; + + rootFolders = mkOption { + type = types.listOf types.str; + default = []; + }; + }; + })); + default = {}; + }; + }; + + config = { + services = + cfg + |> lib.mapAttrsToList (service: { enable, port, ... }: (mkIf enable { + "${service}" = { + enable = true; + openFirewall = true; + + environmentFiles = [ + config.sops.templates."${service}/config.env".path + ]; + + settings = { + auth.authenticationMethod = "External"; + + server = { + bindaddress = "0.0.0.0"; + port = port; + }; + + postgres = { + host = "localhost"; + port = "5432"; + user = service; + maindb = service; + logdb = service; + }; + }; + }; + })) + |> lib.mergeAttrsList + |> (set: set // { + postgres = { + ensureDatabases = cfg |> lib.attrNames; + ensureUsers = cfg |> lib.attrNames |> lib.map (service: { + name = service; + ensureDBOwnership = true; + }); + }; + }) + ; + + systemd = + cfg + |> lib.mapAttrsToList (service: { enable, debug, port, rootFolders, ... }: (mkIf enable { + tmpfiles.rules = [ + "d /var/lib/${service}ApplyTerraform 0755 ${service} ${service} -" + ]; + + services."${service}ApplyTerraform" = + let + terraformConfiguration = inputs.terranix.lib.terranixConfiguration { + inherit system; + + modules = [ + ({ config, lib, ... }: { + config = { + variable = { + api_key = { + type = "string"; + description = "${service} api key"; + }; + }; + + terraform.required_providers.${service} = { + source = "devopsarr/${service}"; + version = "2.2.0"; + }; + + provider.${service} = { + url = "http://127.0.0.1:${toString port}"; + api_key = lib.tfRef "var.api_key"; + }; + + resource = { + "${service}_root_folder" = + rootFolders + |> lib.imap (i: f: lib.nameValuePair "local${toString i}" { path = f; }) + |> lib.listToAttrs + ; + }; + }; + }) + ]; + }; + in + { + description = "${service} terraform apply"; + + wantedBy = [ "multi-user.target" ]; + wants = [ "${service}.service" ]; + + script = '' + #!/usr/bin/env bash + + # Sleep for a bit to give the service a chance to start up + sleep 5s + + if [ "$(systemctl is-active ${service})" != "active" ]; then + echo "${service} is not running" + exit 1 + fi + + # Print the path to the source for easier debugging + echo "config location: ${terraformConfiguration}" + + # Copy infra code into workspace + cp -f ${terraformConfiguration} config.tf.json + + # Initialize OpenTofu + ${lib.getExe pkgs.opentofu} init + + # Run the infrastructure code + ${lib.getExe pkgs.opentofu} \ + ${if debug then "plan" else "apply -auto-approve"} \ + -var-file='${config.sops.templates."${service}/config.tfvars".path}' + ''; + + serviceConfig = { + Type = "oneshot"; + User = service; + Group = service; + + WorkingDirectory = "/var/lib/${service}ApplyTerraform"; + + EnvironmentFile = [ + config.sops.templates."${service}/config.env".path + ]; + }; + }; + })) + |> lib.mergeAttrsList + ; + + users.users = + cfg + |> lib.mapAttrsToList (service: { enable, ... }: (mkIf enable { + "${service}".extraGroups = [ "media" ]; + })) + |> lib.mergeAttrsList + ; + + sops = + cfg + |> lib.mapAttrsToList (service: { enable, ... }: (mkIf enable { + secrets."${service}/apikey" = { + owner = service; + group = service; + restartUnits = [ "${service}.service" ]; + }; + + templates = { + "${service}/config.env" = { + owner = service; + group = service; + restartUnits = [ "${service}.service" ]; + content = '' + ${lib.toUpper service}__AUTH__APIKEY="${config.sops.placeholder."${service}/apikey"}" + ''; + }; + + "${service}/config.tfvars" = { + owner = service; + group = service; + restartUnits = [ "${service}.service" ]; + content = '' + api_key = "${config.sops.placeholder."${service}/apikey"}" + ''; + }; + }; + })) + |> lib.mergeAttrsList + ; + }; + + + # cfg + # |> lib.mapAttrsToList (service: { enable, debug, port, rootFolders, ... }: (mkIf enable { + + # # sops = { + # # }; + # })) + # |> lib.mergeAttrsList + # ; +} diff --git a/modules/nixos/services/observability/grafana/default.nix b/modules/nixos/services/observability/grafana/default.nix index c399729..6503493 100644 --- a/modules/nixos/services/observability/grafana/default.nix +++ b/modules/nixos/services/observability/grafana/default.nix @@ -42,9 +42,9 @@ in login_attribute_path = "username"; name_attribute_path = "full_name"; role_attribute_path = "contains(urn:zitadel:iam:org:project:roles[*], 'owner') && 'GrafanaAdmin' || contains(urn:zitadel:iam:org:project:roles[*], 'contributer') && 'Editor' || 'Viewer'"; - auth_url = "https://auth.amarth.cloud/oauth/v2/authorize"; - token_url = "https://auth.amarth.cloud/oauth/v2/token"; - api_url = "https://auth.amarth.cloud/oidc/v1/userinfo"; + auth_url = "https://auth.kruining.eu/oauth/v2/authorize"; + token_url = "https://auth.kruining.eu/oauth/v2/token"; + api_url = "https://auth.kruining.eu/oidc/v1/userinfo"; allow_sign_up = true; auto_login = true; use_pkce = true; diff --git a/modules/nixos/services/observability/loki/default.nix b/modules/nixos/services/observability/loki/default.nix index 8f6e0e3..d4774ac 100644 --- a/modules/nixos/services/observability/loki/default.nix +++ b/modules/nixos/services/observability/loki/default.nix @@ -23,7 +23,7 @@ in common = { ring = { instance_addr = "127.0.0.1"; - kvstore.store = "inmmemory"; + kvstore.store = "inmemory"; }; replication_factor = 1; path_prefix = "/tmp/loki"; diff --git a/modules/nixos/services/observability/promtail/default.nix b/modules/nixos/services/observability/promtail/default.nix index 1f32adc..25aabbd 100644 --- a/modules/nixos/services/observability/promtail/default.nix +++ b/modules/nixos/services/observability/promtail/default.nix @@ -29,9 +29,11 @@ in filename = "filename"; }; - clients = { - url = "http://127.0.0.1:3100/loki/api/v1/push"; - }; + clients = [ + { + url = "http://::1:9003/loki/api/v1/push"; + } + ]; scrape_configs = [ { diff --git a/modules/nixos/services/observability/uptime-kuma/default.nix b/modules/nixos/services/observability/uptime-kuma/default.nix new file mode 100644 index 0000000..c23977b --- /dev/null +++ b/modules/nixos/services/observability/uptime-kuma/default.nix @@ -0,0 +1,25 @@ +{ pkgs, config, lib, namespace, ... }: +let + inherit (builtins) toString; + inherit (lib) mkIf mkEnableOption; + + cfg = config.${namespace}.services.observability.uptime-kuma; +in +{ + options.${namespace}.services.observability.uptime-kuma = { + enable = mkEnableOption "enable uptime kuma"; + }; + + config = mkIf cfg.enable { + services.uptime-kuma = { + enable = true; + + settings = { + PORT = toString 9006; + HOST = "0.0.0.0"; + }; + }; + + networking.firewall.allowedTCPPorts = [ 9006 ]; + }; +} diff --git a/modules/nixos/services/persistance/postgesql/default.nix b/modules/nixos/services/persistance/postgesql/default.nix new file mode 100644 index 0000000..dbd6604 --- /dev/null +++ b/modules/nixos/services/persistance/postgesql/default.nix @@ -0,0 +1,26 @@ +{ config, lib, pkgs, namespace, ... }: +let + inherit (lib) mkIf mkEnableOption; + + cfg = config.${namespace}.services.persistance.postgresql; +in +{ + options.${namespace}.services.persistance.postgresql = { + enable = mkEnableOption "Postgresql"; + }; + + config = mkIf cfg.enable { + services = { + postgresql = { + enable = true; + authentication = '' + # Generated file, do not edit! + # TYPE DATABASE USER ADDRESS METHOD + local all all trust + host all all 127.0.0.1/32 trust + host all all ::1/128 trust + ''; + }; + }; + }; +} diff --git a/modules/nixos/services/security/vaultwarden/default.nix b/modules/nixos/services/security/vaultwarden/default.nix index 0bb05f7..abab566 100644 --- a/modules/nixos/services/security/vaultwarden/default.nix +++ b/modules/nixos/services/security/vaultwarden/default.nix @@ -1,13 +1,87 @@ { pkgs, config, lib, namespace, ... }: let inherit (builtins) toString; - inherit (lib) mkIf mkEnableOption; + inherit (lib) mkIf mkEnableOption mkOption types getAttrs toUpper concatMapAttrsStringSep; cfg = config.${namespace}.services.security.vaultwarden; + + databaseProviderSqlite = types.submodule ({ ... }: { + options = { + type = mkOption { + type = types.enum [ "sqlite" ]; + }; + + file = mkOption { + type = types.str; + description = ''''; + }; + }; + }); + + databaseProviderPostgresql = types.submodule ({ ... }: + let + urlOptions = lib.${namespace}.options.mkUrlOptions { + host = { + description = '' + Hostname of the postgresql server + ''; + }; + + port = { + default = 5432; + example = "5432"; + description = '' + Port of the postgresql server + ''; + }; + + protocol = mkOption { + default = "postgres"; + example = "postgres"; + }; + }; + in + { + options = { + type = mkOption { + type = types.enum [ "postgresql" ]; + }; + + sslMode = mkOption { + type = types.enum [ "verify-ca" "verify-full" "require" "prefer" "allow" "disabled" ]; + default = "verify-full"; + example = "verify-ca"; + description = '' + How to verify the server's ssl + + | mode | eavesdropping protection | MITM protection | Statement | + |-------------|--------------------------|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------| + | disable | No | No | I don't care about security, and I don't want to pay the overhead of encryption. | + | allow | Maybe | No | I don't care about security, but I will pay the overhead of encryption if the server insists on it. | + | prefer | Maybe | No | I don't care about encryption, but I wish to pay the overhead of encryption if the server supports it. | + | require | Yes | No | I want my data to be encrypted, and I accept the overhead. I trust that the network will make sure I always connect to the server I want. | + | verify-ca | Yes | Depends on CA policy | I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server that I trust. | + | verify-full | Yes | Yes | I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server I trust, and that it's the one I specify. | + + [Source](https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS) + ''; + }; + } // (urlOptions |> getAttrs [ "protocol" "host" "port" ]); + }); in { options.${namespace}.services.security.vaultwarden = { enable = mkEnableOption "enable vaultwarden"; + + database = mkOption { + type = types.oneOf [ + (types.addCheck databaseProviderSqlite (x: x ? type && x.type == "sqlite")) + (types.addCheck databaseProviderPostgresql (x: x ? type && x.type == "postgresql")) + null + ]; + default = null; + description = ''''; + }; }; config = mkIf cfg.enable { @@ -15,6 +89,8 @@ in "d '/var/lib/vaultwarden' 0700 vaultwarden vaultwarden - -" ]; + # systemd.services.vaultwarden.wants = [ "zitadelApplyTerraform.service" ]; + services = { vaultwarden = { enable = true; @@ -26,8 +102,6 @@ in SIGNUPS_ALLOWED = false; DOMAIN = "https://vault.kruining.eu"; - ADMIN_TOKEN = ""; - DATABASE_URL = "postgres://localhost:5432/vaultwarden?sslmode=disable"; WEB_VAULT_ENABLED = true; @@ -39,11 +113,8 @@ in SSO_ROLES_ENABLED = true; SSO_ORGANIZATIONS_ENABLED = true; SSO_ORGANIZATIONS_REVOCATION = true; - SSO_AUTHORITY = "https://auth.amarth.cloud/"; + SSO_AUTHORITY = "https://auth.kruining.eu/"; SSO_SCOPES = "email profile offline_access"; - SSO_AUDIENCE_TRUSTED = "^333297815511892227$"; - SSO_CLIENT_ID = "335178854421299459"; - SSO_CLIENT_SECRET = ""; ROCKET_ADDRESS = "::1"; ROCKET_PORT = 8222; @@ -52,11 +123,15 @@ in SMTP_HOST = "black-mail.nl"; SMTP_PORT = 587; SMTP_SECURITY = "starttls"; - SMTP_USERNAME = "info@amarth.cloud"; - SMTP_PASSWORD = ""; - SMTP_FROM = "info@amarth.cloud"; + SMTP_USERNAME = "chris@kruining.eu"; + SMTP_FROM = "chris@kruining.eu"; SMTP_FROM_NAME = "Chris' Vaultwarden"; }; + + environmentFile = [ + "/var/lib/zitadel/clients/nix_ulmo_vaultwarden" + config.sops.templates."vaultwarden/config.env".path + ]; }; postgresql = { @@ -76,6 +151,12 @@ in "vault.kruining.eu".extraConfig = '' encode zstd gzip + handle_path /admin { + respond 401 { + close + } + } + reverse_proxy http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT} { header_up X-Real-IP {remote_host} } @@ -83,5 +164,54 @@ in }; }; }; + + sops = { + secrets = { + "vaultwarden/email" = { + owner = config.users.users.vaultwarden.name; + group = config.users.users.vaultwarden.name; + key = "email/chris_kruining_eu"; + restartUnits = [ "vaultwarden.service" ]; + }; + }; + + templates = { + "vaultwarden/config.env" = { + content = '' + SMTP_PASSWORD='${config.sops.placeholder."vaultwarden/email"}'; + ''; + owner = config.users.users.vaultwarden.name; + group = config.users.groups.vaultwarden.name; + }; + temp-db-output.content = + let + config = + cfg.database + |> ({ type, ... }@db: + if type == "sqlite" then + { inherit (db) type file; } + else if type == "postgresql" then + { + inherit (db) type; + url = lib.${namespace}.strings.toUrl { + inherit (db) protocol host port; + path = "vaultwarden"; + query = { + sslmode = db.sslMode; + }; + }; + } + else + {} + ) + |> concatMapAttrsStringSep "\n" (n: v: "${toUpper n}=${v}") + ; + in + '' + # GENERATED VALUES + ${config} + ''; + }; + }; }; } diff --git a/modules/nixos/services/virtualisation/podman/default.nix b/modules/nixos/services/virtualisation/podman/default.nix index 9b9dc89..0faf8ce 100644 --- a/modules/nixos/services/virtualisation/podman/default.nix +++ b/modules/nixos/services/virtualisation/podman/default.nix @@ -12,6 +12,7 @@ in config = mkIf cfg.enable { virtualisation = { containers.enable = true; + oci-containers.backend = "podman"; podman = { enable = true; diff --git a/modules/nixos/system/security/sops/default.nix b/modules/nixos/system/security/sops/default.nix index 68ab4ca..bee7b3c 100644 --- a/modules/nixos/system/security/sops/default.nix +++ b/modules/nixos/system/security/sops/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, namespace, inputs, ... }: +{ pkgs, config, namespace, inputs, system, ... }: let cfg = config.${namespace}.system.security.sops; in @@ -13,10 +13,14 @@ in environment.systemPackages = with pkgs; [ sops ]; sops = { - defaultSopsFile = ../../../../../_secrets/secrets.yaml; defaultSopsFormat = "yaml"; + defaultSopsFile = inputs.self + "/systems/${system}/${config.networking.hostName}/secrets.yml"; - age.keyFile = "/home/"; + age = { + # keyFile = "~/.config/sops/age/keys.txt"; + # sshKeyPaths = [ "~/.ssh/id_ed25519" ]; + # generateKey = true; + }; }; }; } \ No newline at end of file diff --git a/shells/default/default.nix b/shells/default/default.nix new file mode 100644 index 0000000..1749c48 --- /dev/null +++ b/shells/default/default.nix @@ -0,0 +1,12 @@ +{ mkShell, inputs, pkgs, ... }: + +mkShell { + packages = with pkgs; [ + bash + sops + just + yq + pwgen + inputs.clan-core.packages.x86_64-linux.clan-cli + ]; +} \ No newline at end of file diff --git a/systems/x86_64-linux/manwe/default.nix b/systems/x86_64-linux/manwe/default.nix index 76d4e6d..c2d9978 100644 --- a/systems/x86_64-linux/manwe/default.nix +++ b/systems/x86_64-linux/manwe/default.nix @@ -5,6 +5,8 @@ ./hardware.nix ]; + system.activationScripts.remove-gtkrc.text = "rm -f /home/chris/.gtkrc-2.0"; + sneeuwvlok = { hardware.has = { gpu.amd = true; diff --git a/systems/x86_64-linux/manwe/disks.nix b/systems/x86_64-linux/manwe/disks.nix index d68db6a..f33ec71 100644 --- a/systems/x86_64-linux/manwe/disks.nix +++ b/systems/x86_64-linux/manwe/disks.nix @@ -8,7 +8,7 @@ in swapDevices = []; boot.supportedFilesystems = [ "nfs" ]; - + fileSystems = { "/" = { device = "/dev/disk/by-label/nixos"; @@ -26,9 +26,9 @@ in fsType = "nfs"; }; - "/home/chris/mandos" = { - device = "mandos:/"; - fsType = "nfs"; - }; + # "/home/chris/mandos" = { + # device = "mandos:/"; + # fsType = "nfs"; + # }; }; } diff --git a/systems/x86_64-linux/ulmo/default.nix b/systems/x86_64-linux/ulmo/default.nix index 13b0f33..cb8f9cc 100644 --- a/systems/x86_64-linux/ulmo/default.nix +++ b/systems/x86_64-linux/ulmo/default.nix @@ -5,28 +5,200 @@ ./hardware.nix ]; + networking = { + interfaces.enp2s0 = { + ipv6.addresses = [ + { address = "2a0d:6e00:1dc9:0::dead:beef"; prefixLength = 64; } + ]; + + useDHCP = true; + }; + + defaultGateway = { + address = "192.168.1.1"; + interface = "enp2s0"; + }; + + defaultGateway6 = { + address = "fe80::1"; + interface = "enp2s0"; + }; + }; + + # Expose amarht cloud stuff like this until I have a proper solution + services.caddy.virtualHosts = { + "auth.amarth.cloud".extraConfig = '' + reverse_proxy http://192.168.1.223:9092 + ''; + + "amarth.cloud".extraConfig = '' + reverse_proxy http://192.168.1.223:8080 + ''; + }; + sneeuwvlok = { services = { - authentication.authelia.enable = true; - authentication.zitadel.enable = true; + backup.borg.enable = true; + + authentication.zitadel = { + enable = true; + + organization = { + nix = { + user = { + chris = { + email = "chris@kruining.eu"; + firstName = "Chris"; + lastName = "Kruining"; + + roles = [ "ORG_OWNER" ]; + instanceRoles = [ "IAM_OWNER" ]; + }; + + kaas = { + email = "chris+kaas@kruining.eu"; + firstName = "Kaas"; + lastName = "Kruining"; + }; + }; + + project = { + ulmo = { + projectRoleCheck = true; + projectRoleAssertion = true; + hasProjectCheck = true; + + role = { + jellyfin = { + group = "jellyfin"; + }; + jellyfin_admin = { + group = "jellyfin"; + }; + }; + + assign = { + chris = [ "jellyfin" "jellyfin_admin" ]; + kaas = [ "jellyfin" ]; + }; + + application = { + jellyfin = { + redirectUris = [ "https://jellyfin.kruining.eu/sso/OID/redirect/zitadel" ]; + grantTypes = [ "authorizationCode" ]; + responseTypes = [ "code" ]; + }; + + forgejo = { + redirectUris = [ "https://git.amarth.cloud/user/oauth2/zitadel/callback" ]; + grantTypes = [ "authorizationCode" ]; + responseTypes = [ "code" ]; + }; + + vaultwarden = { + redirectUris = [ "https://vault.kruining.eu/identity/connect/oidc-signin" ]; + grantTypes = [ "authorizationCode" ]; + responseTypes = [ "code" ]; + exportMap = { + client_id = "SSO_CLIENT_ID"; + client_secret = "SSO_CLIENT_SECRET"; + }; + }; + + matrix = { + redirectUris = [ "https://matrix.kruining.eu/_synapse/client/oidc/callback" ]; + grantTypes = [ "authorizationCode" ]; + responseTypes = [ "code" ]; + }; + }; + }; + }; + + action = { + flattenRoles = { + script = '' + (ctx, api) => { + if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) { + return; + } + + const roles = ctx.v1.user.grants.grants.flatMap(({ roles, projectId }) => roles.map(role => projectId + ':' + role)); + + api.v1.claims.setClaim('nix:zitadel:custom', JSON.stringify({ roles })); + }; + ''; + }; + }; + + triggers = [ + { flowType = "customiseToken"; triggerType = "preUserinfoCreation"; actions = [ "flattenRoles" ]; } + { flowType = "customiseToken"; triggerType = "preAccessTokenCreation"; actions = [ "flattenRoles" ]; } + ]; + }; + }; + }; + + communication.matrix.enable = true; development.forgejo.enable = true; networking.ssh.enable = true; media.enable = true; + media.homer.enable = true; media.nfs.enable = true; + media.servarr = { + # radarr = { + # port = 2001; + # }; + + sonarr = { + enable = true; + # debug = true; + port = 2002; + rootFolders = [ + "/var/media/series" + ]; + }; + + lidarr = { + enable = true; + debug = true; + port = 2003; + rootFolders = [ + "/var/media/music" + ]; + }; + + prowlarr = { + enable = true; + debug = true; + port = 2004; + }; + }; observability = { grafana.enable = true; prometheus.enable = true; loki.enable = true; promtail.enable = true; + # uptime-kuma.enable = true; }; persistance.convex.enable = true; - security.vaultwarden.enable = true; + security.vaultwarden = { + enable = true; + database = { + # type = "sqlite"; + # file = "/var/lib/vaultwarden/state.db"; + + type = "postgresql"; + host = "localhost"; + port = 5432; + sslMode = "disabled"; + }; + }; }; editor = { diff --git a/systems/x86_64-linux/ulmo/disks.nix b/systems/x86_64-linux/ulmo/disks.nix index a4033f7..0b272f4 100644 --- a/systems/x86_64-linux/ulmo/disks.nix +++ b/systems/x86_64-linux/ulmo/disks.nix @@ -5,9 +5,7 @@ in { # TODO :: Implement disko at some point - swapDevices = [ - { device = "/dev/disk/by-uuid/0ddf001a-5679-482e-b254-04a1b9094794"; } - ]; + swapDevices = []; boot.supportedFilesystems = [ "nfs" ]; diff --git a/systems/x86_64-linux/ulmo/secrets.yml b/systems/x86_64-linux/ulmo/secrets.yml new file mode 100644 index 0000000..7a26401 --- /dev/null +++ b/systems/x86_64-linux/ulmo/secrets.yml @@ -0,0 +1,45 @@ +email: + chris_kruining_eu: ENC[AES256_GCM,data:/JS+dQ6ABlkdjRZP+sGeUY3js30swS4=,iv:d5CcoY6DD3DJ/e3t0OU/KUULccJpTN0uBQPQzl/3R0s=,tag:aTN7RdzXkIpci9tEBjevSA==,type:str] + info_amarth_cloud: ENC[AES256_GCM,data:/x7aAFAxXYYf79tB08VQmmuTIy2TvdSTFfAzIWdIr+I=,iv:plNxS6oOin+oEql+1xsePOsUfLJkf+ZPBviPRTbIghE=,tag:hjtK3rysd2NNBA2mWdv8cw==,type:str] +zitadel: + masterKey: ENC[AES256_GCM,data:4MPvBo407qrS7NF4oUTf84tZoPkSRmiHdD7qpkYeHME=,iv:H2NIAN0xBUDqnyco9gA3zYAsKtSeA/JpqYrPhc1eqc0=,tag:6OFGDfsucG5gDerImgpuXA==,type:str] + nix: {} + users: ENC[AES256_GCM,data:xkjm0+PBt6gmZyfi3n3OIEe5b+d4OtN0Y3UfmdcbcJHbJZuiz+60oUjlAN0vjtsi0muufoAqtGJTIpm9nDZzzN7b7LK43TAhcuSlIm5LpbZFp1U3H4laRbTwauAT6wA0aDCfAkwTozxAuEUk1jAu+65ktJNJb7b0PR7s/I/wf7IgW2+K4Jv3LIOZIipUwfuvXuTzsxCElYRvGZXmIuXrYq1EaymksHHggemrKeMWLAae7mzz5v3aBbwxiVjQNkQkS4ApsO/5nZUat0oqXA==,iv:fptZn4NmX3iYKSEPLJAOFpt+KQ6TR1w9KaY9IF4p/Wk=,tag:UKvMOSIT5/mhfZA3usbLhQ==,type:str] +forgejo: + action_runner_token: ENC[AES256_GCM,data:yJ6OnRq5kinbuhvH06K5o3l86EafuBoojMwg/qhP+cgeH+BwPeE+Ng==,iv:IeXJahPxgLNIUFmkgp495tLVh8UyQBmJ2SnVEUhlhHs=,tag:XYQi613CxSp8AQeilJMrsg==,type:str] +synapse: + oidc_id: ENC[AES256_GCM,data:XbCpyGq0LeRJWq8dv/5Dipvp,iv:YDhgl26z1NBbIQLoLdGVz0+ze6o1ZcmgVHPfwoRj57I=,tag:y2vUuqnDmtTvVQmZCAlnLg==,type:str] + oidc_secret: ENC[AES256_GCM,data:nVFi5EFbNMZ0mvrDHVYC0NiwJlo2eEw44D+Fcv9SKSb2oO00lGEDkP/oXDj5YgDq6RLQSe3f/SUOn77ntwnZYg==,iv:awe7VNUYOn9ofl1QlQTrEN5d0i5WkVM35qndruL4VXo=,tag:8Yoc9lFF9aWbtAa5fzQGEA==,type:str] +kaas: ENC[AES256_GCM,data:3yI6lH0rw+f2OFJ94Z7zb0pYwy4FDFs9rJi2wpd9VVWghmey5g4O788ypXa34XqKCQDDHDgTxwyDs6KpvCQQaLV1PDhXd4Po0SSlIOkUtCWhOf6Tp3PM2ASoE+AAAzJLJUc6AZdBJRyYU9V+UvO9jW+WmlpZpsg5crnVMzZo7f2AF0ep9A/A5BL1Y2UhYQE4LDVkLC9AL3hl8IhF5xSdZdO0ugrP0x7CKVUxA7fJyOjx7/IKVwvgKD4xlhIgv9lYPTvE2vUs+w==,iv:e6b98ZnBqf7hh3SSKGdTl63OpQm1oK95lHXdwTiLft8=,tag:IS/lDgvJvSd7OmDLP+uG1g==,type:str] +radarr: + apikey: ENC[AES256_GCM,data:G141GW4PyS5pbAV39HcVscMw3s30txOgTZzWaL7o+ccZfnfDLv796O6xKXdqGZ8saLsveghLw9Z6a5luusHyQ3Q5ESL6W7SVeZVTuSqSC3i/4jl75FJxhnsgVsfrnYxzLGpKiw==,iv:sZl/XLh6y3WgSAn6nH3sFB6atBifZdghm+QsCNDbcjY=,tag:Tw+R80nrF0T0yDti0Uf+ig==,type:str] +sonarr: + apikey: ENC[AES256_GCM,data:s8bgDJ+LpIH1Mt3KSiIKB8LnxztOkHdc8J6+50o+HoDUAfIIsZkA2oX/m7UecrTSRi6ay8D9yjhe6ZwSNXhJh6wQqTS7gZWn8f6QfrfI+8DKdc9enh91suQxjkz8Q+wnKK0zBg==,iv:LmAe6v+6ItVnHB6gko6mhiGOuVBksBYP4dXfbxpAIPE=,tag:DZ8kwOwaWwWTGWEGu5S0Kg==,type:str] +lidarr: + apikey: ENC[AES256_GCM,data:I2eKaxidmxem7C7ukmyIfwASNqrkS4vEOiCcU5kSNY6DR0pXsYg0PBdgu8vzK6llbXODLdG5t55BordIWvVRJGAauo0FMvtp59NSNpza7cK68tdKGvNefD6bqhUIR06BY11niQ==,iv:48AD7cd17TlWY5yAagepLOIVwgxhD/d13Pnup6GsWDA=,tag:teOVtW8opE99hqAXQwvlrA==,type:str] +prowlarr: + apikey: ENC[AES256_GCM,data:pyZ2WGEs/PlIdhDsQq2TPGJbplkd5fLF0ZkBjITqIJlnAzYHb+rl+KOM4rHqQcI6yAJM8X1Y3ymGrD7vG7GiRxB7yoEG13SKhZIWOddTnxIhbkz81RfrL2fUJIydOaP6sS//9Q==,iv:Tr6MWoC6nC7rdVTOjT1T2itT+lVL4GnUiAr5/+IHAs0=,tag:keIJNuGeVht8+xSN3FnBGA==,type:str] +sops: + age: + - recipient: age19qfpf980tadguqq44zf6xwvjvl428dyrj46ha3n6aeqddwhtnuqqml7etq + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwdDZyZkxvNU4zM3NHb2gx + ZlhLZk5JWUFGMWZGeUVHNkFFU1NtZlBQVVhjCmZGai9NdmdUeU5VcW9ROVZKTW5q + cmZaQ2JlaldaTWduQklocUZLT2FUcGcKLS0tIHlqVU0wdXJ0dTE4dlZSVEczd2Yv + RVFxVHFxbkVNbEZsaVcwYXZCdUc5R1kKQdAN6LEKmGLCSkKhNuEr0YK2zl9Aw1kK + 6C25lN532mG55zIRectZda1Fmi1GMZ/2v3b5qz7x+TDMA9m/47OjmA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1ewes0f5snqx3sh5ul6fa6qtxzhd25829v6mf5rx2wnheat6fefps5rme2x + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoK3lqRDhEMXEvaUp3OWdV + eFlZSGpJcGs0RTdRbllWdmdZTzl3RTlDNlIwCm92R290NjNyK2NNbWpINTBhazNS + NTJYWEw0SGc1TUtrd0NZSmowakMvSlEKLS0tIG5uUEIrZGVORkRNVnBVOHgyMXZG + TTRWaHhpNWlkVDFmMFN4ZTNHMUxyNVkKV693pzTKRkZboQCMPr9IyMGSgxfuHXcb + Y6BNcp6Qg6PWtX5QI7wRkPNINAK1TEbRBba+b8h6gMmVU4DliQyFiQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-11-19T09:51:26Z" + mac: ENC[AES256_GCM,data:pMMkxHPochpI8si/oHhU7MHqC1JjNhMP7HCRNQQEkwBQI489xiC02t+qUwpmG4oIheqi8lEcZPpL4t9HzRN9sZImaI2LrJn3cHFojHzXzo7FPfvfUilZe1+JXLfm+wn+bflAEutIcfDiZc/MjiKOxRHwZy5Pr41Mj6uPIUr62zk=,iv:GwvMVgJ6m1DQcRZMVzshbuMK/Kx8vE8Ym83KbxuvYRg=,tag:wVSol9LDRzoFjQppB8J9gA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0