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

substrate

package
v0.6.2 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package substrate defines the confinement-substrate sub-interface: the seam beneath the runner.Runner surface that lets a non-OCI microVM VMM (SmolVM, Firecracker, …) back a Confinement Class alongside the OCI/Docker substrate, without the control plane (or each substrate) re-implementing the runner contract. The build-tag-free orchestrator (internal/runner/orchestrator) is the runner.Runner the control plane talks to; it multiplexes Substrates by Confinement Class and aggregates their capabilities.

A Substrate owns the mechanism of bringing up + tearing down a governed sandbox (its isolated per-run network, the wardyn-proxy sidecar, and the agent unit) on one substrate. Every Substrate MUST uphold Wardyn's non-negotiables for the sandboxes it creates:

  • Confined egress, proven EITHER of two ways — never merely asserted:
  • L0 structural: the agent has NO default route; its SOLE egress path is the wardyn-proxy sidecar (no direct off-host route). This is the docker substrate's guarantee: absence of route, not a filter to bypass.
  • L1 network-policy: a packet-filter layer (e.g. Kubernetes NetworkPolicy) default-denies the agent's egress except the proxy sidecar, AND the substrate has PROVEN that enforcement on THIS host/cluster — a policy object existing is not proof; a boot-time canary that positively confirms the deny takes effect (and refuses to boot when it does not) is. See ClassSupport.NetworkPolicy.
  • A substrate that can prove NEITHER MUST advertise no Confinement Classes at all (fail closed, never overclaim) — the sole documented exception is an explicit, operator-set opt-out env var read by that substrate. That opt-out is itself an admission of unconfined egress, not a third proof, and it MUST NOT be an invisible downgrade: the substrate (a) emits a warning at construction or CreateSandbox naming what is going unconfined, and (b) still advertises StructuralEgress=false AND NetworkPolicy=false regardless — an opted-out substrate must never read identical to a genuinely confined one on /healthz.
  • Fail closed: CreateSandbox MUST error (never silently downgrade) when the demanded Confinement Class cannot be enforced, before creating anything.
  • The run token / secrets NEVER enter the agent's environment.
  • Teardown is idempotent and reconstructable from the run id (crash-safe).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Names added in v0.3.1

func Names() []string

Names returns the registered substrate names (for /healthz and error messages).

func Register added in v0.3.1

func Register(name string, c Constructor)

Register adds a confinement-substrate implementation; call it from an init(). The OCI/Docker substrate registers itself only under `-tags docker`, so a tagless control plane fails closed at Resolve ("not registered") rather than carrying target-specific code (the parity rule).

Types

type ClassSupport

type ClassSupport struct {
	// Classes the substrate can enforce, strongest last. A class is listed ONLY
	// when its enforcing runtime is actually available (never overclaim).
	Classes []types.ConfinementClass
	// Resolved maps each available class to its substrate label ("oci/<runtime>").
	Resolved map[types.ConfinementClass]string
	// StructuralEgress reports L0 (no default route; sole egress = wardyn-proxy).
	StructuralEgress bool
	// NetworkPolicy reports L1 (a packet-filter default-deny, e.g. Kubernetes
	// NetworkPolicy, default-denying the agent's egress except the proxy
	// sidecar) — PROVEN on this host/cluster, not merely configured. A
	// substrate sets this true only after a boot-time canary has positively
	// confirmed the deny is actually enforced (see the package doc); a
	// NetworkPolicy object that exists but is silently ignored by a
	// non-enforcing CNI is exactly the false claim this field must never make.
	// StructuralEgress and NetworkPolicy are not mutually exclusive in
	// principle, but today's substrates each prove exactly one.
	NetworkPolicy bool
	// SessionRecording reports wardyn-rec PTY recording support.
	SessionRecording bool
}

ClassSupport reports the Confinement Classes a substrate can enforce on this host and the concrete substrate label backing each (e.g. CC3 -> "oci/kata-qemu"). It is the substrate-level analogue of runner.Capabilities; the orchestrator aggregates these across substrates into the runner.Capabilities it advertises.

type Constructor added in v0.3.1

type Constructor func(Deps) (Substrate, error)

Constructor builds a Substrate from Deps.

type Deps added in v0.3.1

