commandrisk

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: 9 Imported by: 0

Documentation

Overview

Package commandrisk analyzes recipe commands for dangerous patterns. It parses a command to an AST and emits deterministic risk signals — it never executes anything and performs no network I/O. Shell commands are parsed with mvdan.cc/sh; Python steps (interpreter "python3") are parsed with gpython, and shell strings passed to os.system / subprocess.* recurse into the shell detectors. The signals feed an OPA policy decision and user-facing risk review; an LLM may later explain them but is never authoritative.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Advisor

type Advisor interface {
	Advise(ctx context.Context, command string, detected Detected) (*LLMAdvice, error)
}

Advisor produces an advisory classification for a command. Implementations must be best-effort: any failure returns (nil, err) and never blocks a run. This is the pluggable seam — an LLM today, a local ONNX/fastText classifier or a honey-trained command-risk model later — without touching callers.

A future trained classifier would map (command, context) to labels such as: read_only, deletes_files, privilege_escalation, network_download_execute, service_restart, cloud_destructive, kubernetes_destructive, prod_sensitive.

type Analysis

type Analysis struct {
	Signals     []RiskSignal `json:"signals"`
	Detected    Detected     `json:"detected"`
	MaxSeverity Severity     `json:"max_severity,omitempty"`
	Critical    bool         `json:"critical"`
	// ParseError is set when the command could not be parsed; this also yields a
	// medium UNPARSEABLE_COMMAND signal rather than a hard failure.
	ParseError string `json:"parse_error,omitempty"`
	// Interpreter is the step's declared interpreter (e.g. "python3", "bash"), or
	// empty for the default shell. It selects the parser and is passed to policy.
	Interpreter string `json:"interpreter,omitempty"`
	// contains filtered or unexported fields
}

Analysis is the deterministic result for one command string.

func Analyze

func Analyze(command string) Analysis

Analyze parses a shell command and returns deterministic risk signals. A parse failure is reported as a medium signal, not an error — the gate treats unparseable commands as suspicious but not hard-denied.

func AnalyzeStep

func AnalyzeStep(command, interpreter string) Analysis

AnalyzeStep analyzes a recipe step's command with the parser matching its interpreter: the default shell (empty) or a shell interpreter uses the mvdan/sh analyzer; python uses the gpython analyzer; any other interpreter is left unparsed (no bogus signals) and deferred to policy. The interpreter is recorded on the result so it can be passed to OPA and shown in reviews.

func (*Analysis) FirstCritical

func (a *Analysis) FirstCritical() *RiskSignal

FirstCritical returns the first critical signal, or nil when none.

type CompleteFunc

type CompleteFunc func(ctx context.Context, system, user, model string, maxTokens int) (string, error)

CompleteFunc is the model-completion dependency (matches aichat.Complete). It is injected so this package stays free of any specific LLM client and is trivially testable with a stub.

type Detected

type Detected struct {
	Commands []string `json:"commands"`
	Flags    []string `json:"flags"`
	Paths    []string `json:"paths"`
}

Detected summarizes the parsed command surface, for policy input and display.

type LLMAdvice

type LLMAdvice struct {
	Risk        Severity `json:"risk"`
	Reasons     []string `json:"reasons"`
	Explanation string   `json:"explanation,omitempty"`
}

LLMAdvice is an advisory risk classification from a model. It augments the deterministic Analysis for explanation/UX only — it is NEVER used in any allow/deny decision. The engine order is: built-in critical → OPA → (advice).

type LLMAdvisor

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

LLMAdvisor classifies command risk via a chat-completion model (e.g. a local Ollama/llama.cpp endpoint through aichat). It is authoritative for nothing.

func NewLLMAdvisor

func NewLLMAdvisor(complete CompleteFunc, model string) *LLMAdvisor

NewLLMAdvisor builds an advisor over the given completion func and model.

func (*LLMAdvisor) Advise

func (a *LLMAdvisor) Advise(ctx context.Context, command string, detected Detected) (*LLMAdvice, error)

Advise asks the model to classify the command. Parsing is defensive: a missing or malformed response yields (nil, err) and must never affect any decision.

type RiskSignal

type RiskSignal struct {
	ID       string   `json:"id"`
	Severity Severity `json:"severity"`
	Command  string   `json:"command,omitempty"`
	Args     []string `json:"args,omitempty"`
	Reason   string   `json:"reason"`
}

RiskSignal is one detected risk in a command.

type Severity

type Severity string

Severity ranks a risk signal. Critical signals are hard-denied by the engine regardless of policy.

const (
	SeverityLow      Severity = "low"
	SeverityMedium   Severity = "medium"
	SeverityHigh     Severity = "high"
	SeverityCritical Severity = "critical"
)

Severity levels, ascending. SeverityCritical triggers a built-in hard deny.

Jump to

Keyboard shortcuts

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