mounts: take an SMB source's username as a setting and its password as its own secret, and wait for them
mesh/merge-gate fail: builds mounts → shanks; no bus step; a manifest the change touches fails the module check: modules/mounts/module.json: this manifest …
mesh/repo-check fail: its merge-check.sh failed: files asking for a setting without saying whether it is trusted: 24
mesh/delivery superseded: a newer head of the same pull request

The one INI secret smb-credentials could not be given through the desk
prompt, which takes one hidden line, and a missing login was said as a
fault: the first-node gate put the build back and the operator was told
nothing was theirs to do. The username is now the setting smb-users and
each password the one-line secret smb-password-<source>; a source missing
either answers waits through mesh-sdk's health answer (hq ADR 0283,
issue 386, issue 379).
This commit is contained in:
jochen
2026-10-10 21:11:16 +02:00
parent a14fa306f2
commit bbb3161ade
11 changed files with 328 additions and 346 deletions
+41 -36
View File
@@ -11,15 +11,16 @@ provision `nfs-share`, which `nfs-server` provides on the machine that shares.
## What it owns
- The packages `nfs-utils` and `cifs-utils`.
- `/etc/mesh-mounts/mounts.conf`, placed by the mesh from the assignment: the settings `shares` and
`sources`, the binding of `nfs-share` (`from`, the sharing machine, and `at`, where it is reached on
the private network), the operator account, and where the module's secret is.
- `/etc/mesh-mounts/mounts.conf`, placed by the mesh from the assignment: the settings `shares`,
`sources` and `smb-users`, the binding of `nfs-share` (`from`, the sharing machine, and `at`, where it is
reached on the private network), the operator account, and where the module's secrets are placed.
- One `.mount` and one `.automount` unit per share or source, in `/etc/systemd/system`, named as
`systemd-escape --path` names the mount point and opened by the marker
`# Written by the mesh (module mounts, novox/hq ADR 0263).` A unit file without that marker is not the
module's: it is never written over, stopped or removed, and the share whose mount point it holds is
said as not set up.
- The SMB logins, one file per source in the module's state directory, readable by root only.
- The SMB logins, one credentials file per source in the module's state directory, readable by root only,
written from the source's username and password.
- `/var/lib/mesh-mounts/from-bus` (the bundle's: what the sharing machine exports) and `/run/mesh-mounts`
(the processes': what was applied and what was found).
@@ -58,7 +59,7 @@ read-write share is mounted hard, so a write is never dropped while the server i
## Settings
Both are preferences whose default, `none`, mounts nothing (ADR 0262 allows no empty default).
All three are preferences whose default, `none`, names nothing (ADR 0262 allows no empty default).
- `shares`: space-separated `name=mountpoint`, each optionally `:ro`. The name is the share's on the
sharing machine; its path there comes from that machine over the bus, never from this setting.
@@ -66,45 +67,39 @@ Both are preferences whose default, `none`, mounts nothing (ADR 0262 allows no e
- `sources`: space-separated occasional sources, each optionally `:ro`:
`name=smb://<host>/<share>@<mountpoint>` or `name=disk:<filesystem uuid>@<mountpoint>`.
For example `games=smb://192.0.2.76/Share@/mnt/games`.
- `smb-users`: the username each SMB source logs in with, space-separated `name=username`, for example
`games=root`. A username is not a secret, so it is a setting (novox/hq ADR 0283). It holds no space,
comma or `=`.
A mount point is an absolute, plainly written path, not a directory of the system's own (`/etc`, `/usr`,
`/run`, …). An entry that cannot be read is said, and only that entry is left out.
## The secret
All three are trusted settings: an agent proposes them (`settings propose mounts … --node <node>`) and the
operator approves the change on their phone; it is set on that approval and pushed after (ADR 0277).
`smb-credentials` is the module's own secret, issued by an outside party (the device's owner), so the mesh
never makes one in its place. It holds one login per SMB source, named by the source's name in brackets.
## The secrets
The operator gives it at the desk with `secret ask <node> mounts smb-credentials` (ADR 0277): a one-line
prompt opens that shows nothing of what is typed, and the login is typed as one line, the keys
space-separated after the name:
Each SMB source's password is its own secret, `smb-password-<source>`: a member of the module's secret
family `smb-password-*`, issued by an outside party (the device's owner). The mesh never makes a value for
a member (ADR 0283), so one not given is no file, and the module reads that as not given.
```
[games] username=… password=…
```
The operator gives it at the desk: an agent asks for it with the controller's `secret-ask` verb (or the
operator runs `secret ask <node> mounts smb-password-<source>`), a prompt opens on that machine's desk that
shows nothing of what is typed and names the module, the secret and who asked, and the password is typed
as one line (ADR 0277). It may also be given from a file at the controller's terminal with
`secret accept <node> mounts smb-password-<source> --from <file>`.
`password=` is last and takes everything after it to the end of the line, so a password may hold spaces
and `=`; `domain=`, when the device wants one, comes before it. The line is read trimmed, so a password
does not end with a space; after `password=` it is kept as typed, so it may begin with one. Several
sources are several such lines, which the prompt cannot take at once: a file can, given with
`secret accept <node> mounts smb-credentials --from <file>`, holding
one line per source, or one section per source with one key a line:
The file is read as one line: one trailing line break is dropped and everything else is kept as typed, so
a password may hold spaces and `=`. An empty file is not given. A file of more than one line is refused,
saying so and never what it holds; give it again. No tool answers a password: the options, fstab lines and
mountinfo the tools read are redacted.
```
[games]
username=…
password=…
domain=… (optional)
```
Both forms give the same login, and a file may mix them. A line the module cannot read is said with the
form it expected, never with what was typed. A source whose login is missing is not mounted, and is said
with that remedy. No tool answers a password: the options, fstab lines and mountinfo the tools read are
redacted.
A source whose username or password is not given is not mounted. It is said `waiting`, naming the setting
or the secret it waits for, and the module's health answers *waits* (below).
## The processes and the bus
- `apply` (root, judged by its unit) writes and removes the unit pairs and the logins, makes a missing
- `apply` (root, judged by its unit) writes and removes the unit pairs and the credentials files, makes a missing
mount point, reloads the service manager when anything changed and arms every automount, every 30 s.
- `watch` (root, judged by `mounts_health`) tries each source without touching its mount point — TCP 2049
for a node's share, 445 for an SMB source, the device for a disk — and says each one's state.
@@ -144,15 +139,25 @@ And what it never does:
The states: `armed` (the automount waits), `mounted`, `absent` (an occasional source that is not there —
a state, not a fault), `unreachable` (should be there and is not), `failed` (tried and refused, or not
set up; `why` says which).
set up; `why` says which), `waiting` (an SMB source whose username or password the operator has not
given; `waits` names the setting or the secret).
## Health
The answer is mesh-sdk's (`go/health`): healthy, unhealthy, or waits (novox/hq ADR 0283).
Unhealthy when a share that should always be there has been unreachable or failed for five minutes ("The
share library of <machine> is not reachable from this machine since 19:21."), when an automount is not
armed, when something the settings name cannot be set up (a missing login, a unit file that is not the
module's), or when `watch` has not looked for two minutes. An occasional source that is absent is
healthy, and said as not present since when.
armed, when something the settings name cannot be set up (a unit file that is not the module's, a
password of more than one line), or when `watch` has not looked for two minutes. An occasional source that
is absent is healthy, and said as not present since when.
A source waiting for its username or password is not a fault. With nothing else found, the answer is
*waits*, with one wait per thing not given: the setting `smb-users` ("the username of the source games")
or the secret `smb-password-games` ("the password of the source games"). The node-engine states the
resource `waiting`, the controller says it to the operator as needing them, naming the act, and the
first-node gate does not fail a build for it. Beside a fault, the waits are said and the answer is
unhealthy.
## Taking over a hand-written line