From 3ebaca6e742ec71ba166a36f3062be700e4871e5 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sat, 26 Sep 2026 16:38:29 +0600 Subject: [PATCH] [2026-09-26] eagle: family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md family/how-to/vault-git-sync.md personal/plans/music-tags-review/music-tags-review.md personal/tech/music-tags-repair-truenas.md --- ...cthing-clone-root-objects-acl-confusion.md | 59 ++++++++++++- family/how-to/vault-git-sync.md | 83 ++++++++++++++--- .../music-tags-review/music-tags-review.md | 11 ++- personal/tech/music-tags-repair-truenas.md | 88 ++++++++++++++++++- 4 files changed, 221 insertions(+), 20 deletions(-) diff --git a/family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md b/family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md index df6939b6..20f3c771 100755 --- a/family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md +++ b/family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md @@ -4,12 +4,13 @@ type: log namespace: family tags: [vault, sync, syncthing, git, permissions, acl, nfsv4, root] date: 2026-09-26 +status: resolved --- # `obsidian-syncthing`: 4031 root-объект, битый remote, ACL/chown не стоит **Когда:** 2026-09-26, разбор по запросу Alex «почему документ не доехал до телефона». -**Статус:** диагностика завершена, **фиксы НЕ применены** — ждём решения Alex. +**Статус:** ✅ **РЕШЕНО** — ACL с `nas_users` + INHERIT применён, синк работает (см. «РЕШЕНИЕ» ниже). ## Симптом @@ -95,7 +96,61 @@ midclt call filesystem.getacl /mnt/RED_2TB/Edu > .../acl-edu-before-YYYYmmdd-HHM > POSIX-gid файла, а не ACE. Без смены gid группа не получает ничего. Менять gid надо через > `midclt filesystem.setacl` (root-контекст), а не `chgrp`/`chown` из шелла. -## Почему однократный `chown` не лечил +## ✅ РЕШЕНИЕ (2026-09-26, после требования Alex «Да, ставь acl inherit») + +Alex отверг предложенные варианты и дал прямую команду: **«Да, ставь acl inherit»**. +Выбран **вариант A** — ACL + INHERIT, применён на `/mnt/RED_2TB/storage/obsidian-syncthing`. + +**Что сделано (по порядку):** + +```bash +# 1. бэкап ACL +midclt call filesystem.getacl /mnt/RED_2TB/storage/obsidian-syncthing \ + > /home/truenas_admin/variantA_bk/acl-obsidian-syncthing-before-20260926-154827.json + +# 2. скрипт read-modify-write (файлом, не инлайном) → scp на NAS → python3 +# payload: gid=3000 (nas_users), uid=950, recursive=true, +# все ACE → FILE_INHERIT+DIRECTORY_INHERIT, stripacl=false +# → job 25046 SUCCESS + +# 3. remote клона +git remote set-url origin /mnt/RED_2TB/storage/git/obsidian-vault.git +``` + +**Результат (проверено ФАКТОМ):** + +| | До | После | +|---|---|---| +| `nfs4xdr_getfacl` | `trivial_acl: true` | **`trivial_acl: false`** | +| `group` | 950 | **3000** (`nas_users`) | +| флаги ACE | `-------` (NOINHERIT) | **`fd-----`** (FILE+DIRECTORY_INHERIT) | +| объекты от root | 4051 | **0** (все 4073 = `truenas_admin`) | +| `git fetch` | падал | `Already up to date` | +| новый файл `touch` | — | `truenas_admin:nas_users` ✅ | + +**Наследование подтверждено:** `touch .inherit_test` и `mkdir .inherit_dir_test` внутри папки +получили `truenas_admin:nas_users` (тестовые артефакты удалены после проверки). + +**Нота доехала:** коммит с Mac `f2501dc` (`1-needs-decision.md`, разбор 28 файлов) найден в +истории клона, поверх уже лежал `8efe5c8` от Taiga. + +### 🔴 ГЛАВНЫЙ ПИТФОЛЛ: `midclt getacl` = КЭШ + +Сразу после `setacl` скрипт делал верификацию через `midclt filesystem.getacl` — и получал +**старые** значения (`trivial: True`, `gid: 950`, `NOINHERIT`), печатая ложный «VERIFY FAILED». +Правка на диске при этом была уже применена. + +> **Реальное состояние проверять только:** `nfs4xdr_getfacl ` (`trivial_acl: false`, +> флаги `fd-----`) + `stat -c '%A %U:%G %n'` + фактический `touch` нового файла. +> **Не откатывать и не повторять `setacl` по показаниям `getacl`.** + +### Альтернативный вариант B (не использован, для истории) + +`user: "950:950"` в taiga service — устранил бы корень (контейнер не от root), но риск: +образ может требовать root для `/opt/data`. Оставлен как возможное усиление; +текущий ACL-INHERIT закрывает последствия. + +## ℹ️ Почему однократный `chown` не лечил (историческая справка) Прошлый разовый `chown` объектов на `truenas_admin` чинил только **уже существующие** объекты. Следующий `git pull` от root снова рождал root-owned объекты — и `chown` приходилось повторять. diff --git a/family/how-to/vault-git-sync.md b/family/how-to/vault-git-sync.md index 9696aab2..d753e305 100755 --- a/family/how-to/vault-git-sync.md +++ b/family/how-to/vault-git-sync.md @@ -25,20 +25,40 @@ tags: > реальная доставка до телефона — в пределах тика. Перезапись `schedule_display` через > `hermes cron edit 29851c413903 --schedule '*/5 * * * *'` — на решение Алексея (косметика, на исполнение не влияет). -> **🔴 STATE 2026-09-26 (later) — `obsidian-syncthing` НЕ получает обновления: root-owned objects + битый remote.** -> Нота `1-needs-decision.md` была запушена с Mac (`66d4d62..f2501dc`), но в клон -> `/obsidian-syncthing` **не доехала**. Два независимых дефекта: -> **(1)** `origin` в клоне был **`/vault.git`** (потерян префикс пути) → `git fetch` падал -> `does not appear to be a git repository`. Переписан на полный путь `git remote set-url`. -> **(2)** **4051 из 4055 объектов принадлежат `root`** — контейнер `hermes-taiga` работает от -> root (`Config.User` пусто, `id` → `uid=0`), он и делает pull → новые объекты root-owned, -> git под uid 950 не может писать (`insufficient permission for adding an object`). -> **ACL на `obsidian-syncthing` НЕ СТОИТ** — `nfs4xdr_getfacl` показывает `trivial_acl: true` -> (только `owner@`/`group@`/`everyone@`, ни одной именованной записи). Рекурсивный ACL с группой -> ставился ранее (2026-09-23), но на **`/mnt/RED_2TB/Edu`**, не на эту папку. -> 🔴 **Урок: «ACL уже ставили» ≠ «ACL стоит на этой папке» — проверять фактом.** +> **✅ STATE 2026-09-26 (later, RESOLVED) — ACL с `nas_users`+INHERIT применён на `obsidian-syncthing`, синк работает.** +> Оба дефекта закрыты: +> **(1) Битого remote** — `origin = /vault.git` переписан на полный путь (но **снова слетел** после +> `sync-vault.sh`: тот форсит `file:///vault.git` внутри контейнера — это правильно для `/vault`, +> но для хостового клона путь другой. Проверять `git remote -v` перед диагностикой прав). +> **(2) Права — решено перманентно:** `midclt filesystem.setacl` рекурсивно на +> `/mnt/RED_2TB/storage/obsidian-syncthing` с `gid=3000` (`nas_users`) и флагами +> `FILE_INHERIT`+`DIRECTORY_INHERIT` на **все** ACE. Было `trivial_acl: true` + 4051 объект root → +> стало `trivial_acl: false`, `group: 3000`, **0 объектов root** (все 4073 = `truenas_admin`). +> Группа `nas_users` (gid 3000) содержит `root`, `truenas_admin`, `nas`, `mallexxx`, `transmission` — +> поэтому и root-процесс Taiga, и Syncthing (uid 950) пишут в одну папку. +> **Наследование проверено ФАКТОМ:** `touch .inherit_test` → `truenas_admin:nas_users`, +> `mkdir .inherit_dir_test` → `truenas_admin:nas_users`. Артефакты после теста удалены. +> `git fetch origin main` → `Already up to date`; HEAD клона содержал коммит с Mac (`f2501dc`). +> **Бэкап ACL перед правкой:** `/home/truenas_admin/variantA_bk/acl-obsidian-syncthing-before-20260926-154827.json`. +> **Скрипт:** `acllib_obsidian_syncthing_fix.py` (см. раздел «ACL repair» → рецепт). +> +> **🔴 ГЛАВНЫЙ ПИТФОЛЛ ЭТОЙ ПРАВКИ: `midclt filesystem.getacl` отдаёт КЭШ.** +> Сразу после `setacl` он печатал старые значения (`trivial: True`, `gid: 950`, `NOINHERIT`), +> и скрипт рапортовал ложный «VERIFY FAILED». Реальное состояние видно только через +> **`nfs4xdr_getfacl`** и **`stat`**. Никогда не верить `midclt getacl` сразу после `setacl` — +> сверять `nfs4xdr_getfacl` (там `trivial_acl: false` и `fd-----` = FILE_INHERIT+DIRECTORY_INHERIT) +> плюс `stat -c '%A %U:%G'`. +> +> **Историческая путаница (для будущих сессий):** рекурсивный ACL с `nas_users` действительно +> ставился 2026-09-23, но на **`/mnt/RED_2TB/Edu`** (запрос Alex: «можешь просто группу под acl +> сделать с inherit чтобы весь edu был доступен группе включающей truenas_admin?»), **не** на +> `obsidian-syncthing`. Отсюда «я это уже чинил» — чинил, но другую папку. Искать прошлые сессии: +> `sqlite3 ~/.hermes/hermes-whale/state.db "SELECT session_id, substr(content,1,300) FROM messages WHERE content LIKE '%setfacl%' ORDER BY id DESC LIMIT 40;"`. +> > Разовый `chown` лечит только уже существующие объекты; следующий pull от root возвращает дефект. -> Фиксы НЕ применены. Подробно: `family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md`. +> Перманентно лечит `ACL`+`INHERIT` (наследование новыми объектами) либо запуск процесса **не от root**. +> Корень по-прежнему не устранён: контейнер `hermes-taiga` работает от root. +> Подробно: `family/documents/vault-sync/2026-09-26-syncthing-clone-root-objects-acl-confusion.md`. > > **🔴 STATE 2026-09-26 — РАСХОЖДЕНИЕ РАСПИСАНИЯ: Taiga-сервер синкается РАЗ В ЧАС, не 5 минут.** > Job `sync-vault` внутри контейнера `hermes-taiga` (Hermes cron, id `29851c413903`) расписан @@ -226,9 +246,10 @@ cd ~/Developer/vault-sync-test && bash test-sync.sh ## Pitfalls - **`nfs4xdr_getfacl`, а НЕ `getfacl`, если проверяешь наличие расширенного ACL** (2026-09-26). POSIX-вид (`getfacl`, `ls -l`) показывает `user::rwx group::rwx` и **скрывает** отсутствие именованных ACE. Только `nfs4xdr_getfacl` печатает `trivial_acl: true` — что значит «кастомного ACL нет». Все диагностики прав на TrueNAS начинать с него. +- 🔴 **`midclt filesystem.getacl` СРАЗУ ПОСЛЕ `setacl` отдаёт КЭШ** (2026-09-26). Печатает старые значения (`trivial: True`, старый `gid`, `NOINHERIT`), из-за чего правка выглядит неприменённой. Реальное состояние — только `nfs4xdr_getfacl ` (`trivial_acl: false`, флаги `fd-----`) + `stat -c '%A %U:%G %n'` + фактический `touch` внутрь папки. Не откатывать и не повторять `setacl` по показаниям `getacl`. - **`chgrp` / `chown` от `truenas_admin` → `Operation not permitted`** (2026-09-26). В NFSv4 `group@` — это POSIX-gid файла, а не ACE: без смены gid группа не получает доступа. Менять gid/uid только через `midclt filesystem.setacl` (root-контекст). TrueNAS `sudo` требует пароль (в отличие от Kraken, где `sudo -n` работает). - **Разовый `chown` — лечение симптома, не фикс** (2026-09-26). Если root-процесс продолжает писать в папку, root-owned объекты вернутся на следующем же запуске. Перманентно лечит только `ACL`+`INHERIT` (наследование новыми объектами) либо запуск процесса **не от root**. -- **«Этот фикс уже делали» — проверить, что он на ТОЙ САМОЙ папке** (2026-09-26). Рекурсивный ACL с группой `nas_users` ставился 2026-09-23, но на `/mnt/RED_2TB/Edu`. На `obsidian-syncthing` ACL не было никогда. Каждый «известный фикс» верифицировать фактом на целевом объекте, а не памятью. Искать прошлые сессии: `sqlite3 ~/.hermes/hermes-whale/state.db "SELECT session_id, substr(content,1,300) FROM messages WHERE content LIKE '%setfacl%' ORDER BY id DESC LIMIT 40;"`. +- **«Этот фикс уже делали» — проверить, что он на ТОЙ САМОЙ папке** (2026-09-26). Рекурсивный ACL с группой `nas_users` ставился 2026-09-23, но на `/mnt/RED_2TB/Edu` (запрос Alex про `Маскелиаде`). На `obsidian-syncthing` ACL не было никогда — отсюда ложное «я это уже чинил». Каждый «известный фикс» верифицировать фактом на целевом объекте, а не памятью. Искать прошлые сессии: `sqlite3 ~/.hermes/hermes-whale/state.db "SELECT session_id, substr(content,1,300) FROM messages WHERE content LIKE '%setfacl%' ORDER BY id DESC LIMIT 40;"`. - **Клон может иметь битый `origin`** (2026-09-26). `obsidian-syncthing` имел `origin = /vault.git` (потерян префикс пути) → `fatal: does not appear to be a git repository`. Проверять `git remote -v` в клоне до диагностики прав — это независимый дефект, который выглядит как проблема доступа. - **`sync-vault-lib.sh` глушит ошибки (`2>/dev/null` на fetch/merge)** → «Pushed ✓» / `exit 0` при фактически упавшем pull. Это уже второй раз, когда поломка синка была не видна в логе. Диагностировать по `git status`/`git log` в клоне, не по exit-code. - `git add pathspec` fails with `fatal: pathspec did not match any files` when a directory doesn't exist on disk — use `git add -A` instead @@ -255,8 +276,42 @@ midclt call filesystem.setacl '{"path":"/x","acltype":"NFS4","dacl":[…], Pitfalls: `setacl`/`setperm` are **async** (return a job id) — poll `core.get_jobs` until `SUCCESS`/`FAILED`, or the immediate `WAITING` reads as a failure. `filesystem.setperm` refuses when a non-trivial ACL is present (`[EINVAL] … Option "stripacl" required`). +### ✅ Рабочий рецепт: группа + INHERIT на папку (проверено 2026-09-26) + +Скрипт (`acllib_obsidian_syncthing_fix.py`, отработал на `/mnt/RED_2TB/storage/obsidian-syncthing`): +read-modify-write ACL — читает существующий dacl, **сохраняет `id` полей** (без них TrueNAS падает +`missing required keys: {'id'}`), переписывает `flags` в `FILE_INHERIT+DIRECTORY_INHERIT`, +ставит `gid` нужной группы, `recursive: true`, `stripacl: false`. + +```python +payload = { + "path": TARGET, + "uid": 950, # truenas_admin — оставить владельцем + "gid": 3000, # nas_users — группа, в которой и root, и uid 950 + "acltype": "NFS4", + "dacl": new_dacl, # read-modify-write, флаги INHERIT, id сохранены + "options": {"recursive": True, "traverse": True, "stripacl": False}, +} +``` + +Запуск: `scp` скрипта на NAS → `ssh truenas_admin@mallexxx.duckdns.org "python3 /home/truenas_admin/