Documentation
¶
Index ¶
- Variables
- func CheckPath(userPath string) (string, error)
- type Manager
- func (m *Manager) Create(sessionID uuid.UUID) (string, error)
- func (m *Manager) CreateSnapshot(sessionID, snapshotID uuid.UUID) (archivePath string, sizeBytes int64, err error)
- func (m *Manager) Delete(sessionID uuid.UUID) error
- func (m *Manager) DeleteSnapshot(archivePath string) error
- func (m *Manager) Exists(sessionID uuid.UUID, userPath string) (bool, error)
- func (m *Manager) OpenFile(sessionID uuid.UUID, userPath string) (*os.File, error)
- func (m *Manager) RestoreSnapshot(sessionID uuid.UUID, archivePath string) error
- func (m *Manager) SafePath(sessionID uuid.UUID, userPath string) (string, error)
- func (m *Manager) SessionDirs() ([]uuid.UUID, error)
- func (m *Manager) SessionPath(sessionID uuid.UUID) string
- func (m *Manager) WriteFile(sessionID uuid.UUID, userPath string, r io.Reader, maxBytes int64) (int64, error)
Constants ¶
This section is empty.
Variables ¶
var ErrPathTraversal = errors.New("path traversal detected")
ErrPathTraversal is returned for a path with a ".." component.
Functions ¶
func CheckPath ¶ added in v0.4.7
CheckPath rejects a user-provided path that contains a ".." component and returns the path with percent-encoding fully decoded. Callers use it to answer with an error instead of quietly rewriting "../x" to "/x".
The path is URL-decoded in a loop until stable to catch double/triple-encoded traversals (%252e%252e%2f), and the check is per component, not strings.Contains, so "foo..txt" stays valid.
Types ¶
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
func (*Manager) Create ¶
Create initializes an isolated workspace directory for a session.
os.MkdirAll honours the process umask, which can strip permission bits; the explicit os.Chmod afterwards is umask-independent.
func (*Manager) CreateSnapshot ¶
func (m *Manager) CreateSnapshot(sessionID, snapshotID uuid.UUID) (archivePath string, sizeBytes int64, err error)
CreateSnapshot creates a gzip-compressed tar archive of the session workspace. The archive is written to {baseDir}/snapshots/<snapshotID>.tar.gz and the archive path + uncompressed size are returned.
func (*Manager) DeleteSnapshot ¶
DeleteSnapshot removes a snapshot archive from disk.
func (*Manager) Exists ¶ added in v0.3.2
Exists reports whether userPath refers to a real file/dir inside the session workspace. Symlinks that escape the workspace root are treated as absent (not an oracle for host paths).
func (*Manager) OpenFile ¶
OpenFile opens a file inside the workspace for reading. Symlink targets are validated to remain inside the workspace.
func (*Manager) RestoreSnapshot ¶
RestoreSnapshot extracts a snapshot archive into the session workspace. Files in the archive overwrite existing files; the workspace is not cleared first so existing files not in the snapshot are preserved.
func (*Manager) SafePath ¶
SafePath resolves a user-provided path within the workspace, enforcing:
- URL-decoded (loop until stable) to catch double/triple-encoded traversals
- No ".." path components (checked after full decoding, before Clean)
- Resolved path stays inside the workspace root (filepath.Clean + HasPrefix)
func (*Manager) SessionDirs ¶ added in v0.4.1
SessionDirs returns the session IDs that have a directory under the base directory. Entries whose name is not a UUID (snapshots/, warm pool) are skipped.
func (*Manager) WriteFile ¶
func (m *Manager) WriteFile(sessionID uuid.UUID, userPath string, r io.Reader, maxBytes int64) (int64, error)
WriteFile writes data to a safe path inside the workspace, creating intermediate directories as needed.
Security: guards against symlink-escape attacks where a container process creates a symlink inside /workspace pointing to a host path outside the workspace root. Two layers of protection are applied:
- The entire parent-directory chain is symlink-resolved and verified to stay inside the workspace root before any write takes place.
- The file is opened with O_NOFOLLOW so that if the final path component is itself a symlink (e.g. created in a TOCTOU window) the open fails.
Permissions: directories use DirMode and files 0o644. os.Chmod is called after creation to bypass the process umask.