Skip to content

fix(preflight): match FUSE network mounts by normalised name, not by spelling (client#725) - #726

Open
LukasWodka wants to merge 1 commit into
developfrom
fix/725-fuse-fstype-normalisation
Open

fix(preflight): match FUSE network mounts by normalised name, not by spelling (client#725)#726
LukasWodka wants to merge 1 commit into
developfrom
fix/725-fuse-fstype-normalisation

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Fixes #725

Summary

_pf_is_network_fstype (shared by _pf_storage_type and the pre-log early_data_dir_guard, #432) matched the FUSE network filesystems only as fuse.sshfs / fuse.s3fs / fuse.rclone / fuse.glusterfs / fuse.ceph / fuse.davfs — and three of those six had no bare twin.

Which spelling arrives depends on which reader in _pf_fstype answered, and two of its three readers never emit a fuse. prefix. Measured by mounting each filesystem for real on Ubuntu 24.04 (libfuse 3.14.0, util-linux 2.39.3, coreutils 9.4) and Ubuntu 20.04 (libfuse 2.9.9) — identical on both:

reader (in _pf_fstype order) sshfs rclone bindfs
findmnt -nro FSTYPE fuse.sshfs fuse.rclone fuse
stat -f -c %T (Linux fallback, no findmnt) fuseblk fuseblk fuseblk
df + mount (the macOS path) macfuse macfuse macfuse

So on macOS none of the six entries can ever match — macOS has no findmnt and deliberately skips the stat reader (BSD stat -f is a format string), so the df+mount path always answers, with the macFUSE vfs name. And wherever findmnt is absent on Linux, stat -f -c %T collapses every FUSE mount to fuseblk (the fuse and fuseblk kernel filesystems share one magic number). In both cases the guard read "Local storage" and MySQL was installed onto exactly the filesystem it exists to reject.

The originally-suspected mechanism — a bare sshfs in the mount table — did not reproduce on either libfuse generation; sshfs and rclone always set a subtype. The prefixed spellings are right for findmnt; the defect is that they were the only spellings.

Change

  • Normalise, don't enumerate. Strip a leading fuse. before matching; the case list now carries bare names only, so it cannot regrow a prefixed entry with no bare twin. A guard test asserts the list contains no fuse.-prefixed entry, and fails closed if it can't read the function.
  • Opaque FUSE (fuse, fuseblk, macfuse, osxfuse) — FUSE with the subtype erased — gets its own predicate and warns instead of hard failing. sshfs and a local ntfs-3g/gocryptfs are indistinguishable at that point, so a refusal would block legitimate local installs, and TRACEBLOC_ALLOW_NETWORK_FS reads as nonsense to someone who is not on a network filesystem. The silent "Local storage" pass was the defect; the warn names what it might be and continues.

Deliberately not in this PR: recovering the real subtype when a reader degrades (readable from /proc/mounts on Linux and from the sshfs#… device field on macOS). That would let the named cases hard fail on every platform instead of only warning. Happy to file it as a follow-up.

Test plan

New tests write their input filesystem names down from the measured reader outputs, not from the case list — a list checked against itself is self-consistent and blind. The measurement table is recorded in the test file header.

  • bats scripts/tests/preflight.bats134/134 pass (5 new tests, 0 failures)
  • bats scripts/tests/bats-hygiene.bats — green; every new assertion is || return 1-hardened
  • bats scripts/tests/copy-catalog.bats — green (no user-facing copy in the goldens changed)
  • make check — green; make check-all — green (465 helm unit tests, 31 suites)
  • scripts/gen-manifest.sh re-run; scripts/manifest.sha256 committed (R8 gate)

Mutation-proof — each mutation was verified to have actually applied (anchor gone) before trusting the result:

mutation result
drop the fuse. strip 5 tests red
regrow the original bug (fuse.sshfs entry, no bare sshfs) 7 tests red, incl. the no-prefix structural guard
opaque predicate always false 3 tests red
restore the classifier exactly as it ships on develop 5 of the new tests red

The last row is the one that matters: the tests fail against the real pre-fix code, not just against a synthetic mutation.

Found while fact-checking tracebloc/e2e-test-agent#125, which documents this guard and flags the gap without fixing it (the defect is here, not there).

🤖 Generated with Claude Code


Note

Medium Risk
Changes install-time HOST_DATA_DIR guards that affect MySQL placement; behavior is safer for misdetected sshfs but opaque FUSE only warns, so network-backed FUSE can still proceed unless explicitly named or blocked.

Overview
Fixes installer preflight so network-backed FUSE mounts (sshfs, s3fs, rclone, etc.) are caught even when _pf_fstype reports a bare subtype or a generic FUSE name (fuseblk, macfuse, fuse) instead of fuse.sshfs.

_pf_is_network_fstype now lowercases and strips a leading fuse. before matching a bare-name allowlist (no more fuse.*-only entries that two of three fstype readers never return). _pf_is_opaque_fuse_fstype and _pf_opaque_fuse_warn handle subtype-erased FUSE: early_data_dir_guard and _pf_storage_type warn instead of silently treating storage as local or hard-failing legitimate local FUSE (ntfs-3g, bindfs).

docs/INSTALL.md pre-install checklist documents named network FUSE vs opaque-FUSE warning behavior. scripts/manifest.sha256 updates for preflight.sh. scripts/tests/preflight.bats adds coverage from measured reader outputs (prefix/bare parity, opaque vs network paths, guard agreement).

Reviewed by Cursor Bugbot for commit 021eb1f. Bugbot is set up for automated code reviews on this repo. Configure here.

…spelling (client#725)

_pf_is_network_fstype matched the FUSE network filesystems only in their
`fuse.`-prefixed spelling, and three of those six (sshfs, s3fs, rclone) had
no bare twin. Which spelling arrives depends on which reader in _pf_fstype
answered — and two of its three readers never produce a `fuse.` prefix, so
the entries were unreachable there and a network HOST_DATA_DIR was accepted
by the guard that exists to reject it.

Measured on Ubuntu 24.04 (libfuse 3.14.0 / util-linux 2.39.3 / coreutils 9.4)
and 20.04 (libfuse 2.9.9), mounting each filesystem for real:

  reader                     sshfs        rclone        bindfs
  findmnt -nro FSTYPE        fuse.sshfs   fuse.rclone   fuse
  stat -f -c %T              fuseblk      fuseblk       fuseblk
  df + mount (macOS path)    macfuse      macfuse       macfuse

So macOS — which has no findmnt and deliberately skips the stat reader —
could never match ANY of the six, and the Linux stat fallback collapses every
FUSE mount to `fuseblk`.

Normalise instead of enumerate: strip a leading `fuse.` before matching and
keep bare names only, so the list cannot regrow a prefixed entry with no bare
twin. A subtype-erased reading (fuse / fuseblk / macfuse / osxfuse) is now
classified as opaque FUSE and WARNS rather than hard failing — sshfs and a
local ntfs-3g read identically there, so refusing would block legitimate local
installs, and TRACEBLOC_ALLOW_NETWORK_FS is nonsense advice off a network FS.
Silently reading as "Local storage" was the actual defect.

Tests state the input names independently of the matcher (from the measured
reader outputs, not from the case list) and cover both spellings, the local
fuse.* filesystems that must NOT be swept up by the prefix strip, the opaque
readings, and agreement between _pf_storage_type and early_data_dir_guard. All
five new tests fail against the classifier as it ships on develop.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@LukasWodka
LukasWodka requested a review from saadqbal as a code owner August 14, 2026 21:51
@LukasWodka LukasWodka self-assigned this Aug 14, 2026
@LukasWodka

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 021eb1f. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

preflight: the network-FS guard's FUSE entries are unreachable on macOS and on the stat fallback

1 participant