Help us shape the future of Go! Take the 2026 Go Developer Survey

core

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package capkit defines the platform-independent contracts for reusable security capabilities.

The host owns policy: scope, approval, evidence, storage, secrets, audit and rate limiting are injected as ports. Capability kits only depend on this package, never on each other or on a host project.

Index

Constants

View Source
const (
	CodeInvalidInput        = "bad_input"
	CodeScopeDenied         = "scope_denied"
	CodeApprovalRequired    = "approval_required"
	CodeNotFound            = "not_found"
	CodeConflict            = "conflict"
	CodeRateLimited         = "rate_limited"
	CodeUnavailable         = "unavailable"
	CodeInternal            = "internal"
	CodeNeedHuman           = "need_human"
	CodeToolMissing         = "tool_missing"
	CodeTargetUnreachable   = "target_unreachable"
	CodeTimeout             = "timeout"
	CodeUpstreamError       = "upstream_error"
	CodeEvidenceWriteFailed = "evidence_write_failed"
)
View Source
const MaxDataBytes = 8 << 10

MaxDataBytes is the single-call Data ceiling. Oversized payloads are truncated with Truncated=true and the real total reported in Page.Total.

View Source
const MaxListItems = 100

MaxListItems is the list length above which results must paginate.

View Source
const MaxSummaryRunes = 200

MaxSummaryRunes bounds Summary so an agent can read it directly.

Variables

This section is empty.

Functions

func ClampSummary

func ClampSummary(s string) string

ClampSummary trims s to MaxSummaryRunes runes, appending an ellipsis.

func CursorFor

func CursorFor(offset int) string

CursorFor renders the opaque cursor that addresses item offset, for tools to hand back in Page.Cursor.

func FirstNonEmpty

func FirstNonEmpty(vals ...string) string

FirstNonEmpty returns the first value that is not empty after trimming surrounding whitespace.

func FirstPositive

func FirstPositive(v, fallback int) int

FirstPositive returns v when it is positive, otherwise fallback.

func PreviewRunes

func PreviewRunes(s string, n int) string

PreviewRunes returns at most n runes of s, for an EvidenceRef preview (docs §5.5.4: the preview is <=200 characters, and runes — not bytes — are what "characters" means for a Chinese target).

func ProjectIDFrom

func ProjectIDFrom(ctx context.Context) int64

ProjectIDFrom returns the project id, or 0 if unset.

func ShellQuote

func ShellQuote(s string) string

ShellQuote quotes s for POSIX shells when it contains shell metacharacters. Adapters that build a remote command line should use this; adapters that stream arguments directly (execve over SSH) must not.

func TimeoutFromMS

func TimeoutFromMS(ms int, def, max time.Duration) time.Duration

TimeoutFromMS converts a millisecond budget into a duration, falling back to def when the budget is unset and clamping anything larger than max.

func Truncate

func Truncate(s string, n int) string

Truncate cuts s to at most n bytes, appending an ellipsis when it had to.

func WithCallContext

func WithCallContext(ctx context.Context, cc CallContext) context.Context

WithCallContext attaches the caller/task context to a request context. The runtime does this before invoking a capability; gate-aware adapters read it for scope/audit decisions.

Types

type ApprovalRequest

type ApprovalRequest struct {
	Capability string
	Tool       string
	Risk       Risk
	Targets    []Target
	Actor      string
	ProjectID  int64
}

ApprovalRequest is presented to the host before a risky tool runs.

type Approver

type Approver interface {
	Require(ctx context.Context, req ApprovalRequest) error
}

Approver is the human/automated approval gate. The runtime requires it for high-risk tools; returning an error denies the call.

type ArtifactStore

type ArtifactStore interface {
	Put(ctx context.Context, name string, data []byte) (path string, err error)
	Get(ctx context.Context, path string) ([]byte, error)
	Delete(ctx context.Context, path string) error
}

type AuditEvent

type AuditEvent struct {
	TraceID     string    `json:"trace_id"`
	Actor       string    `json:"actor"`
	ProjectID   int64     `json:"project_id"`
	TaskID      string    `json:"task_id,omitempty"`
	Capability  string    `json:"capability"`
	Tool        string    `json:"tool"`
	Risk        Risk      `json:"risk"`
	Targets     []Target  `json:"targets,omitempty"`
	Phase       string    `json:"phase"` // start | finish
	Status      string    `json:"status,omitempty"`
	Error       string    `json:"error,omitempty"`
	InputHash   string    `json:"input_hash,omitempty"`
	DurationMS  int64     `json:"duration_ms,omitempty"`
	EvidenceIDs []string  `json:"evidence_ids,omitempty"`
	StartedAt   time.Time `json:"started_at"`
	FinishedAt  time.Time `json:"finished_at,omitempty"`
}

type AuditSink

type AuditSink interface {
	Record(ctx context.Context, ev AuditEvent)
}

type AuthFlow

