Documentation
¶
Overview ¶
Package workspace provides a file-system sandbox abstraction. Knowledge, Skills, and Memory subsystems share a single Workspace to manage persistent state as a unified file tree.
Index ¶
- Variables
- func AtomicWrite(ctx context.Context, ws Workspace, path string, data []byte) error
- func Copy(ctx context.Context, ws Workspace, src, dst string) error
- func Glob(ctx context.Context, ws Workspace, pattern string) ([]string, error)
- func Walk(ctx context.Context, ws Workspace, dir string, fn WalkFunc) error
- func WithWorkspace(ctx context.Context, ws Workspace) context.Context
- type Capabilities
- type CapabilityReporter
- type CommandOption
- type CommandRunner
- type ExecOptions
- type ExecResult
- type GitWorkspace
- type LocalCommandRunner
- type LocalWorkspace
- func (w *LocalWorkspace) Append(_ context.Context, path string, data []byte) error
- func (w *LocalWorkspace) Capabilities() Capabilities
- func (w *LocalWorkspace) Delete(_ context.Context, path string) error
- func (w *LocalWorkspace) Exists(_ context.Context, path string) (bool, error)
- func (w *LocalWorkspace) GitClone(ctx context.Context, url, dest string) error
- func (w *LocalWorkspace) GitHead(ctx context.Context, dir string) (string, error)
- func (w *LocalWorkspace) GitPull(ctx context.Context, dir string) error
- func (w *LocalWorkspace) List(_ context.Context, dir string) ([]fs.DirEntry, error)
- func (w *LocalWorkspace) Read(_ context.Context, path string) ([]byte, error)
- func (w *LocalWorkspace) RemoveAll(_ context.Context, path string) error
- func (w *LocalWorkspace) Rename(_ context.Context, src, dst string) error
- func (w *LocalWorkspace) Root() string
- func (w *LocalWorkspace) Stat(_ context.Context, path string) (fs.FileInfo, error)
- func (w *LocalWorkspace) Write(_ context.Context, path string, data []byte) error
- type MemWorkspace
- func (m *MemWorkspace) Append(_ context.Context, path string, data []byte) error
- func (m *MemWorkspace) Capabilities() Capabilities
- func (m *MemWorkspace) Contains(path, substr string) bool
- func (m *MemWorkspace) Delete(_ context.Context, path string) error
- func (m *MemWorkspace) Exists(_ context.Context, path string) (bool, error)
- func (m *MemWorkspace) List(_ context.Context, dir string) ([]fs.DirEntry, error)
- func (m *MemWorkspace) MustWrite(path string, data []byte)
- func (m *MemWorkspace) Read(_ context.Context, path string) ([]byte, error)
- func (m *MemWorkspace) RemoveAll(_ context.Context, path string) error
- func (m *MemWorkspace) Rename(_ context.Context, src, dst string) error
- func (m *MemWorkspace) Stat(_ context.Context, path string) (fs.FileInfo, error)
- func (m *MemWorkspace) Write(_ context.Context, path string, data []byte) error
- type NoopCommandRunner
- type ScopedCommandRunner
- type ScopedGitWorkspace
- type ScopedOption
- type ScopedWorkspace
- func (s *ScopedWorkspace) Append(ctx context.Context, path string, data []byte) error
- func (s *ScopedWorkspace) Capabilities() Capabilities
- func (s *ScopedWorkspace) Delete(ctx context.Context, path string) error
- func (s *ScopedWorkspace) Exists(ctx context.Context, path string) (bool, error)
- func (s *ScopedWorkspace) List(ctx context.Context, dir string) ([]fs.DirEntry, error)
- func (s *ScopedWorkspace) Read(ctx context.Context, path string) ([]byte, error)
- func (s *ScopedWorkspace) RemoveAll(ctx context.Context, path string) error
- func (s *ScopedWorkspace) Rename(ctx context.Context, src, dst string) error
- func (s *ScopedWorkspace) Stat(ctx context.Context, path string) (fs.FileInfo, error)
- func (s *ScopedWorkspace) Write(ctx context.Context, path string, data []byte) error
- type ViolationLogger
- type ViolationRecord
- type WalkFunc
- type Workspace
Constants ¶
This section is empty.
Variables ¶
var ( ErrPathTraversal = errdefs.Forbidden(errors.New("workspace: path traversal denied")) ErrAccessDenied = errdefs.Forbidden(errors.New("workspace: access denied")) ErrNotFound = errdefs.NotFound(errors.New("workspace: not found")) )
Common errors.
Functions ¶
func AtomicWrite ¶ added in v0.1.13
AtomicWrite writes data to path via a tmp file + Rename, so concurrent readers never observe a half-written payload. The tmp file is placed in the same directory as path so Rename stays atomic on POSIX filesystems (cross-directory renames are not guaranteed atomic).
On workspaces whose Rename is non-atomic (e.g. object stores) AtomicWrite still runs cleanly; durability/atomicity is then bounded by the underlying store's guarantees, but never weaker than a plain Write.
func Glob ¶
Glob returns paths matching a simple pattern relative to the workspace root. It supports patterns like "*.json", "dir/*.yaml", or "**/*.go". The "**" component matches zero or more directory levels.
Types ¶
type Capabilities ¶ added in v0.2.11
type Capabilities struct {
// AtomicRename is true when [Workspace.Rename] succeeds or
// fails as a single observable operation; readers never see a
// half-renamed state. POSIX rename(2) on the same filesystem
// satisfies this. Object stores that emulate Rename as
// copy+delete do not.
AtomicRename bool
// ReadAfterWrite is true when a successful [Workspace.Write]
// or [Workspace.Append] is immediately observable to a
// subsequent [Workspace.Read] / [Workspace.List] /
// [Workspace.Exists] / [Workspace.Stat] from the same client.
// Strongly-consistent stores (local filesystem, sufficiently
// recent S3) are true; eventually-consistent stores are false.
ReadAfterWrite bool
// DurableOnWrite is true when a successful Write hits stable
// storage before returning. Implementations that only buffer
// in user-space (in-memory mocks, write-back caches) report
// false. Adapters that own crash-recovery logic (WAL replay,
// manifest swap) read this to decide whether to perform extra
// flush operations themselves.
DurableOnWrite bool
// Distributed is true when more than one process or host can
// be opened against the same workspace concurrently. Single-
// process backends (in-memory map, exclusive local directory)
// report false; cluster file systems and object stores report
// true. Coordinators use this to choose between a process-
// local mutex and a distributed lock primitive.
Distributed bool
}
Capabilities describes the storage characteristics of a Workspace implementation. Higher-layer adapters that need accurate semantics (e.g. an LSM-style retrieval index that relies on atomic Rename, or a multi-process coordinator that needs to know whether the workspace is shareable) read these via CapabilityReporter instead of hard-coding per-implementation assumptions.
All fields default to false, which is the conservative interpretation: adapters that do not bother to type-assert CapabilityReporter — or that handle a workspace whose author has not yet implemented the interface — see "no guarantees" and pick the safe path. Adding a new field is therefore additive.
func CapabilitiesOf ¶ added in v0.2.11
func CapabilitiesOf(ws Workspace) Capabilities
CapabilitiesOf returns ws.Capabilities() when ws implements CapabilityReporter, or a zero-value Capabilities otherwise. nil ws also returns the zero value.
type CapabilityReporter ¶ added in v0.2.11
type CapabilityReporter interface {
Capabilities() Capabilities
}
CapabilityReporter is an optional interface that Workspace implementations may satisfy to publish their Capabilities. Adapters that need the information should type-assert; an implementation that does not satisfy the interface should be treated as a conservative all-false Capabilities.
Convenience: see CapabilitiesOf which performs the type-assert + zero-value fallback in one call.
type CommandOption ¶
type CommandOption func(*LocalCommandRunner)
func WithMaxOutput ¶
func WithMaxOutput(n int64) CommandOption
type CommandRunner ¶
type CommandRunner interface {
Exec(ctx context.Context, cmd string, args []string, opts ExecOptions) (*ExecResult, error)
}
CommandRunner executes shell commands within or relative to a workspace.
type ExecOptions ¶
ExecOptions configures a command execution.
type ExecResult ¶
type ExecResult struct {
ExitCode int `json:"exit_code"`
Stdout string `json:"stdout"`
Stderr string `json:"stderr"`
}
ExecResult captures command output.
type GitWorkspace ¶
type GitWorkspace interface {
Workspace
GitClone(ctx context.Context, url, dest string) error
GitPull(ctx context.Context, dir string) error
GitHead(ctx context.Context, dir string) (string, error)
}
GitWorkspace extends Workspace with Git operations.
type LocalCommandRunner ¶
type LocalCommandRunner struct {
// contains filtered or unexported fields
}
LocalCommandRunner executes commands on the local OS.
func NewLocalCommandRunner ¶
func NewLocalCommandRunner(rootDir string, opts ...CommandOption) *LocalCommandRunner
func (*LocalCommandRunner) Exec ¶
func (r *LocalCommandRunner) Exec(ctx context.Context, cmd string, args []string, opts ExecOptions) (*ExecResult, error)
type LocalWorkspace ¶
type LocalWorkspace struct {
// contains filtered or unexported fields
}
LocalWorkspace implements Workspace backed by a local directory.
func NewLocalWorkspace ¶
func NewLocalWorkspace(root string) (*LocalWorkspace, error)
NewLocalWorkspace creates a workspace rooted at the given directory. The root path is resolved through EvalSymlinks to prevent the root itself from being a symlink that could be swapped later.
func (*LocalWorkspace) Capabilities ¶ added in v0.2.11
func (w *LocalWorkspace) Capabilities() Capabilities
Capabilities reports LocalWorkspace's storage characteristics: backed by the host filesystem, so Rename is atomic on the same device, writes are read-after-write consistent, and durability matches the underlying filesystem's default flush behaviour. Distributed is false because LocalWorkspace assumes exclusive access to its directory tree.
func (*LocalWorkspace) Delete ¶
func (w *LocalWorkspace) Delete(_ context.Context, path string) error
func (*LocalWorkspace) GitClone ¶
func (w *LocalWorkspace) GitClone(ctx context.Context, url, dest string) error
func (*LocalWorkspace) GitPull ¶
func (w *LocalWorkspace) GitPull(ctx context.Context, dir string) error
func (*LocalWorkspace) RemoveAll ¶
func (w *LocalWorkspace) RemoveAll(_ context.Context, path string) error
func (*LocalWorkspace) Rename ¶ added in v0.1.13
func (w *LocalWorkspace) Rename(_ context.Context, src, dst string) error
func (*LocalWorkspace) Root ¶
func (w *LocalWorkspace) Root() string
Root returns the absolute path of the workspace root.
type MemWorkspace ¶
type MemWorkspace struct {
// contains filtered or unexported fields
}
MemWorkspace implements Workspace entirely in memory.
func NewMemWorkspace ¶
func NewMemWorkspace() *MemWorkspace
func (*MemWorkspace) Capabilities ¶ added in v0.2.11
func (m *MemWorkspace) Capabilities() Capabilities
Capabilities reports MemWorkspace's storage characteristics: in-memory map under a single mutex, so writes are immediately observable, Rename is atomic, but nothing reaches stable storage and the workspace is single-process by construction.
func (*MemWorkspace) Contains ¶
func (m *MemWorkspace) Contains(path, substr string) bool
Contains checks if a path contains a substring — intended for tests.
func (*MemWorkspace) MustWrite ¶
func (m *MemWorkspace) MustWrite(path string, data []byte)
MustWrite panics on error — intended for tests.
func (*MemWorkspace) RemoveAll ¶
func (m *MemWorkspace) RemoveAll(_ context.Context, path string) error
func (*MemWorkspace) Rename ¶ added in v0.1.13
func (m *MemWorkspace) Rename(_ context.Context, src, dst string) error
type NoopCommandRunner ¶
type NoopCommandRunner struct{}
NoopCommandRunner always returns an empty successful result.
func (NoopCommandRunner) Exec ¶
func (NoopCommandRunner) Exec(_ context.Context, _ string, _ []string, _ ExecOptions) (*ExecResult, error)
type ScopedCommandRunner ¶
type ScopedCommandRunner struct {
// contains filtered or unexported fields
}
ScopedCommandRunner wraps a CommandRunner with a command whitelist. Only commands whose base name appears in the whitelist are permitted.
func NewScopedCommandRunner ¶
func NewScopedCommandRunner(inner CommandRunner, allowed []string) *ScopedCommandRunner
NewScopedCommandRunner creates a runner that only allows listed commands.
func (*ScopedCommandRunner) Exec ¶
func (r *ScopedCommandRunner) Exec(ctx context.Context, cmd string, args []string, opts ExecOptions) (*ExecResult, error)
type ScopedGitWorkspace ¶
type ScopedGitWorkspace struct {
*ScopedWorkspace
// contains filtered or unexported fields
}
func NewScopedGitWorkspace ¶
func NewScopedGitWorkspace(inner GitWorkspace, opts ...ScopedOption) *ScopedGitWorkspace
func (*ScopedGitWorkspace) GitClone ¶
func (s *ScopedGitWorkspace) GitClone(ctx context.Context, url, dest string) error
type ScopedOption ¶
type ScopedOption func(*ScopedWorkspace)
func WithAllowWrite ¶
func WithAllowWrite(patterns ...string) ScopedOption
func WithDenyRead ¶
func WithDenyRead(patterns ...string) ScopedOption
func WithMandatoryDeny ¶
func WithMandatoryDeny(patterns ...string) ScopedOption
func WithViolationLogger ¶
func WithViolationLogger(l ViolationLogger) ScopedOption
type ScopedWorkspace ¶
type ScopedWorkspace struct {
// contains filtered or unexported fields
}
ScopedWorkspace wraps a Workspace with dual-mode permission enforcement:
- Read: deny-only mode — everything readable unless path matches denyRead
- Write: allow-only mode — nothing writable unless path matches allowWrite
- Mandatory deny paths are always blocked for both read and write
func NewScopedWorkspace ¶
func NewScopedWorkspace(inner Workspace, opts ...ScopedOption) *ScopedWorkspace
func (*ScopedWorkspace) Capabilities ¶ added in v0.2.11
func (s *ScopedWorkspace) Capabilities() Capabilities
Capabilities forwards to the wrapped Workspace, since scoping is a security boundary that does not change durability / atomicity / consistency / distribution semantics. A wrapped Workspace that does not implement CapabilityReporter yields a zero-value (all-false) Capabilities via CapabilitiesOf.
ScopedGitWorkspace embeds ScopedWorkspace and therefore inherits this method.
func (*ScopedWorkspace) Delete ¶
func (s *ScopedWorkspace) Delete(ctx context.Context, path string) error
func (*ScopedWorkspace) RemoveAll ¶
func (s *ScopedWorkspace) RemoveAll(ctx context.Context, path string) error
func (*ScopedWorkspace) Rename ¶ added in v0.1.13
func (s *ScopedWorkspace) Rename(ctx context.Context, src, dst string) error
type ViolationLogger ¶
type ViolationLogger interface {
LogViolation(ctx context.Context, record ViolationRecord)
}
ViolationLogger receives violation records from ScopedWorkspace.
type ViolationRecord ¶
type ViolationRecord struct {
Time time.Time `json:"time"`
Operation string `json:"operation"`
Path string `json:"path"`
Reason string `json:"reason"`
}
ViolationRecord captures a rejected operation for audit logging.
type WalkFunc ¶
WalkFunc is the callback for Walk. Return filepath.SkipDir to skip a directory subtree, or any other non-nil error to abort the walk.
type Workspace ¶
type Workspace interface {
Read(ctx context.Context, path string) ([]byte, error)
Write(ctx context.Context, path string, data []byte) error
Append(ctx context.Context, path string, data []byte) error
// Rename moves src to dst within the same workspace. Implementations
// MUST be atomic when the underlying medium supports it (e.g. POSIX
// rename(2) on a local filesystem). When the medium cannot rename
// atomically (e.g. object stores) the implementation MAY fall back
// to copy + delete, but callers should treat Rename as the canonical
// "publish a finalized payload" operation: write to a tmp path then
// Rename to the live path so readers never observe a half-written file.
//
// Returns ErrNotFound if src does not exist. Overwriting an existing
// dst is allowed; on local filesystems this is atomic.
Rename(ctx context.Context, src, dst string) error
Delete(ctx context.Context, path string) error
RemoveAll(ctx context.Context, path string) error
List(ctx context.Context, dir string) ([]fs.DirEntry, error)
Exists(ctx context.Context, path string) (bool, error)
Stat(ctx context.Context, path string) (fs.FileInfo, error)
}
Workspace abstracts file operations over a sandboxed directory tree. All paths are relative to the workspace root; absolute paths and path traversals ("..") are rejected.
func MustWorkspaceFrom ¶
MustWorkspaceFrom extracts the Workspace from ctx or panics. Intended for use in code paths where a Workspace is guaranteed to be present (e.g. after middleware injection).