Help us shape the future of Go! Take the 2026 Go Developer Survey

openshell

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package openshell runs AgentRun workloads in NVIDIA OpenShell sandboxes.

The operator never creates OpenShell's Kubernetes objects itself: it talks to the OpenShell gateway over its Go SDK, and the gateway's Kubernetes compute driver creates the agent-sandbox Sandbox CR, the supervisor and workload pods, and their network fence in the gateway's sandbox namespace. This package owns the translation from agent-orca CRDs to a sandbox spec and policy, so upstream schema changes stay contained here.

Index

Constants

View Source
const (
	// GitHubHost is the git transport host the token is bound to.
	GitHubHost = "github.com"
	// GitTokenEnvVar holds the token placeholder in the workload.
	GitTokenEnvVar = "AGENTORCA_GIT_TOKEN"
)
View Source
const (
	LabelRunName           = "agentorca.io/run"
	LabelRunNamespace      = "agentorca.io/run-namespace"
	LabelWorkflowName      = "agentorca.io/workflow"
	LabelWorkflowNamespace = "agentorca.io/workflow-namespace"
)

Labels set on every sandbox the operator creates, so a sandbox found on the gateway can be traced back to its AgentRun.

View Source
const (
	SupervisorComponentLabel = "openshell.ai/component"
	SupervisorComponentValue = "supervisor"
	SandboxIDLabel           = "openshell.ai/sandbox-id"
)

Supervisor pod labels set by the OpenShell Kubernetes driver. The supervisor opens the workload's outbound connections, so it is the peer the router NetworkPolicy admits.

View Source
const CredentialsEnvVar = "AGENTORCA_TOOL_CREDENTIALS"

CredentialsEnvVar names the non-secret env var describing the credentialed tools, so an agent can build its MCP clients without hardcoding env names.

View Source
const EnvB64Suffix = "_B64"

EnvB64Suffix marks the base64 copy of an environment value that had line breaks (see sandboxEnv).

View Source
const OCSFLogLevel = "OCSF"

OCSFLogLevel is the level of the gateway log lines that carry OCSF events.

Variables

View Source
var RouterPorts = []uint32{8080, 8082}

RouterPorts are the model-router ports the workload may reach: the OpenAI-compatible API and the Gemini-compatible API.

Functions

func ApplyGitAccess added in v0.9.0

func ApplyGitAccess(policy *osv1.SandboxPolicy, git *GitAccess)

ApplyGitAccess adds the credential-bound git endpoint to policy. A destination may have only one endpoint, so any plain egress rule for github.com:443 gives way to it.

func BindCredentials

func BindCredentials(eps []ToolEndpoint, creds []*ToolCredential, providerName func(*ToolCredential) string) ([]ToolEndpoint, []*ToolCredential, error)

BindCredentials marks the tool endpoints that a credential binds to, and drops credentials whose endpoint is not in eps (its host was excluded). Credentials of excluded tools must not be passed in. It returns the endpoints and the credentials still in use. When two sources bind the same endpoint, the first wins: an endpoint can carry only one binding.

func BuildSpec

func BuildSpec(in SpecInput) *osv1.SandboxSpec

BuildSpec returns the sandbox spec for a run: the agent image as the workload with the Agent's resources and the operator's placement, the agent command as the sandbox's main process, and the compiled policy.

func CompilePolicy

func CompilePolicy(routerHost string, sb *agentorcav1alpha1.SandboxSpec, tools []ToolEndpoint) *osv1.SandboxPolicy

CompilePolicy builds the sandbox policy for an agent. The model-router is always reachable; every other destination must be listed in sb.Egress or come from tools. The policy is deterministic for a given input.

func DescribeCredentials

func DescribeCredentials(creds []*ToolCredential) string

DescribeCredentials renders CredentialsEnvVar: for each credentialed tool, its URL and each auth header as a template over the placeholder env var, e.g. {"Authorization": "Bearer ${AGENTORCA_GITHUB_TOKEN}"}. It holds no secrets.

func GitEnv added in v0.9.0

func GitEnv() map[string]string

GitEnv configures git, through its GIT_CONFIG_* environment, to answer github.com credential prompts with x-access-token and the placeholder. It replaces any other helper for github.com so nothing prompts or caches.