type AuthFlow interface {
	Kind() string
	Login(ctx context.Context, creds Credentials) (Identity, error)
}

AuthFlow performs a site-specific login and returns an Identity. The host implements concrete flows (form/json/oauth/cas/bearer); capkit provides helpers for the common steps.

type AuthFlowFunc

type AuthFlowFunc struct {
	KindName string
	Fn       func(ctx context.Context, creds Credentials) (Identity, error)
}

AuthFlowFunc adapts a function to AuthFlow.

func (AuthFlowFunc) Kind

func (f AuthFlowFunc) Kind() string

func (AuthFlowFunc) Login

func (f AuthFlowFunc) Login(ctx context.Context, creds Credentials) (Identity, error)

type BinaryManager

type BinaryManager interface {
	Ensure(ctx context.Context, name, version string) (path string, status BinaryStatus, err error)
	Update(ctx context.Context, name, version string) (BinaryStatus, error)
	Status(ctx context.Context, name string) (BinaryStatus, error)
}

type BinaryStatus

type BinaryStatus struct {
	Installed bool      `json:"installed"`
	Version   string    `json:"version"`
	Path      string    `json:"path"`
	UpdatedAt time.Time `json:"updated_at,omitempty"`
}

type Call

type Call struct {
	Tool    string
	Input   json.RawMessage
	Context CallContext
}

Call is one tool invocation routed by the runtime.

type CallContext

type CallContext struct {
	TraceID   string `json:"trace_id,omitempty"`
	ProjectID int64  `json:"project_id,omitempty"`
	TaskID    string `json:"task_id,omitempty"`
	Actor     string `json:"actor,omitempty"`
	DryRun    bool   `json:"dry_run,omitempty"`
}

CallContext carries the caller identity and task context. It never carries raw credentials; secrets are passed through the Sealer/HTTP ports.

func CallContextFrom

func CallContextFrom(ctx context.Context) (CallContext, bool)

CallContextFrom returns the attached call context.

type Capability

type Capability interface {
	Manifest() Manifest
	Call(ctx context.Context, call Call) (Result, error)
}

Capability is one self-contained capability (http, nuclei, shell, ...). Implementations must be safe for concurrent Call invocations.

type ChainPlanner

type ChainPlanner struct {
	Planners []Planner
}

ChainPlanner merges several planners, deduping by tool name (first planner that suggests a tool wins, so order expresses priority).

func (*ChainPlanner) Add

func (c *ChainPlanner) Add(p Planner)

Add appends a planner (nil is ignored).

func (*ChainPlanner) Suggest

func (c *ChainPlanner) Suggest(ctx context.Context, f Finding) ([]NextStep, error)

type Clock

type Clock interface {
	Now() time.Time
}

type Completer added in v0.5.0

type Completer interface {
	Complete(ctx context.Context, system, user string, maxTokens int) (string, error)
}

Completer is the host-provided single-shot text completion port. Kits hold no model credentials and import no provider SDK: the host maps a request to whichever profile is active and applies its own temperature and token budget. A nil Completer means the host has no model configured, and every generation tool reports "unavailable" instead of failing silently.

type Credentials

type Credentials struct {
	Username string            `json:"username,omitempty"`
	Password string            `json:"password,omitempty"`
	Token    string            `json:"token,omitempty"`
	Cookies  map[string]string `json:"cookies,omitempty"`
	Fields   map[string]string `json:"fields,omitempty"`
	Actor    string            `json:"actor,omitempty"`
}

Credentials is the cleartext credential set handed to an AuthFlow. The host resolves these from the Sealer at the edge; kits never persist them.

type Deps

type Deps struct {
	Scope     ScopeChecker
	Approval  Approver
	Evidence  EvidenceSink
	HTTP      HTTPDoer
	Fetcher   Fetcher
	Limiter   Limiter
	Audit     AuditSink
	Settings  Settings
	Sealer    Sealer
	Logger    Logger
	Clock     Clock
	IDs       IDGenerator
	Processes ProcessRunner
	Artifacts ArtifactStore
	Binaries  BinaryManager

	Fingerprints    FingerprintProvider
	Templates       TemplateCatalog
	TemplateEngines map[string]TemplateEngine
	Sessions        SessionManager

	Intel     IntelStore
	Completer Completer

	// ExtraIntel are advisory sources the host fetches itself and wants polled
	// through the same store and dedup path as the kit's own sources. See
	// IntelSource: this is the seam for sources that need host-specific
	// machinery (a JS engine, an authenticated API, a private feed).
	ExtraIntel []IntelSource
}

Deps is the full set of host-provided ports. Runtime fills defaults for Logger/Clock/IDs; everything else is intentionally explicit.

type Downloader

type Downloader interface {
	Download(ctx context.Context, remote string) (io.ReadCloser, error)
}

Downloader reads a remote path.

type Error

