Hanzo Dev c9e57245fa 0.3.1: macOS FUSE via github.com/jacobsa/fuse — SQLite e2e passes on macOS
bazil.org/fuse dropped macOS support (commit 65cc252+). 0.3.0
shipped Linux-only. This drop adds a parallel pkg/mount/fuse_darwin.go
using github.com/jacobsa/fuse, which still supports both macFUSE
(kext) and fuse-t (userspace, no kext, SIP-friendly).

Same Mount(*vfs.FS, mountpoint) signature; the `fuse` build tag
picks the right driver per GOOS at compile time.

What's new
----------
- pkg/mount/fuse_darwin.go (`-tags fuse && darwin`): full
  fuseutil.FileSystem implementation using jacobsa/fuse. Maps every
  POSIX op the kernel sends:
    LookUpInode → FS.Lookup
    GetInodeAttributes → FS.Lookup + inode→attrs
    SetInodeAttributes(size) → File.Truncate + Sync
    MkDir → FS.Mkdir
    CreateFile → FS.Create + FS.Open + handle alloc
    Unlink/RmDir → FS.Remove
    OpenDir/ReadDir/ReleaseDirHandle → FS.ReadDir
    OpenFile/ReadFile/WriteFile → FS.Open + File.{ReadAt,WriteAt}
    SyncFile/FlushFile → File.Sync
    ReleaseFileHandle → File.Close
    StatFS → ~1 PiB pseudo-quota (backend is unlimited)

- pkg/vfs/fs.go: new FS.PathOfInode(InodeID) for the macOS driver,
  which gets ops as (parent_id, name) tuples instead of bazil's
  node-pointer style. O(depth) walk up the parent chain.

- pkg/mount/fuse_sqlite_test.go: build tag widened to
  `fuse && (linux || darwin)`. Adds `runtime.GOOS` switch to invoke
  the right unmount tool (`fusermount`/`fusermount3` on Linux,
  `umount`/`diskutil unmount` on macOS).

Verified
--------
On macOS with fuse-t installed:
  VFS_FUSE_E2E=1 go test -tags fuse -timeout 60s \
      -run TestFUSESQLite ./pkg/mount/ -v
  → PASS: TestFUSESQLite (1.16s)
  → 100 rows survived umount+remount, integrity_check=ok

Real FUSE mount, real SQLite opening test.db directly on the
mountpoint, 100 INSERTs, unmount, remount, PRAGMA integrity_check.
Zero copy step.
2026-05-08 12:37:30 -07:00

vfs

S3-backed virtual block filesystem with PQ encryption — unlimited write storage for stateful services.

Build

Quick start

# Build
make build

# Generate an age key (one-time)
go run filippo.io/age/cmd/age-keygen > /tmp/vfs.key
RECIPIENT=$(grep 'public key' /tmp/vfs.key | cut -d: -f2 | tr -d ' ')

# Put + get a block (file:// backend, dev only)
echo "hello world" > /tmp/in.txt
ID=$(./bin/vfs put /tmp/in.txt --backend file:///tmp/vfs-store --age-recipient "$RECIPIENT" --age-key /tmp/vfs.key)
echo "block: $ID"
./bin/vfs get "$ID" --backend file:///tmp/vfs-store --age-key /tmp/vfs.key

# Same flow against S3
./bin/vfs put /tmp/in.txt \
    --backend "s3://my-bucket/vfs-prefix?region=us-east-1" \
    --age-recipient "$RECIPIENT" \
    --age-key /tmp/vfs.key

What it is

A 4 KiB block-level virtual filesystem that:

  • Hashes every block with blake3-256 for content addressability + integrity.
  • Encrypts every block with luxfi/age (X25519, optionally hybrid PQ via ML-KEM-768) before it touches the backend.
  • Stores blocks as blocks/<2-hex-shard>/<full-hash>.zap.age on a pluggable backend (file://, s3://, gcs:// (TODO), azureblob:// (TODO)).
  • Caches recently-used blocks in an in-memory LRU (NVMe write-back cache lands in 0.2.0).
  • Mounts as a FUSE filesystem (make build-fuse; mount layer lands in 0.2.0).

Why

Stateful services in K8s usually pre-size a PVC and either over-provision or run out of disk. vfs lets a service write as if it has unlimited local NVMe — the hot tier is a configurable local cache, the cold tier is S3 (or any object store), and the PQ-encrypted blocks let the operator put cold pages in any region without leaking content.

Companion to hanzo/replicatereplicate streams SQLite WAL frames file-level; vfs does block-level for any file system.

See LLM.md for the full architecture, K8s sidecar pattern, encryption design, and roadmap.

License

Apache 2.0

S
Description
Hanzo tenant service — sourced from hanzoai/vfs
Readme
343 KiB
Languages
Go 97.8%
ZAP 1.2%
Makefile 0.6%
Dockerfile 0.4%