func GitProfile added in v0.9.0

func GitProfile(namespace string) *osv1.ProviderProfile

GitProfile declares the token as a Basic-auth credential. Like the tool profiles it has no endpoints: the sandbox policy's credential binding is the only place the token may go.

func GitProfileID added in v0.9.0

func GitProfileID(namespace string) string

GitProfileID is the gateway profile declaring the git token env var. It is shared by every run in the namespace.

func GitProvider added in v0.9.0

func GitProvider(namespace, runName, token string, labels map[string]string) *osv1.Provider

GitProvider is the run's provider holding token. Updating it with a fresh token reaches the running sandbox: each git command is a new process and resolves the placeholder to the provider's current value.

func GitProviderName added in v0.9.0

func GitProviderName(namespace, runName string) string

GitProviderName is the run's provider instance holding its git token.

func MergeSandboxSpecs added in v0.9.0

MergeSandboxSpecs unions the parts of sandbox configuration that a shared workflow sandbox can honor: egress, filesystem and the stricter enforcement. Runtime identity, resources, placement, tool selection and git credentials stay with the base. The inputs are not modified.

func PresetEgress added in v0.9.0

PresetEgress returns the rules behind a preset.

func Profile

func Profile(namespace string, cred *ToolCredential) *osv1.ProviderProfile

Profile returns the endpointless profile declaring cred's env vars. It has no endpoints so the only credential boundary is the sandbox policy's credential_binding, which names exactly the tool's MCP endpoint.

func ProfileID

func ProfileID(namespace, source string) string

ProfileID is the gateway profile for a credential source in a namespace. It is shared by every run that uses the source.

func Provider

func Provider(namespace, runName string, cred *ToolCredential, values, labels map[string]string) *osv1.Provider

Provider returns the run's provider instance holding cred's values, keyed by env var. labels identify the run, for cleanup.

func ProviderName

func ProviderName(namespace, runName, source string) string

ProviderName is the run's provider instance for a credential source. It is stable across a run's retries, so a retry reuses (and refreshes) it.

func SandboxName

func SandboxName(namespace, runName string, attempt int) string

SandboxName returns the gateway name for one attempt of a run's sandbox. The gateway caps sandbox names at 19 characters and names are unique per workspace, while AgentRun names are only unique per namespace, so the name is a short hash. It is stable within an attempt, which makes Create idempotent across reconciles, and changes per retry so a retry never collides with the previous attempt's sandbox while the gateway is still deleting it.

func StartCommandJob added in v0.9.0

func StartCommandJob(ctx context.Context, ex Executor, sandbox, id string, command, args []string, env map[string]string, workDir string) error

StartCommandJob starts an argv command as a detached job. Arguments are shell-quoted individually: unlike a script, model- or ticket-derived data in an argument cannot become shell syntax. command must name the executable.

func StartJob added in v0.9.0

func StartJob(ctx context.Context, ex Executor, sandbox, id, script string, env map[string]string, workDir string) error

StartJob starts script (run by sh) as a detached job named id in the sandbox. env is exported to the script; workDir, if set, is its working directory.

func StopJob added in v0.9.0

func StopJob(ctx context.Context, ex Executor, sandbox, id string) error

StopJob asks a running job to stop. A job that is not running is left alone.

func ValidEnvName added in v0.9.0

func ValidEnvName(name string) bool

ValidEnvName reports whether name is usable as an environment variable name in a job (it is written into a shell script, so it must be a plain name).

func WorkflowJobName added in v0.9.0

func WorkflowJobName(namespace, runName string) string

WorkflowJobName returns a detached job ID for an AgentRun. Continuations have different run names and therefore different jobs in the same fresh sandbox.

func WorkflowSandboxName added in v0.9.0

func WorkflowSandboxName(namespace, workflowName string) string

WorkflowSandboxName returns the stable gateway name of a workflow's shared sandbox. Its finalizer removes the sandbox before the workflow can be recreated with the same namespace and name.

func WorkflowStepSandboxName added in v0.9.0

func WorkflowStepSandboxName(namespace, workflowName, stepName string) string

