First catalog apps to exercise core 26.17's app-to-app dependency feature — until now every app was standalone. - mosquitto: MQTT broker, first dependency *provider*. Mandatory auth; per-consumer accounts created by on_install/on_start hooks (scripts/provision-client.sh, scripts/ensure-client.sh) that run inside the broker container via `docker compose exec`. Provider-side password stash so on_start can restore an account after a volume wipe. - zigbee2mqtt: first dependency *consumer*. `requires` mosquitto; MQTT creds wired in from the provisioning hook via ZIGBEE2MQTT_CONFIG_* env. Serial coordinator path as a text setting + devices mapping. Supporting changes: - Bump vendored furtka_manifest.py (26.10-era -> 26.17) so the validator actually validates the `requires` schema instead of ignoring it. - Document `requires`/hooks in apps/README.md (was undocumented), including the three framework gaps building this pair surfaced. - CI now shellchecks app hook scripts (apps/*/scripts/*.sh), not just repo-root scripts/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
1.9 KiB
Bash
Executable file
47 lines
1.9 KiB
Bash
Executable file
#!/bin/sh
|
|
# on_start hook (provider: mosquitto).
|
|
#
|
|
# Runs INSIDE the mosquitto container on EVERY boot, before the consumer's
|
|
# container starts (reconcile visits providers first). Must be idempotent.
|
|
#
|
|
# Job: make sure the consumer's MQTT account still exists. The common path is
|
|
# a no-op — the passwd file lives on a persistent volume and survives reboots.
|
|
# This only does work if the account went missing (e.g. the data volume was
|
|
# wiped), in which case it restores the SAME password the consumer holds. It
|
|
# never rotates a live password, so the consumer's stored MQTT_PASS keeps
|
|
# working.
|
|
#
|
|
# Where the password comes from:
|
|
# - Core that injects consumer .env into on_start hooks hands it to us as
|
|
# $FURTKA_CONSUMER_ENV_MQTT_PASS — the clean path.
|
|
# - Older core gives on_start no consumer context, so we fall back to the
|
|
# copy provision-client.sh stashed on our own volume at install time.
|
|
# This hook's stdout is discarded by the reconciler (unlike on_install), so
|
|
# restoring the password is the only way to keep the consumer connectable.
|
|
# Errors go to stderr and fail the hook, which makes reconcile skip the
|
|
# consumer's `compose up` rather than start it with a broken account.
|
|
set -eu
|
|
|
|
user="${FURTKA_CONSUMER_APP:?ensure-client: FURTKA_CONSUMER_APP not set}"
|
|
passwd_file=/mosquitto/data/passwd
|
|
stash="/mosquitto/data/furtka-clients/${user}.pw"
|
|
|
|
# Account already present → nothing to do.
|
|
if [ -f "$passwd_file" ] && grep -q "^${user}:" "$passwd_file"; then
|
|
exit 0
|
|
fi
|
|
|
|
pass="${FURTKA_CONSUMER_ENV_MQTT_PASS:-}"
|
|
if [ -z "$pass" ] && [ -f "$stash" ]; then
|
|
pass="$(cat "$stash")"
|
|
fi
|
|
|
|
if [ -z "$pass" ]; then
|
|
echo "ensure-client: account '${user}' is missing and no password is" \
|
|
"available to restore it (no FURTKA_CONSUMER_ENV_MQTT_PASS, no stash);" \
|
|
"reinstall the app to re-provision." >&2
|
|
exit 1
|
|
fi
|
|
|
|
mosquitto_passwd -b "$passwd_file" "$user" "$pass"
|
|
kill -HUP 1 2>/dev/null || true
|