Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
3.7 KiB
felhom.eu — task reports
Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md; the scripts history lives in scripts/CHANGELOG.md.
SPIKE — NAS verify mechanisms + NFS squash matrix — 2026-07-11
Class: spike (findings doc is the only artifact; no production code touched).
Record: documentation/audits/SPIKE-nas-verify-2026-07-11.md.
Baselines (read-only): felhom-agent 300f06722b (v0.80.0, netmount.go = recipe under test),
felhom-controller 3db9126121 (v0.112.0, the probe container), felhom.eu 8ca1272db6.
Verdicts (all five questions answered live, evidence in the record)
- Q1 — in-guest automount trigger: PASS (make-or-break). A
pct execls AND a docker bind-mount access from inside guest 9201 both wake the host systemd automount (~1 s); content correct, nfs4 propagates host→guest; idle-unmount + re-trigger proven. Q1c open item: whether a trigger installed BEFORE guest start carries through at boot needs a restart-window test (no restart permitted this spike). - Q2 — controller uid-1000 probe: PASS.
docker exec -u 1000:1000chain proof +setpriv --reuid 1000mechanism proof (same syscalls assyscall.Credential); CapEffa80425fbhas SETUID/SETGID; server-side files land101000:101000. - Q3 — Route A: ACCEPTED-with-caveats.
all_squashto an arbitrary server uid (1050) gives the guest-uid-1000 app full read/create/rename/hardlink/delete. Caveats: guest seesnobody:nogroup;chownfails immediate-clean EPERM;chmodSUCCEEDS and persists server-side. q3c pinned the June WRONG case:anonuidwithoutall_squashnever applies to non-root traffic — wire uid 101000 fails on others-perms. Consumer guidance must require the "map/squash ALL users" mode, not just an anon-uid field. - Q4 — error taxonomy + timing: full table in the record. Headlines: NFSv4 returns the IDENTICAL
No such file or directoryfor nonexistent vs not-permitted exports (merge those error categories); dead server = systemdtimeoutat 90 s (systemd kills mount.nfs before its 2-min retry — no diagnostic string);retry=0recommended for the PRODUCTION unit (dead-server verify 90 s→3.1 s with cleanNo route to host; guest on-demand access 91 s→3.8 s ENODEV; happy path untouched; autofs retries fresh per access). SMB splits cleanly:error(13)=credentials,error(2)=share name. Budget (Q4-vii): verify cannot ride the agentapi global 15 s timeout (client.go:87) — worst case is systemd's 90 s; give AddNetStorage its own longer-lived path or async status-poll, ~120 s end-to-end, agent-sidesystemctl startbounded at ~95 s. - Q5 — plain-user SMB: PASS. Stock user + rw share, zero server-side uid config, all 8 probe
steps pass INCLUDING hardlink (on Debian Samba/ext4 — re-verify on a real appliance); server-side
ownership = the authenticated account; guest sees forced
1000:1000/0664.
Safety rails held
Isolated scratch root /srv/nas-spike2/ on 180 (backups .bak-nasspike2); no iptables/network
manipulation (unreachable case = verified-unused 192.168.0.199); no guest restart; spike mounts only
under /mnt/felhom-drives/spike2-*. Teardown verified: exports back to pre-count 2, smb.conf
sections 6, spike users/scratch/units/creds/mountpoints all gone, 0 spike2 mounts on host and in
guest, controller 0.112.0 healthy, spike-pulled alpine image removed.
Next: the production "NAS verify-before-commit + UI redesign" TASK is written by the operator side on these findings (STOP honored — no production work started).