WorkflowStepSandboxName returns the gateway name of a step's fresh sandbox. It differs from both the shared sandbox and every other step's sandbox.

Types

type Config

type Config struct {
	// Address is the gateway gRPC address, e.g. "openshell.openshell.svc:8080".
	Address string
	// Workspace is the gateway workspace sandboxes are created in.
	Workspace string
	// SandboxNamespace is the namespace the gateway creates sandbox pods in. The
	// router NetworkPolicy admits the run's supervisor pod from this namespace.
	SandboxNamespace string
	// CertFile, KeyFile and CAFile configure mTLS to the gateway.
	CertFile string
	KeyFile  string
	CAFile   string
	// TokenFile optionally holds a bearer token (OIDC gateways).
	TokenFile string
	// Insecure disables TLS verification. Development only.
	Insecure bool
}

Config holds the operator's connection settings for the OpenShell gateway.

func ConfigFromEnv

func ConfigFromEnv() (cfg Config, ok bool)

ConfigFromEnv reads the gateway settings from OPENSHELL_* environment variables. ok is false when OPENSHELL_GATEWAY_ADDRESS is unset, meaning sandbox support is disabled.

type CredentialKey

type CredentialKey struct {
	// EnvVar is the workload env var holding the placeholder.
	EnvVar string
	// Header is the HTTP header the value goes in, and Prefix what precedes it.
	Header string
	Prefix string
	// SecretName and SecretKey locate the value in the tool's namespace.
	SecretName string
	SecretKey  string
}

CredentialKey is one secret header value.

type Decision added in v0.9.0

type Decision struct {
	Time time.Time `json:"time"`
	// Kind is "net" (a connection) or "http" (a request on an allowed connection).
	Kind string `json:"kind"`
	// Activity is the OCSF activity, e.g. OPEN for a connection.
	Activity string `json:"activity,omitempty"`
	// Action is "allowed" or "denied" (lower-cased OCSF action).
	Action   string `json:"action"`
	Severity string `json:"severity,omitempty"`
	// Binary is the process that connected (without its pid).
	Binary string `json:"binary,omitempty"`
	// Destination is host:port for connections.
	Destination string `json:"destination,omitempty"`
	Method      string `json:"method,omitempty"`
	URL         string `json:"url,omitempty"`
	// Policy and Engine name the rule that decided.
	Policy string `json:"policy,omitempty"`
	Engine string `json:"engine,omitempty"`
	Reason string `json:"reason,omitempty"`
	// Raw is the original shorthand line.
	Raw string `json:"raw"`
}

Decision is one network decision the sandbox supervisor made.

func ParseDecision added in v0.9.0

func ParseDecision(line string) (d Decision, ok bool)

ParseDecision reads a NET or HTTP shorthand event. ok is false for other lines (process, SSH, config and inference events).

type ExecOptions added in v0.9.0

type ExecOptions = osv1.ExecOptions

ExecOptions and ExecResult are the SDK's: environment and working directory in, exit code and output out.

type ExecResult added in v0.9.0

type ExecResult = osv1.ExecResult

ExecOptions and ExecResult are the SDK's: environment and working directory in, exit code and output out.

type Executor added in v0.9.0

type Executor interface {
	Exec(ctx context.Context, sandbox string, command []string, opts ExecOptions) (*ExecResult, error)
}

Executor is the part of the gateway jobs need.

type Gateway

