plugins

package
v1.19.1 Latest Latest
Warning

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

Go to latest
Published: May 29, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package plugins owns the v1.13 daemon-side plugin runtime: filesystem discovery, manifest parsing, cosign signature verification, sandbox dial-time egress enforcement, and hot-reload of Rego packs.

The public types (Manifest, Plugin, Kind, Catalog) live under pkg/compliancekit/plugin so embedders see a stable surface; this package is the daemon's private wiring.

Discovery (phase 2): walk $XDG_DATA_HOME/compliancekit/plugins/ (or the explicit --plugins-dir override) and load every direct subdirectory that contains a manifest.yaml. Each subdirectory is one plugin; the directory name doesn't have to match the manifest's `name` field but the daemon emits a warning when they diverge.

Index

Constants

View Source
const DefaultDebounce = 500 * time.Millisecond

DefaultDebounce is the burst-coalescing window. 500ms balances "fast enough to feel live" against "slow enough that a tar extraction doesn't trigger N reloads."

View Source
const DefaultDirName = "compliancekit/plugins"

DefaultDirName is the relative XDG directory the daemon scans when --plugins-dir is unset.

Variables

View Source
var ErrEgressDenied = errors.New("plugins: egress denied — host not in manifest.declared_egress")

ErrEgressDenied is returned by the sandbox dialer when a plugin tries to reach a host outside its DeclaredEgress allow-list.

View Source
var ErrNoSignatureFile = errors.New("plugins: signature.sig missing")

ErrNoSignatureFile is returned when a plugin's directory has no signature.sig alongside its manifest.

View Source
var ErrUnsigned = errors.New("plugins: unsigned plugin refused (operators may opt in with --allow-unsigned-plugins)")

ErrUnsigned is returned by Catalog.loadOne when the plugin has no valid signature + the catalog was not opted into --allow-unsigned-plugins.

View Source
var ErrUnsupportedKey = errors.New("plugins: pubkey type unsupported (want ECDSA P-256 or Ed25519)")

ErrUnsupportedKey is returned when the operator's pubkey PEM decodes to a type the verifier doesn't handle (only ECDSA P-256 and Ed25519 are supported at v1.13).

Functions

func DefaultDir

func DefaultDir() string

DefaultDir returns the absolute path the daemon discovers plugins from. Honors $XDG_DATA_HOME; falls back to $HOME/.local/share on Linux / macOS and a sensible default on Windows.

Types

type AuditFunc

type AuditFunc func(pluginName, host string)

AuditFunc is the optional callback the sandbox invokes when an egress dial is denied. Lets the daemon log the rejection into the v1.12 audit_log without the plugins package importing the UI.

type Catalog

type Catalog struct {
	Dir           string
	AllowUnsigned bool
	// contains filtered or unexported fields
}

Catalog tracks the set of installed plugins under Dir. The daemon constructs one at boot, calls Refresh(), and re-calls it on fsnotify writes from the phase-5 hot-reload watcher.

func New

func New(dir string, allowUnsigned bool) *Catalog

New returns a Catalog rooted at dir. dir is created if absent so the daemon doesn't fail to boot just because the operator hasn't installed any plugins yet.

func (*Catalog) All

func (c *Catalog) All() []*pubplugin.Plugin

All returns every loaded plugin, sorted by manifest.Name. Returns a fresh slice on every call so callers can mutate without locking the catalog.

func (*Catalog) ByName

func (c *Catalog) ByName(name string) (*pubplugin.Plugin, bool)

ByName returns the plugin keyed by manifest.Name; reports ok=false when absent.

func (*Catalog) Refresh

func (c *Catalog) Refresh(ctx context.Context) (*Discovered, error)

Refresh walks the plugin directory + replaces the in-memory catalog with the current on-disk state. Returns a Discovered report so the daemon (or CLI) can surface partial failures.

func (*Catalog) WithVerifier

