diff --git a/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md b/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md index 4abf2087..f48880eb 100644 --- a/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md +++ b/family/documents/vault-sync/2026-09-02-restore-privilege-scope.md @@ -2,7 +2,7 @@ tags: [truenas, restore, incident, git, media, arr, permission] created: 2026-09-02 updated: 2026-09-02 -status: in-progress (Этап 0-3 done — transmission пересоздан под PUID=950 штатно, медиа-права рекурсивно исправлены; ОСТАЛОСЬ: git/nas/второй root-заход на добивку, запуск arr-стека, первый sync-vault на маке) +status: in-progress (Этап 0-3 + 2-й root-проход DONE — storage все 950, git-sync fetch ОК; ОСТАЛОСЬ основной блокер: NFS4 ACL DENY READ_DATA на ~1946 git-объектах → push на маке падает) --- # Incident 2026-09-02: Поломка прав uid 921/0000 после restore — масштаб и влияния @@ -169,11 +169,60 @@ ssh truenas_admin@mallexxx.duckdns.org 'bash /tmp/fix-storage-nfs4-acl.sh' - ✅ **Этап 3 — рекурсивный фикс прав вглубь ВЫПОЛНЕН Alex (root) + проверен.** Результат верификации 2026-09-02: - Медиа-папки → `950:950 drwxrwx---`: Cartoons, Downloads, Movies, Music, art, books, cartoons-series, documentaries(-series), series, shared, work. ✅ - Вглубь Movies: файлы → `950:950`, права разблокированы (`rw-r-----`/`rwxrwx---`). ✅ - - **ЕЩЁ НЕ ДОБИТО (остаточек):** `git/` bare repo dir → `d--------- 950:950` (0000) → **git-sync на маке всё ещё стоит** `fatal: not a git repository`; `nas` (921/0000, не попал в chown/chmod), `ada3s1`, `photo_dedup_test`, `seafile`, `singularity` (0000/700); скрытые mac-файлы корня `.DS_Store/.bash*/.profile/.com.apple*` (921); сам корень `storage` → `921:921 drwxrwx---`. + - ✅ **Второй root-проход ВЫПОЛНЕН Alex (вторая команда ниже) — добиты `git`, `nas`, `ada3s1`, `photo_dedup_test`, `seafile`, `singularity`, `radarr`, `sonarr`:** все теперь `950:950 drwxrwx---`. Проверено: + - Все топ-папки storage теперь `950:950 drwxrwx---` (сплошняком, кроме скрытых файлов корня и самого корня). ✅ + - `storage/git/obsidian-vault.git` теперь **открывается** — `git log` показывает коммиты (HEAD `a2c72793` [2026-08-17]...). + - `git/nas` уже не «matching вне-списка» — chown/chmod догнаны вторым проходом. -### ⬜ Остаточный root-шаг (второй проход, готов для Alex) — добить git + nas + прочее +### ⬜ Найден БЛОКЕР PUSH: NFS4 ACL `DENY READ_DATA` на тировых объектах git-репозитория -Команда подготовлена в сессии, Alex ещё не запускал: +**Симптом (после починки прав):** на маке git-sync теперь: +``` +git fetch nas main → OK (bare repo доступен, fetch exit=0) +git push nas main → FAIL: + remote: fatal: loose object acd1b45542e82aa40f345da3b8ac9f721633b138 ... is corrupt + remote unpack failed: index-pack abnormal exit +``` +`sync-vault.sh` — `Committed` потом `Push failed`. Ahead вырос 55 → 62 (коммиты локально копятся, не пушатся). + +**Диагностика — это НЕ повреждение данных, а NFS4 ACL-блокировка чтения:** + +| Проверка | Результат | +|---|---| +| `git fsck --full` через **root** (контейнер gitea, монтирует `/git-repos`) | ЧИСТО: только `dangling commit/tree`, **ни одного corrupt/missing/bad** | +| `git cat-file -t acd1b45...` под root (gitea) | `tree` — объект читается, цел | +| NFS4 ACL самого файла `objects/ac/d1b...` (через `filesystem.getacl`) | **`owner@ DENY READ_DATA=True`** поверх `ALLOW` → перекрывает | + +**Суть:** у ~**1946 из 3373** loose git-объектов в `obsidian-vault.git/objects/` стоит битый NFS4 ACL `owner@ type=DENY READ_DATA=True`. DENY-запись в NFSv4 **перекрывает ALLOW**, поэтому владелец (uid 950 = truenas_admin) **не может mmap/прочитать эти объекты** при push. Git на приеме (`git-receive-pack`/`index-pack`) трактует нечитаемость как «loose object corrupt» → push rejected. Root игнорирует ACL → поэтому fsck под gitea чист, а push от 950 падает. **Данные целы.** + +POSIX-признак битых файлов: **mode `40` (`r--------`)**; нормальные объекты — mode `750`. (count: 3373 объектов, ~1946 с mode 4xx.) + +**Фикс (root/root-midclt) — ГОТОВ, Alex ещё не запускал (ждёт отдельного подтверждения, т.к. влияет на ACL объектов):** +```bash +# снять битые NFS4 ACL (DENY) на весь git-репозиторий, вернуть стандарт из uid/gid +midclt call filesystem.setacl /mnt/RED_2TB/storage/git/obsidian-vault.git \ + '{"uid":950,"gid":950,"dacl":[],"options":{"recursive":true,"traverse":true,"stripacl":true}}' + +# проверить, что проблемный объект читается владельцем: +git --git-dir=/mnt/RED_2TB/storage/git/obsidian-vault.git cat-file -t acd1b45542e82aa40f345da3b8ac9f721633b138 + +# затем с мака: +cd ~/obsidian && git push nas main +``` +> ⚠️ `chmod`/`chown` НЕ снимает NFS4 `DENY` ACE — нужен именно `stripacl:true` (или `setfacl -Rb` на хосте, если доступен). TrueNAS SCALE: `setacl` с `stripacl:true` + пустым `dacl` переведёт на POSIX-default из owner@/group@. +> ⚠️ Перед применением снять бэкап ACL `git/` (read-only): `midclt call filesystem.getacl /mnt/RED_2TB/storage/git > ~/variantA_bk/git_after.acl`. +> ⚠️ Стоп-правило Alex: nothing destructive без явного подтверждения — не делался, ждёт команды. + +**Куда попадают DENY-ACL:** артефакт restore — часть loose-объектов при переносе данных получили инверсивный NFS4 ACL (`owner@ DENY read`). Это НЕ родние git-права (git-репо хранит объекты как read-only `r--r--r--` в обычном случае); на полке после поломки. + +### Диагностические insights (для будущих сессий) +- `docker exec transmission ...` даёт root вглубь `/mnt/storage` (transmission монтирует `storage`); `gitea` контейнер монтирует `/mnt/RED_2TB/storage/git → /git-repos` и имеет `git` — удобен для `git fsck`-честных проверок (root-контекст). `hermes-taiga` монтирует `/vault.git` = `storage/git/obsidian-vault.git` и тоже имеет git. +- NFS4 `owner@ DENY` перекрывает `ALLOW` — клинический кейс «ls показывает доступно, а процесс не читает». +- POSIX-бит файла (mode 40/750) коррелирует с NFS4 ACL; «corrupt» от `index-pack` при целых данных = почти всегда ACL/права на приеме, не реальное повреждение. + +### ✅ Остаточный root-шаг (второй проход) — ВЫПОЛНЕН Alex; команда для справки (историческая) + +> Уже пройдено — итоговое состояние `950:950 drwxrwx---` на всех топ-папках см. в Этапе 3 выше. Команда зафиксирована как рецепт для будущего: ```bash S=/mnt/RED_2TB/storage @@ -190,9 +239,9 @@ git --git-dir="$S/git/obsidian-vault.git" log --oneline -2 2>&1 | head # пр > ⚠️ `rm -f` скрытых файлов корня — mac-мусор/остатки старого владельца 921, безопасно. Если `.profile`/`.bashrc` рабочие — убрать их из rm по решению. -### После остаточного фикса -- **На маке**: `bash ~/scripts/sync-vault.sh` → 55 коммитов уедут в bare repo (launchd возобновит); проверить `git log nas/main..main` = 0. -- **Arr-стек**: `cd /mnt/RED_2TB/docker/arr && docker compose up -d` → проверить `docker compose ps` + что jellyfin видит библиотеки (пути `/storage/*`). +### ⚠️ Текущий статус после второго прохода (актуально) +- **Push на маке БЛОКИРОВАН** NFS4 ACL `DENY READ_DATA` на ~1946 loose git-объектах — см. секцию «Найден БЛОКЕР PUSH» выше. Фикс `filesystem.setacl ... stripacl:true` ГОТОВ, Alex должен подтвердить. +- **Arr-стек**: после снятия DENY-блокера на git и починки прав медиа — `cd /mnt/RED_2TB/docker/arr && docker compose up -d` → проверить `docker compose ps` + что jellyfin видит библиотеки (пути `/storage/*`). PUID/PGID=950 уже прописаны во всех 4 сервисах докер-стека. ### Точное содержание transmission compose (оригинал, важно для пересоздания) ```yaml diff --git a/family/how-to/arr-stack-taiga.md b/family/how-to/arr-stack-taiga.md index 3688baa9..c13c0588 100644 --- a/family/how-to/arr-stack-taiga.md +++ b/family/how-to/arr-stack-taiga.md @@ -15,13 +15,13 @@ Secondary arr stack on Taiga (TrueNAS), added 2026-05-20. > **STATE 2026-09-02:** Стек **выключен** — в `docker ps -a` нет ни radarr/sonarr/prowlarr/jellyfin контейнеров (стек не пересоздавался). Compose-структура живёт в `/mnt/RED_2TB/docker/arr/` (`docker-compose.yml` + подпапки `prowlarr/ radarr/ sonarr/ jellyfin/ media-pipeline/`). Работает только `transmission` (отдельный compose `/mnt/RED_2TB/docker/transmission/`). > -> **Почему не запускается просто так — медиа-права сломаны** (тот же restore-инцидент uid 921/0000): `/mnt/RED_2TB/storage/{Movies,Cartoons,Downloads,Music,series,shared}` → `d---------`/`drwx------`, owner `transmission` (uid 921). radarr/sonarr монтируют `/storage` (rw), jellyfin `:ro` — со сломанными правами не прочитают библиотеку. Фикс + запуск: см. `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md`. +> **Почему стек изначально не запускался — медиа-права были сломаны** (тот же restore-инцидент uid 921/0000): `/mnt/RED_2TB/storage/{Movies,Cartoons,Downloads,Music,series,shared}` были `d---------`/`drwx------`, owner `transmission` (uid 921). radarr/sonarr монтируют `/storage` (rw), jellyfin `:ro` — со сломанными правами не прочитали бы библиотеку. ⚠️ **Сейчас (2026-09-02, конец сессии) права медиа ИСПРАВЛЕНЫ** до `950:950 drwxrwx---` (см. PROGRESS ниже) — но контейнеры arr/jellyfin всё ещё не созданы/не запущены. Полный контекст: `family/documents/vault-sync/2026-09-02-restore-privilege-scope.md`. -> **Docker-image facts (2026-09-02):** All 5 media images **loaded locally** on TrueNAS (`docker images`): `lscr.io/linuxserver/{radarr,sonarr,jellyfin,transmission,prowlarr}:latest`. Only **transmission** container exists (running). **jellyfin/radarr/sonarr/prowlarr containers are NOT yet created** — they never get launched until perms fixed. -> **Transmission runs as ROOT** (not 911/950): its compose `/mnt/RED_2TB/docker/transmission/docker-compose.yml` has **no `PUID`/`PGID`**, so linuxserver `/init` (s6-overlay) leaves it root (`docker exec transmission id` → uid 0). This is why it works on the 0000 media dirs. It mounts `storage` → `/mnt/storage`, download-dir = `/mnt/storage/Downloads`. +> **Docker-image facts (2026-09-02):** All 5 media images **loaded locally** on TrueNAS (`docker images`): `lscr.io/linuxserver/{radarr,sonarr,jellyfin,transmission,prowlarr}:latest`. Only **transmission** container exists (now running as uid 950). **jellyfin/radarr/sonarr/prowlarr containers are NOT yet created** — their compose services have PUID/PGID=950 ready, but they have not been `up`'ed yet. +> **Transmission originally ran as ROOT** (not 911/950): its compose had no `PUID`/`PGID`, so linuxserver `/init` (s6-overlay) left it root. ✅ **Fixed 2026-09-02:** `PUID=950 PGID=950` added and container force-recreated → now daemon under uid 950. It mounts `storage` → `/mnt/storage`, download-dir = `/mnt/storage/Downloads`. > **Fix direction (approved Variant A):** set `PUID=950 PGID=950` on transmission + all arr/jellyfin compose services so every service shares uid `950` and mutually reads files; then recursively fix perms in depth. Plan + commands: `2026-09-02-restore-privilege-scope.md` §5. > -> **PROGRESS 2026-09-02:** Both compose files edited for PUID/PGID=950 (transmission at `/mnt/RED_2TB/docker/transmission/docker-compose.yml`, arr at `/mnt/RED_2TB/docker/arr/docker-compose.yml` incl. all 4 services). **transmission container force-recreated** from its proper folder and now runs its daemon as **uid 950** (was root) — env `PUID=950 PGID=950` confirmed, process under `abc`/950. Media perms in depth recursively fixed to `950:950` (Movies etc.). **STILL OPEN:** `storage/git/` and `storage/nas` perms not yet fixed (second root pass pending) → **do NOT start arr stack until git/nas done**; then `cd /mnt/RED_2TB/docker/arr && docker compose up -d`. +> **PROGRESS 2026-09-02 (updated end-of-session):** Both compose files edited for PUID/PGID=950 (transmission at `/mnt/RED_2TB/docker/transmission/docker-compose.yml`, arr at `/mnt/RED_2TB/docker/arr/docker-compose.yml` incl. all 4 services). **transmission container force-recreated** from its proper folder (`cd /mnt/RED_2TB/docker/transmission && docker compose up -d --force-recreate`) and now runs its daemon as **uid 950** (was root) — env `PUID=950 PGID=950` confirmed, process under `abc`/950. Media perms in depth recursively fixed to `950:950 drwxrwx---` on all top storage folders (incl. git/nas 2nd root pass). **Still to do before arr stack is useful / to unblock git-sync:** (1) strip the broken NFS4 `DENY READ_DATA` ACL on ~1946 loose git objects in `obsidian-vault.git` (this breaks `git push` from Mac with fake "corrupt" error) — fix command and details in `2026-09-02-restore-privilege-scope.md`; (2) then `cd /mnt/RED_2TB/docker/arr && docker compose up -d` and verify jellyfin sees libraries (`/storage/*`). ## Notes from Setup (2026-05-20) diff --git a/family/how-to/vault-git-sync.md b/family/how-to/vault-git-sync.md index 12fc7419..7b70c0d2 100644 --- a/family/how-to/vault-git-sync.md +++ b/family/how-to/vault-git-sync.md @@ -131,6 +131,7 @@ cd ~/Developer/vault-sync-test && bash test-sync.sh - `git add -A` in sparse worktree still stages deletions of out-of-cone files tracked in index — need to unstage them (fixed in old script; irrelevant with proper clone) - `core.quotePath=true` (default) escapes Cyrillic paths in `git ls-files` output — use `-c core.quotePath=false` - ZFS on TrueNAS blocks `chmod` — `git init` fails from host; must run from inside Docker container or create `.git` structure manually +- **NFS4 `owner@ DENY READ_DATA` ACL breaks push (fake "corrupt" objects)** — see History 2026-09-02. Key: after a TrueNAS **pool restore**, a subset of loose git objects in the bare repo can carry an inverted NFS4 ACL `owner@ type=DENY READ_DATA=True`. In NFSv4 a DENY overlays ALLOW, so the owning uid (e.g. 950) can't mmap-read those objects → on receive, `git-receive-pack`/`index-pack` reports `loose object ... is corrupt` and rejects push, even though data is intact (`git fsck --full` under root is clean). Fix = `filesystem.setacl ... {stripacl:true}` (chmod/chown do NOT remove DENY ACEs). Tell-tale: POSIX file mode `40` (`r--------`) on loose objects vs normal `750`. ## History