type Gateway interface {
	// Create creates a sandbox. It returns the existing sandbox when one with the
	// same name already exists, so a reconcile retry is idempotent.
	Create(ctx context.Context, name string, spec *osv1.SandboxSpec, labels map[string]string) (*osv1.Sandbox, error)
	// Get returns the sandbox, or an error satisfying osv1.IsNotFound.
	Get(ctx context.Context, name string) (*osv1.Sandbox, error)
	// Delete deletes the sandbox. A missing sandbox is not an error.
	Delete(ctx context.Context, name string) error
	// MainProcessLogs returns the tail of the workload's main-process output.
	MainProcessLogs(ctx context.Context, sb *osv1.Sandbox) (string, error)
	// SandboxNamespace is the Kubernetes namespace the gateway creates sandbox pods in.
	SandboxNamespace() string
	// EnsureProfile creates the provider profile, or updates it when its
	// declared credentials changed.
	EnsureProfile(ctx context.Context, profile *osv1.ProviderProfile) error
	// EnsureProvider creates the provider, or updates its credentials.
	EnsureProvider(ctx context.Context, provider *osv1.Provider) error
	// DeleteProviders deletes every provider carrying all of labels.
	DeleteProviders(ctx context.Context, labels map[string]string) error
	// PendingDrafts returns the sandbox's pending policy proposals: rules the
	// gateway drafted from connections its policy denied.
	PendingDrafts(ctx context.Context, sandbox string) ([]osv1.PolicyChunk, error)
	// ApproveDraft adds a proposal to the sandbox's live policy.
	ApproveDraft(ctx context.Context, sandbox, chunkID, reviewToken string) error
	// RejectDraft declines a proposal.
	RejectDraft(ctx context.Context, sandbox, chunkID, reason string) error
	// Decisions returns the network decisions the sandbox's supervisor logged
	// after since, oldest first.
	Decisions(ctx context.Context, sandbox string, since time.Time) ([]Decision, error)
	// Exec runs a command in the sandbox and returns once it exits. Long-running
	// work should be started with StartJob rather than held on an Exec call.
	Exec(ctx context.Context, sandbox string, command []string, opts ExecOptions) (*ExecResult, error)
}

Gateway is the slice of the OpenShell gateway API the AgentRun controller uses, bound to one workspace.

func Connect

func Connect(cfg Config, podLogs PodLogFunc) (Gateway, error)

Connect dials the gateway described by cfg. podLogs reads main-process output from the workload pod.

type GitAccess added in v0.9.0

type GitAccess struct {
	// Repositories are "owner/name" slugs.
	Repositories []string
	// Push allows git push (git-receive-pack) as well as clone and fetch.
	Push bool
	// Provider is the run's provider holding the token.
	Provider string
}

GitAccess grants a sandbox git access to GitHub repositories.

type JobPhase added in v0.9.0

type JobPhase string

JobPhase is where a job stands.

const (
	// JobRunning means the job's process is alive.
	JobRunning JobPhase = "running"
	// JobExited means the job finished; ExitCode says how.
	JobExited JobPhase = "exited"
	// JobLost means the job started but its process is gone without an exit code:
	// it was killed from outside (an out-of-memory kill, a sandbox restart).
	JobLost JobPhase = "lost"
	// JobMissing means no such job was ever started in this sandbox.
	JobMissing JobPhase = "missing"
)

Job phases.

type JobStatus added in v0.9.0

type JobStatus struct {
	Phase    JobPhase
	ExitCode int
	// Output is the tail of what the job printed, stdout and stderr together.
	Output string
}

JobStatus is a snapshot of a job.

func PollJob added in v0.9.0

func PollJob(ctx context.Context, ex Executor, sandbox, id string) (JobStatus, error)

PollJob reads a job's state and the tail of its output.

func WaitJob added in v0.9.0

func WaitJob(ctx context.Context, ex Executor, sandbox, id string, interval time.Duration) (JobStatus, error)

WaitJob polls a job every interval until it is no longer running, or ctx ends. The controller does not use it (it polls once per reconcile); it is for callers that want to block, such as the sandbox checkout.

type Outcome

type Outcome int

Outcome is a sandbox's run state as the AgentRun controller sees it.

const (
	// OutcomeRunning means the sandbox is provisioning or its main process is running.
	OutcomeRunning Outcome = iota
	// OutcomeSucceeded means the main process exited 0.
	OutcomeSucceeded
	// OutcomeFailed means the main process exited nonzero or the sandbox errored.
	OutcomeFailed
)

func Observe

func Observe(sb *osv1.Sandbox) (Outcome, string)

Observe maps a sandbox's status to an Outcome, with a failure reason for OutcomeFailed.

type Placement added in v0.9.0

type Placement struct {
	NodeSelector      map[string]string   `json:"nodeSelector,omitempty"`
	Tolerations       []corev1.Toleration `json:"tolerations,omitempty"`
	RuntimeClassName  string              `json:"runtimeClassName,omitempty"`
	PriorityClassName string              `json:"priorityClassName,omitempty"`
}

