Skip to content

install: report stock macFUSE status and mount KBFS only on Finder opt-in - #29775

Draft
chrisnojima wants to merge 7 commits into
nojima/macfuse-01-kbfs-mountfrom
nojima/macfuse-02-fuse-status
Draft

chrisnojima wants to merge 7 commits into
nojima/macfuse-01-kbfs-mountfrom
nojima/macfuse-02-fuse-status

Conversation

@chrisnojima

@chrisnojima chrisnojima commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What

Second of seven PRs moving macOS from the bundled kbfuse to user-installed macFUSE.

  • keybase fuse status and the service's FuseStatus describe stock macFUSE: not installed, outdated (< 5), unreadable version, kext info error, no kext for the running macOS, or ready (with whether its kext is loaded). A leftover kbfuse install is flagged in the status fields. The --bundle-version flag goes away.
  • macFUSE ships one kext per macOS major version. When none matches the running macOS (usually right after a macOS update) and no macFUSE kext is loaded, the status is INSTALLED/UPGRADE with status name MACOS_UNSUPPORTED and a macosVersion field, so nothing mounts and the app can ask for a macFUSE update instead of kext approval (D57). A loaded kext is used whatever the macOS.
  • Mount infos come from getfsstat(MNT_NOWAIT) (no /sbin/mount parsing, and no waiting on an unresponsive file system), keep only KBFS fstypes the current user owns, and the service keeps only the one at this user's mount dir, matched with its parent dir resolved, since other apps mount with fstype macfuse too.
  • FuseStatus adds a finderAccess=on field while the user has Finder access turned on, so the app knows to wait for the mount after KBFS connects.
  • The fuse install component no longer installs anything: it checks macFUSE and loads its kext with the setuid load_macfuse. It exits 5 when macOS has not allowed the kext yet, so the app can show approval help; it fails with the status message when macFUSE is missing, outdated or does not support the running macOS.
  • Finder access becomes a per-user opt-in marker in the config dir. KBFS always starts (chat and the in-app Files tab need it) but mounts only when the user opted in and macFUSE is ready. The service's InstallKBFS sets the marker; UninstallKBFS clears it, unmounts and restarts KBFS unmounted instead of removing the driver.
  • Nothing installs the helper, kbfuse, the mount dir or the redirector any more. install-auto and the default keybase install components need no privileges or macFUSE, and keybase install prints failed components on stderr.
  • The mount listing helpers live in a file that also builds for iOS, which shares install_darwin.go.

Why

Keybase no longer installs a FUSE driver, so status has to describe the user's macFUSE, and mounting has to be something the user turns on rather than a side effect of installing the driver.

Testing

  • Go builds (darwin, linux, windows, iOS); go vet clean on this branch; golangci-lint --new-from-rev master clean on the stack tip; go test ./install/..., including table tests of the status derivation (deriveFuseStatus, the macOS-unsupported case among them), macosMajor, the owner and fstype filter over getfsstat results, listMounts, mount dir resolution and the KBFS mount filter, shouldMountKBFS, the install-auto component list and the opt-in marker round trip.
  • Manual, test account, macOS 27 with macFUSE 5.4: keybase fuse status unmounted → 5.4.0, the …macfuse.25 kext ID, kext started, no mounts; mounted → only /Volumes/Keybase (<user>), path with spaces intact. keybase install --components=fuse → exit 0 with macFUSE ready. With macFUSE removed: status NOT_INSTALLED with the macfuse.io message; after reinstalling, the next status read is ready again with no click.

Not verified yet

  • The not-approved kext state (exit 5) on a fresh Mac: macOS remembered the approval on the test Mac, and resetting it needs Recovery.
  • The outdated-macFUSE (macFUSE 4) and MACOS_UNSUPPORTED paths live (unit-tested only), and keybase install; echo $? without macFUSE (exit 0 is by reading the code only).

Judgment calls

  • KBFS always runs; only the mount is gated on the opt-in. Turning Finder access off just unmounts (no "Remove & Restart" dialog), since there is no driver to remove any more.
  • A macFUSE without a kext for the running macOS is reported as needing an update rather than as ready, even though its version is ≥ 5. Minor macOS updates share the major's kext and are not covered.
  • Until PR 3 lands, the app component and --source-path stay: the updater's rename fallback still uses them.

@chrisnojima
chrisnojima added this pull request to stack #29781 October 15, 2026 02:54
@chrisnojima chrisnojima changed the title feat(install): report stock macFUSE and mount KBFS only on opt-in install: report stock macFUSE status and mount KBFS only on Finder opt-in Oct 15, 2026
@chrisnojima
chrisnojima force-pushed the nojima/macfuse-02-fuse-status branch from 79ebb9f to 2169421 Compare October 20, 2026 13:47
@chrisnojima
chrisnojima force-pushed the nojima/macfuse-02-fuse-status branch from 2169421 to 6e866fa Compare October 20, 2026 18:45
`keybase fuse status` and the service's FuseStatus now describe the
user-installed macFUSE (5 or later) instead of the bundled kbfuse:
not installed, outdated, unreadable, kext error, or ready (with whether
its kext is loaded). Mount infos are filtered to this user's KBFS mount
dir, since other apps mount with fstype macfuse too. A leftover kbfuse
install is flagged in the status fields.

- The `fuse` install component no longer installs anything: it checks
  macFUSE and loads its kext with the setuid load_macfuse. It exits 5
  when macOS has not allowed the kext yet, so the app can show the
  approval help.
- Finder access is a per-user opt-in marker in the config dir. KBFS is
  always started (chat and the in-app Files tab need it) but mounts only
  when the user opted in and macFUSE is ready. Turning Finder access off
  unmounts and restarts KBFS unmounted; it no longer removes the driver.
- Nothing installs the helper, kbfuse, the mount dir or the redirector
  any more: install-auto and the default `keybase install` components
  need no privileges, and `keybase install` prints failed components on
  stderr.
…er's

MountInfos now comes from getfsstat(MNT_NOWAIT) instead of parsing
/sbin/mount, holds only mounts the current user owns, and is matched
against the cleaned mount dir.
The kernel reports a mount at its real path, so a mount dir whose parent
is a link, or that ends in a slash, now still finds its mount.
install_darwin.go also builds for iOS, so listMounts, mountInfosOwnedBy
and resolveMountDir move from fuse_status_darwin.go (not built for iOS)
to mounts_darwin.go.
… needing an update

macFUSE ships one kext per macOS major version, so after a macOS update
an older macFUSE has none to load. The status now reports it as an
upgrade (status name MACOS_UNSUPPORTED, field macosVersion) instead of
ready, so nothing tries to mount and the app asks for a macFUSE update
rather than kext approval. A loaded kext is still used as is.
…ss on

The service adds a finderAccess=on status field, so the GUI knows to
wait for the KBFS mount after a connect.
@chrisnojima
chrisnojima force-pushed the nojima/macfuse-02-fuse-status branch from 6e866fa to 309c973 Compare October 20, 2026 21:30
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.

1 participant