Skip to content

Zer0Fit v1.0.1 — Code Review Hardening Release

Choose a tag to compare

@porespellar porespellar released this 12 Jul 02:43
· 10 commits to main since this release

Zer0Fit v1.0.1 — Code Review Hardening Release

This release incorporates findings from two rounds of Claude Opus 4.6 code review covering security hardening, performance improvements, and bug fixes across all source files.

🔒 Security

  • IDOR prefix strengthened: WebUI file ID matching now requires 32+ character prefixes (was 8), preventing brute-force file discovery in multi-user environments
  • Symlink escape prevention: Upload directory lookups now verify realpath containment (matching the existing WebUI upload path check)
  • TOCTOU race hardened: WebUI upload symlink check now rejects symlinks outright with os.path.islink() before resolving, preventing time-of-check-time-of-use attacks
  • Dockerfile non-root user: The server now runs as zer0fit user instead of root, reducing blast radius from container escapes
  • Specific exception handling: File parse errors now catch specific exceptions (ParserError, EmptyDataError, etc.) instead of bare except Exception

🐛 Bug Fixes

  • Install.sh orphaned processes: Fixed subshell scoping bug that prevented LOG_PID from being captured — background docker compose logs processes are now properly killed and waited on
  • Model inference blocking event loop: TimesFM forecast and TabFM inference are now wrapped in asyncio.to_thread() with timeouts (120s / 300s), preventing event-loop blocking and hung requests
  • JSON/JSONL OOM risk: _read_tabular_file now enforces nrows truncation for JSON formats (was already enforced for CSV/Excel), preventing unbounded RAM consumption on large uploads
  • Trailing-separator consistency: _cleanup_uploads symlink escape check now adds trailing separator on both sides for correct path matching
  • _cleanup_uploads silent error masking: Bare OSError catch refined to distinguish FileNotFoundError (benign race) from other errors (logged as warnings)

🛠️ Infrastructure

  • Fixed JAX/numpy incompatibility preventing TabFM preload: TabFM's classifier_and_regressor.py imports JAX at module level (wrapped in try/except ImportError). JAX v0.10+ requires numpy 2.0+ (StringDType), but the project pins numpy <2.0.0 for TimesFM compatibility. Since the PyTorch backend doesn't need JAX at all, the Dockerfile now uninstalls jax/jaxlib after installing TabFM dependencies, allowing the try/except fallback to activate. Removed chex, optax, and orbax-checkpoint (the transitive deps pulling in JAX) from the dependency list.
  • HF cache path mismatch fixed: Dockerfile now sets HF_HOME=/app/.cache/huggingface for a deterministic cache path regardless of container user; install.sh health check updated to match (was checking /root/.cache/ which doesn't exist with the zer0fit user)
  • .env.example defaults: Changed from ARM64 to x86_64 (amd64) to match docker-compose.yml defaults, with comments explaining both architectures

🧹 Cleanup

  • _json_safe renamed to _json_safe_scalar — now handles np.ndarray via .tolist() and np.str_ via str() conversion
  • Removed unused fastapi dependency (server uses Starlette directly)
  • Deprecated pandas alias: "H""h" frequency alias for pandas 2.2+ compatibility
  • Late imports moved to top: StreamableHTTPSessionManager and asynccontextmanager now imported at the top of server.py
  • docker-compose.yml defaults: Architecture defaults changed from ARM64 to x86_64 (more common for GPU servers)
  • install.sh version: Added ZER0FIT_VERSION variable shown in banner, build summary, and success message

🩺 Performance

  • Inference timeout: TimesFM forecast now has a 2-minute timeout, TabFM inference has a 5-minute timeout — prevents model hangs from blocking VRAM

Full diff: v1.0.0...v1.0.1