nextcloud: the module makes its own mesh-admin account right on a 401 and backs off on a refusal, so its shares poll stops being refused every minute (issue 1253)
#478
Merged
jschoubbenmerged 4 commits from fix/nextcloud-admin-401 into main2026-10-25 16:01:38 +00:00
The nextcloud module's shares poll (node-tools on novox) logged in every 60 s as mesh-admin and was refused (401, or 429 under the brute-force throttle). mesh-admin does not exist in novox's Nextcloud: the image creates NEXTCLOUD_ADMIN_USER only on a fresh install, and this instance predates the mesh. Nothing was rotated; the vault holds no such secret.
Repair on a 401 only: the client makes its own account right through occ, once per run of refusals. It checks with user:info mesh-admin: missing only on exit 1 AND "not found", so a stopped container is not read as missing. A missing account gets user:add; an existing one gets user:resetpassword, with the password from the module's state through OC_PASS and --password-from-env, never on argv.
Only its own account: the repair runs only for mesh-admin; under any other user setting it throws LoginRefusedError and writes nothing. The "admin" fallback is gone and the setting's description is corrected.
Least privilege: mesh-admin is a plain user in no group; the OCS shares endpoint lists only the caller's own shares, so admin rights would buy nothing.
A 429 is never repaired: a throttle is no evidence the password is wrong, and the brute-force record is shared by every client on the same address, so the module never resets it.
Back-off: a lasting refusal is said once, then the poll waits 5, 10, 20, 40, then 60 minutes, saying the ceiling and the recovery once each.
Tests (each seen to fail on main's client): test/admin-login.test.ts, 1253/AC1-AC9 including AC7 (another account name writes nothing), AC3b (429 then 200 twice writes nothing), AC3c (a 401 writes once), and AC9 (the real occ() through a fake docker printing "user not found" on stdout). Unit suite 20 of 20.
Operator-visible: after delivery a new Nextcloud account, mesh-admin ("Mesh administration"), in no group; the operator agreed on 2026-10-25. Live check (1253/AC6): novox's nextcloud access log shows the shares call answered 200 as mesh-admin, and node-tools' journal shows no 401.
No try: the operator decided no checks run during the recovery (issue 1945 note 27).
Issue 1253.
The nextcloud module's shares poll (node-tools on novox) logged in every 60 s as mesh-admin and was refused (401, or 429 under the brute-force throttle). mesh-admin does not exist in novox's Nextcloud: the image creates NEXTCLOUD_ADMIN_USER only on a fresh install, and this instance predates the mesh. Nothing was rotated; the vault holds no such secret.
- **Repair on a 401 only:** the client makes its own account right through occ, once per run of refusals. It checks with user:info mesh-admin: missing only on exit 1 AND "not found", so a stopped container is not read as missing. A missing account gets user:add; an existing one gets user:resetpassword, with the password from the module's state through OC_PASS and --password-from-env, never on argv.
- **Only its own account:** the repair runs only for mesh-admin; under any other `user` setting it throws LoginRefusedError and writes nothing. The "admin" fallback is gone and the setting's description is corrected.
- **Least privilege:** mesh-admin is a plain user in no group; the OCS shares endpoint lists only the caller's own shares, so admin rights would buy nothing.
- **A 429 is never repaired:** a throttle is no evidence the password is wrong, and the brute-force record is shared by every client on the same address, so the module never resets it.
- **Back-off:** a lasting refusal is said once, then the poll waits 5, 10, 20, 40, then 60 minutes, saying the ceiling and the recovery once each.
Tests (each seen to fail on main's client): test/admin-login.test.ts, 1253/AC1-AC9 including AC7 (another account name writes nothing), AC3b (429 then 200 twice writes nothing), AC3c (a 401 writes once), and AC9 (the real occ() through a fake docker printing "user not found" on stdout). Unit suite 20 of 20.
Operator-visible: after delivery a new Nextcloud account, mesh-admin ("Mesh administration"), in no group; the operator agreed on 2026-10-25. Live check (1253/AC6): novox's nextcloud access log shows the shares call answered 200 as mesh-admin, and node-tools' journal shows no 401.
No try: the operator decided no checks run during the recovery (issue 1945 note 27).
Reviewed-by: reviewer-nc@shanks at 1cc54959afcf4d2fe658ed47531829e45c6aee89
The image creates NEXTCLOUD_ADMIN_USER only on a fresh install. novox's
instance was installed before the mesh adopted it, so mesh-admin was never
created there, and the shares poll asked Nextcloud every minute with a login
that cannot pass: 401, then Nextcloud's brute-force throttle (429), which
also held the backup before a delivery.
On a refused login the client now adds the account through occ (admin
group), or sets its password to the module's own secret, passing it by
OC_PASS so it is on no argv, and asks once more. A refusal that stays is
said once and the poll backs off from 5 minutes to an hour instead of nine
lines of XML every minute. An empty setting no longer becomes an empty name.
Right after the delivery the first answer may be Nextcloud's 429, not a 401;
without a repair then the account would never be made and the back-off would
wait out a throttle that cannot end.
Deliverynovox/mesh-catalog@1cc54959afcf — held since 2026-10-25T16:01:40Z
Held for a person: merged without a passing check: only a person decides what follows — the merge reached the trunk without a passing check.
Source — source.main moved to novox/mesh-catalog@a85d903741. Whether it reached the machines is mesh-delivery-view's, derived from source.main, the wants and the haves.
Transitions
2026-10-25 15:59 (new) → proposed (announced): novox/mesh-catalog#478's head announced
2026-10-25 16:01 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides what follows
The commit's note under refs/notes/mesh-plan keeps every transition of this change up to its merge: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@1cc54959afcf` — **held** since 2026-10-25T16:01:40Z
Held for a person: merged without a passing check: only a person decides what follows — the merge reached the trunk without a passing check.
**Source** — source.main moved to novox/mesh-catalog@a85d90374195. Whether it reached the machines is `mesh-delivery-view`'s, derived from `source.main`, the wants and the haves.
**Transitions**
- 2026-10-25 15:59 (new) → proposed (announced): novox/mesh-catalog#478's head announced
- 2026-10-25 16:01 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides what follows
The commit's note under `refs/notes/mesh-plan` keeps every transition of this change up to its merge: `git log --notes=mesh-plan`.
occ's user:info says 'user not found' on stdout with an empty stderr, so the
error read as 'occ produced no output' and mesh-admin was never made on novox:
occ now says stderr and stdout both, and existence is read from user:list.
The repair could reset whatever account the user setting names, the
operator's included, and the 'admin' fallback is a hand-made install's human
administrator: only mesh-admin is repaired now, and it is the default. The
shares poll needs no admin rights, so the account gets no group. After a
repair the throttle of the caller's address is reset, and a failing repair
reaches the back-off's one loud line with occ's message.
Resetting Nextcloud's brute-force record for the docker gateway cleared it for
every client behind that address: someone guessing passwords could drive the
throttle to 429 and have the module's poll wipe it. A throttle is no evidence
the password is wrong, so a 429 is now backed off only, and the back-off
outlasts the throttle. The account's existence is read from user:info's exit
status, since user:list pages.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Issue 1253.
The nextcloud module's shares poll (node-tools on novox) logged in every 60 s as mesh-admin and was refused (401, or 429 under the brute-force throttle). mesh-admin does not exist in novox's Nextcloud: the image creates NEXTCLOUD_ADMIN_USER only on a fresh install, and this instance predates the mesh. Nothing was rotated; the vault holds no such secret.
usersetting it throws LoginRefusedError and writes nothing. The "admin" fallback is gone and the setting's description is corrected.Tests (each seen to fail on main's client): test/admin-login.test.ts, 1253/AC1-AC9 including AC7 (another account name writes nothing), AC3b (429 then 200 twice writes nothing), AC3c (a 401 writes once), and AC9 (the real occ() through a fake docker printing "user not found" on stdout). Unit suite 20 of 20.
Operator-visible: after delivery a new Nextcloud account, mesh-admin ("Mesh administration"), in no group; the operator agreed on 2026-10-25. Live check (1253/AC6): novox's nextcloud access log shows the shares call answered 200 as mesh-admin, and node-tools' journal shows no 401.
No try: the operator decided no checks run during the recovery (issue 1945 note 27).
Reviewed-by: reviewer-nc@shanks at
1cc54959afDelivery
novox/mesh-catalog@1cc54959afcf— held since 2026-10-25T16:01:40ZHeld for a person: merged without a passing check: only a person decides what follows — the merge reached the trunk without a passing check.
Source — source.main moved to novox/mesh-catalog@a85d903741. Whether it reached the machines is
mesh-delivery-view's, derived fromsource.main, the wants and the haves.Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition of this change up to its merge:git log --notes=mesh-plan.