plugins

package
v0.3.7 Latest Latest
Warning

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

Go to latest
Published: Aug 2, 2026 License: MIT Imports: 41 Imported by: 0

Documentation

Overview

Package plugins loads Extism WASM plugins for honey (CUE transforms, custom steps, secret ref backends, and local hooks). Enable via honey config plugins.enabled.

Index

Constants

View Source
const (
	CapCueTransform = "cue_transform"
	CapCustomStep   = "custom_step"
	CapSecret       = "secret"
	CapStackUnwrap  = "stack_unwrap"
	CapHook         = "hook"
)

Capability names registered in plugin.yaml.

Variables

This section is empty.

Functions

func KVSessionFromContext

func KVSessionFromContext(ctx context.Context) (*stepkv.Session, bool)

KVSessionFromContext returns the session bound for this plugin call, if any.

func LocateShimBinaryForArch added in v0.3.7

func LocateShimBinaryForArch(goarch string) (string, error)

LocateShimBinaryForArch finds the honey-plugin-init binary built for the given GOARCH ("amd64"/"arm64"), for staging onto a remote host of that architecture (the remote docker-plugin path). Searches, in order, for "honey-plugin-init-linux-<goarch>" in: $HONEY_PLUGIN_INIT_DIR, the directory of $HONEY_PLUGIN_INIT_PATH (release archives ship both arches side by side, so the arch-suffixed sibling of the operator's own binary is the natural spot), then alongside the running honey executable. Unlike locatePluginInitBinary it never uses HONEY_PLUGIN_INIT_PATH's file directly or the unsuffixed name — those identify a single (operator-arch) binary that may not match the remote host's arch.

func PluginsFromConfig

func PluginsFromConfig(f *config.File) config.PluginsEffective

PluginsFromConfig builds effective settings from honey config file.

func ResolvePostgresDSN added in v0.3.0

func ResolvePostgresDSN(ctx context.Context, h *HostRunContext, ref string) (string, error)

ResolvePostgresDSN resolves config.dsn_secret from a secrets map key or direct secure:v1 ref.

func RunKVForTest

func RunKVForTest(ctx context.Context, in apiv1.KVInput) apiv1.KVOutput

RunKVForTest exposes runKV for unit tests.

func RunPostgresExecForTest added in v0.3.0

func RunPostgresExecForTest(ctx context.Context, in apiv1.PostgresSQLInput) apiv1.PostgresOutput

RunPostgresExecForTest exposes postgres_exec for unit tests.

func RunPostgresQueryForTest added in v0.3.0

func RunPostgresQueryForTest(ctx context.Context, in apiv1.PostgresSQLInput) apiv1.PostgresOutput

RunPostgresQueryForTest exposes postgres_query for unit tests.

func RunRemoteExecForTest added in v0.3.0

func RunRemoteExecForTest(ctx context.Context, in apiv1.RemoteExecInput) apiv1.RemoteExecOutput

RunRemoteExecForTest exposes remote_exec handling for unit tests.

func RunRemoteStatForTest added in v0.3.0

func RunRemoteStatForTest(ctx context.Context, in apiv1.RemoteStatInput) apiv1.RemoteStatOutput

RunRemoteStatForTest exposes remote_stat handling for unit tests.

func RunRemoteUploadForTest added in v0.3.0

func RunRemoteUploadForTest(ctx context.Context, in apiv1.RemoteUploadInput) apiv1.RemoteUploadOutput

RunRemoteUploadForTest exposes remote_upload handling for unit tests.

func RunTemplateRenderForTest added in v0.3.0

func RunTemplateRenderForTest(ctx context.Context, in apiv1.TemplateRenderInput) apiv1.TemplateRenderOutput

RunTemplateRenderForTest exposes template_render handling for unit tests.

func WithHostRunContext added in v0.3.0

func WithHostRunContext(ctx context.Context, h *HostRunContext) context.Context

WithHostRunContext attaches host execution context for plugin remote host functions.

func WithKVSession

func WithKVSession(ctx context.Context, sess *stepkv.Session) context.Context

WithKVSession attaches the recipe stepkv session for plugin host functions.

Types

type DockerBackend added in v0.3.7

type DockerBackend interface {
	// Client returns the moby client for the target daemon. The transport
	// does not close it — Close (below) owns that.
	Client() *client.Client
	// ShimHostPath returns the path, on the daemon host, of the
	// honey-plugin-init binary to bind-mount as the container entrypoint.
	// Remote backends stage the binary onto the host here (idempotently).
	ShimHostPath(ctx context.Context) (string, error)
	// DialShim dials the shim's published loopback address on the daemon
	// host. Local dials directly; remote tunnels through SSH. The signature
	// matches http.Transport.DialContext so it can be wired straight in.
	DialShim(ctx context.Context, network, address string) (net.Conn, error)
	// Close releases backend-owned resources (the moby client, etc.). It
	// must not close a borrowed/shared SSH connection it does not own.
	Close() error
}

DockerBackend abstracts the daemon a docker plugin's shim-container runs against: the operator's local Docker daemon (localBackend, below) or a remote host's daemon over SSH (the engine's ssh backend). It captures exactly the three operator-local assumptions of the shim model — which daemon, where the honey-plugin-init binary lives to bind-mount, and how to reach the shim's published loopback port. Everything else in dockerTransport (container lifecycle, the /call HTTP protocol) is backend-agnostic, so local and remote share one code path.

