package system import "time" // Consuming-namespace filesystem classification (RCA AUDIT-nas-cwa-rca-2026-07-11 fix 2). // // THE LESSON: the add-time probe, the deploy flow and the dashboard all trusted host-side (agent) // health for network storage — while the namespace the apps actually consume the path in (the // controller container's, an rslave copy of the guest's) can silently hold a plain local stub // after a guest reboot. This classifier answers "what IS this path in THIS process's namespace" // from statfs f_type, so verification happens where consumption happens. // FS classes. const ( // FSClassNetwork: a real network filesystem is mounted here (nfs/cifs/smb2). FSClassNetwork = "network" // FSClassAutofs: an idle automount trigger — HEALTHY (first access mounts it). Callers must // NOT force-mount to "check deeper"; waking the NAS defeats the idle-unmount design. FSClassAutofs = "autofs" // FSClassStub: anything else (ext4/tmpfs/plain dir on the system device) — the RCA's silent // local stub. For a registered network path this is always a defect. FSClassStub = "stub" // FSClassUnknown: statfs failed or timed out — no verdict (callers fail open; a wedged share // is the agent-unreachable branch's business). FSClassUnknown = "unknown" ) // classifyFSMagic maps a statfs f_type (linux/magic.h) to an FS class. Pure — unit-tested against // the magic table. Compared through the unsigned-32 view: the kernel returns f_type as a signed // long, so CIFS_MAGIC_NUMBER (0xFF534D42) can arrive negative depending on how it was widened. func classifyFSMagic(ftype int64) string { u := uint64(ftype) & 0xFFFFFFFF switch u { case 0x0187: // AUTOFS_SUPER_MAGIC return FSClassAutofs case 0x6969: // NFS_SUPER_MAGIC (all nfs versions) return FSClassNetwork case 0xFF534D42: // CIFS_MAGIC_NUMBER return FSClassNetwork case 0xFE534D42: // SMB2_MAGIC_NUMBER return FSClassNetwork default: return FSClassStub } } // fsClassTimeout bounds a classification statfs — a mounted-but-dead network fs can block statfs // for the NFS soft-timeout window; the dashboard/deploy paths must not hang on it. const fsClassTimeout = 3 * time.Second // ClassifyPathFSTimeout classifies path in this process's mount namespace, bounded by // fsClassTimeout. Timeout or statfs error → FSClassUnknown (no verdict — fail open). This is the // entry point for the deploy-time gate and the dashboard stub badge; the probe child uses the // unbounded ClassifyPathFS (its whole run is already deadline-bounded by the parent). func ClassifyPathFSTimeout(path string) string { ch := make(chan string, 1) go func() { ch <- ClassifyPathFS(path) }() select { case c := <-ch: return c case <-time.After(fsClassTimeout): return FSClassUnknown } }