The argocd_private_repo provisioner only ran when its static triggers
(namespace, repo_url, ssh_key_path) changed. When the Gitea SSH host key
rotated (container rebuild / Debian rekey), the trigger set stayed
identical so tofu apply never re-ran the ssh-keyscan, silently leaving
Argo CD with 'knownhosts: key is unknown' and all Applications in
ComparisonError.
Add a timestamp()-based scan_revision trigger so the keyscan +
configmap/secret merge runs on EVERY apply, self-healing the host key
in argocd-ssh-known-hosts-cm. The provisioner is idempotent (reads the
existing configmap, merges the fresh scan, sorts, reapplies), so
re-running is safe.
Codify the full Matrix homeserver stack, OmniRoute LLM gateway, and
Hermes agent into the Jeannie deploy pipeline so the repo reproduces
the running homelab from scratch.
New files:
infra/matrix-server/ — Synapse + Postgres + Element docker-compose,
homeserver.yaml.tpl, log_config, element config, bootstrap.sh
infra/omniroute/ — diegosouzapw/omniroute:latest on port 20128
infra/hermes.secret.yaml — SOPS-encrypted bot password + API key
infra/matrix-server/matrix.secret.yaml — SOPS-encrypted Synapse secrets
.sops.yaml — age recipient + encrypted_regex: '.*'
jeannie additions:
deploy_matrix() — renders homeserver.yaml from template, creates
signing key via 'generate' on first boot, delegates to bootstrap.sh
deploy_omniroute() — docker compose up with env-file support
deploy_hermes() — git clone + venv + 'hermes gateway install',
writes ~/.hermes/.env (mode 600), registers non-admin bot via
shared-secret CLI, idempotent
sops_load_secrets() — decrypts *.secret.yaml via age key at deploy
time; fails loudly if the age key is missing
ensure_sops_age_tools() — installs sops from getsops GitHub release
when apt has no sops package (Debian trixie)
DAG: hermes-deploy depends on matrix-deploy + omniroute-deploy.
Root cause: deploy_hermes previously used wrong entrypoint (python
module instead of ./hermes launcher); generate was called with
--generate-config (invalid subcommand); .sops.yaml encrypted_regex
'^password$' left prefixed keys as plaintext — all fixed in this
commit.