Placement chooses the nodes sandbox pods run on. It is operator-wide configuration (chart value openshell.placement), not part of the Agent: a toleration can admit a sandbox to any tainted node, including the control plane, so only cluster admins set it.

The gateway applies it only with drivers.kubernetes.allowDriverConfig=true; otherwise it rejects every sandbox that sets it.

func ApplyClass added in v0.9.0

func ApplyClass(agent *agentorcav1alpha1.Agent, class *agentorcav1alpha1.SandboxClass, operatorPlacement Placement) (*agentorcav1alpha1.Agent, Placement)

ApplyClass returns the Agent as the sandbox sees it, with its SandboxClass (nil for none) and egress presets folded in, and the placement for its pods. Class and Agent settings are combined, never narrowed: egress and filesystem paths are unioned, enforcement is the stricter of the two, resources come from the Agent and default to the class's, and placement comes from the class, else the operator's. The Agent passed in is not modified.

func PlacementFromEnv added in v0.9.0

func PlacementFromEnv() (Placement, error)

PlacementFromEnv reads the placement from OPENSHELL_SANDBOX_PLACEMENT, a JSON Placement. Unset or empty means no placement.

func (Placement) IsZero added in v0.9.0

func (p Placement) IsZero() bool

IsZero reports whether the placement sets nothing.

type PodLogFunc

type PodLogFunc func(ctx context.Context, namespace, pod, container string) (string, error)

PodLogFunc reads a container's logs from a pod. The gateway does not relay main-process output, so the operator reads it from the workload pod directly.

type SDKGateway

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

SDKGateway implements Gateway over the OpenShell Go SDK.

func NewGateway

func NewGateway(sandboxes osv1.SandboxInterface, providers osv1.ProviderInterface, workspace, sandboxNamespace string, podLogs PodLogFunc) *SDKGateway

NewGateway binds a sandbox client to a workspace. With a nil podLogs, MainProcessLogs returns an error.

func (*SDKGateway) ApproveDraft added in v0.9.0

func (g *SDKGateway) ApproveDraft(ctx context.Context, sandbox, chunkID, reviewToken string) error

ApproveDraft implements Gateway.

func (*SDKGateway) Create

func (g *SDKGateway) Create(ctx context.Context, name string, spec *osv1.SandboxSpec, labels map[string]string) (*osv1.Sandbox, error)

Create implements Gateway.

func (*SDKGateway) Decisions added in v0.9.0

func (g *SDKGateway) Decisions(ctx context.Context, sandbox string, since time.Time) ([]Decision, error)

Decisions implements Gateway.

func (*SDKGateway) Delete

func (g *SDKGateway) Delete(ctx context.Context, name string) error

Delete implements Gateway.

func (*SDKGateway) DeleteProviders

func (g *SDKGateway) DeleteProviders(ctx context.Context, labels map[string]string) error

DeleteProviders implements Gateway.

func (*SDKGateway) EnsureProfile

func (g *SDKGateway) EnsureProfile(ctx context.Context, profile *osv1.ProviderProfile) error

EnsureProfile implements Gateway.

func (*SDKGateway) EnsureProvider

func (g *SDKGateway) EnsureProvider(ctx context.Context, provider *osv1.Provider) error

EnsureProvider implements Gateway. The provider's profile is looked up in the gateway workspace EnsureProfile imports into; an empty ProfileWorkspace would mean the global scope.

func (*SDKGateway) Exec added in v0.9.0

func (g *SDKGateway) Exec(ctx context.Context, sandbox string, command []string, opts ExecOptions) (*ExecResult, error)

Exec implements Gateway.

func (*SDKGateway) Get

func (g *SDKGateway) Get(ctx context.Context, name string) (*osv1.Sandbox, error)

Get implements Gateway.

func (*SDKGateway) MainProcessLogs

func (g *SDKGateway) MainProcessLogs(ctx context.Context, sb *osv1.Sandbox) (string, error)

MainProcessLogs implements Gateway.

func (*SDKGateway) PendingDrafts added in v0.9.0

