200 lines
12 KiB
Markdown
Executable File
200 lines
12 KiB
Markdown
Executable File
---
|
||
title: obsidian-syncthing — root-owned objects + битый remote + путаница ACL/chown
|
||
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 «почему документ не доехал до телефона».
|
||
**Статус:** ✅ **РЕШЕНО** — ACL с `nas_users` + INHERIT применён, синк работает (см. «РЕШЕНИЕ» ниже).
|
||
|
||
## Симптом
|
||
|
||
Нота `personal/plans/music-tags-review/1-needs-decision.md` закоммичена и запушена с Mac
|
||
(`66d4d62..f2501dc main -> main`), но в клон `/obsidian-syncthing` на TrueNAS **не попала**.
|
||
`git pull` в клоне падает, а `sync-vault.sh` глушит ошибку (`2>/dev/null`) — синк выглядит
|
||
успешным.
|
||
|
||
## Две независимые поломки
|
||
|
||
### 1. Битый remote в клоне (починено в этой сессии)
|
||
|
||
```
|
||
было: origin /vault.git ← потерян префикс пути
|
||
стало: origin /mnt/RED_2TB/storage/git/obsidian-vault.git
|
||
```
|
||
|
||
`git fetch` при этом падал с `fatal: '/vault.git' does not appear to be a git repository`.
|
||
Remote переписан через `git remote set-url`. **Это не связано с правами** — отдельный дефект.
|
||
|
||
### 2. Права: новые объекты пишет root (НЕ починено)
|
||
|
||
```
|
||
объекты от root: 4051 ← свежие, 2026-09-26 02:42
|
||
объекты от truenas_admin: 4 ← только старые pack с 2026-07-06
|
||
```
|
||
|
||
`git fetch` падает на записи:
|
||
|
||
```
|
||
error: insufficient permission for adding an object to repository database .git/objects
|
||
fatal: failed to write object
|
||
fatal: unpack-objects failed
|
||
```
|
||
|
||
**Причина:** контейнер `hermes-taiga` работает **от root** (`docker inspect` → `Config.User`
|
||
пусто, `docker exec ... id` → `uid=0(root)`). Именно он делает `git pull` в
|
||
`/obsidian-syncthing` — значит каждый новый loose-объект рождается `root:root`, а git под
|
||
`truenas_admin` (uid 950) писать в них не может.
|
||
|
||
## ACL на `obsidian-syncthing` НЕ СТОИТ — `trivial_acl: true`
|
||
|
||
```
|
||
nfs4xdr_getfacl /mnt/RED_2TB/storage/obsidian-syncthing
|
||
# owner: 950 # group: 950 # mode: 0o40770
|
||
# trivial_acl: true ← расширенного ACL нет
|
||
owner@:rwxpD-aARWcCos:-------:allow
|
||
group@:rwxpD-a-R-c--s:-------:allow
|
||
everyone@:------a-R-c--s:-------:allow
|
||
```
|
||
|
||
Только дефолтный набор TrueNAS (`owner@` / `group@` / `everyone@`), **ни одной именованной
|
||
записи**. POSIX-вид (`getfacl`) показывает `user::rwx group::rwx other::---` и **скрывает**
|
||
отсутствие расширенного ACL — поэтому диагностировать надо `nfs4xdr_getfacl`, а не `getfacl`.
|
||
|
||
## 🔴 Путаница: ACL ставился на `Edu`, не на `obsidian-syncthing`
|
||
|
||
Alex помнил, что фикс ACL уже делался («ты вроде ставил рекурсивный acl а не chown»).
|
||
Проверка по базе Hermes (`state.db`, таблица `messages`) нашла сессию
|
||
**`20260923_124118_9e70782e` (2026-09-23)** — там рекурсивный ACL **действительно ставился**,
|
||
но на **`/mnt/RED_2TB/Edu`**, по прямой просьбе Alex: «ты можешь просто группу под acl
|
||
сделать с inherit чтобы весь edu был доступен группе включающей truenas_admin?»
|
||
|
||
Что тогда было сделано (и сработало — на `Edu`):
|
||
|
||
```bash
|
||
# 1. бэкап ACL
|
||
midclt call filesystem.getacl /mnt/RED_2TB/Edu > .../acl-edu-before-YYYYmmdd-HHMMSS.json
|
||
# 2. setacl recursive: gid -> 3000 (nas_users) + INHERIT на всех ACE → job SUCCESS
|
||
# 3. chgrp -R nas_users → FAILED (Operation not permitted)
|
||
# 4. повтор через midclt setacl с uid/gid=3000 → job 15393 SUCCESS
|
||
```
|
||
|
||
Результат на `Edu`: `drwxrwxr-x root:nas_users`, `gid=3000`, все ACE `INHERITED: True`,
|
||
`touch` → WRITE_OK. **Группа `nas_users` (gid 3000)** — рабочая: в ней `truenas_admin`,
|
||
`mallexxx`, `nas`, `root`, `transmission`.
|
||
|
||
> ⚠️ **Урок: «ACL уже ставили» ≠ «ACL стоит на этой папке».** Правка была на `Edu`.
|
||
> На `obsidian-syncthing` расширенного ACL **не было никогда** (`trivial_acl: true` доказывает).
|
||
> Прежде чем повторять «известный фикс» — проверить, что он на **той самой** папке.
|
||
|
||
> 🔴 **`chgrp` от `truenas_admin` даёт `Operation not permitted`.** В NFSv4 `group@` — это
|
||
> POSIX-gid файла, а не ACE. Без смены gid группа не получает ничего. Менять gid надо через
|
||
> `midclt filesystem.setacl` (root-контекст), а не `chgrp`/`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 <path>` (`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` приходилось повторять.
|
||
**Это лечение симптома.** Перманентный фикс — либо `ACL + INHERIT` (новые объекты наследуют
|
||
права группы), либо запуск синка **не от root** (`user: "950:950"` в taiga service).
|
||
|
||
## Что предлагается (решение за Alex)
|
||
|
||
| Вариант | Как | Плюс / минус |
|
||
|---|---|---|
|
||
| **A. ACL + INHERIT** | `setfacl`/`midclt setacl` с `g:truenas_admin:rwx` + `d:` (default) + `chmod g+s` | root и uid 950 пишут одновременно; нужен контроль, что TrueNAS не сбросит ACL при операциях датасета |
|
||
| **B. Контейнер не от root** | `user: "950:950"` в taiga service `/mnt/RED_2TB/docker/hermes/docker-compose.yml` | устраняет корень; риск — образ может требовать root для `/opt/data` |
|
||
| **C. Повторный `chown`** | перед каждым pull | НЕ рекомендуется — лечит симптом |
|
||
|
||
## Сопутствующий дефект: скрипт глушит ошибки
|
||
|
||
`sync-vault.sh` / `sync-vault-lib.sh` вызывают `git fetch` и `git merge` с `2>/dev/null`.
|
||
При падении синк рапортует **«Pushed ✓» / exit 0**, хотя pull не прошёл. Это и скрывало
|
||
поломку. Предложение — убрать `2>/dev/null` с `fetch`/`merge`, чтобы падение было видно в логе
|
||
(та же логика, что уже описана для launchd: `exit code 0` ≠ «синк прошёл»).
|
||
|
||
## Диагностика (воспроизвести)
|
||
|
||
```bash
|
||
# владельцы объектов в клоне
|
||
ssh truenas_admin@mallexxx.duckdns.org \
|
||
"cd /mnt/RED_2TB/storage/obsidian-syncthing && find .git/objects -type f -printf '%u\n' | sort | uniq -c"
|
||
|
||
# реальный ACL (NFSv4, не POSIX!)
|
||
nfs4xdr_getfacl /mnt/RED_2TB/storage/obsidian-syncthing # trivial_acl: true?
|
||
|
||
# под кем реально работает контейнер
|
||
docker inspect hermes-taiga --format '{{.Config.User}}' # пусто => root
|
||
docker exec hermes-taiga id # uid=0(root)
|
||
|
||
# remote клона
|
||
cd /mnt/RED_2TB/storage/obsidian-syncthing && git remote -v
|
||
```
|
||
|
||
## Связанные документы
|
||
|
||
- `family/how-to/vault-git-sync.md` — архитектура и питфоллы синка
|
||
- `family/documents/vault-sync/2026-09-21-bare-repo-push-permission-denied.md` — тот же
|
||
root-инстанс Hermes, но на **bare repo**
|
||
- `family/documents/vault-sync/2026-09-26-mode-flip-644-755.md` — шум прав от Syncthing
|
||
- `personal/tech/truenas-administration` (skill) — NFSv4 ACL через `midclt`
|