Skip to content

Release Notes v0.8.0

Released: 2026-10-22

Highlights

Path checks that give the same answer on every platform. fs.ValidatePath no longer depends on filepath.IsAbs, fs.IsAbsAny reports a path that is absolute or rooted anywhere, and fs.ValidateSlashPath checks paths that use forward slashes everywhere, such as paths inside a repository.

New Features

fs.IsAbsAny

Problem solved: filepath.IsAbs answers for the platform it runs on. A path read from a document, an archive or a configuration file must stay inside its root on every platform, and the platforms disagree:

Path filepath.IsAbs on Unix on Windows fs.IsAbsAny
/etc/passwd true false true
\etc\passwd false false true
\\server\share false true true
C:\x, C:/x false true true
C:x false false true
docs/a.md false false false

Solution:

import "github.com/grokify/oscompat/fs"

if fs.IsAbsAny(entry.Name) {
    return fmt.Errorf("%s: absolute path in archive", entry.Name)
}

For a path on this machine, such as a command-line argument, keep filepath.IsAbs: there the platform's own rules are the right ones.

fs.ValidateSlashPath

Problem solved: a path inside a repository, an archive or a URL uses forward slashes on every platform. Checking it with OS path functions lets a backslash or a drive letter through on one platform and not another.

Solution:

if err := fs.ValidateSlashPath(src.Path); err != nil {
    return fmt.Errorf("source path %q: %w", src.Path, err)
}
data, err := os.ReadFile(filepath.Join(checkout, filepath.FromSlash(src.Path)))
Path Result
examples/a_test.go, a..b.go, .github/x.yaml nil
"" ErrEmptyPath
/etc/passwd, \etc\passwd, C:/x.go ErrAbsolutePath
.., ../x.go, a/../../x.go ErrPathTraversal
examples\x.go, ab:c.go, ./x.go, a//b.go, a/ ErrInvalidPath (new)

Bug Fixes

  • fs.ValidatePath used filepath.IsAbs, so it rejected /etc/passwd only off Windows, and accepted \etc\passwd and \\server\share off Windows. It now rejects every path that fs.IsAbsAny reports, on every platform. fs.SafeJoin, which calls it, gains the same fix.

Tests

The path tests run every case on every platform. The absolute-path cases had been kept to the platform where each passed, which hid the difference.

Documentation

  • The fs guide explains which check to use for a path on this machine, a path from elsewhere, and a forward-slash path.
  • The portable tests guide warns against checking such paths with filepath.IsAbs, and against keeping path cases in runtime.GOOS branches.

Installation

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

Compatibility

fs.ValidatePath and fs.SafeJoin now return ErrAbsolutePath for rooted, UNC and drive-relative paths that they accepted before on some platforms. Such a path would have been read outside the intended root, so code that relied on it being accepted had a traversal bug. Everything else is unchanged, and the module still has no dependencies outside the standard library.