Bunny Storage
A filesystem over Bunny.net Edge Storage, spoken as plain HTTP.
A vfs.FileSystem over
Bunny.net Edge Storage, spoken
as plain HTTP (no SDK). Auth is the storage-zone password sent in the
AccessKey header.
Configuration
remotes:
cdn: # addressed as cdn://path/to/file
type: bunnystorage
zone: my-storage-zone
region: ny # optional; selects <region>.storage.bunnycdn.com
# endpoint: https://storage.bunnycdn.com # optional explicit base URL
# prefix: dumont # optional: root the remote at zone/<prefix>
emulate: true # optional: add random write/append via RMW
credentials:
password: env:BUNNY_STORAGE_PASSWORDThe remote name is the URI scheme and the whole path follows it
(cdn://images/logo.png); the zone and credentials are fixed per remote.
Capabilities
| Cap | Value | Why |
|---|---|---|
| RandomRead | ❌ | whole-object GET |
| RandomWrite | ❌ | whole-object PUT |
| Append | ❌ | — |
| Truncate | ❌ | — |
| AtomicRename | ❌ | rename = download + upload + delete |
| Directories | ❌ | modeled as synthesized-from-prefix |
| MTime | ✅ | LastChanged (second resolution) |
| CaseSensitive | ✅ | keys are case-sensitive |
Wrap with emulate: true for random write/append, and the metadata cache cuts
listing round-trips automatically.
Semantic surprises
- No HEAD for a single object.
Statlists the parent directory and finds the entry — Bunny's listing reportsLength,LastChanged, andIsDirectoryper child. - Directories are modeled as synthesized. Although Bunny does persist
directory objects (created implicitly when a file is uploaded into a path),
empty directories can't be created via the API, so dumont treats a directory
as existing iff it has children.
Mkdiris a no-op (the path appears once a file lands in it); removing an empty directory issues a recursiveDELETEon the trailing-slash path. - Rename copies. There is no server-side copy:
Renamedownloads, re-uploads under the new key, and deletes the old (non-atomic; directory rename iterates every descendant). - mtime is second-resolution, truncated so
StatandReadDiragree.
Testing
-
A full conformance suite runs against an in-process mock of the API (no credentials, always runs).
-
An integration suite runs the same battery plus a smoke test against a real zone when
BUNNY_STORAGE_ZONEandBUNNY_STORAGE_PASSWORDare set. Each run is sandboxed under a unique key prefix and deleted on completion, leaving the zone clean:BUNNY_STORAGE_ZONE=my-zone BUNNY_STORAGE_PASSWORD=... \ go test -run TestIntegration ./backend/bunnystorage/