Documentation
¶
Overview ¶
Package answers runs plugins on a fetched file and turns their outcomes into what the agent may see: per plugin 1, 0, or no answer with a code from a closed list. Everything else goes to the audit entries.
Index ¶
- Constants
- Variables
- func ExecutePlan(ctx context.Context, p Plan, d Deps) (res Result, ref *Refusal, audit []AuditEntry)
- func Quantize(ctx context.Context, start time.Time, q time.Duration, now func() time.Time) error
- type Answer
- type AuditEntry
- type Code
- type Deps
- type FetchAudit
- type Pin
- type Plan
- type Refusal
- type Result
- type Runner
- func (r *Runner) Answer(ctx context.Context, h workspace.Handle, plugins []string) ([]Answer, []AuditEntry, error)
- func (r *Runner) AnswerPinned(ctx context.Context, h workspace.Handle, plugins []string, pins map[string]Pin) ([]Answer, []AuditEntry, error)
- func (r *Runner) Used(h workspace.Handle) int
Constants ¶
const DefaultMaxPerHandle = 16
DefaultMaxPerHandle bounds the answers disclosed about one fetched file.
const DefaultQuantum = 5 * time.Second
DefaultQuantum is the step at which plan results are released.
const WarningUnofficial = "unofficial_marketplace"
WarningUnofficial marks an answer from a plugin of an unofficial marketplace.
Variables ¶
var Codes = []Code{ CodePluginError, CodeFetchFailed, CodeKeyOutsidePrefix, CodeUnknownProfile, CodeTooManyPlugins, CodePluginNotInstalled, CodePluginTampered, CodePluginYanked, CodeSandboxUnavailable, CodeProcNotHidden, CodeApprovalDenied, CodeApprovalTimeout, CodeHandleExpired, CodeStale, }
Codes is the closed list.
var ErrTooManyPlugins = errors.New("too_many_plugins")
ErrTooManyPlugins refuses a request that would take a handle above its answer budget. Its text is the agent code.
Functions ¶
func ExecutePlan ¶
func ExecutePlan(ctx context.Context, p Plan, d Deps) (res Result, ref *Refusal, audit []AuditEntry)
ExecutePlan fetches (unless the plan names a handle), runs the plugins and releases the outcome at the next quantum. Every failure maps to a Code; causes go to the audit entries.
Types ¶
type Answer ¶
type Answer struct {
Plugin string `json:"plugin"`
Version string `json:"version"`
Official bool `json:"official"`
Result *int `json:"result"`
Error string `json:"error,omitempty"`
Warning string `json:"warning,omitempty"`
}
Answer is one plugin's answer as the agent sees it.
type AuditEntry ¶
type AuditEntry struct {
Plugin string
Version string
BinarySHA256 string
Result *int
Cause pluginspec.FailureCause
Report sandbox.Report
ConsoleError string
// Fetch is set on the entry that records a plan's fetch.
Fetch *FetchAudit
}
AuditEntry is what the audit keeps about one plugin run.
type Code ¶
type Code string
Code is an agent-visible error or refusal code. The list is closed (docs/security-model.md): nothing else about a request or a file reaches the agent.
const ( CodePluginError Code = "plugin_error" CodeFetchFailed Code = "fetch_failed" CodeKeyOutsidePrefix Code = "key_outside_prefix" CodeUnknownProfile Code = "unknown_profile" CodeTooManyPlugins Code = "too_many_plugins" CodePluginNotInstalled Code = "plugin_not_installed" CodePluginTampered Code = "plugin_tampered" CodePluginYanked Code = "plugin_yanked" CodeProcNotHidden Code = "proc_not_hidden" CodeApprovalDenied Code = "approval_denied" CodeApprovalTimeout Code = "approval_timeout" CodeHandleExpired Code = "handle_expired" // CodeStale: the fetched bytes are not the ones the plan was approved // on (their sha256 differs); no plugin ran on them. CodeStale Code = "stale" )
type FetchAudit ¶
FetchAudit is what the audit keeps about the fetch of a plan.
type Pin ¶ added in v0.3.0
Pin is what the human approved of a plugin: the lock entry the runner opens must still be this one.
type Plan ¶
type Plan struct {
Profile string
Key string
Handle workspace.Handle
Plugins []string
// Pins, when set, are the approved versions and hashes per plugin: a
// plugin whose opened lock entry differs (updated or reinstalled since
// the plan was approved) does not run and answers plugin_tampered.
Pins map[string]Pin
// SHA256, when set, is the hex sha256 of the bytes the plan was
// approved on. The fetch spools the object into the workspace and
// hashes the bytes it writes; when they differ the spool is released
// before any plugin runs, and the plan is refused stale. The plugins
// read only the spool: the bytes they answer on are the hashed ones.
// A follow-up on a handle is not checked: its spool does not change.
SHA256 string
}
Plan is a request: a fetch of Key from Profile, or (Handle set) a follow-up on an already fetched file, and the plugins to run.
type Refusal ¶
type Refusal struct {
Code Code `json:"refusal"`
}
Refusal is a plan that gave no answers. It holds a Code only: it is never built from an error's text.
type Runner ¶
type Runner struct {
WS *workspace.Manager
Store plugin.Store
Run func(context.Context, sandbox.Spec) (pluginspec.Outcome, sandbox.Report, error)
MaxPerHandle int
// contains filtered or unexported fields
}
func (*Runner) Answer ¶
func (r *Runner) Answer(ctx context.Context, h workspace.Handle, plugins []string) ([]Answer, []AuditEntry, error)
Answer runs plugins, in order, each on a fresh read-only open of h's file, and returns all answers once every plugin has finished. Every requested plugin counts against the handle's budget, answered or not. The error is ErrTooManyPlugins, a workspace error (expired or unknown handle) or ctx's; nothing is returned with it.
func (*Runner) AnswerPinned ¶ added in v0.3.0
func (r *Runner) AnswerPinned(ctx context.Context, h workspace.Handle, plugins []string, pins map[string]Pin) ([]Answer, []AuditEntry, error)
AnswerPinned is Answer with pins: when pins is not nil, a plugin runs only if the entry its binary was opened (and hashed) from matches its pin; a plugin without a pin, or with another version or hash, answers plugin_tampered without running. The check is made on the opened file, so a plugin update between the approval and the run cannot slip in.