{"id":49438111,"url":"https://github.com/sohonetlabs/testfs","last_synced_at":"2026-04-29T18:01:22.370Z","repository":{"id":354296075,"uuid":"1223011813","full_name":"sohonetlabs/testfs","owner":"sohonetlabs","description":"Synthetic read-only FSKit filesystem serving tree -J -s JSON trees on macOS","archived":false,"fork":false,"pushed_at":"2026-04-28T00:14:00.000Z","size":7415,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-28T01:25:57.419Z","etag":null,"topics":["developer-tools","filesystem","fskit","macos","swift","testing"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sohonetlabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-27T23:39:46.000Z","updated_at":"2026-04-28T00:20:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sohonetlabs/testfs","commit_stats":null,"previous_names":["sohonetlabs/testfs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/sohonetlabs/testfs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sohonetlabs%2Ftestfs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sohonetlabs%2Ftestfs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sohonetlabs%2Ftestfs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sohonetlabs%2Ftestfs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sohonetlabs","download_url":"https://codeload.github.com/sohonetlabs/testfs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sohonetlabs%2Ftestfs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32437111,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T17:34:55.123Z","status":"ssl_error","status_checked_at":"2026-04-29T17:34:45.749Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["developer-tools","filesystem","fskit","macos","swift","testing"],"created_at":"2026-04-29T18:01:09.438Z","updated_at":"2026-04-29T18:01:22.353Z","avatar_url":"https://github.com/sohonetlabs.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TestFS\n\nA read-only synthetic filesystem for macOS, built on **FSKit**. Mount a\nJSON tree as a filesystem whose contents are made up on demand — either a\nfill character or deterministic pseudo-random bytes. Useful for testing\nsoftware against arbitrarily large directory structures without spending\nthe disk space.\n\nNative Swift, no kernel extension, no `fuse-t` shim. macOS 15.4 or later\n(FSKit V1 is the floor).\n\nThis is the macOS-native port of\n[`sohonetlabs/test_json_fs`](https://github.com/sohonetlabs/test_json_fs)\n(Python + FUSE).\n\n## Install (end users)\n\n1. Grab the latest `TestFS-X.Y.Z.dmg` from\n   [Releases](https://github.com/sohonetlabs/testfs/releases).\n2. Open the DMG and drag `TestFS.app` to the `Applications` shortcut.\n   (The DMG also contains an `Examples/` folder of sample JSON trees —\n   drag that to `~/Documents/` if you want them handy.)\n3. Launch `/Applications/TestFS.app`. The first time, a banner asks you\n   to enable the FSKit extension — click **Open System Settings…**, then\n   toggle **TestFS** on under *General → Login Items \u0026 Extensions →\n   File System Extensions*.\n4. Pick a JSON tree (the **File ▸ Try an example…** menu opens an\n   embedded set), pick an empty directory as the mountpoint, click\n   **Mount**. **Avoid Desktop / Documents / Downloads / iCloud\n   Drive / Pictures / Movies / Music** — macOS won't let `fskitd`\n   write to those, and the mount will fail with *Operation not\n   permitted*. A subdir under your home folder root or `/tmp` works.\n\nThe DMG is signed with a Developer ID Application certificate and\nnotarized by Apple, so Gatekeeper accepts it without warnings.\n\nSubsequent releases install themselves: TestFS embeds\n[Sparkle](https://sparkle-project.org), checks\n`https://raw.githubusercontent.com/sohonetlabs/testfs/main/appcast.xml`\nin the background, and prompts when a new version is available. You\ncan also force a check from **App ▸ Check for Updates…**.\n\n## Build from source\n\n```bash\ngit clone --recurse-submodules git@github.com:sohonetlabs/testfs.git\ncd testfs\nxcodebuild -project TestFS.xcodeproj -scheme TestFS \\\n    -configuration Debug -destination 'platform=macOS' \\\n    -allowProvisioningUpdates build\n```\n\nThe build phase rsyncs `research/test_json_fs/example/` into\n`TestFS.app/Contents/Resources/Examples/`, so the in-app picker works\nstraight from a `Debug` build.\n\nIf you don't have a Sohonet team signing identity, change\n`DEVELOPMENT_TEAM` and the bundle IDs across both targets to your own.\n\n## Mount from the CLI\n\nPrerequisites: `TestFS.app` is installed (so the FSKit extension is\nregistered) and toggled on under *General → Login Items \u0026 Extensions\n→ File System Extensions*. `scripts/smoke.sh` verifies both before\nyou bother trying to mount. Sample JSON trees live at\n`research/test_json_fs/example/` — clone with `--recurse-submodules`.\n\n```bash\nscripts/smoke.sh                                # check the install + extension registration\nscripts/mount.sh                                # mounts test.json at /tmp/testfs\nscripts/mount.sh path/to/tree.json              # custom tree, default /tmp/testfs\nscripts/mount.sh path/to/tree.json /mountpoint  # custom tree + mountpoint\nscripts/unmount.sh                              # unmount + detach the dummy disk\n```\n\nRun as your normal user — **not** `sudo`. The `mount(8) -F` path that\nFSKit V1 uses fails under sudo: `fskitd` checks the caller's audit\ntoken uid against the dev node's owner, and the user-owned dev node\nthat `hdiutil` attached can't be opened by uid 0.\n\nMountpoint must be outside macOS's privacy-protected directories\n(Desktop, Documents, Downloads, iCloud Drive, Pictures, Movies,\nMusic) — `fskitd` is denied access there and the mount fails with\n*Operation not permitted*. The default `/tmp/testfs` and any fresh\nsubdir under your home folder root are fine.\n\n## Architecture\n\n```\nTestFS.app\n├── TestFS                       (SwiftUI host, unsandboxed*)\n└── TestFSExtension.appex        (FSKit V1 block-resource extension,\n                                  sandboxed, reads its sidecar JSON\n                                  from its own container)\n```\n\nThe mounted volume is **case-sensitive** (matches the Python `jsonfs.py`\nupstream). `Foo.txt` and `foo.txt` are independent entries; lookup is\nbyte-exact after `unicode_normalization` is applied (default NFD).\n\n\\* The host is intentionally unsandboxed because mounting in-process\nneeds `hdiutil` access to attach a dummy raw disk image — a path that\nDiskArbitration + the IOKit user client refuse from a sandboxed\nprocess. The FSKit extension itself is sandboxed.\n\n## Examples\n\nSample JSON trees live in\n[`research/test_json_fs/example/`](research/test_json_fs/example/) (a\ngit submodule pointing at `sohonetlabs/test_json_fs`). The\nrelease-built DMG includes a copy of the same set under\n`Examples/`. Highlights:\n\n| File | What it demonstrates |\n|---|---|\n| `test.json` | 10-file basic demo |\n| `bad_windows.json` / `bad_s3.json` | Names that break on those platforms |\n| `big_list_of_naughty_strings_fs.json` | Unicode/edge-case fuzzing |\n| `archive_torture_*.json` | Pathological inputs for archive tools |\n| `imdbfslayout.json.zip` | 460k-file IMDB-shaped layout (unzip first) |\n\n## Releasing (maintainer)\n\nThe release pipeline produces a notarized, stapled DMG containing\n`TestFS.app`, an `Applications` drop-link, and the `Examples/` folder.\n\nOne-time setup on each release machine:\n\n- `brew install create-dmg swiftlint`\n- Developer ID Application certificate for team `H6XW263G62` in the\n  login keychain.\n- Notarization keychain profile:\n  ```bash\n  xcrun notarytool store-credentials testFS \\\n      --apple-id \u003cyour-apple-id\u003e --team-id H6XW263G62 \\\n      --password \u003capp-specific-password\u003e\n  ```\n- Sparkle Ed25519 signing key. On the first machine, generate it once:\n  ```bash\n  $(ls -td ~/Library/Developer/Xcode/DerivedData/TestFS-*/SourcePackages/artifacts/sparkle/Sparkle/bin | head -1)/generate_keys --account testfs\n  ```\n  Back up the private key (e.g. via 1Password) — losing it means new\n  installs would have to ship under a different bundle ID. To restore\n  on a second machine, `generate_keys --account testfs -f \u003ckey-file\u003e`.\n\nPer release:\n\n```bash\n# Bump version\necho 0.1.4 \u003e VERSION\ngit commit -am \"Bump version to $(cat VERSION)\"\n\n# Build, lint-gate, sign, notarize, staple, sparkle-sign, update appcast\nscripts/release.sh\n# ⇒ build/TestFS-0.1.4.dmg + appcast.xml updated locally\n\n# Tag, push code, push the new appcast, upload the DMG to a Release\ngit tag v$(cat VERSION)\ngit push --follow-tags\ngh release create v$(cat VERSION) build/TestFS-$(cat VERSION).dmg \\\n    --notes \"Release notes here\"\ngit add appcast.xml \u0026\u0026 git commit -m \"Appcast: $(cat VERSION)\" \u0026\u0026 git push\n```\n\n`scripts/release.sh` runs `swiftlint --strict` first (cheap fail-fast\ngate), then archives in Release configuration, exports with\n`method=developer-id`, builds the DMG via `create-dmg`, submits to\n`notarytool --wait`, staples, mounts the DMG to assess the embedded\napp via `spctl`, signs the DMG with Sparkle's Ed25519 key, and\nprepends the new entry to `appcast.xml`. Wall time is 3–5 minutes\ndepending on Apple's notarization queue.\n\n## Reference implementation\n\nThe Python original is vendored at `research/test_json_fs/` as a git\nsubmodule. See its README for the full feature list and CLI flags;\nthis Swift port aims for parity.\n\n## License\n\n[MIT](LICENSE). The port builds on Sohonet Labs' `test_json_fs` and\nKhaosT's [`FSKitSample`](https://github.com/KhaosT/FSKitSample) — see\n`LICENSE` for the attribution notices.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsohonetlabs%2Ftestfs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsohonetlabs%2Ftestfs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsohonetlabs%2Ftestfs/lists"}