plugin

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package plugin runs third-party analyzers out of process, so the community (and other AI tools) can extend detection without forking or being linked into the binary. A plugin is any executable that speaks a tiny JSON protocol over stdin/stdout; a JSON manifest declares its name, the target types it handles, and how to launch it. The host adapts each plugin to the engine.Module interface, so a loaded plugin appears in the CLI, HTTP API, and MCP server exactly like a built-in module.

Out-of-process is a deliberate isolation boundary. A plugin cannot corrupt the engine's memory, and a plugin that hangs, crashes, or floods stdout is contained: every run is time-bounded (context), output-bounded (a hard byte cap), launched with no shell and a scrubbed environment, and any failure is recorded as a module error rather than taking down the scan.

WASM and gRPC transports were considered for stronger sandboxing but both need a third-party runtime; per the project's zero-dependency rule they are parked (see NOTES.md). The subprocess protocol is the stdlib-only design that still delivers real isolation today.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Command

func Command(args []string) int

Command implements `dsecrat plugins`: discover and inspect out-of-process plugins. It does not need the engine registry (it reports on the plugins themselves), so its signature is the standard Command(args). The master wires it as (see NOTES.md):

case "plugins":
    return plugin.Command(rest)

Subcommands: list (default) prints discovered plugins; validate exits non-zero if any manifest in the directory is invalid.

func RegisterDir

func RegisterDir(reg *engine.Registry, dir string) error

RegisterDir is the one-call convenience: load dir and register everything it contains into reg. It returns any load warning (skipped manifests) but always registers whatever loaded successfully.

Types

type Host

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

Host is a loaded set of plugins.

func LoadDir

func LoadDir(dir string) (*Host, error)

LoadDir discovers and loads every *.json manifest in dir (non-recursive). It returns a Host with all valid plugins plus an error summarizing any that were skipped, so one bad manifest never hides the good ones. A missing directory is not an error — it yields an empty host (plugins are opt-in).

func (*Host) Plugins

func (h *Host) Plugins() []*Plugin

Plugins returns the loaded plugins in name order.

func (*Host) Register

func (h *Host) Register(reg *engine.Registry)

Register adds every loaded plugin to the registry. The master calls this during integration when a plugin directory is configured (see NOTES.md):

if h, err := plugin.LoadDir(dir); err == nil { h.Register(reg) }

type Manifest

type Manifest struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Version     string   `json:"version,omitempty"`
	Domains     []string `json:"domains,omitempty"`
	// TargetTypes lists the engine target types this plugin handles, e.g.
	// ["dockerfile","filesystem"]. Empty means it handles none (inert).
	TargetTypes []string `json:"target_types,omitempty"`
	// Exec is the argv used to launch the plugin: the command followed by its
	// arguments. It is executed directly (no shell), so nothing is interpolated.
	Exec []string `json:"exec"`
	// TimeoutMS bounds one Analyze call. Zero uses defaultTimeoutMS.
	TimeoutMS int `json:"timeout_ms,omitempty"`
	// contains filtered or unexported fields
}

Manifest declares a plugin's identity and how to launch it. It is plain JSON so a plugin author writes it by hand. Any Exec element containing the token ${dir} has it replaced with the manifest's directory, so a manifest can point at a script shipped alongside it without hard-coding an absolute path.

type Plugin

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

Plugin adapts one manifested executable to the engine.Module interface.

func Load

func Load(path string) (*Plugin, error)

Load reads and validates a single manifest file, returning a Plugin. The plugin's launch argv is resolved (${dir} expanded to the manifest directory) but the executable is not run.

func (*Plugin) Analyze

func (p *Plugin) Analyze(ctx context.Context, t *engine.Target) ([]engine.Finding, error)

Analyze runs the plugin subprocess and projects its findings. Any failure — launch error, timeout, oversized or malformed output, or a plugin-reported error — is returned so the engine records it as a module error; it never panics the run. The plugin's declared name is stamped onto every finding so a plugin cannot impersonate another module.

func (*Plugin) Description

func (p *Plugin) Description() string

func (*Plugin) Domains

func (p *Plugin) Domains() []string

func (*Plugin) Manifest

func (p *Plugin) Manifest() Manifest

func (*Plugin) Name

func (p *Plugin) Name() string

Name, Description, Domains satisfy engine.Module from the manifest.

func (*Plugin) Supports

func (p *Plugin) Supports(tt engine.TargetType) bool

Supports reports whether the plugin declared this target type.

Jump to

Keyboard shortcuts

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