func (g *SDKGateway) PendingDrafts(ctx context.Context, sandbox string) ([]osv1.PolicyChunk, error)

PendingDrafts implements Gateway.

func (*SDKGateway) RejectDraft added in v0.9.0

func (g *SDKGateway) RejectDraft(ctx context.Context, sandbox, chunkID, reason string) error

RejectDraft implements Gateway.

func (*SDKGateway) SandboxNamespace

func (g *SDKGateway) SandboxNamespace() string

SandboxNamespace implements Gateway.

func (*SDKGateway) WithExec added in v0.9.0

func (g *SDKGateway) WithExec(e osv1.ExecInterface) *SDKGateway

WithExec gives the gateway the exec client Exec uses.

func (*SDKGateway) WithPolicy added in v0.9.0

func (g *SDKGateway) WithPolicy(p osv1.PolicyInterface) *SDKGateway

WithPolicy gives the gateway the policy client its draft methods use.

type SpecInput

type SpecInput struct {
	Agent *agentorcav1alpha1.Agent
	// RouterHost is the router Service hostname the workload's base URL names.
	RouterHost string
	// ExtraRouterHosts are further router Service hostnames the sandbox may
	// reach: a workflow's shared sandbox serves one router per agent step. Each
	// must be a literal name, since OpenShell resolves policy hosts ahead of time
	// and refuses names it has no mapping for.
	ExtraRouterHosts []string
	// Env is the agent process environment, including the router base URL and
	// the per-run router credential.
	Env map[string]string
	// Tools are the tool endpoints the agent may reach directly, already
	// filtered by spec.runtime.sandbox.tools and bound to credential providers.
	Tools []ToolEndpoint
	// Providers are the provider instances to attach to the sandbox.
	Providers []string
	// Placement chooses the sandbox pod's nodes (operator-wide).
	Placement Placement
	// Git, when set, grants git access to GitHub through a credential-bound
	// endpoint (see ApplyGitAccess).
	Git *GitAccess
}

SpecInput is everything BuildSpec needs to describe a run's sandbox.

type ToolCredential

type ToolCredential struct {
	// Source owns the credential: the MCPServer the tool was generated from, or
	// the tool itself. Tools from one MCPServer share one credential.
	Source string
	// Tool is the first tool (in spec.tools order) that declared the credential.
	Tool string
	// URL is the MCP server URL, and Host/Port its endpoint the credential binds to.
	URL  string
	Host string
	Port uint32
	Keys []CredentialKey
}

ToolCredential is the static secret material a tool sends to its MCP server.

func ToolCredentials

func ToolCredentials(tool *agentorcav1alpha1.Tool, source string) *ToolCredential

ToolCredentials returns the static credentials of a remote MCP tool, or nil when the tool has none. OAuth tools are skipped: their access token rotates, and a snapshot would go stale mid-run. Secret references to other namespaces are skipped, matching the router, which mounts only same-namespace Secrets. source is the credential owner (see ToolCredential.Source).

type ToolEndpoint

type ToolEndpoint struct {
	Tool string
	Host string
	Port uint32
	// CredentialProvider, when set, binds the named provider's static
	// credentials to this endpoint (see BindCredentials).
	CredentialProvider string
}

ToolEndpoint is one network destination of one of the Agent's tools.

func FilterToolEndpoints

func FilterToolEndpoints(sb *agentorcav1alpha1.SandboxSpec, eps []ToolEndpoint) []ToolEndpoint

FilterToolEndpoints applies spec.runtime.sandbox.tools to the Agent's tool endpoints.

func ToolEndpoints

func ToolEndpoints(tool *agentorcav1alpha1.Tool, extraEgress ...agentorcav1alpha1.EgressRule) []ToolEndpoint

ToolEndpoints returns the network destinations of one Tool that a sandboxed agent may reach: its networkEgress rules that name a host (plus extraEgress, e.g. its MCPServer's networkEgress), and the URL of a remote MCP server. Port-only egress rules are skipped because sandbox policy is per host, and loopback URLs because they name the router pod's own sidecars and the sandbox can never reach loopback destinations.

Jump to

Keyboard shortcuts

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