type Error struct {
	Code         string `json:"code"`
	Message      string `json:"message"`
	Retryable    bool   `json:"retryable,omitempty"`
	RetryAfterMS int    `json:"retry_after_ms,omitempty"`
	Hint         string `json:"hint,omitempty"`   // how the agent should fix its input
	Detail       string `json:"detail,omitempty"` // for developers, never fed to the LLM
}

Error is the stable error shape crossing the capability boundary. Hosts map Code to HTTP status / agent error text without parsing messages. The Code set is a fixed enum — never free text (see docs §5.5.3).

func AsError

func AsError(err error) *Error

AsError converts any error into the stable wire shape.

func Conflict

func Conflict(msg string) *Error

func EvidenceWriteFailed

func EvidenceWriteFailed(msg string) *Error

func InvalidInput

func InvalidInput(msg string) *Error

func NeedHuman

func NeedHuman(msg string) *Error

func NewError

func NewError(code, message string) *Error

func NotFound

func NotFound(msg string) *Error

func ScopeDenied

func ScopeDenied(msg string) *Error

func TargetUnreachable

func TargetUnreachable(msg string) *Error

func Timeout

func Timeout(msg string) *Error

func ToolMissing

func ToolMissing(msg string) *Error

func Unavailable

func Unavailable(msg string) *Error

func UpstreamError

func UpstreamError(msg string) *Error

func (*Error) Error

func (e *Error) Error() string

type EventSpec

type EventSpec struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

EventSpec declares an event the host may map to notifications/SSE/webhooks.

type Evidence

type Evidence struct {
	Kind      string            `json:"kind"`
	Title     string            `json:"title"`
	Target    Target            `json:"target"`
	Request   []byte            `json:"request,omitempty"`
	Response  []byte            `json:"response,omitempty"`
	Data      json.RawMessage   `json:"data,omitempty"`
	Metadata  map[string]string `json:"metadata,omitempty"`
	CreatedAt time.Time         `json:"created_at"`
}

Evidence is a portable evidence record. The host decides where to store it (traffic store, object store, DB) and returns its stable ID.

type EvidenceRef

type EvidenceRef struct {
	ID      string `json:"id"`
	Kind    string `json:"kind"` // http_exchange | file | command_output | scan_log
	Size    int    `json:"size"`
	SHA256  string `json:"sha256,omitempty"`
	Preview string `json:"preview,omitempty"` // <=200 chars
}

EvidenceRef points at stored evidence. Full bodies never travel in Data; they live in the evidence store and are referenced by ID.

func EvidenceRefs

func EvidenceRefs(outs ...Output) []EvidenceRef

EvidenceRefs collects one reference per distinct evidence id, in the order the outputs were produced, so a result can point at its stored command output.

type EvidenceSink

type EvidenceSink interface {
	Record(ctx context.Context, ev Evidence) (id string, err error)
}

type ExecOpts

type ExecOpts struct {
	Timeout    time.Duration     `json:"timeout,omitempty"`
	Env        map[string]string `json:"env,omitempty"`
	Dir        string            `json:"dir,omitempty"`
	Stdin      []byte            `json:"stdin,omitempty"`
	Shell      string            `json:"shell,omitempty"` // sh | bash | cmd | powershell
	TTY        bool              `json:"tty,omitempty"`
	MaxOutput  int               `json:"max_output,omitempty"` // bytes; host default if 0
	Background bool              `json:"background,omitempty"`
}

ExecOpts tunes one command. Zero values mean "host default".

type Fetcher

type Fetcher interface {
	Fetch(ctx context.Context, req Request) (*Response, error)
}

Fetcher is the external-data fetch port: rule updates, GitHub search, threat intel and other non-target-scoped downloads. The host still applies proxy, timeout, rate limit and audit policy, but not project target scope.

type Finding

type Finding struct {
	Target      Target   `json:"target"`
	Kind        string   `json:"kind"` // cmdi | sqli | ssti | lfi | ssrf | upload | deser | ...
	Fingerprint string   `json:"fingerprint,omitempty"`
	Confirmed   bool     `json:"confirmed"`
	Payload     string   `json:"payload,omitempty"`
	Evidence    []string `json:"evidence,omitempty"`
	Source      string   `json:"source,omitempty"` // nuclei | exploitkit | yuque-template | manual
}

Finding is a normalized vulnerability conclusion. Fingerprint is a normalized target+kind+param+path key used to dedupe the same issue across sources such as nuclei, exploitkit and yuque templates.

type Fingerprint

type Fingerprint struct {
	Product    string `json:"product"`
	Version    string `json:"version,omitempty"`
	Category   string `json:"category,omitempty"`
	Source     string `json:"source,omitempty"`
	Confidence int    `json:"confidence,omitempty"`
}

Fingerprint is one detected technology. Kits return it; the host decides whether/how to write it into its asset graph.

type FingerprintProvider

