localprocess

package
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package localprocess implements the executor.Executor interface by forking child processes on the control-plane host.

This is the legacy execution path, extracted verbatim from the raw exec.Command calls that used to live in pkg/ui/server.go. It offers no isolation whatsoever: workloads inherit the control plane's user, filesystem, and network. It exists so the executor abstraction can be introduced without a behavior change, and so single-machine installs keep working with zero configuration — not because it is a good place to run untrusted agent workloads.

Deployments that must not execute agents on the control-plane host should bind their projects to an isolated executor and refuse to fall back here.

Behavior preserved from the pre-abstraction code:

  • cmd.Dir is the project directory; an empty WorkDir inherits the server's cwd (the voice handler relies on this).
  • The environment is inherited unless the Spec overrides it.
  • stdout and stderr are merged into one os.Pipe, exactly as the live-log panel expects.
  • No new process group: children stay in the control plane's group, so a Ctrl-C on an interactively-run server still reaches them.
  • The real OS PID is reported, which is what the /proc scan in pkg/multiui (CloopRunPIDsInDir → the Stop button) matches against.
  • Started workloads outlive the request that started them.

Index

Constants

View Source
const DefaultID = "local"

DefaultID is the executor ID used by the zero-config singleton.

Variables

This section is empty.

Functions

func Ensure

func Ensure(reg *executor.Registry) error

Ensure idempotently registers the singleton host executor into reg, which may be nil to mean executor.DefaultRegistry. Safe to call from several entry points (CLI bootstrap, UI server construction, tests).

Types

type Executor

type Executor struct {
	// contains filtered or unexported fields
}

Executor is the host-process driver. Use New or Shared to obtain one.

func New

func New(id string) *Executor

New returns a new host-process executor with the given ID. An empty id defaults to DefaultID.

func Shared

func Shared() *Executor

Shared returns the process-wide singleton host executor.

func (*Executor) AttachHandleStore

func (e *Executor) AttachHandleStore(store executor.HandleStore)

AttachHandleStore installs the durable handle store and immediately reattaches to whatever it describes.

It is the *primary* wiring path for this driver, not the fallback it is for the container and Kubernetes drivers. Those are built from configuration and can take an Options.HandleStore at construction; this one is a process-wide singleton reached through Shared(), whose New(id) signature is fixed by every existing caller and takes no options at all. Adding a store-aware constructor beside it would leave two ways to build the same singleton and no way to make the Shared() path use the new one, so the store is installed after construction instead — which the boot order wanted anyway, since the state database that backs the store is opened long after the executor registry is built.

Calling it more than once is safe, including with a different store: see rehydrate for why re-adoption cannot produce a duplicate watcher.

A nil store is ignored rather than clearing the current one. "Forget how to find your processes" is not something a caller should be able to ask for by passing a zero value.

func (*Executor) Capabilities

func (e *Executor) Capabilities() executor.Capabilities

Capabilities implements executor.Executor. Note SupportsResourceLimits is false: this driver cannot enforce CPU/memory caps, and Start rejects Specs that request them rather than silently ignoring the request.

SupportsWorkspaceProvisioning is false for a different reason, and it is an answer rather than a gap: this driver forks in the operator's own working directory, so the tree is already there. See Start.

func (*Executor) HandleStatuses

func (e *Executor) HandleStatuses(ctx context.Context) ([]executor.Status, error)

HandleStatuses implements executor.Lister: a snapshot of every retained handle, running or recently finished. The Executors panel derives its "current load" column from this.

func (*Executor) Handles

func (e *Executor) Handles() []string

Handles returns the IDs of every handle this executor still knows about, newest first. Used for diagnostics and by tests.

func (*Executor) HealthCheck

func (e *Executor) HealthCheck(ctx context.Context) error

HealthCheck verifies the host can still hand out the file descriptors a Start needs. File-descriptor exhaustion is the realistic failure mode for a long-running control plane, and it manifests as os.Pipe failing.

func (*Executor) HoldsLease

func (e *Executor) HoldsLease(leaseID string) bool

HoldsLease reports whether any process this executor tracks was started with material from leaseID.

func (*Executor) ID

func (e *Executor) ID() string

ID implements executor.Executor.

func (*Executor) Kind

func (e *Executor) Kind() string

Kind implements executor.Executor.

func (*Executor) Leases

func (e *Executor) Leases() []string

Leases lists the lease IDs this executor is holding material for.

func (*Executor) Revocations

func (e *Executor) Revocations() []executor.RevokeOutcome

Revocations reports this executor's revocation log for the Secrets panel.

func (*Executor) RevokeLease

RevokeLease takes one lease's material back from every process holding it.

func (*Executor) ScrubEnv

func (e *Executor) ScrubEnv(handleID string, keys []string) []string

ScrubEnv drops the values of the named environment variables from this driver's retained copies of handleID's environment, returning the names it actually found.

Returning the names rather than a count is what lets a revocation ack say which credentials were reached. A caller that asked for three and got one back knows the other two were never here, which is a different situation from a scrub that failed.

Unknown handles and unknown keys are not errors: both mean "that material is not here", which is the end state a revocation wants.

func (*Executor) ScrubSpecSecrets

func (e *Executor) ScrubSpecSecrets(handleID string, bindings []executor.SecretBinding) []string

ScrubSpecSecrets scrubs every environment variable a spec's secret bindings contributed, for callers that have the spec rather than a key list.

func (*Executor) Signal

func (e *Executor) Signal(ctx context.Context, handleID string, sig executor.Signal) error

Signal implements executor.Executor. Signalling a finished handle is a no-op success: the caller wanted it stopped and it is stopped.

func (*Executor) Start

func (e *Executor) Start(ctx context.Context, spec executor.Spec) (executor.Handle, error)

Start forks the workload described by spec and returns its handle. The child outlives ctx: ctx only bounds the act of starting.

func (*Executor) Status

func (e *Executor) Status(ctx context.Context, handleID string) (executor.Status, error)

Status implements executor.Executor.

func (*Executor) Stream

func (e *Executor) Stream(ctx context.Context, handleID string) (<-chan executor.LogLine, error)

Stream implements executor.Executor. The returned channel first replays the bounded output backlog produced since Start, then delivers live chunks, then closes when the workload has finished and been reaped.

Cancelling ctx unsubscribes this consumer only; the workload and any other consumers are unaffected.

func (*Executor) SupportsRevocation

func (e *Executor) SupportsRevocation() bool

SupportsRevocation reports whether a revocation issued now would be honoured. Always true: the process, its environment and its credential files are all on this machine, owned by this process.

Jump to

Keyboard shortcuts

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