type DockerHostSession added in v0.3.7

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

DockerHostSession scopes remote docker-plugin containers to one recipe run: one long-lived shim-container per (pluginID, hostKey), reused across the session, all stopped+removed on Close. The engine creates one per run so containers never outlive a run — important for the long-lived `honey web` process, where a single Manager is shared across scheduled runs and a leaked container would sit on the target host indefinitely.

It reuses the exact same dockerTransport (shim protocol, /call HTTP, container lifecycle) as the local path; only the DockerBackend differs (see the engine's ssh backend), so remote and local execution share one code path.

func (*DockerHostSession) Close added in v0.3.7

func (s *DockerHostSession) Close(ctx context.Context) error

Close stops and removes every per-host container the session created, returning the first teardown error (all are attempted).

func (*DockerHostSession) ExecuteStep added in v0.3.7

func (s *DockerHostSession) ExecuteStep(ctx context.Context, newBackend func() (DockerBackend, error), hostKey, pluginID, action string, config json.RawMessage, stepIndex int, hostJSON []byte, env map[string]string, execute, secretsDry bool, kvSession *stepkv.Session) (apiv1.ExecuteStepOutput, error)

ExecuteStep runs the execute_step export for pluginID on the daemon that the backend built by newBackend targets, against a shim-container keyed by (pluginID, hostKey) and reused for the session's lifetime. newBackend is invoked only on a cache miss, so a caller building an expensive backend (an SSH-tunneled moby client) pays that cost once per host, not per call.

The result decoding mirrors Manager.Call exactly: a plugin-reported error or nonzero transport exit becomes a Go error; a normal step failure arrives as ExecuteStepOutput data (Success:false) via the transport's own convention.

type DockerRestartConfig added in v0.3.7

type DockerRestartConfig struct {
	MaxBackoff string `yaml:"max_backoff,omitempty"` // duration string, default "30s"
}

DockerRestartConfig tunes auto-restart of a crashed plugin container.

type DockerRuntime added in v0.3.7

type DockerRuntime struct {
	Image      string              `yaml:"image"`
	PullPolicy string              `yaml:"pull_policy,omitempty"` // "if_not_present" (default) or "always"
	Restart    DockerRestartConfig `yaml:"restart,omitempty"`
	// Volumes are static bind mounts, Docker syntax ("host_path:container_path[:ro|rw]"),
	// same format container.HostConfig.Binds already takes. For plugins that need file
	// I/O (e.g. ffmpeg reading/writing files) under one predictable host root — not
	// per-call dynamic mounts.
	Volumes []string `yaml:"volumes,omitempty"`
	// Init selects who provides honey-plugin-init: "" or "bind" (default) —
	// honey bind-mounts the host binary and overrides the entrypoint; "embedded"
	// — the image already contains honey-plugin-init as its entrypoint, so no
	// host binary is needed (required for images distributed from a registry).
	Init string `yaml:"init,omitempty"`
	// InitPath is the in-image path of honey-plugin-init when Init=="embedded".
	// Defaults to defaultEmbeddedInitPath at load. Ignored in bind mode.
	InitPath string `yaml:"init_path,omitempty"`
	// Network selects the container network mode: "" (default, bridge — honey
	// publishes the shim port to a loopback host port) or "host" (container
	// shares the daemon host's network namespace to reach the host's loopback
	// directly). "host" is operator-gated by plugins.allow_host_network.
	Network string `yaml:"network,omitempty"`
}

DockerRuntime configures a runtime: docker plugin's container.

type HostRunContext added in v0.3.0

type HostRunContext struct {
	SSHUser              string
	Record               hosts.Record
	RecipeDir            string
	Execute              bool
	SecretsDry           bool
	RunAs                string
	Env                  map[string]string
	Bridge               RemoteBridge
	Postgres             PostgresBridge
	TunnelCoord          TunnelCoordinator
	AllowedPaths         map[string]string
	RecipeSecrets        map[string]string
	ResolveSecret        SecretResolveFunc
	PluginID             string
	MaxPostgresTimeoutMS int
}

HostRunContext carries per-host recipe execution state for plugin host functions.

func HostRunContextFromContext added in v0.3.0

func HostRunContextFromContext(ctx context.Context) (*HostRunContext, bool)

HostRunContextFromContext returns the host run context for this plugin call, if any.

type Info

type Info struct {
	ID                   string            `json:"id"`
	Version              string            `json:"version"`
	Capabilities         []string          `json:"capabilities"`
	Path                 string            `json:"path"`
	SecretRefPrefixes    []string          `json:"secret_ref_prefixes,omitempty"`
	AllowHostExec        bool              `json:"allow_host_exec,omitempty"`
	AllowRemoteExec      bool              `json:"allow_remote_exec,omitempty"`
	AllowSFTP            bool              `json:"allow_sftp,omitempty"`
	AllowTemplateRender  bool              `json:"allow_template_render,omitempty"`
	AllowPostgres        bool              `json:"allow_postgres,omitempty"`
	AllowKV              bool              `json:"allow_kv,omitempty"`
	AllowedHosts         []string          `json:"allowed_hosts,omitempty"`
	AllowedPaths         map[string]string `json:"allowed_paths,omitempty"`
	AllowedEnv           []string          `json:"allowed_env,omitempty"`
	MaxHTTPResponseBytes int64             `json:"max_http_response_bytes,omitempty"`
}

Info describes a loaded plugin for listing.

type Manager

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

Manager loads Extism WASM plugins and routes capability calls.

func LoadFromDir

func LoadFromDir(ctx context.Context, dir string) (*Manager, error)

LoadFromDir is a test helper that loads plugins from a directory without config allowlist.

func NewManager

func NewManager(ctx context.Context, cfg config.PluginsEffective) (*Manager, error)

NewManager loads plugins from cfg. When plugins are disabled, returns a manager with no plugins.

func Open

func Open(ctx context.Context, cfg *config.File) (*Manager, error)

Open loads plugins from honey config (returns non-nil manager even when disabled).

func (*Manager) Call

func (m *Manager) Call(ctx context.Context, pluginID, export string, in, out any) error

Call invokes export on pluginID with JSON input; decodes JSON output or returns plugin error string.

func (*Manager) Close

func (m *Manager) Close() error

Close releases plugin resources.

func (*Manager) EffectivePaths added in v0.3.0

func (m *Manager) EffectivePaths(pluginID string) map[string]string

EffectivePaths returns validated allowed_paths for a loaded plugin id.

func (*Manager) Enabled

func (m *Manager) Enabled() bool

Enabled reports whether plugins are turned on in config.

func (*Manager) ExecuteStep

func (m *Manager) ExecuteStep(ctx context.Context, pluginID, action string, config json.RawMessage, stepIndex int, hostJSON []byte, env map[string]string, execute, secretsDry bool, kvSession *stepkv.Session) (apiv1.ExecuteStepOutput, error)

ExecuteStep runs the execute_step export for a plugin step on one host. kvSession is optional; when non-nil it is bound for allow_kv plugins via the kv host function.

func (*Manager) IsDockerPlugin added in v0.3.7

func (m *Manager) IsDockerPlugin(pluginID string) bool

IsDockerPlugin reports whether pluginID is a loaded runtime:docker plugin (vs. a WASM plugin). The remote-host execution path (DockerHostSession) applies only to docker plugins.

func (*Manager) List

func (m *Manager) List() []Info

List returns metadata for loaded plugins.

func (*Manager) NewDockerHostSession added in v0.3.7

func (m *Manager) NewDockerHostSession() *DockerHostSession

NewDockerHostSession returns a session bound to m's loaded plugins.

func (*Manager) OnStepResult

func (m *Manager) OnStepResult(ctx context.Context, pluginID, action string, config json.RawMessage, in apiv1.OnStepResultInput, kvSession *stepkv.Session) (apiv1.OnStepResultOutput, error)

OnStepResult runs the on_step_result export for a local hook plugin.

func (*Manager) PluginIDsWithCapability

func (m *Manager) PluginIDsWithCapability(capability string) []string

PluginIDsWithCapability returns plugin IDs that declare the capability.

func (*Manager) SecretRefBackends

func (m *Manager) SecretRefBackends() []secrets.ExtraBackend

SecretRefBackends returns ExtraBackend functions for plugins with the secret capability.

func (*Manager) SecretRefPrefixes

func (m *Manager) SecretRefPrefixes() []string

SecretRefPrefixes returns all registered secret ref prefixes from secret-capable plugins.

func (*Manager) TimeoutMS added in v0.3.0

func (m *Manager) TimeoutMS() int

TimeoutMS returns configured plugin timeout milliseconds (default 30000).

func (*Manager) TransformCue

func (m *Manager) TransformCue(ctx context.Context, cueBytes []byte, hostsCount int) ([]byte, error)

TransformCue runs cue_transform plugins in manifest order.

type Manifest

type Manifest struct {
	ID                   string            `yaml:"id"`
	Version              string            `yaml:"version"`
	Capabilities         []string          `yaml:"capabilities"`
	SecretRefPrefixes    []string          `yaml:"secret_ref_prefixes,omitempty"`
	AllowK8sHTTP         bool              `yaml:"allow_k8s_http,omitempty"`
	AllowHostExec        bool              `yaml:"allow_host_exec,omitempty"`
	AllowRemoteExec      bool              `yaml:"allow_remote_exec,omitempty"`
	AllowSFTP            bool              `yaml:"allow_sftp,omitempty"`
	AllowTemplateRender  bool              `yaml:"allow_template_render,omitempty"`
	AllowPostgres        bool              `yaml:"allow_postgres,omitempty"`
	AllowKV              bool              `yaml:"allow_kv,omitempty"`
	AllowedEnv           []string          `yaml:"allowed_env,omitempty"`
	AllowedHosts         []string          `yaml:"allowed_hosts,omitempty"`
	AllowedPaths         map[string]string `yaml:"allowed_paths,omitempty"`
	Config               map[string]string `yaml:"config,omitempty"`
	MaxHTTPResponseBytes int64             `yaml:"max_http_response_bytes,omitempty"`
	Order                int               `yaml:"order,omitempty"`
	Runtime              string            `yaml:"runtime,omitempty"` // "wasm" (default) or "docker"
	Docker               *DockerRuntime    `yaml:"docker,omitempty"`
}

Manifest describes a plugin bundle (plugin.yaml next to plugin.wasm).

func Install added in v0.3.2

func Install(ctx context.Context, src, destDir string, force bool) (*Manifest, error)

Install installs a plugin from src (https:// URL, local .tar.gz/.zip, or local directory) into destDir/<plugin-id>/. Returns the installed Manifest. If force is false, returns an error when the plugin id already exists in destDir.

type PostgresBridge added in v0.3.0

PostgresBridge performs Postgres operations on the operator via pgx.

type RemoteBridge added in v0.3.0

RemoteBridge performs SSH/SFTP operations on behalf of a WASM plugin for one host.

type SecretBackend

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

SecretBackend resolves secret refs via a WASM plugin prefix.

type SecretResolveFunc added in v0.3.0

type SecretResolveFunc func(ctx context.Context, ref string) (string, error)

SecretResolveFunc resolves a secure:v1 ref to plaintext (operator-side only).

type TunnelCoordinator added in v0.3.0

type TunnelCoordinator interface {
	LookupEndpoint(stepID, sshUser string, record hosts.Record) (host string, port int, ok bool)
}

TunnelCoordinator resolves recipe tunnel step endpoints for DSN rewrite.

Directories

Path Synopsis
api
v1
Package v1 defines the honey.plugins/v1 JSON contract between the host and WASM plugins.
Package v1 defines the honey.plugins/v1 JSON contract between the host and WASM plugins.

Jump to

Keyboard shortcuts

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