type FingerprintProvider interface {
	Fingerprint(ctx context.Context, target Target) ([]Fingerprint, error)
}

FingerprintProvider is implemented by the host or fingerprintkit. verifykit depends only on this interface.

type HTTPDoer

type HTTPDoer interface {
	Do(ctx context.Context, req Request) (*Response, error)
}

HTTPDoer is the only HTTP client a kit may use. The host injects a gate-aware implementation that enforces scope, rate limits and audit.

type IDGenerator

type IDGenerator interface {
	New(prefix string) string
}

type Identity

type Identity interface {
	Headers(ctx context.Context) (http.Header, error)
	Refresh(ctx context.Context) error
	Scope() IdentityScope
}

Identity produces the HTTP headers that authenticate a request to a target.

type IdentityScope

type IdentityScope struct {
	ProjectID int64    `json:"project_id,omitempty"`
	Hosts     []string `json:"hosts,omitempty"`
	User      string   `json:"user,omitempty"`
	Label     string   `json:"label,omitempty"`
}

IdentityScope bounds what an identity may be used for.

type IntelItem added in v0.5.0

type IntelItem struct {
	ID          string   `json:"id,omitempty"`
	Source      string   `json:"source,omitempty"`
	UniqueKey   string   `json:"unique_key"`
	Title       string   `json:"title,omitempty"`
	Description string   `json:"description,omitempty"`
	Severity    string   `json:"severity,omitempty"`
	CVE         string   `json:"cve,omitempty"`
	Disclosure  string   `json:"disclosure,omitempty"`
	Solutions   string   `json:"solutions,omitempty"`
	SourceURL   string   `json:"source_url,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	References  []string `json:"references,omitempty"`
}

IntelItem is one advisory published by a public vulnerability-intel source. The kit owns the protocol; the host owns the schema and the dedup policy, so the only key the kit guarantees is UniqueKey (stable per source).

type IntelQuery added in v0.5.0

type IntelQuery struct {
	Text     string `json:"text,omitempty"`
	CVE      string `json:"cve,omitempty"`
	Severity string `json:"severity,omitempty"`
	Source   string `json:"source,omitempty"`
	Limit    int    `json:"limit,omitempty"`
	Cursor   string `json:"cursor,omitempty"`
}

IntelQuery filters the host's intel store. Empty fields do not filter.

type IntelSource added in v0.5.0

type IntelSource interface {
	Name() string
	Fetch(ctx context.Context, limit int) ([]IntelItem, error)
}

IntelSource is an advisory source the host contributes to the intel kit's poll loop.

It exists because some sources cannot be fetched with a plain HTTP client: they answer every request with an anti-automation page that only a JS runtime can turn into a real URL. Solving that needs a JavaScript engine, which is the wrong dependency for this library — so the host implements the source with whatever it already ships, and the kit polls it alongside its own sources through the same store and dedup path.

Implementations must return normalized items with a stable UniqueKey and a non-empty Source. A failure is reported per source, never as a failed poll.

type IntelStore added in v0.5.0

type IntelStore interface {
	Upsert(ctx context.Context, item IntelItem) (id string, created bool, err error)
	Query(ctx context.Context, q IntelQuery) ([]IntelItem, error)
	Get(ctx context.Context, id string) (*IntelItem, error)
}

IntelStore is the host-owned persistence for vulnerability intel. Kits never open a database: they hand the host normalized items and the host decides how to store, dedupe and version them.

Upsert is idempotent by UniqueKey. It returns the stored record id and whether it was newly created, so a polling kit can report real deltas instead of a raw insert count.

type JobRef

type JobRef struct {
	JobID       string `json:"job_id"`
	PollAfterMS int    `json:"poll_after_ms"`
}

JobRef references a long-running job. Operations over 30s return StatusPartial plus a JobRef and are polled with job_status.

type Limiter

type Limiter interface {
	Acquire(ctx context.Context, key string, spec RateLimitSpec) (release func(), err error)
}

type Logger

type Logger interface {
	Info(msg string, kv ...any)
	Warn(msg string, kv ...any)
	Error(msg string, kv ...any)
}

type Manifest

type Manifest struct {
	Name       string        `json:"name"`
	Version    string        `json:"version"`
	APIVersion string        `json:"api_version"`
	Requires   []string      `json:"requires,omitempty"`
	Tools      []ToolSpec    `json:"tools"`
	Settings   []SettingSpec `json:"settings,omitempty"`
	Events     []EventSpec   `json:"events,omitempty"`
}

Manifest describes a capability. Requires lists port names the host must provide; Registry.Validate enforces them.

func (*Manifest) Validate

func (m *Manifest) Validate() error

Validate checks the static contract.

type Meta

type Meta struct {
	Tool       string   `json:"tool"`
	Version    string   `json:"version,omitempty"`
	DurationMS int64    `json:"duration_ms"`
	Requests   int      `json:"requests,omitempty"`
	Target     string   `json:"target,omitempty"`
	GateTrace  []string `json:"gate_trace,omitempty"`
	Cached     bool     `json:"cached,omitempty"`
}

Meta is the fixed envelope metadata. Requests lets an agent see how much of its request budget it just spent; GateTrace makes "why was it slow" visible.

type NextStep

type NextStep struct {
	Tool          string          `json:"tool"`
	Reason        string          `json:"reason"`
	Preconditions []string        `json:"preconditions,omitempty"`
	Risk          Risk            `json:"risk,omitempty"`
	Params        json.RawMessage `json:"params,omitempty"`
}

NextStep is a suggested follow-up action. It is data, not a command: the agent (or host policy) decides whether to run it.

func DedupeNext

func DedupeNext(groups ...[]NextStep) []NextStep

DedupeNext merges suggestions from several sources into one ordered list, deduping by tool. Convenience for tools that build Next from a finding plus local knowledge.

func SortByRisk

func SortByRisk(steps []NextStep) []NextStep

SortByRisk orders steps by descending risk then tool name (stable output for tests and UIs).

type Output

type Output struct {
	Command    string `json:"command"`
	Stdout     string `json:"stdout,omitempty"`
	Stderr     string `json:"stderr,omitempty"`
	ExitCode   int    `json:"exit_code"`
	DurationMS int64  `json:"duration_ms"`
	Truncated  bool   `json:"truncated,omitempty"`
	// EvidenceID references the stored raw exchange when the host recorded one.
	EvidenceID string `json:"evidence_id,omitempty"`
}

Output is the result of one command.

func OutputFor

func OutputFor(cmd, stdout, stderr string, exit int, dur time.Duration, max int) Output

OutputFor builds an Output with a bounded stdout/stderr, marking Truncated.

type Page

type Page struct {
	Total   int    `json:"total"`
	Cursor  string `json:"cursor,omitempty"`
	HasMore bool   `json:"has_more"`
}

Page describes list pagination. List results exceeding 100 items must paginate and be resumed with Cursor.

func PageWindow

func PageWindow(total int, cursor string, pageSize int) (start, end int, page *Page, err error)

PageWindow resolves a list request into the [start,end) window of a list of total items, plus the Page describing it. Tools whose list can exceed MaxListItems call this so rows are never silently dropped (docs §5.5.4: "列表类结果…超过 100 条必须分页,用 Cursor 续取"). pageSize <= 0 means MaxListItems.

An unusable cursor is an error rather than a silent restart at zero: an agent that paged past the end must be told, not handed the first page again.

type Planner

type Planner interface {
	Suggest(ctx context.Context, f Finding) ([]NextStep, error)
}

Planner turns one Finding into candidate next actions. Hosts and agents read the same suggestions. Kits contribute candidates; capkit defines only the contract (see docs §5.3).

func DefaultPlanner

func DefaultPlanner() Planner

DefaultPlanner is the built-in kind->action table. It only suggests the next step for a CONFIRMED finding (an unconfirmed finding yields nothing), and it names tools that the host may or may not have registered.

type PlannerFunc

type PlannerFunc func(ctx context.Context, f Finding) ([]NextStep, error)

PlannerFunc adapts a function to Planner.

func (PlannerFunc) Suggest

func (f PlannerFunc) Suggest(ctx context.Context, finding Finding) ([]NextStep, error)

type ProcessResult

type ProcessResult struct {
	ExitCode int
	Stdout   []byte
	Stderr   []byte
}

type ProcessRunner

type ProcessRunner interface {
	Run(ctx context.Context, spec ProcessSpec) (*ProcessResult, error)
}

ProcessRunner is the only way a kit may spawn a subprocess. The host injects a gate-aware implementation (scope/rate/audit/env policy).

type ProcessSpec

type ProcessSpec struct {
	Path      string
	Args      []string
	Env       []string
	Dir       string
	Timeout   time.Duration
	Stdin     []byte
	Targets   []Target
	RateLimit RateLimitSpec
}

type RateLimitSpec

type RateLimitSpec struct {
	PerSecond   float64 `json:"per_second,omitempty"`
	Burst       int     `json:"burst,omitempty"`
	Concurrency int     `json:"concurrency,omitempty"`
}

RateLimitSpec is the declared per-key rate budget for a tool.

func (RateLimitSpec) Normalized

func (s RateLimitSpec) Normalized() RateLimitSpec

Normalized fills safe defaults. PerSecond<=0 means "use host default".

type Registry

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

Registry is the single source of truth for capability declarations. It only validates and stores specs; the runtime instantiates them.

func NewRegistry

func NewRegistry() *Registry

func (*Registry) Add

func (r *Registry) Add(spec Spec) error

Add validates and registers one capability spec.

func (*Registry) Specs

func (r *Registry) Specs() []Spec

Specs returns a copy of the registered specs.

func (*Registry) Validate

func (r *Registry) Validate(deps Deps) error

Validate checks that every declared port is available.

type Request

type Request struct {
	Method  string            `json:"method"`
	URL     string            `json:"url"`
	Headers map[string]string `json:"headers,omitempty"`
	Body    []byte            `json:"body,omitempty"`
	Proxy   string            `json:"proxy,omitempty"`
	Timeout time.Duration     `json:"timeout,omitempty"`
}

type Response

type Response struct {
	Status      int                 `json:"status"`
	Headers     map[string][]string `json:"headers,omitempty"`
	Body        []byte              `json:"body,omitempty"`
	Duration    time.Duration       `json:"duration"`
	FinalURL    string              `json:"final_url,omitempty"`
	RequestText string              `json:"request_text,omitempty"`
	RespText    string              `json:"response_text,omitempty"`
}

type Result

type Result struct {
	OK        bool            `json:"ok"`
	Status    Status          `json:"status,omitempty"`
	Summary   string          `json:"summary,omitempty"`
	Data      json.RawMessage `json:"data,omitempty"`
	Findings  []Finding       `json:"findings,omitempty"`
	Evidence  []EvidenceRef   `json:"evidence,omitempty"`
	Next      []NextStep      `json:"next,omitempty"`
	Truncated bool            `json:"truncated,omitempty"`
	Page      *Page           `json:"page,omitempty"`
	Error     *Error          `json:"error,omitempty"`
	Meta      Meta            `json:"meta"`

	// Text is a legacy human-readable convenience retained for compatibility.
	Text string `json:"text,omitempty"`
	// EvidenceIDs are the evidence-store IDs of recorded Evidence entries,
	// mirrored here for hosts written against earlier versions.
	EvidenceIDs []string `json:"evidence_ids,omitempty"`
}

Result is the structured outcome of a tool call. The envelope is the contract agents rely on: Status says what happened, Summary is readable in <=200 chars, Data is a bounded schema-constrained payload, Findings are normalized conclusions, Evidence holds references (never inline bodies), Next lists suggested follow-ups, Meta carries timing/budget trace.

OK stays for wire compatibility with hosts written against earlier versions; it is derived from Status (success/partial => true) and never read for decisions on its own.

func BlockedResult

func BlockedResult(err *Error) Result

BlockedResult is a call stopped by a gate (scope/approval/ratelimit).

func DataResult

func DataResult(v any) (Result, error)

DataResult is a convenience for structured output.

func FailResult

func FailResult(err error) Result

FailResult wraps an error into a Result, mapping the error code to a Status.

func NewResult

func NewResult(status Status, summary string) Result

NewResult builds an envelope with the given status and summary.

func PartialResult

func PartialResult(summary string, data any) (Result, error)

PartialResult is a partly-completed call carrying structured data and, optionally, a job reference for polling.

func SuccessResult

func SuccessResult(summary string, data any) (Result, error)

SuccessResult is a completed call carrying structured data.

func TextResult

func TextResult(text string) Result

TextResult is a convenience for human/agent-readable output.

func (*Result) ClampData

func (r *Result) ClampData()

ClampData enforces the 8KB Data ceiling, replacing oversized payloads with a valid-JSON truncation marker. The real size of the dropped payload is reported in Page.Total so the agent knows how much it did not receive (docs §5.5.4).

func (Result) Normalize

func (r Result) Normalize(tool, version string) Result

Normalize completes the envelope fields a kit owns on every return path, so a tool cannot satisfy the contract on its happy path and violate it on an error path: it fills an unset Status from Error/OK, keeps OK consistent with Status, stamps Meta.Tool and Meta.Version, and clamps Summary.

A kit calls it once, in its Call dispatcher, rather than at each return. It deliberately does not invent a Summary — a generic "完成" tells an agent nothing, so a missing Summary has to surface as a contract failure.

type Risk

type Risk string

Risk is the declared blast radius of a tool. Hosts use it to decide approval and UI affordances; the runtime also enforces a minimum gate.

const (
	RiskLow    Risk = "low"
	RiskMedium Risk = "medium"
	RiskHigh   Risk = "high"
)

func (Risk) AtLeast

func (r Risk) AtLeast(other Risk) bool

AtLeast reports whether r is at least as risky as other.

func (Risk) Valid

func (r Risk) Valid() bool

Valid reports whether r is a known risk level.

type ScopeChecker

type ScopeChecker interface {
	Check(ctx context.Context, target Target) error
}

ScopeChecker is the authorization boundary. Implementations must fail closed: an unknown/unparseable target is denied.

type Sealer

type Sealer interface {
	Seal(plain string) (string, error)
	Open(sealed string) (string, error)
}

Sealer protects secrets at rest. Implementations should use AEAD and a host managed key; kits never see plaintext storage details.

type Session

type Session interface {
	Exec(ctx context.Context, cmd string, opts ExecOpts) (Output, error)
	Info() SessionInfo
	Close() error
}

Session is one established, ready-to-use foothold. Implementations must be safe for concurrent Exec calls unless Info reports otherwise.

type SessionInfo

type SessionInfo struct {
	ID       string            `json:"id"`
	Kind     string            `json:"kind"` // ssh | winrm | smb | webshell | cli | c2
	Host     string            `json:"host,omitempty"`
	Port     int               `json:"port,omitempty"`
	User     string            `json:"user,omitempty"`
	OS       string            `json:"os,omitempty"` // linux | windows
	Arch     string            `json:"arch,omitempty"`
	Elevated bool              `json:"elevated,omitempty"`
	Labels   []string          `json:"labels,omitempty"`
	Meta     map[string]string `json:"meta,omitempty"`
}

SessionInfo describes the foothold without performing I/O.

type SessionManager

type SessionManager interface {
	Open(ctx context.Context, spec SessionSpec) (SessionInfo, error)
	Get(id string) (Session, bool)
	List() []SessionInfo
	Close(id string) error
}

SessionManager is the host-facing port that owns live footholds: it opens sessions through the registered opener for a kind, tracks them by ID, and closes them. Kits (shellkit's session tools, privesc/lat/persist/cleanup) depend only on this port, never on a concrete transport.

type SessionOpener

type SessionOpener interface {
	Open(ctx context.Context, spec SessionSpec) (Session, error)
}

SessionOpener opens a new Session from a spec. Adapters (SSH, WinRM, SMB, CLI, WebShell) implement it; hosts register openers and let agents pick one.

type SessionSpec

type SessionSpec struct {
	Kind     string            `json:"kind"` // ssh | winrm | smb | cli | webshell
	Host     string            `json:"host"`
	Port     int               `json:"port,omitempty"`
	User     string            `json:"user,omitempty"`
	Secret   string            `json:"secret,omitempty"` // password or private key
	KeyPass  string            `json:"key_pass,omitempty"`
	Domain   string            `json:"domain,omitempty"`
	Protocol string            `json:"protocol,omitempty"`
	ProxyURL string            `json:"proxy,omitempty"`
	Timeout  time.Duration     `json:"timeout,omitempty"`
	Labels   []string          `json:"labels,omitempty"`
	Options  map[string]string `json:"options,omitempty"`
}

SessionSpec is a transport-neutral request for a foothold. Secret is passed in cleartext here because the host resolves it from the Sealer at the edge; kits never persist it.

type SettingSpec

type SettingSpec struct {
	Key         string `json:"key"`
	Type        string `json:"type"` // string | bool | int
	Default     any    `json:"default,omitempty"`
	Description string `json:"description,omitempty"`
	Secret      bool   `json:"secret,omitempty"`
}

SettingSpec lets the host render a settings form without kit-specific UI.

type Settings

type Settings interface {
	GetString(ctx context.Context, key string) (string, bool)
	GetBool(ctx context.Context, key string) (bool, bool)
	GetInt(ctx context.Context, key string) (int64, bool)
}

type Spec

type Spec struct {
	Manifest Manifest
	New      func(Deps) (Capability, error)
}

Spec is a static capability declaration: manifest + constructor. It holds no instances and no mutable state.

type Status

type Status string

Status is the six-state outcome of a tool call. Six states exist because an agent's reaction differs per state: blocked means change target or request authorization, need_human means suspend for a human, unavailable means report an environment problem. Collapsing these into OK=false makes agents retry blindly and loop against scope checks.

const (
	StatusSuccess     Status = "success"     // completed, no risk
	StatusPartial     Status = "partial"     // partly done (e.g. some targets timed out)
	StatusFailed      Status = "failed"      // failed, possibly retryable
	StatusBlocked     Status = "blocked"     // stopped by a gate: scope / approval / ratelimit
	StatusNeedHuman   Status = "need_human"  // high-risk action awaiting human confirmation
	StatusUnavailable Status = "unavailable" // dependency missing (e.g. nuclei not installed)
)

func StatusForError

func StatusForError(e *Error) Status

StatusForError maps a stable error code to the agent-facing status. This is the single place the code->status mapping lives.

func (Status) Terminal

func (s Status) Terminal() bool

Terminal reports whether the status is final (no polling needed).

func (Status) Valid

func (s Status) Valid() bool

Valid reports whether s is one of the six defined states.

type Target

type Target struct {
	ProjectID int64      `json:"project_id,omitempty"`
	Kind      TargetKind `json:"kind"`
	URL       string     `json:"url,omitempty"`
	Host      string     `json:"host,omitempty"`
	Port      int        `json:"port,omitempty"`
	IP        string     `json:"ip,omitempty"`
	CIDR      string     `json:"cidr,omitempty"`
}

Target is a normalized, scope-checkable target. Every tool declares how to extract its targets; the runtime validates them before the kit runs.

func TargetFromString

func TargetFromString(projectID int64, raw string) (Target, error)

TargetFromString normalizes a URL, IP, CIDR or hostname.

func TargetFromURL

func TargetFromURL(projectID int64, raw string) (Target, error)

TargetFromURL normalizes an http(s) URL.

func TargetsFromStrings

func TargetsFromStrings(projectID int64, raws []string) ([]Target, error)

TargetsFromStrings normalizes a slice; any invalid target fails the whole set.

func (Target) Key

func (t Target) Key() string

Key is the rate-limit / dedupe key. Hostnames and IPs are kept distinct.

type TargetKind

type TargetKind string

TargetKind is the shape of a target.

const (
	TargetURL    TargetKind = "url"
	TargetHost   TargetKind = "host"
	TargetDomain TargetKind = "domain"
	TargetIP     TargetKind = "ip"
	TargetCIDR   TargetKind = "cidr"
)

type TemplateCatalog

type TemplateCatalog interface {
	Search(ctx context.Context, q TemplateQuery) ([]TemplateRef, error)
	Get(ctx context.Context, id string) (TemplateRef, bool, error)
}

TemplateCatalog is the engine-neutral template index. It never executes.

type TemplateEngine

type TemplateEngine interface {
	Kind() string
	Execute(ctx context.Context, refs []TemplateRef, target Target, opts map[string]any) (Result, error)
}

TemplateEngine executes one kind of template (http, nuclei, shell, chain). Execution scheduling/concurrency belongs to the engine implementation.

type TemplateQuery

type TemplateQuery struct {
	Text        string   `json:"text,omitempty"`
	Products    []string `json:"products,omitempty"`
	Fingerprint string   `json:"fingerprint,omitempty"`
	CVE         string   `json:"cve,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	Severity    []string `json:"severity,omitempty"`
	Kind        string   `json:"kind,omitempty"`
	Limit       int      `json:"limit,omitempty"`
}

