Archived
internal/tenant/ provides FS, a sandboxed handle for a single tenant's notes directory. Implementation strategy: - Defence in depth: every relative path is validated up front (rejects "..", absolute paths, NUL bytes, empty), then handed to os.Root (Go 1.24+) which enforces the boundary at the syscall layer using openat(2)+RESOLVE_BENEATH on Linux. This closes TOCTOU races and symlink-target swapping. - WriteFile is atomic (write to .tmp, rename in-root). Mode 0o600 on files, 0o700 on directories. Tenant root is created with 0o700 by Open(). - Errors are normalised: fs.ErrNotExist -> ErrNotFound, anything os.Root rejects as "outside" the root -> ErrInvalidPath. The HTTP layer can map cleanly to 404 / 400. Tests cover the full traversal attack surface — "../", absolute paths, mixed separators, NUL bytes, "." and "" — plus symlink escapes and cross-tenant isolation. All vectors return errors; none escape the root. Closes #10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>