isolation

package
v0.2.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2026 License: MIT Imports: 11 Imported by: 0

README

pkg/isolation

pkg/isolation provides process-level isolation for child processes started by picoclaw.

It does not sandbox the main picoclaw process itself.

Scope

The current scope is the child-process startup path:

  • exec tool
  • CLI providers such as claude-cli and codex-cli
  • process hooks
  • MCP stdio servers

One-Sentence Model

  • The picoclaw main process still runs in the host environment.
  • Every child process should enter the shared pkg/isolation startup path first.
  • The startup path applies platform-specific isolation according to config.

Architecture

The implementation has four layers:

  1. Configuration layer: reads config.Config.Isolation and injects it through isolation.Configure(cfg).
  2. Instance layout layer: resolves config.GetHome(), prepares instance directories, and builds the runtime user environment.
  3. Platform backend layer: Linux uses bwrap; Windows uses a restricted token, low integrity, and a Job Object; other platforms are not implemented.
  4. Unified startup layer: PrepareCommand(cmd), Start(cmd), and Run(cmd).

All integrations that spawn subprocesses should reuse these helpers instead of calling cmd.Start or cmd.Run directly.

Configuration

Isolation lives under:

{
  "isolation": {
    "enabled": false,
    "expose_paths": []
  }
}

Field meanings:

  • enabled: enables or disables subprocess isolation. Default: false.
  • expose_paths: explicitly exposes host paths inside the isolated environment. It only matters when enabled=true. This is currently supported on Linux only.

Example:

{
  "isolation": {
    "enabled": true,
    "expose_paths": [
      {
        "source": "/opt/toolchains/go",
        "target": "/opt/toolchains/go",
        "mode": "ro"
      },
      {
        "source": "/data/shared-assets",
        "target": "/opt/picoclaw-instance-a/workspace/assets",
        "mode": "rw"
      }
    ]
  }
}

Rules for expose_paths:

  • source is a host path.
  • target is the path inside the isolated environment.
  • mode must be ro or rw.
  • When target is empty, it defaults to source.
  • Only one final rule may exist for the same target.
  • Later-loaded config overrides earlier rules for the same target.

Platform note:

  • Linux uses a real source -> target mount view.
  • Windows does not currently support expose_paths.

Instance Root And Directories

The instance root follows config.GetHome():

  • If PICOCLAW_HOME is set, use it.
  • Otherwise use the default .picoclaw directory under the user home.

If config.GetHome() falls back to . while isolation is enabled, startup should fail.

Default instance directories include:

  • instance root
  • skills
  • logs
  • cache
  • state
  • runtime-user-env

workspace is derived from cfg.WorkspacePath() when configured, otherwise from the default workspace rule.

Windows also prepares:

  • runtime-user-env/AppData/Roaming
  • runtime-user-env/AppData/Local

User Environment Redirect

When isolation is enabled, child processes receive a redirected per-instance user environment.

Linux variables:

  • HOME
  • TMPDIR
  • XDG_CONFIG_HOME
  • XDG_CACHE_HOME
  • XDG_STATE_HOME

Windows variables:

  • USERPROFILE
  • HOME
  • TEMP
  • TMP
  • APPDATA
  • LOCALAPPDATA

These paths point into runtime-user-env under the instance root.

Platform Behavior

Linux

The Linux backend currently depends on bwrap (bubblewrap).

Capabilities:

  • minimal filesystem view
  • ipc namespace isolation
  • redirected child-process user environment
  • source -> target read-only or read-write mounts

Default mounts include the instance root plus the minimum runtime system paths such as /usr, /bin, /lib, /lib64, and /etc/resolv.conf.

At runtime, PicoClaw also adds the executable path, its directory, the effective working directory, and absolute path arguments when needed.

There is no automatic fallback when bwrap is missing.

Install examples:

  • apt install bubblewrap
  • dnf install bubblewrap
  • yum install bubblewrap
  • pacman -S bubblewrap
  • apk add bubblewrap

If isolation must be disabled temporarily:

{
  "isolation": {
    "enabled": false
  }
}

Disabling isolation increases the risk that child processes can access or modify more host files.

Windows

Windows isolation currently supports process-level restrictions such as restricted tokens, low integrity, job objects, and redirected user-environment directories.

expose_paths is not currently supported on Windows. If it is configured, startup should fail instead of pretending the paths were exposed.

The Windows backend currently uses:

  • a restricted primary token
  • low integrity level
  • a Job Object
  • redirected child-process user environment

It does not currently implement true source -> target filesystem remapping.

macOS And Other Platforms

They are not implemented yet.

When isolation is explicitly enabled on an unsupported platform, the higher-level runtime should surface that as an unsupported configuration instead of pretending isolation succeeded.

Logging And Debugging

When isolation is enabled, PicoClaw logs the generated isolation plan.

