From c4be520190da8897b8e179b3786dbcaef6372bb2 Mon Sep 17 00:00:00 2001 From: Richie Cahill Date: Fri, 26 Sep 2025 22:18:57 -0400 Subject: [PATCH] adding brain --- .github/workflows/build_systems.yml | 3 +- .sops.yaml | 2 + systems/brain/default.nix | 42 ++++++ systems/brain/docker/default.nix | 11 ++ systems/brain/docker/docker_networks.md | 3 + systems/brain/hardware.nix | 67 +++++++++ systems/brain/programs.nix | 7 + systems/brain/services/default.nix | 9 ++ systems/brain/services/home_assistant.nix | 71 ++++++++++ systems/brain/services/jellyfin.nix | 6 + systems/brain/services/postgress.nix | 151 +++++++++++++++++++++ systems/brain/syncthing.nix | 24 ++++ users/richie/home/gui/vscode/settings.json | 3 + users/richie/systems/brain.nix | 5 + users/secrets.yaml | 59 ++++---- 15 files changed, 437 insertions(+), 26 deletions(-) create mode 100644 systems/brain/default.nix create mode 100644 systems/brain/docker/default.nix create mode 100644 systems/brain/docker/docker_networks.md create mode 100644 systems/brain/hardware.nix create mode 100644 systems/brain/programs.nix create mode 100644 systems/brain/services/default.nix create mode 100644 systems/brain/services/home_assistant.nix create mode 100644 systems/brain/services/jellyfin.nix create mode 100644 systems/brain/services/postgress.nix create mode 100644 systems/brain/syncthing.nix create mode 100644 users/richie/systems/brain.nix diff --git a/.github/workflows/build_systems.yml b/.github/workflows/build_systems.yml index eda22d3..4a14dd1 100644 --- a/.github/workflows/build_systems.yml +++ b/.github/workflows/build_systems.yml @@ -15,9 +15,10 @@ jobs: matrix: system: - "bob" + - "brain" - "jeeves" - - "rhapsody-in-green" - "leviathan" + - "rhapsody-in-green" continue-on-error: true steps: - uses: actions/checkout@v4 diff --git a/.sops.yaml b/.sops.yaml index 8e89195..04eb2f5 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -5,6 +5,7 @@ keys: - &admin_richie age1u8zj599elqqvcmhxn8zuwrufsz8w8w366d3ayrljjejljt2q45kq8mxw9c # cspell:disable-line - &system_bob age1q47vup0tjhulkg7d6xwmdsgrw64h4ax3la3evzqpxyy4adsmk9fs56qz3y # cspell:disable-line + - &system_brain age1jhf7vm0005j60mjq63696frrmjhpy8kpc2d66mw044lqap5mjv4snmwvwm # cspell:disable-line - &system_jeeves age13lmqgc3jvkyah5e3vcwmj4s5wsc2akctcga0lpc0x8v8du3fxprqp4ldkv # cspell:disable-line - &system_leviathan age1l272y8udvg60z7edgje42fu49uwt4x2gxn5zvywssnv9h2krms8s094m4k # cspell:disable-line - &system_rhapsody age1ufnewppysaq2wwcl4ugngjz8pfzc5a35yg7luq0qmuqvctajcycs5lf6k4 # cspell:disable-line @@ -15,6 +16,7 @@ creation_rules: - age: - *admin_richie - *system_bob + - *system_brain - *system_jeeves - *system_leviathan - *system_rhapsody diff --git a/systems/brain/default.nix b/systems/brain/default.nix new file mode 100644 index 0000000..38e9729 --- /dev/null +++ b/systems/brain/default.nix @@ -0,0 +1,42 @@ +{ inputs, ... }: +{ + imports = [ + ../../users/richie + ../../common/global + ../../common/optional/docker.nix + ../../common/optional/ssh_decrypt.nix + ../../common/optional/syncthing_base.nix + ../../common/optional/systemd-boot.nix + ../../common/optional/update.nix + ../../common/optional/zerotier.nix + ./docker + ./hardware.nix + ./networking.nix + ./nvidia.nix + ./programs.nix + ./runners + ./services + ./syncthing.nix + inputs.nixos-hardware.nixosModules.framework-11th-gen-intel + ]; + + networking = { + hostName = "brain"; + hostId = "93a06c6e"; + firewall = { + enable = true; + allowedTCPPorts = [ ]; + }; + networkmanager.enable = true; + }; + + services = { + openssh.ports = [ 129 ]; + + smartd.enable = true; + }; + + users.mutableUsers = true; + + system.stateVersion = "25.05"; +} diff --git a/systems/brain/docker/default.nix b/systems/brain/docker/default.nix new file mode 100644 index 0000000..e384ee5 --- /dev/null +++ b/systems/brain/docker/default.nix @@ -0,0 +1,11 @@ +{ lib, ... }: +{ + imports = + let + files = builtins.attrNames (builtins.readDir ./.); + nixFiles = builtins.filter (name: lib.hasSuffix ".nix" name && name != "default.nix") files; + in + map (file: ./. + "/${file}") nixFiles; + + virtualisation.oci-containers.backend = "docker"; +} diff --git a/systems/brain/docker/docker_networks.md b/systems/brain/docker/docker_networks.md new file mode 100644 index 0000000..c612f26 --- /dev/null +++ b/systems/brain/docker/docker_networks.md @@ -0,0 +1,3 @@ +# docker_networks + +docker network create -d bridge web diff --git a/systems/brain/hardware.nix b/systems/brain/hardware.nix new file mode 100644 index 0000000..ac2315d --- /dev/null +++ b/systems/brain/hardware.nix @@ -0,0 +1,67 @@ +{ + config, + lib, + modulesPath, + ... +}: +{ + imports = [ (modulesPath + "/installer/scan/not-detected.nix") ]; + + boot = { + initrd = { + availableKernelModules = [ + "ahci" + "ehci_pci" + "nvme" + "sd_mod" + "usb_storage" + "usbhid" + "xhci_pci" + ]; + kernelModules = [ ]; + luks.devices."luks-root-pool-nvme-Samsung_SSD_990_PRO_2TB_S7KHNJ0Y121613P-part2" = { + device = "/dev/disk/by-id/nvme-Samsung_SSD_990_PRO_2TB_S7KHNJ0Y121613P-part2"; + bypassWorkqueues = true; + allowDiscards = true; + }; + }; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + }; + + fileSystems = { + "/" = lib.mkDefault { + device = "root_pool/root"; + fsType = "zfs"; + }; + + "/home" = { + device = "root_pool/home"; + fsType = "zfs"; + }; + + "/var" = { + device = "root_pool/var"; + fsType = "zfs"; + }; + + "/nix" = { + device = "root_pool/nix"; + fsType = "zfs"; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/12CE-A600"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/systems/brain/programs.nix b/systems/brain/programs.nix new file mode 100644 index 0000000..54d4b13 --- /dev/null +++ b/systems/brain/programs.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: +{ + environment.systemPackages = with pkgs; [ + filebot + docker-compose + ]; +} diff --git a/systems/brain/services/default.nix b/systems/brain/services/default.nix new file mode 100644 index 0000000..1133fcb --- /dev/null +++ b/systems/brain/services/default.nix @@ -0,0 +1,9 @@ +{ lib, ... }: +{ + imports = + let + files = builtins.attrNames (builtins.readDir ./.); + nixFiles = builtins.filter (name: lib.hasSuffix ".nix" name && name != "default.nix") files; + in + map (file: ./. + "/${file}") nixFiles; +} diff --git a/systems/brain/services/home_assistant.nix b/systems/brain/services/home_assistant.nix new file mode 100644 index 0000000..206444b --- /dev/null +++ b/systems/brain/services/home_assistant.nix @@ -0,0 +1,71 @@ +{ + users = { + users.hass = { + isSystemUser = true; + group = "hass"; + }; + groups.hass = { }; + }; + + services = { + home-assistant = { + enable = true; + openFirewall = true; + config = { + http = { + server_port = 8123; + server_host = [ + "192.168.99.14" + "192.168.95.9" + "127.0.0.1" + ]; + use_x_forwarded_for = true; + trusted_proxies = "127.0.0.1"; + }; + homeassistant = { + time_zone = "America/New_York"; + unit_system = "us_customary"; + temperature_unit = "F"; + }; + recorder = { + db_url = "postgresql://@/hass"; + auto_purge = true; + purge_keep_days = 3650; + db_retry_wait = 15; + }; + assist_pipeline = { }; + backup = { }; + bluetooth = { }; + config = { }; + dhcp = { }; + energy = { }; + history = { }; + homeassistant_alerts = { }; + image_upload = { }; + logbook = { }; + media_source = { }; + mobile_app = { }; + ssdp = { }; + sun = { }; + webhook = { }; + zeroconf = { }; + automation = "!include automations.yaml"; + script = "!include scripts.yaml"; + scene = "!include scenes.yaml"; + group = "!include groups.yaml"; + }; + extraPackages = + python3Packages: with python3Packages; [ + jellyfin-apiclient-python + psycopg2 + uiprotect + ]; + extraComponents = [ "isal" ]; + }; + esphome = { + enable = true; + openFirewall = true; + address = "192.168.90.40"; + }; + }; +} diff --git a/systems/brain/services/jellyfin.nix b/systems/brain/services/jellyfin.nix new file mode 100644 index 0000000..8379831 --- /dev/null +++ b/systems/brain/services/jellyfin.nix @@ -0,0 +1,6 @@ +{ + services.jellyfin = { + enable = true; + openFirewall = true; + }; +} diff --git a/systems/brain/services/postgress.nix b/systems/brain/services/postgress.nix new file mode 100644 index 0000000..4233e23 --- /dev/null +++ b/systems/brain/services/postgress.nix @@ -0,0 +1,151 @@ +{ pkgs, ... }: +{ + networking.firewall.allowedTCPPorts = [ 5432 ]; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_17_jit; + enableTCPIP = true; + enableJIT = true; + + authentication = pkgs.lib.mkOverride 10 '' + + # admins + local all postgres trust + host all postgres 127.0.0.1/32 trust + host all postgres ::1/128 trust + + local all richie trust + host all richie 127.0.0.1/32 trust + host all richie ::1/128 trust + host all richie 192.168.90.1/24 trust + host all richie 192.168.99.1/24 trust + + #type database DBuser origin-address auth-method + local hass hass trust + + # ipv4 + host hass hass 192.168.90.1/24 trust + host hass hass 127.0.0.1/32 trust + + # ipv6 + host hass hass ::1/128 trust + ''; + + identMap = '' + # ArbitraryMapName systemUser DBUser + superuser_map root postgres + superuser_map postgres postgres + # Let other names login as themselves + superuser_map richie postgres + superuser_map hass hass + ''; + ensureUsers = [ + { + name = "postgres"; + ensureClauses = { + superuser = true; + login = true; + createrole = true; + createdb = true; + replication = true; + }; + } + { + name = "richie"; + ensureDBOwnership = true; + ensureClauses = { + superuser = true; + login = true; + createrole = true; + createdb = true; + replication = true; + }; + } + { + name = "hass"; + ensureDBOwnership = true; + ensureClauses = { + login = true; + createrole = true; + createdb = true; + replication = true; + }; + } + ]; + ensureDatabases = [ + "hass" + "richie" + ]; + # Thank you NotAShelf + # https://github.com/NotAShelf/nyx/blob/d407b4d6e5ab7f60350af61a3d73a62a5e9ac660/modules/core/roles/server/system/services/databases/postgresql.nix#L74 + settings = { + # Connectivity; + max_connections = 100; + superuser_reserved_connections = 3; + + # Memory Settings; + shared_buffers = "1024 MB"; + work_mem = "32 MB"; + maintenance_work_mem = "320 MB"; + huge_pages = "off"; + effective_cache_size = "2 GB"; + effective_io_concurrency = 100; # concurrent IO only really activated if OS supports posix_fadvise function; + random_page_cost = 1.25; # speed of random disk access relative to sequential access (1.0); + + # Monitoring; + shared_preload_libraries = "pg_stat_statements,auto_explain"; # per statement resource usage stats & log explain statements for slow queries + track_io_timing = "on"; # measure exact block IO times; + track_functions = "pl"; # track execution times of pl-language procedures if any; + # Replication; + wal_level = "replica"; # consider using at least "replica"; + max_wal_senders = 0; + synchronous_commit = "on"; + + # Checkpointing: ; + checkpoint_timeout = "15 min"; + checkpoint_completion_target = 0.9; + max_wal_size = "1024 MB"; + min_wal_size = "512 MB"; + + # WAL writing; + wal_compression = "on"; + wal_buffers = -1; # auto-tuned by Postgres till maximum of segment size (16MB by default); + wal_writer_delay = "200ms"; + wal_writer_flush_after = "1MB"; + + # Background writer; + bgwriter_delay = "200ms"; + bgwriter_lru_maxpages = 100; + bgwriter_lru_multiplier = 2.0; + bgwriter_flush_after = 0; + + # Parallel queries: ; + max_worker_processes = 6; + max_parallel_workers_per_gather = 3; + max_parallel_maintenance_workers = 3; + max_parallel_workers = 6; + parallel_leader_participation = "on"; + + # Advanced features ; + enable_partitionwise_join = "on"; + enable_partitionwise_aggregate = "on"; + jit = "on"; + + jit_above_cost = 100000; + jit_inline_above_cost = 150000; + jit_optimize_above_cost = 500000; + + # log slow queries + log_min_duration_statement = 100; + "auto_explain.log_min_duration" = 100; + + # logging configuration + log_connections = true; + log_statement = "ddl"; + logging_collector = true; + log_disconnections = true; + log_rotation_age = "14d"; + }; + }; +} diff --git a/systems/brain/syncthing.nix b/systems/brain/syncthing.nix new file mode 100644 index 0000000..ba09529 --- /dev/null +++ b/systems/brain/syncthing.nix @@ -0,0 +1,24 @@ +{ + services.syncthing.settings.folders = { + "dotfiles" = { + path = "/home/richie/dotfiles"; + devices = [ + "jeeves" + "bob" + "rhapsody-in-green" + ]; + fsWatcherEnabled = true; + }; + "important" = { + id = "4ckma-gtshs"; # cspell:disable-line + path = "/home/richie/important"; + devices = [ + "bob" + "jeeves" + "phone" + "rhapsody-in-green" + ]; + fsWatcherEnabled = true; + }; + }; +} diff --git a/users/richie/home/gui/vscode/settings.json b/users/richie/home/gui/vscode/settings.json index e0c903a..a70cf21 100644 --- a/users/richie/home/gui/vscode/settings.json +++ b/users/richie/home/gui/vscode/settings.json @@ -54,6 +54,9 @@ "[python]": { "editor.defaultFormatter": "charliermarsh.ruff" }, "[yaml]": { "editor.defaultFormatter": "redhat.vscode-yaml" }, "[javascriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[github-actions-workflow]": { + "editor.defaultFormatter": "redhat.vscode-yaml" + }, // spell check "cSpell.enabled": true, diff --git a/users/richie/systems/brain.nix b/users/richie/systems/brain.nix new file mode 100644 index 0000000..6bbef61 --- /dev/null +++ b/users/richie/systems/brain.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ../home/global.nix + ]; +} diff --git a/users/secrets.yaml b/users/secrets.yaml index d4041b7..a6035ac 100644 --- a/users/secrets.yaml +++ b/users/secrets.yaml @@ -9,47 +9,56 @@ sops: - recipient: age1u8zj599elqqvcmhxn8zuwrufsz8w8w366d3ayrljjejljt2q45kq8mxw9c enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMb09DaUl0TVB1dXN0Y0lu - OFZpUVJ3ZWVIZ3hwS3kzZXkySTZXaURtZ3lnCkpKQll0MUFiRG5KSUlBQ3J6Z2xo - ZDVGQWZnR2t1RlVkcnV4Yk9oOGhLbmcKLS0tIEtoL1d6QVpXYTdmQmh6Vk1WSTVE - aGNiY0hCK2g4SkREMWlKbzdScGNiYW8KfywOdYuX4RcBlf4jQsRPhZ7ZkDpZBwMa - G3I2sZSrOm9UYS/x4sDuawM+Oj82vKVEBBxLddByD92aTluvARTp1Q== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBObHhkaFlnaG4zaTZtbkIw + TkxSQnMxbDNwUVo4R1VYRDNKVFRDUE9kb0ZjCnpWWElJUVNuNFBsMzZod1ZQY0Fa + VXgxNjZ0TUJ3cEt2OTFWL2dGY0txVHMKLS0tIHNQU3Rsanh4dkc3ZElsai9YMFdH + cXUzVmFxTUVIOWZVR2Fpa2crdWsrdlkKwdGLfbKWc25qfBKyd/cawiUWv9iepKHN + EOp/LdH2GbCfnQSVbxi28ukLHxWqOLdqMm8xSni/Of2PXvMnpdyCyQ== -----END AGE ENCRYPTED FILE----- - recipient: age1q47vup0tjhulkg7d6xwmdsgrw64h4ax3la3evzqpxyy4adsmk9fs56qz3y enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByekVack5MY2JOQ0lEYmRs - aXFpMUJkYVg4SlhNb2c3OHNKNitXOUNDODJRCmNrNFUzbldiR0pVTUZ3dGNndVIx - YmM2c1A1em5CMDBPZzJ6S2w3WTJDZTAKLS0tIDFMTWxFOUQrZkdzb2szOTdxOXk1 - Nzlxa1J2UGZoaTh0SG5zN1Y0a3B3dTAKatwUbV4gvQeHACRfD+aBqM5X2/cKK6MK - RZM1PBXJPb8vG8mYeF8PRq2//mf3q5ZY5TKZSBrlyzUGQW5odE8Z4Q== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6R0djMTArVmFySE5DMnFr + WFdBUERFbE1HRVVFd0oyaXJ2eU5HUStBUFN3CnR3ckZ2bkpGZFFScHQwTlBZYTMv + cTBXbGVoTXlWczhId05QVjZDRzFqRjQKLS0tIDNIcVBydHYwTGRnVU1mWWk4WTlR + eVlwQWgxSG5SdmFrWTlOcFo5eXZONWMKgx4huoSnbkRq0wQbsYgsWUKDTxDGNvYR + anVMQg+c7PwDlk1V4JQZ4WrYLx63Ep5qDjGlN/Ssf2Vo6rAuuKetcA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1jhf7vm0005j60mjq63696frrmjhpy8kpc2d66mw044lqap5mjv4snmwvwm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2QjZYejFYbCswQjdmaDA0 + L2ZqUUhtYU12YlpISmxueHQzRG5YL0tQNXh3CndGamMwRzYvUzkvaE9DVnMwTkNC + cFMxczZuOUorS3dnVUpjaVdCUjhLZ2MKLS0tIGlDeGRGa3dRbWgzT3NVYjBaYUJ4 + VW5yeFlvWUZ5MVpNZHA5M1VXR1hxU1kKqii08/MB2aabgP4RQs1ry8AxmFqB8Mn+ + m7B0u64aziKXLSl0u471wqgD+YGRwNcajXT2pHCy8QWLznzvIMSrxA== -----END AGE ENCRYPTED FILE----- - recipient: age13lmqgc3jvkyah5e3vcwmj4s5wsc2akctcga0lpc0x8v8du3fxprqp4ldkv enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCY2hUV011aDh5YVo4TVBa - d0dpQ1dPU05yQlpMN1YraTg5UDliZ29GUVNnCjBRZ2xSdC9za2IvcWJ2RGhyVEZr - YWVmRllNWTA3R1orVWM5U3VtMzQ5NHcKLS0tIFZtUk5pdGhrNlhPTUtqYWJhbkVH - TmFjOVlaRlNRa0w4R05VSkZZNEJxYmMKT8caJNvmoLIl5XRY/jba1BGKSkNy8dbz - Ja0yn//2z+TZ+dDBTNfaSJxCehu+APPbd1TNI8SUOfkit3CJP//O4w== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrSUc3VnllVDFZTm1jRnlP + ZDBqelhkeHliZ1VlcjVnblQyeFlWclZTWkZjCjhJQk5EWkVoQjdoMHg4Zko4OU1C + NWFnVTIwV3RYbTZSeWttaVRPbjNrMG8KLS0tIDZWUHJSbVVlR0lKUDRtc3VqOTc1 + cGJ3NDBLem9FNUpnbStYRTlqQStHV2sKwxPe4nTULsU0mVeUh8mhr2KX9U0iT5dL + zvHldoQG6mZHgtHK6XI5AQJYf+zUW66OKqNSxAnn+BM20QkAQVZNVw== -----END AGE ENCRYPTED FILE----- - recipient: age1l272y8udvg60z7edgje42fu49uwt4x2gxn5zvywssnv9h2krms8s094m4k enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEVHlXdGo2am5iSHVSajNR - TnFoK2lkRk9VSW5DRjk0Tk9NT1VVd3d2RkhzClYrL3UvVGFYaUVabVVuMkpoQ1Vs - SGdldTYyY0I0VHcvYWRseElCT09mczQKLS0tIDBsdERWWG03R3N0bzdOa0poSkVD - YVNCYVZFT3hpTGprQzF1czA2Q2I2RmsKDkfZoT8q8xlaBWXfCIiKEK/15UJ3TGrf - a3mKyIP0+4UmfAEuxq4HhlHp0mMKplGV9PgbipaBO8Sz5+o3rXZZ8Q== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0NU9ac2FuRHI1dkQycmc0 + YlhGK29UeTdiZEZXcWtPUW4rMis4Z2NWYWpJCkVldEdMc3ZTaDFidHpaZk5mM283 + bTd0RlN5SHVabGhjeXFnSThydnVoem8KLS0tIElWclYvTmtkb0wyNDlKT3ZEckwx + L2NObzZadlJ5d3MyeGRqKy95L3BOMFEKtoswi6r2TmCZzngUkiGQV5TTsuzisMFS + 5QI0aQZwhexqUMvbPuajYKvcPj+D6a2xaxbL3TBRLjOrFmcp5J7/YA== -----END AGE ENCRYPTED FILE----- - recipient: age1ufnewppysaq2wwcl4ugngjz8pfzc5a35yg7luq0qmuqvctajcycs5lf6k4 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyTi9jYmlZK01CT3pJdFVM - czRmdC90aE5JK0ZYa0tCdmVxeGRKTnhMMUNBCm4wTUF4aDZyYlhKUXU0Z2pDMDd1 - SjdMeTZ1L0pNVUZjY25GYkMvQXEwS00KLS0tIHFpYnV3dkRDaTNnbkZlMGRkV3FL - OFhISDl2eHNsNDljeit3TkFnRU5xZnMK+/+DMt2yfA3uZCV3mRBo+QuSkvOOsB0T - 1r7hg2cmulURu794+CnwTNp2VW2/BwWsoCHweTflDok6fsHjsKLHsQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByUlVjM2xpc281bHZzOGVo + L3VEclhJZDd5SS9mazFiTk9DcmxMaWxPT213ClNPWERKQU03OWk0OEVIY05ib2VG + WXhiZDhuMDZ5ZmFPWHB5RTFKYmpkVzAKLS0tIGppUndCb25wb2dyV01YbENrWjdU + TmMvWVpobnl0eXBIOGQwMW5BSlhJTUkKzua1artJWbZlKfzv27xfZJeBpntBYwUf + c8i1gNlvRwkhFAlrWcKR65vgyxsO3rbkLJRkcwG/q4hHj9zBeC/K2A== -----END AGE ENCRYPTED FILE----- lastmodified: "2025-08-24T22:36:28Z" mac: ENC[AES256_GCM,data:gtY2M4+BGBRJFzuRURjJypTTbjhn+pVJoKy2REa4a/hSpn7Rnp2Nk3t0/DNYKIquGS7gFxYpXQnUyhBHlAfXqnQWu5InE2b6iLG6INdzeyPI4dGfJaop8ZxXTCKNy3kLgW9kkjBbS1uQlHvy9y/2J+QjjjHPw7M4Fh+E9XKwDGk=,iv:OoCyzLvP6iVwrU2xmK/7ov4h0QqrWk+XbGDiUJ68kJo=,tag:iYVF12f7iHm/dkWFTIsO8Q==,type:str]