Documentation
¶
Overview ¶
Package vfs is the single home for workspace-root containment: normalizing a candidate path against a root and rejecting anything that escapes it, symlinks included. Two callers used to carry their own copy of this logic — the local_fs agent tool (runtime/localtools) and the /files browse API (runtime/localfileservice); both now delegate here so there is exactly one symlink-escape guard to reason about.
The API is deliberately small:
- Contain(root, candidate) resolves a path within a root and is the core primitive. It tolerates a non-existent leaf (resolving the deepest existing parent) so create/write paths validate before any I/O.
- Within(root, abs) is the raw within-root predicate for callers that have already resolved the absolute path themselves.
- Factory holds the serve-level allowlist of workspace roots and vends rooted Views. A session may only operate within an allowlisted root.
- View is a Factory-vended, root-bound convenience wrapper over Contain.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEscape = errors.New("path escapes workspace root")
ErrEscape is returned (wrapped) when a candidate path resolves outside its root. Callers translate it into their own domain error via errors.Is.
var ErrNotAllowed = errors.New("workspace root is not allowed")
ErrNotAllowed is returned when a requested root is not in the Factory's allowlist.
Functions ¶
func Contain ¶
Contain resolves candidate (absolute, or relative to root) to a cleaned, symlink-resolved absolute path guaranteed to lie within root. Symlinks are followed so an in-sandbox link pointing outside the root is caught before any I/O. A non-existent leaf is permitted: the deepest existing parent is resolved and the missing suffix re-appended, so writing "link/new.txt" where "link" escapes is still rejected. Returns an error wrapping ErrEscape when the path leaves root.
func ResolveRoot ¶
ResolveRoot returns the cleaned, absolute, symlink-resolved form of root. A non-existent root is tolerated (its cleaned absolute form is returned) so a workspace directory that has not been created yet still validates.
Types ¶
type Factory ¶
type Factory struct {
// contains filtered or unexported fields
}
Factory holds the serve-level allowlist of workspace roots — the set of directories a browser client may choose as a session's workspace. Choosing a root outside the allowlist is refused. The first root is the default, used when a client asks for the sentinel "/" (or nothing), which keeps existing clients that always send cwd:"/" working.
func NewFactory ¶
NewFactory builds a Factory from an ordered list of roots. The first root is the default. Roots are cleaned, made absolute, symlink-resolved, and de-duplicated (preserving first-seen order). At least one root is required.
func (*Factory) Allows ¶
Allows reports whether root resolves to an allowlisted root, returning the normalized root when it does.
func (*Factory) Default ¶
Default returns the default root (the first configured), used for the "/" / empty sentinel.
func (*Factory) Open ¶
Open returns a View rooted at root, which must be allowlisted (via Resolve semantics, so "/" opens the default root).
func (*Factory) Resolve ¶
Resolve maps a requested root to an allowlisted, resolved root. The sentinel "/" and the empty string both resolve to the default root — the compat story for clients (beam today) that always send cwd:"/". Any other value must resolve to a member of the allowlist; otherwise ErrNotAllowed is returned.
type View ¶
type View struct {
// contains filtered or unexported fields
}
View is a root-bound convenience wrapper over Contain. It caches the symlink-resolved root so repeated Resolve calls avoid re-walking it.
func OpenView ¶
OpenView returns a View rooted at root, resolving its symlinks. Unlike Factory.Open it enforces no allowlist — use it for a single fixed root that is trusted by construction (e.g. a serve-owned browse root).
func (*View) Contains ¶
Contains reports whether an already-absolute path lies within the view root.