type Deps struct {
	// ProxyImage is the wardyn-proxy sidecar image the substrate launches beside
	// each agent (the sole egress path — L0).
	ProxyImage string
	// ConfinementRuntimes are the operator's fail-closed per-class runtime pins
	// (WARDYN_CONFINEMENT_MAP); nil = the substrate's built-in defaults.
	ConfinementRuntimes map[types.ConfinementClass]string
}

Deps are the platform primitives a Substrate constructor may use. Heterogeneous seams keep their own typed Deps; an impl ignores fields it does not need (a non-OCI VMM ignores ProxyImage-as-OCI-ref semantics) and reads its own impl-specific config from the env in its constructor — see the docker impl's WARDYN_RECORDING_MOUNT / WARDYN_INTERNAL_NETWORK reads in register.go.

type Substrate

type Substrate interface {
	// Name reports the substrate kind ("docker"/OCI today), surfaced on /healthz.
	Name() string
	// Classes reports the enforceable Confinement Classes + their substrate labels.
	Classes(ctx context.Context) (ClassSupport, error)
	// CreateSandbox provisions the run's isolated network + proxy + agent unit,
	// fail-closed with full rollback on any error.
	CreateSandbox(ctx context.Context, spec runner.SandboxSpec) (runner.Sandbox, error)
	// Exec launches the agent process inside the sandbox ref, returning the
	// substrate-specific agent exec id ("" for exec-less/main-process substrates)
	// so the control plane can persist it for restart-safe liveness.
	//
	// A substrate MAY support only ONE Exec per ref over the sandbox's
	// lifetime: Kubernetes ephemeral containers are ADD-ONLY (a pod's
	// ephemeral-container list can only grow, never be replaced), so a k8s
	// substrate cannot honour a second Exec on the same ref the way the
	// docker substrate's "latest Exec wins" re-exec does today. Callers MUST
	// NOT re-Exec a ref expecting replace semantics — treat Exec as
	// one-shot per sandbox. A substrate that cannot honour a second Exec on
	// ref MUST return an error: never silently no-op, and never return the
	// PRIOR exec's id — a stale agentExecID would point AgentStatus at the
	// wrong process (fail closed; don't misreport liveness).
	//
	// This one-shot constraint is EXEC-SPECIFIC. ExecStream (below) is the
	// opposite: a substrate MUST support repeated ExecStream calls against
	// the same ref.
	Exec(ctx context.Context, ref string, argv []string) (agentExecID string, err error)
	// Wait blocks until the agent process for ref exits and returns its code.
	Wait(ctx context.Context, ref string) (int, error)
	// Attach opens an interactive PTY session inside ref.
	Attach(ctx context.Context, ref string, opts runner.AttachOptions) (runner.Session, error)
	// ExecStream launches spec.Argv inside ref as a fresh, streamable exec.
	// See runner.ExecStream's doc for the streaming, TTY-merge, and
	// invariant-3/4 security contract.
	//
	// UNLIKE Exec, ExecStream MUST be repeatable against the SAME ref: a
	// substrate MUST support many ExecStream calls against one long-lived
	// sandbox (e.g. one per SSH/SFTP channel). A k8s substrate implements
	// ExecStream on the streaming exec subresource (pods/<name>/exec —
	// repeatable, leaves no pod-spec residue), NOT an ephemeral container
	// (add-only — that limit is what makes Exec one-shot, not ExecStream).
	ExecStream(ctx context.Context, ref string, spec runner.ExecSpec) (*runner.ExecSession, error)
	// Status reports the sandbox lifecycle state.
	Status(ctx context.Context, ref string) (runner.Status, error)
	// AgentStatus reports the AGENT's state restart-safely given the persisted
	// agentExecID (inspects the exec for exec-based substrates; falls back to
	// Status when agentExecID is "").
	AgentStatus(ctx context.Context, ref, agentExecID string) (runner.Status, error)
	// StopSandbox is the graceful teardown (idempotent on a gone sandbox).
	StopSandbox(ctx context.Context, ref string) error
	// KillSandbox is the immediate kill-switch teardown (idempotent).
	KillSandbox(ctx context.Context, ref string) error
}

Substrate is runner.Runner's lifecycle contract for ONE confinement substrate, with Capabilities replaced by Classes (per-class substrate detail). The OCI substrate (internal/runner/docker) satisfies it today; a non-OCI VMM satisfies the same contract to plug into CC3.

func New added in v0.3.1

func New(name string, d Deps) (Substrate, error)

New constructs the substrate selected by name (empty => default).

Jump to

Keyboard shortcuts

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