From 971ab74d441ddd2e5ffde13450a754f8daf7a5f1 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 9 Aug 2026 21:28:38 -0400 Subject: [PATCH] Escape $ in the compose-interpolated .env so MQTT passwords survive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compose interpolates the top-level .env, so a password containing "$fP" was read as the variable $fP and replaced with an empty string — hence the repeated "The \"fP\" variable is not set" warnings on every compose command. The env_file templates are not interpolated, so c2-core kept the literal password while mosquitto's entrypoint received the mangled one. The two sides disagreed and c2-core could not authenticate to the broker. Escaping $ as $$ here (and only here) makes compose collapse it back to the real value. Co-Authored-By: Claude Opus 5 --- infra/ansible/roles/deploy/templates/root.env.j2 | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/infra/ansible/roles/deploy/templates/root.env.j2 b/infra/ansible/roles/deploy/templates/root.env.j2 index d71cefb..b8c307a 100644 --- a/infra/ansible/roles/deploy/templates/root.env.j2 +++ b/infra/ansible/roles/deploy/templates/root.env.j2 @@ -1,10 +1,19 @@ # Top-level docker-compose environment — MQTT credentials and registry prefix. # Managed by Ansible. Do not edit manually. +# +# The passwords are $-escaped ($ -> $$). Compose INTERPOLATES this file, so a +# raw "$fP" in a password is read as the variable $fP, warned about, and +# replaced with an empty string. The env_file templates (c2-core.env.j2 etc.) +# are NOT interpolated, so they keep the literal value — which means an +# unescaped $ here silently gives mosquitto and c2-core two different +# passwords and MQTT auth fails. Compose collapses $$ back to a single $, so +# both sides end up with the real password. +# Do not add the same escaping to the env_file templates; it would be literal. MQTT_C2_USER={{ vault_mqtt_c2_user }} -MQTT_C2_PASS={{ vault_mqtt_c2_pass }} +MQTT_C2_PASS={{ vault_mqtt_c2_pass | replace('$', '$$') }} MQTT_NODE_USER={{ vault_mqtt_node_user }} -MQTT_NODE_PASS={{ vault_mqtt_node_pass }} +MQTT_NODE_PASS={{ vault_mqtt_node_pass | replace('$', '$$') }} # Container registry prefix — docker compose uses this for image: ${REGISTRY}/name:latest REGISTRY={{ vault_registry }}