mosquitto: its directories are placed, not stated, and it runs the build in use #144

Merged
mesh-admin merged 2 commits from feat/mosquitto-placed into main 2026-09-30 14:14:14 +00:00
Contributor

The module stated /var/lib/mosquitto-module and /services/mosquitto/data —
novox's layout, a path no definition may carry (ADR 0112). State, grants and
data are now placed directories (${dir:state}, ${dir:grants}, ${dir:data}),
the admin secret lives beside the broker account under the mesh's own state,
and the receives/grants maps follow the grants directory. Paths inside the
sidecar are its own view and are unchanged.

Image pinned to the 2.1.2 build ace's predecessor runs (2026-09-17); the old
pin was the same version, built in June.

Found preparing ace, whose broker carries a password-file user (an IoT switch
and home-assistant). Carrying it is a data step, not a manifest one: the
migration repo has scripts/mosquitto-pwdfile-to-dynsec.py, which moves 7
PBKDF2 entries into the dynsec store hash-for-hash (tested end to end).

The module stated /var/lib/mosquitto-module and /services/mosquitto/data — novox's layout, a path no definition may carry (ADR 0112). State, grants and data are now placed directories (${dir:state}, ${dir:grants}, ${dir:data}), the admin secret lives beside the broker account under the mesh's own state, and the receives/grants maps follow the grants directory. Paths inside the sidecar are its own view and are unchanged. Image pinned to the 2.1.2 build ace's predecessor runs (2026-09-17); the old pin was the same version, built in June. Found preparing ace, whose broker carries a password-file user (an IoT switch and home-assistant). Carrying it is a data step, not a manifest one: the migration repo has scripts/mosquitto-pwdfile-to-dynsec.py, which moves $7$ PBKDF2 entries into the dynsec store hash-for-hash (tested end to end).
mesh-admin added 1 commit 2026-09-29 21:05:44 +00:00
The module stated /var/lib/mosquitto-module and /services/mosquitto/data —
novox's layout, a path no definition may carry (ADR 0112). State, grants and
data are now placed directories (${dir:state}, ${dir:grants}, ${dir:data}),
the admin secret lives beside the broker account under the mesh's own state,
and the receives/grants maps follow the grants directory. Paths inside the
sidecar are its own view and are unchanged.

Image pinned to the 2.1.2 build ace's predecessor runs (2026-09-17); the old
pin was the same version, built in June.

Found preparing ace, whose broker carries a password-file user (an IoT switch
and home-assistant). Carrying it is a data step, not a manifest one: the
migration repo has scripts/mosquitto-pwdfile-to-dynsec.py, which moves $7$
PBKDF2 entries into the dynsec store hash-for-hash (tested end to end).
jschoubben added 1 commit 2026-09-30 11:11:57 +00:00
mqtt-topic served nothing: with two listens the mesh could not say which port a consumer dials, so a
consumer had to type 1883 into its config. It now serves the MQTT listener's port (the machine's,
once assigned) and the scheme, so `${bound:mqtt-topic:port}` fills.

The provisioner confined every consumer to `<as>/#`, which leaves nothing for the consumers the
broker exists for: Home Assistant discovers under homeassistant/# and tasmota/discovery/#, and
Node-RED's flows follow the devices' own topics. A consumer now contributes `topics` (MQTT topic
filters) to its mqtt-topic requirement and is granted exactly those; with none, its own subtree as
before. Settings merge into contributions, so an operator narrows a grant per assignment. The role
is brought to exactly the wanted ACLs (stale ones removed), `holds` checks the ACLs too, and an
invalid list is refused, never quietly narrowed. Only the role named for the consumer is touched:
a client carried from the predecessor's password file keeps its own.
Author
Contributor

