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 ¶
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."
const DefaultDirName = "compliancekit/plugins"
DefaultDirName is the relative XDG directory the daemon scans when --plugins-dir is unset.
Variables ¶
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.
var ErrNoSignatureFile = errors.New("plugins: signature.sig missing")
ErrNoSignatureFile is returned when a plugin's directory has no signature.sig alongside its manifest.
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.
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 ¶
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 ¶
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 ¶
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 ¶
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.
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 ¶
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 ¶
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 ¶
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 ¶
NewWatcher returns a Watcher bound to cat. Callers may override debounce; passing 0 uses DefaultDebounce.
func (*Watcher) Generation ¶
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.