- Services: Added Part-DB

- Implementation: Added nix-sops based secret version controlling.
This commit is contained in:
Root User 2026-02-07 17:31:23 +01:00
parent 99a0ed1719
commit 5e68e6ee96
Signed by: root
GPG key ID: 087F0A95E5766D72
19 changed files with 258 additions and 86 deletions

3
.gitignore vendored
View file

@ -1,5 +1,4 @@
/target
# Secrets and local env
/nix-system-configs/modules/secrets/secrets.nix
/.env
.env

15
.sops.yaml Normal file
View file

@ -0,0 +1,15 @@
keys:
- &admin_christine age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m
- &server_songsheet age1es0va2hjshgsv8tfyfjw6sfu6dm7q9u6wza3t9nevlakxzmxr4lqn2q7r6
- &server_traefik age1rdcs8y4fjfyagwt2q9599ax329thceersh6dg2f0p6nsghm5xufq00qu0p
creation_rules:
- path_regex: nix-system-configs/secrets/songsheet/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *admin_christine
- *server_songsheet
- path_regex: nix-system-configs/secrets/traefik/[^/]+\.(yaml|json|env|ini)$
key_groups:
- age:
- *admin_christine
- *server_traefik

View file

@ -136,13 +136,14 @@
services.postgresql = {
enable = true;
enableTCPIP = true;
ensureDatabases = ["forgejo"];
ensureDatabases = ["forgejo" "part_db_database"];
settings = {
listen_addresses = "*";
};
authentication = pkgs.lib.mkOverride 10 ''
local all all trust
host all all 10.1.1.4/32 scram-sha-256
host all all 10.1.1.249/32 scram-sha-256
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
'';
@ -158,7 +159,7 @@
services.openssh.enable = true;
# Open ports in the firewall.
networking.firewall.allowedTCPPorts = [5432 3306]; # PostgreSQL default port
networking.firewall.allowedTCPPorts = [5432 3306]; # PostgreSQL and MariaDB default port
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;

View file

@ -1,61 +0,0 @@
version: '3.3'
services:
partdb:
container_name: partdb
# By default Part-DB will be running under Port 8080, you can change it here
ports:
- '633:80'
volumes:
# By default
- ./uploads:/var/www/html/uploads
- ./public_media:/var/www/html/public/media
- ./db:/var/www/html/var/db
restart: unless-stopped
image: jbtronics/part-db1:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.YOUR.DOMAIN`)"
- "traefik.http.routers.myservice.entrypoints=websecure"
- "traefik.http.services.myservice.loadbalancer. server.port=80"
depends_on:
- database
environment:
# Replace 4321112sss with the value of MYSQL_PASSWORD from below
- DATABASE_URL=mysql://partdb:4321112sss@database:3306/partdb
# In docker env logs will be redirected to stderr
- APP_ENV=docker
# Uncomment this, if you want to use the automatic database migration feature. With this you do not have to
# run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/
# folder (under .automigration-backup), so you can restore it, if the migration fails.
# This feature is currently experimental, so use it at your own risk!
- DB_AUTOMIGRATE=true
# You can configure Part-DB using the webUI or environment variables
# However you can add any other environment configuration you want here
# See .env file for all available options or https://docs.part-db.de/configuration.html
# Override value if you want to show a given text on homepage.
# When this is commented out the webUI can be used to configure the banner
#- BANNER=This is a test banner<br>with a line break
# If you need to install additional composer packages (e.g., for specific mailer transports), you can specify them here:
# - COMPOSER_EXTRA_PACKAGES=symfony/mailgun-mailer symfony/sendgrid-mailer
database:
container_name: partdb_database
image: mysql:8.0
restart: unless-stopped
command: --default-authentication-plugin=mysql_native_password --log-bin-trust-function-creators=1
environment:
# Change this Password
MYSQL_ROOT_PASSWORD: jijoioajdiojasdas1123
MYSQL_DATABASE: partdb
MYSQL_USER: partdb
MYSQL_PASSWORD: 4321112sss
# Uncomment the following line if you need to access, your MySQL database from outside of docker (e.g. for debugging), normally you should leave that disabled
#ports:
# - '4306:3306'
volumes:
- ./mysql:/var/lib/mysql

View file

@ -0,0 +1,2 @@
## Todo, make a proper script for this
compose2nix --inputs nix-system-configs/modules/songsheet/wavelog/docker-compose.yml --sops_file nix-system-configs/secrets/songsheet/secrets.yaml --project=wavelog --output nix-system-configs/modules/songsheet/wavelog/docker-compose.nix --root_path nix-system-configs/modules/songsheet/wavelog

View file

@ -1,19 +0,0 @@
{
config,
pkgs,
lib,
...
}: {
# TODO Figure out a better way to manage secrets.
# CHECK OUT https://github.com/ryantm/agenix
local.secrets = {
gitUserName = "Your Name";
gitUserEmail = "you@example.com";
codeberg = {
username = "your-codeberg-user";
password = "your-codeberg-password-or-token";
};
sshRootPassword = "changeme";
tailscaleAuthKey = "";
};
}

View file

@ -0,0 +1,31 @@
{
config,
pkgs,
lib,
...
}: {
imports = let
# replace this with an actual commit id or tag
commit = "17eea6f3816ba6568b8c81db8a4e6ca438b30b7c";
in [
"${builtins.fetchTarball {
url = "https://github.com/Mic92/sops-nix/archive/${commit}.tar.gz";
# replace this with an actual hash
sha256 = "0000000000000000000000000000000000000000000000000000";
}}/modules/sops"
];
# This will add secrets.yml to the nix store
# You can avoid this by adding a string to the full path instead, i.e.
# sops.defaultSopsFile = "/root/.sops/secrets/example.yaml";
sops.defaultSopsFile = ./secrets/songsheet/secrets.yaml;
# This will automatically import SSH keys as age keys
sops.age.sshKeyPaths = [ "~/.ssh/ssh_host_ed25519_key" ];
# This is using an age key that is expected to already be in the filesystem
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
# This will generate a new key if the key specified above does not exist
sops.age.generateKey = true;
# This is the actual specification of the secrets.
sops.secrets.example-key = {};
sops.secrets."songsheet/database" = {};
}

View file

@ -25,11 +25,63 @@
virtualisation.oci-containers.backend = "podman";
# Containers
virtualisation.oci-containers.containers."partdb" = {
image = "jbtronics/part-db1:latest";
environment = {
"ALLOW_ATTACHMENT_DOWNLOADS" = "0";
"APP_ENV" = "docker";
"BASE_CURRENCY" = "EUR";
"DATABASE_URL" = "postgresql://:@:/?charset=utf8";
"DEFAULT_LANG" = "en";
"DEFAULT_TIMEZONE" = "Europe/Berlin";
"INSTANCE_NAME" = "Part-DB";
"POSTGRES_DB" = "part_db_database";
"POSTGRES_HOST" = "10.1.1.251";
"POSTGRES_PORT" = "5432";
"USE_GRAVATAR" = "0";
};
environmentFiles = [
config.sops.secrets."songsheet/database".path
];
volumes = [
"nix-system-configs/modules/songsheet/wavelog/db:/var/www/html/var/db:rw"
"nix-system-configs/modules/songsheet/wavelog/public_media:/var/www/html/public/media:rw"
"nix-system-configs/modules/songsheet/wavelog/uploads:/var/www/html/uploads:rw"
];
ports = [
"8087:80/tcp"
];
labels = {
"compose2nix.settings.sops.secrets" = "songsheet/database";
};
log-driver = "journald";
extraOptions = [
"--network-alias=partdb"
"--network=wavelog_default"
];
};
systemd.services."podman-partdb" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
};
after = [
"podman-network-wavelog_default.service"
];
requires = [
"podman-network-wavelog_default.service"
];
partOf = [
"podman-compose-wavelog-root.target"
];
wantedBy = [
"podman-compose-wavelog-root.target"
];
};
virtualisation.oci-containers.containers."wavelog-db" = {
image = "mariadb:11.3";
environment = {
"MARIADB_DATABASE" = "wavelog";
"MARIADB_PASSWORD" = "oijawfjiojoijoiawf";
"MARIADB_PASSWORD" = "THIS_IS_NOT_IN_USE_yes";
"MARIADB_RANDOM_ROOT_PASSWORD" = "yes";
"MARIADB_USER" = "wavelog";
};

View file

@ -1,4 +1,65 @@
services:
partdb:
container_name: partdb
# By default Part-DB will be running under Port 8080, you can change it here
ports:
- '8087:80'
volumes:
# By default
- ./uploads:/var/www/html/uploads
- ./public_media:/var/www/html/public/media
- ./db:/var/www/html/var/db
restart: unless-stopped
labels:
- "compose2nix.settings.sops.secrets=songsheet/database"
image: jbtronics/part-db1:latest
environment:
# Put SQLite database in our mapped folder. You can configure some other kind of database here too.
- POSTGRES_HOST=10.1.1.251
- POSTGRES_PORT=5432
- POSTGRES_DB=part_db_database
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?charset=utf8
# In docker env logs will be redirected to stderr
- APP_ENV=docker
# Uncomment this, if you want to use the automatic database migration feature. With this you have you do not have to
# run the doctrine:migrations:migrate commands on installation or upgrade. A database backup is written to the uploads/
# folder (under .automigration-backup), so you can restore it, if the migration fails.
# This feature is currently experimental, so use it at your own risk!
# - DB_AUTOMIGRATE=true
# You can configure Part-DB using environment variables
# Below you can find the most essential ones predefined
# However you can add any other environment configuration you want here
# See .env file for all available options or https://docs.part-db.de/configuration.html
# !!! Do not use quotes around the values, as they will be interpreted as part of the value and this will lead to errors !!!
# The language to use serverwide as default (en, de, ru, etc.)
- DEFAULT_LANG=en
# The default timezone to use serverwide (e.g. Europe/Berlin)
- DEFAULT_TIMEZONE=Europe/Berlin
# The currency that is used inside the DB (and is assumed when no currency is set). This can not be changed later, so be sure to set it the currency used in your country
- BASE_CURRENCY=EUR
# The name of this installation. This will be shown as title in the browser and in the header of the website
- INSTANCE_NAME=Part-DB
# Allow users to download attachments to the server by providing an URL
# This could be a potential security issue, as the user can retrieve any file the server has access to (via internet)
- ALLOW_ATTACHMENT_DOWNLOADS=0
# Use gravatars for user avatars, when user has no own avatar defined
- USE_GRAVATAR=0
# Override value if you want to show a given text on homepage.
# When this is empty the content of config/banner.md is used as banner
#- BANNER=This is a test banner<br>with a line break
# If you use a reverse proxy in front of Part-DB, you must configure the trusted proxies IP addresses here (see reverse proxy documentation for more information):
# - TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
# If you need to install additional composer packages (e.g., for specific mailer transports), you can specify them here:
# The packages will be installed automatically when the container starts
# - COMPOSER_EXTRA_PACKAGES=symfony/mailgun-mailer symfony/sendgrid-mailer
wavelog-db: # THIS IS NOW DANGLING BUT WILL BE THERE TO PREVENT BREAKAGE OF THE MAIN COMPOSE FILE
image: mariadb:11.3
container_name: wavelog-db
@ -6,7 +67,7 @@ services:
MARIADB_RANDOM_ROOT_PASSWORD: yes
MARIADB_DATABASE: wavelog
MARIADB_USER: wavelog
MARIADB_PASSWORD: oijawfjiojoijoiawfoij191229888dajkvhiuviuaiuhvaihuauis1123312 # THIS DATABASE IS NOW MIGRATED PROPERLY
MARIADB_PASSWORD: THIS_IS_NOT_IN_USE_yes # THIS DATABASE IS NOW MIGRATED PROPERLY
volumes:
- wavelog-dbdata:/var/lib/mysql
restart: unless-stopped

View file

@ -38,6 +38,7 @@
#
## Compose modules for Portainer service
./modules/songsheet/wavelog/docker-compose.nix
./modules/secrets/sops-nix.nix
];
config = {

View file

@ -0,0 +1,31 @@
#ENC[AES256_GCM,data:WivH9NVGw2eQUc+4xk3IXc355x7dddo3f/C0f8Pl0JJJCBhvmGI=,iv:5g32fF7BGOUO5/5GkelUBeTP7d0oyIPhAajZHpXIKiY=,tag:fNlYIPKPH8CiZsPvQmgODg==,type:comment]
example-key: ENC[AES256_GCM,data:aoCe/3ALWztLUQ9wyQ==,iv:BFDhmeK5LqqVvh5lBoPIaAXkV0Qi0K2maEwSFuOLO2Q=,tag:PIKqisBResQh7nhv8kxXAg==,type:str]
#ENC[AES256_GCM,data:QMlHRBS1gtTdUMs/gzvekyAAnDHqE9KA+deYvxP18aIln5vX/aFoi/heQp/9W33hiqv5Oc4nepg=,iv:ceJjaqud+qbMWmfJHDmKJeGtO/2BsWQEzeMtQL1WZI0=,tag:QlR7GZ3Om3mT0Ycq3UdJCA==,type:comment]
#ENC[AES256_GCM,data:E1y/QQ1q5u1nC0gjutZuiA1TN6zLWD3EI9qdu8phRZ34GNIytQ5FJpTv+P9JGUN19wpj8S/ZFX3SxqGLIxq5eCr8Zl4gL5bc,iv:3mdIV8+2BEX9NX2PfWtjqKZmR45CpEKvGrd5FqvgMhM=,tag:x5aAWNR/M3OqLRmCAx8frg==,type:comment]
myservice:
my_subdir:
my_secret: ENC[AES256_GCM,data:mTlHHpNvgJGz,iv:Nb3HWXKMI8DopwB020lYBJc/wsLAxl+6ZpYtrtDc4Ic=,tag:sV/2xqwdWzAdcKo6Z1aS+A==,type:str]
sops:
age:
- recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArMmt5dzBaOHV2ZXJNVjUx
Smdxc2w0QXBuQlVZZzYwK0h6Ry9ydnEyWFFNCkdZLzk5RkV0U0I0dmROdUZNUHND
YWRlQnRadWh4YWVHRFF4N0JsanJjc00KLS0tIFlNWG9nSUVRRnJJY0xVZDNzNVE1
MU5xUGlNcWxYZUR5bnI4NXlzZ1F1ejAK+jaAVZ1ePZNWzyIRNZQwLn1YIbQ6czTw
jOO6XHvDJAFzJotjPRqjstiB6aWzGoNXsE2DzWu0MXSIpeGpn9d3tQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1es0va2hjshgsv8tfyfjw6sfu6dm7q9u6wza3t9nevlakxzmxr4lqn2q7r6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCSGFBTktSaHorcE9iOEhh
NDhFbGpySXRYeGhkb1BqTjU3M0V4M0srL1ZFCk81OVRnUzhZMVNnMzlkbTc0ZDh0
akJqMHRXV0xvY3JqczNsV0lQeVRGNEUKLS0tIDgwYk9vOTB2aUVxWnpzRTZMQUZx
UzdHOG0yUGFLZnVGeExwMEp3LzJ6QncKDGGZ1LvafbZ52GOIk8SyhvPIU9hayd+G
FGOgC5n0pbBhk7/OM6JQrc+I5df5Kg4mAaTZ+ANgPBDUrfwFA0EyqA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-07T15:38:34Z"
mac: ENC[AES256_GCM,data:xZg0gY7K1scWgZ4ITRLVPqx3igffvcQTf0/UyUPO7y0AEmxWpPt5sAdHJujjTjXAuSiLV8+XlEAH9ePh6gx8NZDXfscMsjyyOXGcDpYzwSfoWpFsSB4oeDkOw/vy0YTmEbs9R9pXU6Kc3TRnXbZNYzwZqgoI20GXxBesDxDrp4k=,iv:KCKtqUfdi8alD7wxVgF/wTjUoHfYC48r7Ar8NKy4TFM=,tag:U0RU11e/I4C361dDe5jH8Q==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0

View file

@ -0,0 +1,25 @@
songsheet/database: ENC[AES256_GCM,data:cNZsgTmTSjHXK7k0R7/Kz7kW6MacTkzcqZrZd/DswVm1yPQEm9oJyPNCv39LqEvKKNBa4XA0HmjaHzOBHMAr1zSG1vRRB7Fe3ZSQaxAeamRh7X7BxkxXkdvnCtcQ6wNe,iv:aF7skRVNlvoJp9UNBNMEZSMI/hRXnZ6GaDX+GOvVqdQ=,tag:Kytf5ciAd1uSUZVwfOJpbA==,type:str]
sops:
age:
- recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMZE9QbHFZUGFBa0V6dVha
YUQ1a2FKdG96dTVvbW91VzVQL2tkZ3pKdFJBCmJmUWZYaVRmWkM3ZUNxbzhrRXg4
L1p1SXhvQXFzUmNaYUVhRm5PNmVzcFUKLS0tIEl0aXJGcmRPVmpmMVlSb3BZVnhL
K3BpOGZQbG0wR1UveGkwWUU3SjV6NU0K1ThvPddlKv/KaZceGuGv8DDKgdAi7+yZ
rmRI6b9IibZ7F7ECMjEB5Ks+ETi4Voi2lm8UhxlTaL8SDfJc4tCiIw==
-----END AGE ENCRYPTED FILE-----
- recipient: age1es0va2hjshgsv8tfyfjw6sfu6dm7q9u6wza3t9nevlakxzmxr4lqn2q7r6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2NEs3NjR4Ty8xeG1HQ0JT
REVBN1VWRlJ3UlhsTk5BUTN2TStBMTdVa21RCkhtQWFXeXQyMFlMSnpBWnExWHR1
WGhMZUMzdWZlWXRkdEY4Wm5xVllIUUUKLS0tIDRyaVpLUEFKNk05SnZJZ3N6N3Vv
OVZNS1ErTm9hN3IvSHB3bkY1SE5OQlEK1g4PhqXmqIlDLYBiHnH7Z4hgDyhJLH8H
yxfbmpCb9eF3qDhTVD7Cw20sO4YX32OujkCrbnEYS5/tRxEiOyoNHQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-07T16:09:47Z"
mac: ENC[AES256_GCM,data:BR7Vh6P+BseiL7kiK7aHDyV8P5yWxZH3FCX4ubUevOZyGqv+J7CwO+Ezz/E6N3V5E15krfqTPJZtsA+5lXxf8Jl13ylZ/kR27iOOLFy4XTOaQ5aKMGLIjJ7Mz/V4axdfvW/rNgpKAYXth1OaGrl054ua6i6AQ95LHphbofihtTo=,iv:YUku5Nu8xA5E9vNvcGp1M/3x3ug8yNDpciGhXneUtAQ=,tag:AM0rl4ScEji9jkykYoJvzA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0

View file

@ -0,0 +1,34 @@
hello: ENC[AES256_GCM,data:Ht0+7vR6M8YQn3AiMd8VRXX8r5LIjIy/lA8wDytdZwJI8aj8NmJxgC5a5llBSA==,iv:7nmFM2BZYX//LVEdCOCtMSOJL15an/A3UOGtTjma57c=,tag:1GxNe1Kh5v4KNJAoi8TKmA==,type:str]
example_key: ENC[AES256_GCM,data:DPLNFkv40KHgypLLWg==,iv:c3LfkDlckJbSiWBmfD6O6MXvIPM8ps8Rv1h2W9DDyOs=,tag:d+e23wPKvwFySmevmULMdQ==,type:str]
#ENC[AES256_GCM,data:arG8CBMdLjfBCjmdyTP/lw==,iv:9PcE6aokqhUp/+j3QaJSPJ6H+YjnFOkztinI9sSTZ+k=,tag:+KNsGsKIf8XRNf2V3FRRUg==,type:comment]
example_array:
- ENC[AES256_GCM,data:/nVGqCjXBoYAkdCHOrRO93/jJg==,iv:rdONhvd1j8AvWi9M19pR1p00QwuB3bz/Q/S4U8ZfjBQ=,tag:iWDJ7o4ChllJJcNDvhGthQ==,type:str]
- ENC[AES256_GCM,data:/Kgmo6PFheSZbNlKnUVG4rEAwA==,iv:WSEH0q234nDkiGcM3gs/vztWiV6UlkLSSy57kJWKt9c=,tag:d+hu8tM2LOSNn2orVxQZhA==,type:str]
example_number: ENC[AES256_GCM,data:qfxirRhQiqU5XN9iRg==,iv:dTiPBUs5RCEYD04DQZxoXB8lPDrAu+Ra4NvLBmx3X9E=,tag:w43whPCNQmUumBdZ2sD5pw==,type:float]
example_booleans:
- ENC[AES256_GCM,data:+1KdwA==,iv:8JXmEdeukxQIDfy4eacQ48Ayl3cCRfPNcSjzQYC/Yuw=,tag:erCKahtbNDD1S8MilF09Jg==,type:bool]
- ENC[AES256_GCM,data:Y0eWzvE=,iv:MjhUjfHcE+WPkxnwK7m1RMujVcauo6Ftx496R+wdJ7c=,tag:FqiTsd4UinkJ1hnST20Ekw==,type:bool]
sops:
age:
- recipient: age1746rvsvsc3snxfl7cndm222wd5kck4aqj3x7nednlegq0gdjhfcqx0qv7m
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoaHlPc3ZZWVZJQXhXaG1u
OHFDVGxmcWVZbHpmRUlqYlZMRkp0WlU4L25ZCkRGbzJvRDRKOE82bUVlTFVJcTQy
R20rRklCZnMwbVEwQ3FtZGpYNlI3VEkKLS0tIFVLdkp1SEM1Mm1xRi9ZV0o5RlA1
cWtGaTJkdU12NkI4WVREOEt1VHVYYVkKs4lPeAhAazGAo5MZp7gKVYlrYBoNKBid
91ayxAbJKVrUnapd+QNDFG2+apDuirbWhKSxCPnLUEed+YMKNzQVgQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age1rdcs8y4fjfyagwt2q9599ax329thceersh6dg2f0p6nsghm5xufq00qu0p
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUWmpCTGtoS3NpdDVrMS9V
ZG9mZHgzeUpTWVRLVDVMbzFybmF3Q09KekJrCjlBdEZzcmxWcFUxdnNNZ2FuK3Nn
d1RZLytJK0RNVjdTVzFRWHpwMUMzRnMKLS0tIHFMdjErdzNDc2I1czVCRzBlR3o0
NkMrTEtzK3BSVWN0bk1ITHlORVd0bWcKSN/WwEZ2KJwYr3WLShF2gAG/ECKYk8ut
Ay3lMgsQJERQ5xQnauEqinELaN/FQHJgBFYkRgIAb/JU14a6viwDoA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-02-07T16:28:39Z"
mac: ENC[AES256_GCM,data:CK6lT9nrLAE6r+6C5vadtYr6/uP9WcbpRM1QZnNjOblaDvgfGQvQMc3u3Ddu93d9sg5M6bVIh8gUDz+f5KkqMEAnLD+thy1Zl05lDUQFm0TCy1X1uHks3V/XvMl3m5kZYFf6sq4fpN3dwdP2NdofbffyTeD8mqA9j6YHTID4yxk=,iv:GhgePFxI0L83aOaoW5LB/5Q8h730GTcmvQdktrDmRls=,tag:AzOPttDhfJmw2JfnquoAjQ==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0