mqtt-topic is now a provision consumers can use without typing anything (commit 1080f45)

  • serves {"scheme": "mqtt", "port": 1883}. With two listens the mesh couldn't tell which port a consumer dials, so bindings had no port. Now ${bound:mqtt-topic:port} is the machine port.
  • Grants are the topics a consumer asks for. Until now the provisioner confined every consumer to <as>/#. That is useless to Home Assistant, which needs homeassistant/#, tasmota/discovery/# and the devices' topics, and to Node-RED, whose flows follow the devices' own topics.
    • A consumer contributes topics (MQTT topic filters) to mqtt-topic and gets exactly those, for publish, receive and subscribe. With no topics it gets <as>/# as before.
    • Settings merge into contributions, so an operator can narrow a grant per assignment.
    • The consumer's role is brought to exactly the wanted ACLs, and stale ones are removed. holds checks the ACLs too, so a hand-edited role is restored within a minute.
    • An invalid list is refused loudly and never narrowed silently.
    • Only the role named for the consumer is touched. Carried clients (luffy / legacy-full-access from scripts/mosquitto-pwdfile-to-dynsec.py) are never read or changed.
  • Tests: test/topics.test.ts (5 passing). tsc typecheck and build are clean in the mesh-tools build image. The controller's catalogue tests pass with #144, #147 (which includes #156) and #149 merged together. A scratch Resolve/Declaration run for ace shows mosquitto's grants/mesh.json carrying mesh_ace_hass and mesh_ace_nodered with topics: ["#"].
  • E2E (throwaway prov-mosquitto-* on 19381, removed afterwards):
    • The module's bootstrap seeded the store, a password-file user was carried with the migration script, and the provisioner created both clients with #.
    • Narrowing to stat/# and cmnd/+/Power removed the # ACLs.
    • An invalid a/#/b was refused and left the role untouched.
    • An ACL removed by hand was re-applied by holds within 60 s.
**mqtt-topic is now a provision consumers can use without typing anything** (commit 1080f45) - **serves** `{"scheme": "mqtt", "port": 1883}`. With two listens the mesh couldn't tell which port a consumer dials, so bindings had no `port`. Now `${bound:mqtt-topic:port}` is the machine port. - **Grants are the topics a consumer asks for.** Until now the provisioner confined every consumer to `<as>/#`. That is useless to Home Assistant, which needs `homeassistant/#`, `tasmota/discovery/#` and the devices' topics, and to Node-RED, whose flows follow the devices' own topics. - A consumer contributes `topics` (MQTT topic filters) to `mqtt-topic` and gets exactly those, for publish, receive and subscribe. With no `topics` it gets `<as>/#` as before. - Settings merge into contributions, so an operator can narrow a grant per assignment. - The consumer's role is brought to exactly the wanted ACLs, and stale ones are removed. `holds` checks the ACLs too, so a hand-edited role is restored within a minute. - An invalid list is refused loudly and never narrowed silently. - Only the role named for the consumer is touched. Carried clients (`luffy` / `legacy-full-access` from `scripts/mosquitto-pwdfile-to-dynsec.py`) are never read or changed. - Tests: `test/topics.test.ts` (5 passing). tsc typecheck and build are clean in the mesh-tools build image. The controller's catalogue tests pass with #144, #147 (which includes #156) and #149 merged together. A scratch Resolve/Declaration run for ace shows mosquitto's `grants/mesh.json` carrying `mesh_ace_hass` and `mesh_ace_nodered` with `topics: ["#"]`. - **E2E** (throwaway `prov-mosquitto-*` on 19381, removed afterwards): - The module's bootstrap seeded the store, a password-file user was carried with the migration script, and the provisioner created both clients with `#`. - Narrowing to `stat/#` and `cmnd/+/Power` removed the `#` ACLs. - An invalid `a/#/b` was refused and left the role untouched. - An ACL removed by hand was re-applied by `holds` within 60 s.
mesh-admin merged commit 3ae63f10c5 into main 2026-09-30 14:14:14 +00:00
mesh-admin deleted branch feat/mosquitto-placed 2026-09-30 14:14:14 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#144