Skip to content

Release Notes v0.10.0

Released: 2026-10-30

Highlights

Confine a path from a caller to a directory, on every platform. fs.ResolveInRoot turns a tool argument, an upload path or a document entry into a real path inside a root, and refuses everything that would leave it: .., rooted and drive paths, and symbolic links that lead outside.

New Features

fs.ResolveInRoot

root, err := fs.RealDir(uploadRoot) // once, at start-up
if err != nil {
    return err
}
path, err := fs.ResolveInRoot(root, req.Path)
if errors.Is(err, fs.ErrOutsideRoot) {
    return fmt.Errorf("upload path: %w", err)
}

A relative path is taken from the root. An absolute path is accepted only if it lies inside the root. The file need not exist, so a caller can create one in place. These are refused with an error wrapping fs.ErrOutsideRoot:

  • an empty path, or one containing a NUL;
  • any .. element, with / or \ as the separator;
  • a path that is rooted or names a drive but is not absolute on this platform (/etc/passwd or C:x on Windows), which would otherwise be read as relative to the root;
  • a path that leads outside the root once symbolic links are followed.

The answer is the same on every platform, so a path that is refused on Linux is refused on Windows too. The check runs at the moment of the call, so open the returned path promptly and do not treat it as a lock.

fs.RealDir

Returns a directory as an absolute path with symbolic links resolved, and an error if it is missing or not a directory. Resolve a root once with it and pass the result to ResolveInRoot.

Documentation

  • The fs guide explains when to use ResolveInRoot instead of ValidatePath and SafeJoin.
  • The portable tests guide shows how to run a command in a test without building a binary, so no .exe suffix is needed.
  • The getting-started table lists the new functions.

Installation

go get github.com/grokify/oscompat@v0.10.0

Compatibility

Additive only. An API comparison against v0.9.0 reports no incompatible changes. The module still has no dependencies outside the standard library.