func (c *Catalog) WithVerifier(v SignatureVerifier) *Catalog

WithVerifier installs the signature verifier used during Refresh. nil = no verification (phase 2 fallback).

type CosignVerifier

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

CosignVerifier checks plugin signatures against a fixed operator- supplied public key. One verifier per running daemon — the same trust root applies to every installed plugin.

func NewCosignVerifier

func NewCosignVerifier(pemBytes []byte) (*CosignVerifier, error)

NewCosignVerifier parses pemBytes as a PEM-encoded public key (PKIX SubjectPublicKeyInfo) and returns a verifier ready for use. Caller's responsibility to source the PEM securely — the daemon reads it from disk at boot.

func NewCosignVerifierFromFile

func NewCosignVerifierFromFile(path string) (*CosignVerifier, error)

NewCosignVerifierFromFile is a convenience wrapper that reads pem bytes from path.

func (*CosignVerifier) Verify

func (v *CosignVerifier) Verify(pluginDir string, _ *pubplugin.Manifest) (bool, error)

Verify implements SignatureVerifier. Reads <pluginDir>/signature.sig + recomputes SHA-256(manifest.yaml) and validates the signature matches under the verifier's pinned key.

type Discovered

type Discovered struct {
	Plugins []*pubplugin.Plugin
	Errors  map[string]error // keyed by directory name
}

Discovered is the result of one Catalog.Refresh() walk. Splits the successfully-loaded plugins from the per-directory load errors so the operator can see which packs failed without blocking the healthy ones.

type Sandbox

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

Sandbox is the per-plugin dial gate. One instance per plugin (built from the manifest's DeclaredEgress slice). The daemon hands the plugin a fresh *http.Client through HTTPClient() so every outbound request goes through the gate.

func NewSandbox

func NewSandbox(m *pubplugin.Manifest, audit AuditFunc) *Sandbox

NewSandbox returns a Sandbox enforcing the plugin's manifest allow-list. Pass nil audit when the caller doesn't care about the audit-trail side effect (tests).

func (*Sandbox) CheckHost

func (s *Sandbox) CheckHost(host string) bool

CheckHost reports whether host is permitted by the allow-list. Exposed so non-HTTP egress paths (e.g. raw TCP for an SMTP notifier) can consult the same gate without spinning a dialer.

func (*Sandbox) HTTPClient

func (s *Sandbox) HTTPClient() *http.Client

HTTPClient returns an *http.Client whose dialer enforces the allow-list. Callers shouldn't reach for http.DefaultClient or construct their own *http.Transport — every egress must go through the returned client to stay inside the sandbox.

type SignatureVerifier

type SignatureVerifier interface {
	Verify(pluginDir string, m *pubplugin.Manifest) (ok bool, err error)
}

SignatureVerifier validates a plugin's signature.sig against the manifest.yaml in the same directory. Phase 3 wires the cosign-backed implementation.

type Watcher

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

Watcher debounces fsnotify events into Catalog.Refresh calls. Construct via NewWatcher; Start launches the background loop; Stop closes the underlying watcher.

func NewWatcher

func NewWatcher(cat *Catalog, debounce time.Duration) (*Watcher, error)

NewWatcher returns a Watcher bound to cat. Callers may override debounce; passing 0 uses DefaultDebounce.

func (*Watcher) Generation

func (w *Watcher) Generation(name string) int

Generation returns the most recent generation counter for plugin name. Scans cache this at start time + carry the cached value through the scan even if the catalog later reloads.

func (*Watcher) Start

func (w *Watcher) Start(ctx context.Context) error

Start launches the watch + debounce loop. ctx cancellation triggers a clean shutdown. The function returns immediately; the caller is responsible for ctx lifetime.

func (*Watcher) Stop

func (w *Watcher) Stop()

Stop signals the background loop to exit + closes the watcher. Safe to call multiple times.

Jump to

Keyboard shortcuts

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