TemplateQuery filters a catalog. Empty fields do not filter.

type TemplateRef

type TemplateRef struct {
	ID       string            `json:"id"`
	Name     string            `json:"name,omitempty"`
	Kind     string            `json:"kind"`             // http | nuclei | shell | chain
	Engine   string            `json:"engine,omitempty"` // optional engine hint
	Artifact []byte            `json:"artifact,omitempty"`
	Meta     map[string]string `json:"meta,omitempty"`
}

TemplateRef is an engine-neutral reference to one predefined template.

type TokenSnapshot

type TokenSnapshot struct {
	AccessToken string    `json:"access_token,omitempty"`
	ExpiresAt   time.Time `json:"expires_at,omitempty"`
	IssuedAt    time.Time `json:"issued_at,omitempty"`
}

TokenSnapshot captures a token's lifetime so the refresh decision is data, not guesswork.

func (TokenSnapshot) NeedsRefresh

func (t TokenSnapshot) NeedsRefresh(now time.Time, skew time.Duration) bool

NeedsRefresh reports whether the token should be refreshed at now given a safety skew. A zero ExpiresAt is treated as "no expiry information" and never triggers a refresh on its own.

type ToolSpec

type ToolSpec struct {
	Name         string          `json:"name"`
	Description  string          `json:"description"`
	InputSchema  json.RawMessage `json:"input_schema"`
	OutputSchema json.RawMessage `json:"output_schema,omitempty"`
	Risk         Risk            `json:"risk"`
	RateLimit    RateLimitSpec   `json:"rate_limit,omitempty"`
	// ExtractTargets is mandatory for tools that act on a target. It is a Go
	// function (not serialized); the runtime uses it to enforce scope before
	// the kit is called. Tools without a target return nil.
	ExtractTargets func(json.RawMessage) ([]Target, error) `json:"-"`
}

ToolSpec is the stable tool contract. InputSchema is JSON Schema; the host exposes it to the agent framework verbatim. OutputSchema describes the shape of this tool's Result.Data so agents know the return before calling.

func (*ToolSpec) Validate

func (t *ToolSpec) Validate() error

Validate checks one tool contract.

type Tunnel

type Tunnel interface {
	LocalAddr() string
	Close() error
}

Tunnel is a live tunnel. Callers must Close it.

type TunnelSpec

type TunnelSpec struct {
	Kind       string `json:"kind"` // local | remote | socks
	LocalAddr  string `json:"local_addr,omitempty"`
	RemoteAddr string `json:"remote_addr"`
	Network    string `json:"network,omitempty"` // tcp (default) | udp
}

TunnelSpec describes the tunnel a caller wants.

type Tunneler

type Tunneler interface {
	Tunnel(ctx context.Context, spec TunnelSpec) (Tunnel, error)
}

Tunneler opens a network tunnel through the foothold.

type Uploader

type Uploader interface {
	Upload(ctx context.Context, src io.Reader, remote string) error
}

Uploader writes a stream to a remote path.

Jump to

Keyboard shortcuts

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