Linux log name:

  • linux isolation mount plan

Windows log name:

  • windows isolation access rules

If you suspect isolation is ineffective, check whether unexpected host paths appear in those logs.

Relationship To restrict_to_workspace

  • restrict_to_workspace limits the paths an agent is normally allowed to access.
  • pkg/isolation limits what a child process can see and where its user environment points.

They complement each other and do not replace each other.

Current Limits

  • Linux isolation is implemented with bwrap, not a custom in-process isolation runtime.
  • Linux does not currently enable a dedicated pid namespace by default.
  • Windows does not yet implement full host ACL enforcement for every allowed or denied path.
  • macOS is not implemented.
  • The current design isolates child processes, not the main picoclaw process.

Suggested Reading Order

If you are new to this code, read it in this order:

  1. pkg/config/config.go
  2. pkg/isolation/runtime.go
  3. pkg/isolation/platform_linux.go
  4. pkg/isolation/platform_windows.go
  5. Call sites:
  6. pkg/tools/shell.go
  7. pkg/providers/*.go
  8. pkg/agent/hook_process.go
  9. pkg/mcp/manager.go

That path gives the fastest overview of the configuration model, runtime flow, and platform-specific limits.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyUserEnv

func ApplyUserEnv(cmd *exec.Cmd, root string)

ApplyUserEnv rewrites the child process environment so home, temp, and platform-specific user-data directories point into the instance root.

func Configure

func Configure(cfg *config.Config)

Configure updates the process-wide isolation state used by subsequent child process launches.

func CurrentConfig

func CurrentConfig() config.IsolationConfig

CurrentConfig returns the currently active isolation settings.

func DefaultExposePaths

func DefaultExposePaths(root string) []config.ExposePath

DefaultExposePaths returns the minimum built-in host paths required for the current platform to run isolated child processes.

func InstanceDirs

func InstanceDirs(root string) []string

InstanceDirs returns the directories that must exist under the instance root for isolation-aware child processes.

func IsSupported

func IsSupported() bool

IsSupported reports whether the current platform has an implemented isolation backend.

func MergeExposePaths

func MergeExposePaths(defaults []config.ExposePath, overrides []config.ExposePath) []config.ExposePath

MergeExposePaths merges built-in rules with user overrides. Rules are keyed by target path so later entries replace earlier ones for the same target.

func NormalizeExposePath

func NormalizeExposePath(item config.ExposePath) config.ExposePath

NormalizeExposePath fills implicit defaults and cleans path values so merge and validation logic can work with canonical paths.

func Preflight

func Preflight() error

Preflight validates the configured isolation state and prepares the instance runtime directories before any child process is launched.

func PrepareCommand

func PrepareCommand(cmd *exec.Cmd) error

PrepareCommand mutates the command in-place so it inherits the configured isolated environment before being started by the caller.

func PrepareInstanceRoot

func PrepareInstanceRoot(root string) error

PrepareInstanceRoot creates the directories required by the isolation runtime.

func ResolveInstanceRoot

func ResolveInstanceRoot() (string, error)

ResolveInstanceRoot resolves the instance root used to build the isolated filesystem and redirected user environment.

func Run

func Run(cmd *exec.Cmd) error

Run is the Start-and-Wait helper that keeps the same isolation behavior as Start while returning the command's final exit status.

func Start

func Start(cmd *exec.Cmd) error

Start prepares isolation for the command, starts it, and applies any post-start platform hooks required by the active backend.

func ValidateExposePaths

func ValidateExposePaths(items []config.ExposePath) error

ValidateExposePaths verifies the user-supplied path exposure rules before a child process is started.

Types

type AccessRule

type AccessRule struct {
	Path string
	Mode string
}

AccessRule describes the effective Windows-side access rule for a host path.

func BuildWindowsAccessRules

func BuildWindowsAccessRules(root string, overrides []config.ExposePath) []AccessRule

BuildWindowsAccessRules derives the host-path access policy used by the Windows restricted-token backend.

type MountRule

type MountRule struct {
	Source string
	Target string
	Mode   string
}

MountRule describes a source-to-target mount exposed inside the Linux isolation view.

func BuildLinuxMountPlan

func BuildLinuxMountPlan(root string, overrides []config.ExposePath) []MountRule

BuildLinuxMountPlan converts the merged expose-path configuration into the mount rules consumed by the Linux bubblewrap backend.

type UserEnv

type UserEnv struct {
	Home         string
	Tmp          string
	Config       string
	Cache        string
	State        string
	AppData      string
	LocalAppData string
}

UserEnv contains the redirected per-instance user directories injected into isolated child processes.

func ResolveUserEnv

func ResolveUserEnv(root string) UserEnv

ResolveUserEnv derives the redirected user directories rooted under the instance runtime area.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL