mcp

package
v0.136.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Overview

Package mcp exposes Draugr to AI coding agents over the Model Context Protocol.

The reason this exists is narrower than "agents are popular". An agent asked to check a change for security problems will do it one way or another: if Draugr isn't callable it improvises, shells out to whatever scanner it can find, picks its own scope, and reads raw tool output in its own context window. That improvised answer has no recorded scope, no organizational risk context, and no relationship to what CI will decide. Being callable is what makes the agent's answer and the pipeline's answer the same answer.

Two design rules follow from that:

  • **Consent follows the effects.** A scan that reads a local copy is what a user asks an assistant for most often, and it runs on the client's own tool approval. A scan whose scanners declare an effect beyond reading, or whose report leaves the machine, asks the user first, naming each effect and destination. Everything else is safe to call freely.
  • **Return decisions, not data.** A tool that hands back raw scanner output has moved the problem into the agent's context window rather than solving it. These tools return prioritized, deduplicated, normalized results, the same thing a person sees.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ListSurveyorsTool added in v0.98.0

func ListSurveyorsTool(reg *surveyor.Registry) mcp.ToolHandlerFor[struct{}, ListSurveyorsOutput]

ListSurveyorsTool names the surveyors this build has.

From the registry rather than a list written here, so a surveyor added to Draugr is reachable without anyone remembering to mention it in two places.

func NewServer

func NewServer(opts Options) (*mcp.Server, error)

NewServer builds the MCP server. Tools are registered here rather than discovered so the exposed surface is a deliberate, reviewable list.

func ProposeSagaTool added in v0.135.0

func ProposeSagaTool(root string) mcp.ToolHandlerFor[ProposeInput, ProposeOutput]

ProposeSagaTool reads a directory and returns the descriptor `draugr init` would write for it.

It returns the descriptor rather than writing one, for the reason survey does: a tool that writes a file has to ask first, and whether a project wants a descriptor, and where, belongs to whoever owns it. The scaffold is the one `draugr init` writes, from the same package, so the assistant and the CLI never propose two different descriptors for one tree.

func SurveyTool added in v0.98.0

SurveyTool discovers a surface and returns a descriptor for it.

It returns the descriptor rather than writing one. A tool that writes a file is a tool that has to ask first, and merging into an existing descriptor carries decisions. Which exposure wins, what a narrower scope means. That belong with the person who owns the file. Handing back YAML lets an assistant show it, validate it with validate_saga, and let a human decide where it goes.

Writing a descriptor by hand from get_saga_schema is the alternative, and it is guesswork about a live system: which namespaces exist, which images are actually running, at which digest.

Types

type Accepted added in v0.135.0

type Accepted struct {
	RuleID           string `json:"ruleId"`
	Severity         string `json:"severity"`
	Location         string `json:"location,omitempty"`
	Component        string `json:"component,omitempty"`
	Package          string `json:"package,omitempty"`
	Version          string `json:"version,omitempty"`
	Justification    string `json:"justification" jsonschema:"the reason recorded with the decision"`
	AcceptedBy       string `json:"acceptedBy,omitempty" jsonschema:"who accepted it; empty means the decision is unattributed"`
	Expires          string `json:"expires,omitempty" jsonschema:"YYYY-MM-DD the acceptance lapses; empty means it does not"`
	Origin           string `` /* 167-byte string literal not displayed */
	Author           string `json:"author,omitempty" jsonschema:"who made an imported VEX statement"`
	Asserted         string `json:"asserted,omitempty" jsonschema:"when an imported VEX statement was made"`
	Source           string `json:"source,omitempty" jsonschema:"the descriptor, fragment or VEX document the decision was written in"`
	VEXStatus        string `json:"vexStatus,omitempty" jsonschema:"not_affected, affected or fixed; empty reads as affected"`
	VEXJustification string `json:"vexJustification,omitempty" jsonschema:"why the product is not affected, from VEX's fixed vocabulary"`
}

Accepted is a finding a recorded decision took out of the ranking, with the decision.

Returned beside the findings rather than among them: an accepted risk handed back as work is one an assistant proposes to fix against the owner's decision. Returned at all because a count on its own cannot answer who decided, why, or until when, and those are the questions.

type CheckToolsInput added in v0.39.0

type CheckToolsInput struct {
	Path string `json:"path,omitempty" jsonschema:"path to a Saga descriptor; without it, every tool Draugr knows about is checked"`
}

CheckToolsInput optionally narrows the check to what one descriptor actually needs.

type CheckToolsOutput added in v0.39.0

type CheckToolsOutput struct {
	Ready   bool         `json:"ready" jsonschema:"true when nothing required is missing"`
	Tools   []ToolStatus `json:"tools"`
	Missing []string     `json:"missing,omitempty" jsonschema:"required tools that are absent"`
	// Remedy is the single command that installs everything missing.
	Remedy string `json:"remedy,omitempty"`
	Note   string `json:"note"`
}

CheckToolsOutput is the answer to "can Draugr actually scan here?".

func CheckToolsTool added in v0.39.0

CheckToolsTool reports which external scanners are present.

This exists because of what Draugr does when one is missing: the control can't run, and a scan that can't run is not a pass. An assistant that hits that needs to say what's wrong and what fixes it. Which is a question about the machine, and answering it is free.

It deliberately stops there. Draugr will not install anything on a user's behalf over MCP: that's a write to their machine, and their client already has a permission model for running commands which is stronger than anything this server could offer. Report the command; let the person approve it where they already approve such things.

type Control

type Control struct {
	Name            string   `json:"name" jsonschema:"the control's name, as used under config.controls in a Saga"`
	Scope           string   `json:"scope" jsonschema:"whether the control runs per component or once for the project"`
	Purpose         string   `json:"purpose" jsonschema:"what the control checks for"`
	DefaultScanners []string `json:"defaultScanners" jsonschema:"scanners that run when the control is enabled"`
	OptInScanners   []string `` /* 134-byte string literal not displayed */
	// ScannerOptions is what each of this control's scanners accepts in its Saga block, keyed by
	// scanner name. An entry present but empty means that scanner accepts no options; anything
	// else written under its block is rejected before the scan runs.
	ScannerOptions map[string][]plugin.Option `` /* 151-byte string literal not displayed */
}

Control is one control an agent could enable.

type ControlsOutput

type ControlsOutput struct {
	Controls []Control `json:"controls"`
	// Hint is where the agent should put what it learned. Returning capability without saying
	// how to use it just moves the guesswork somewhere else.
	Hint string `json:"hint"`
}

ControlsOutput is the list_controls result.

func ListControls

func ListControls(reg *engine.Registry) ControlsOutput

ListControls reports the controls this build registers.

type Counts

type Counts struct {
	Critical int `json:"critical"`
	High     int `json:"high"`
	Medium   int `json:"medium"`
	Low      int `json:"low"`
}

Counts tallies the whole report, not just what was returned. A narrowed list shouldn't make the rest of the backlog look like it vanished.

type DiffInput added in v0.98.0

type DiffInput struct {
	BasePath string `json:"basePath" jsonschema:"path to the results.sarif from the base revision"`
	HeadPath string `json:"headPath" jsonschema:"path to the results.sarif from the revision being proposed"`
	// FailOnNew mirrors the flag CI uses, so an assistant can ask the question the pipeline
	// will ask rather than a different one.
	FailOnNew string `` /* 261-byte string literal not displayed */
	Limit     int    `json:"limit,omitempty" jsonschema:"maximum new findings to return; defaults to 20"`
}

DiffInput compares two reports.

type DiffOutput added in v0.98.0

type DiffOutput struct {
	NewCount   int `json:"newCount" jsonschema:"findings present in head and absent from base"`
	FixedCount int `json:"fixedCount" jsonschema:"findings present in base and absent from head"`
	// New is what the change introduced, most urgent first, carrying the same remediation and
	// package detail a summary does.
	New []Finding `json:"new,omitempty"`
	// Fixed is named rather than only counted, because it is the half of a change worth saying
	// out loud and an assistant summarizing a diff has nothing else to praise.
	Fixed []Finding `json:"fixed,omitempty"`
	// WouldFail answers the question CI will ask, when failOnNew is given.
	WouldFail   bool   `json:"wouldFail,omitempty" jsonschema:"true when a new finding meets failOnNew; only meaningful when failOnNew was given"`
	GateApplied string `json:"gateApplied,omitempty" jsonschema:"the threshold wouldFail was computed against"`
	Note        string `json:"note,omitempty"`
}

DiffOutput says what a change introduced and what it resolved.

func DiffReportsTool added in v0.98.0

DiffReportsTool compares two scans and reports what the change introduced.

The question in a coding session is almost never "what is wrong with this repository". It is "did what I just wrote make it worse". A project with two hundred inherited findings answers the first question the same way before and after a change, which tells an assistant nothing about the change. This is the same comparison `draugr diff` makes, so the answer an assistant gives and the answer the pull request gate gives cannot differ.

type EmptyInput

type EmptyInput struct{}

EmptyInput is the argument type for tools that take none. The SDK derives a schema from the input type, and an empty struct is how you say "no arguments" rather than "any arguments".

type Escalation added in v0.135.0

type Escalation struct {
	From   string `json:"from" jsonschema:"the severity the scanner reported"`
	To     string `json:"to" jsonschema:"the severity the finding was ranked at"`
	Signal string `json:"signal" jsonschema:"kev (observed exploitation) or epss (predicted probability of exploitation)"`
	Detail string `json:"detail"`
	AsOf   string `json:"asOf,omitempty" jsonschema:"the day the dataset was obtained, YYYY-MM-DD"`
}

Escalation is an exploitability signal that raised a finding's severity.

type ExplainInput added in v0.98.0

type ExplainInput struct {
	RuleID string `json:"ruleId" jsonschema:"the rule to explain, in full or by the part that is unambiguous: 4.3.1 finds kube-bench/cis/4.3.1"`
	Path   string `json:"path" jsonschema:"path to a results.sarif produced by draugr scan"`
}

ExplainInput asks what a rule means and how to fix it.

type ExplainOutput added in v0.98.0

type ExplainOutput struct {
	RuleID      string   `json:"ruleId"`
	Description string   `json:"description,omitempty" jsonschema:"what the check is, in full rather than the truncated line a report shows"`
	Remediation string   `json:"remediation,omitempty" jsonschema:"how to fix it, as the scanner published it"`
	HelpURI     string   `json:"helpUri,omitempty"`
	FoundIn     []string `json:"foundIn,omitempty" jsonschema:"where this rule fired, capped"`
	Note        string   `json:"note,omitempty"`
}

ExplainOutput is what the scan already recorded about a rule.

func ExplainRuleTool added in v0.98.0

ExplainRuleTool answers what a finding means and what to change.

A rule id and a truncated line is enough to rank a finding and not enough to decide anything. The answer is already in the report: scanners publish remediation text and Draugr records it. Without this an assistant is left to fetch a help URI, a network round trip for text on disk, and for a benchmark a registration form in front of a PDF, which is not an answer at all.

type Feed added in v0.135.0

type Feed struct {
	Signal    string  `json:"signal" jsonschema:"kev or epss"`
	AsOf      string  `json:"asOf,omitempty" jsonschema:"the day the copy was obtained, YYYY-MM-DD; empty for a file supplied by hand"`
	Stale     bool    `json:"stale,omitempty" jsonschema:"the copy was older than the scan's maxAge when it was read"`
	Entries   int     `json:"entries,omitempty"`
	Threshold float64 `json:"threshold,omitempty" jsonschema:"the EPSS probability at or above which a finding was raised"`
}

Feed is an exploitability dataset the scan had loaded.

type FeedStatus added in v0.135.0

type FeedStatus struct {
	Name        string `json:"name" jsonschema:"the feed, as named to draugr feeds update"`
	Description string `json:"description"`
	Cached      bool   `json:"cached"`
	FetchedAt   string `json:"fetchedAt,omitempty" jsonschema:"when Draugr fetched the cached copy, RFC 3339 in UTC"`
	Age         string `json:"age,omitempty" jsonschema:"how long ago the cached copy was fetched, rounded for reading"`
	AgeSeconds  int64  `json:"ageSeconds,omitempty"`
	Stale       bool   `json:"stale" jsonschema:"true when the cached copy is older than maxAge"`
	Source      string `json:"source" jsonschema:"the URL the feed is fetched from"`
	Bytes       int64  `json:"bytes,omitempty" jsonschema:"size of the cached copy on disk, decompressed"`
	Size        string `json:"size,omitempty" jsonschema:"size of the cached copy, rounded for reading"`
	SHA256      string `json:"sha256,omitempty" jsonschema:"digest of the cached copy, recorded when it was fetched"`
	// IfStale is stated for every feed, cached or not, because the consequence differs by feed:
	// an exploitability feed past its age is still read, and the Go database is not.
	IfStale string `json:"ifStale" jsonschema:"what a scan does with this feed once its copy is stale"`
}

FeedStatus is one cached dataset a scan reads without the network.

type FeedsStatusOutput added in v0.135.0

type FeedsStatusOutput struct {
	Dir     string       `json:"dir" jsonschema:"the feed cache directory"`
	MaxAge  string       `` /* 133-byte string literal not displayed */
	Feeds   []FeedStatus `json:"feeds"`
	Missing []string     `json:"missing,omitempty" jsonschema:"feeds with no cached copy"`
	Stale   []string     `json:"stale,omitempty" jsonschema:"feeds whose cached copy is older than maxAge"`
	// Next is the command a person would run. Draugr will not run it for you.
	Next string `` /* 131-byte string literal not displayed */
	Note string `json:"note"`
}

FeedsStatusOutput is the answer to "what is this machine's scan reading, and how old is it?".

func FeedsStatus added in v0.135.0

func FeedsStatus(dir string, now time.Time) FeedsStatusOutput

FeedsStatus reports the cache in dir as of now. It never fails: an empty cache is a legitimate state, and every feed is then missing rather than the call being an error.

func FeedsStatusTool added in v0.135.0

FeedsStatusTool reports what the feed cache holds, the same answer as `draugr feeds status`.

It stops short of `draugr feeds update`, for the reason check_tools stops short of installing: a fetch reaches the network and writes to the user's home directory, and their client already has a permission model for running commands. The tool names the command and leaves the running to the person who approves such things.

type Finding

type Finding struct {
	Priority string  `json:"priority,omitempty" jsonschema:"P1 (act now) through P4 (lowest)"`
	Severity string  `json:"severity" jsonschema:"critical, high, medium or low"`
	Score    float64 `json:"score,omitempty" jsonschema:"CVSS-style numeric severity, when the scanner gave one"`
	RuleID   string  `json:"ruleId"`
	Scanner  string  `json:"scanner,omitempty"`
	Location string  `json:"location,omitempty" jsonschema:"file:line, image reference, or endpoint"`
	Message  string  `json:"message"`
	HelpURI  string  `json:"helpUri,omitempty" jsonschema:"where the rule is documented, for background beyond the remediation below"`

	// Remediation is the fix in the scanner's own words, not a summary of it.
	Remediation string `` /* 137-byte string literal not displayed */
	// Action classifies what kind of fix it is, so an assistant can tell work it can do from
	// work that belongs to whoever publishes the image or operates the cluster.
	Action string `` /* 217-byte string literal not displayed */
	// Package names what to upgrade and to what.
	Package      string `json:"package,omitempty" jsonschema:"the package this finding is in"`
	Version      string `json:"version,omitempty" jsonschema:"the version installed"`
	FixedVersion string `` /* 153-byte string literal not displayed */
	Ecosystem    string `` /* 139-byte string literal not displayed */
	PURL         string `json:"purl,omitempty" jsonschema:"package URL, portable across ecosystems"`
	// Component ties a finding to the part of the system it was found in, which is what its
	// priority was computed from.
	Component string `json:"component,omitempty" jsonschema:"the component in the descriptor this finding belongs to"`
	// Image and OSEndOfLife answer "why can I not just upgrade this".
	Image       string `json:"image,omitempty" jsonschema:"the image this finding is in, when it came from one"`
	OSEndOfLife bool   `` /* 134-byte string literal not displayed */

	// The evidence behind the rank, as fields rather than a sentence, so an assistant asked "why is
	// this P1" or "can we even reach it" answers from what Draugr decided rather than guessing.
	Reachability *Reachability `` /* 132-byte string literal not displayed */
	Escalation   *Escalation   `json:"escalation,omitempty" jsonschema:"the exploitability signal that raised this finding's severity, when one did"`
	AlsoFoundBy  []string      `json:"alsoFoundBy,omitempty" jsonschema:"other scanners that reported the same flaw; counted once, under this finding"`
}

Finding is one prioritized result, flattened to what a reader needs to act.

type FixListInput added in v0.98.0

type FixListInput struct {
	Path  string `json:"path" jsonschema:"path to a results.sarif produced by draugr scan"`
	Limit int    `json:"limit,omitempty" jsonschema:"maximum actions to return; defaults to 20"`
}

FixListInput asks what to do about a report.

type FixListOutput added in v0.98.0

type FixListOutput struct {
	Actions []report.Action `json:"actions" jsonschema:"things to do, most urgent first; each says how many findings it clears"`
	Clears  int             `json:"clears" jsonschema:"findings these actions resolve between them"`
	Note    string          `json:"note,omitempty"`
}

FixListOutput is the work a report implies, rather than the findings in it.

func FixListTool added in v0.98.0

FixListTool answers "what should I do" with actions rather than findings.

One remediation usually clears many findings: eight vulnerabilities in one library are one upgrade, and every package inside an image somebody else publishes is one newer image. An assistant handed the findings has to work that out for itself, and will do it differently each time, so this uses the same grouping the terminal prints, and the two cannot disagree.

type ListSurveyorsOutput added in v0.98.0

type ListSurveyorsOutput struct {
	Surveyors []SurveyorInfo `json:"surveyors"`
	Hint      string         `json:"hint"`
}

ListSurveyorsOutput names what can be discovered.

type Options

type Options struct {
	// Scan says whether a client may start scans. The zero value is ScanOff; `draugr mcp` passes
	// ScanEffects.
	Scan ScanMode
	// Registry supplies the controllers and scanners. Required.
	Registry *engine.Registry
	// Root is the directory searched for Saga descriptors to expose as resources. Empty means
	// the working directory.
	Root string
	// Surveyors supplies the discovery plugins. Empty disables survey and list_surveyors, so a
	// caller embedding this server chooses whether it may reach a cluster or a forge at all.
	Surveyors *surveyor.Registry
}

Options configures the server's exposed surface.

type ProposeInput added in v0.135.0

type ProposeInput struct {
	Path string `` /* 169-byte string literal not displayed */
	// PerDirectory is `draugr init --per-directory`.
	PerDirectory bool `` /* 152-byte string literal not displayed */
}

ProposeInput names the directory to propose a descriptor for.

type ProposeOutput added in v0.135.0

type ProposeOutput struct {
	// Saga is the descriptor as YAML, byte for byte what `draugr init` would write.
	Saga string `` /* 155-byte string literal not displayed */
	// Path is where the descriptor belongs: its repositories are written relative to it.
	Path string `json:"path" jsonschema:"the file to save the descriptor as; its repository URLs are relative to this directory"`
	// Components and Controls describe what the proposal asks for without parsing it.
	Components []string `json:"components,omitempty"`
	Controls   []string `json:"controls,omitempty"`
	// Existing names the descriptors already in the directory. `draugr init` refuses to overwrite
	// one, and a proposal handed back beside an existing file reads as a replacement for it unless
	// something says the file is there.
	Existing []string `` /* 145-byte string literal not displayed */
	Note     string   `json:"note,omitempty"`
	Warning  string   `json:"warning,omitempty"`
}

ProposeOutput is a descriptor to look at, the same shape survey returns.

type Reachability added in v0.135.0

type Reachability struct {
	State    string   `json:"state" jsonschema:"reachable, unreachable, or unknown (the analyzer ran and could not tell)"`
	Analyzer string   `json:"analyzer" jsonschema:"the tool that decided"`
	Method   string   `json:"method,omitempty" jsonschema:"how it decided, for example symbol-level call graph"`
	RankedAs string   `json:"rankedAs,omitempty" jsonschema:"the severity the finding was ranked at after reachability was applied, when it moved"`
	Symbols  []string `json:"symbols,omitempty" jsonschema:"the vulnerable functions the analyzer looked for"`
	Path     []string `json:"path,omitempty" jsonschema:"one call path from this project's code to a vulnerable function, outermost first"`
}

Reachability is a reachability analyzer's verdict on one dependency finding.

type ScanInput

type ScanInput struct {
	Path        string `json:"path" jsonschema:"path to the Saga descriptor to scan"`
	MinPriority string `json:"minPriority,omitempty" jsonschema:"only return findings at this priority or above: p1, p2, p3 or p4"`
	Limit       int    `json:"limit,omitempty" jsonschema:"maximum findings to return; defaults to 20"`
}

ScanInput selects what to scan.

type ScanMode

type ScanMode string

ScanMode says whether, and on what terms, a client may start a scan.

const (
	// ScanEffects registers it and asks the user only when the planned scan does more than read a
	// local copy: a scanner declaring an effect, or a publisher delivering off this machine. The
	// default for `draugr mcp`. Secrets, SAST, SCA, IaC and licenses over a checkout declare no
	// effect, so the scans asked for most run on the client's own tool approval, and the prompt is
	// kept for the ones that touch something outside the machine.
	ScanEffects ScanMode = "effects"
	// ScanOff doesn't register the tool at all. The zero value of Options, so a caller that
	// builds one without naming a mode gets no scanning.
	ScanOff ScanMode = "off"
	// ScanAsk registers it and asks the user to approve each call, through the client, whatever the
	// scan does. Like ScanEffects, it needs a client that implements elicitation to ask at all.
	ScanAsk ScanMode = "ask"
	// ScanAlways registers it and runs without asking. Right for a sandbox or CI, where there's
	// nobody to ask.
	ScanAlways ScanMode = "always"
)

The scan modes. A scan clones repositories, executes external tools and reaches the network, so the question isn't only "may it" but "who agrees to it, and when".

func ParseScanMode

func ParseScanMode(s string) (ScanMode, error)

ParseScanMode validates a mode name.

type ScanOutput

type ScanOutput struct {
	Verdict string `json:"verdict" jsonschema:"pass or fail, by the same policy the CI gate applies"`
	// Controls that actually ran, so the caller can see the scope rather than infer it.
	Controls []string `json:"controls" jsonschema:"the controls this scan ran; nothing outside them was examined"`
	// Uncovered names surfaces the descriptor declares that no enabled control looked at.
	Uncovered []string `json:"uncovered,omitempty" jsonschema:"surfaces this descriptor declares that no enabled control examined"`
	// Unread names the dependency files in scope that no scanner took packages from, and the
	// Terraform files calling a module no scanner loaded.
	Unread []UnreadFile `` /* 174-byte string literal not displayed */
	// Unexamined is the same sentence for everything no control covers at all.
	Unexamined string `json:"unexamined" jsonschema:"what a Draugr scan does not examine, whatever the verdict"`
	// Delivered names where the descriptor's publishers put the report, so a caller can point
	// the user at a file, or read it back later instead of scanning again.
	Delivered []string `json:"delivered,omitempty" jsonschema:"where this run's reports were delivered, from the descriptor's config.publishers"`
	SummarizeOutput
}

ScanOutput is the verdict plus the ranked findings behind it, and the boundary of what it describes.

Scope is not decoration. A verdict arriving on its own reads as the answer to whatever question prompted the scan, and the question is usually broader than the one Draugr answers: an assistant asked whether a repository is safe to ship, handed a PASS, has every reason to stop. Naming the controls that ran and the surfaces nothing looked at makes the floor visible as a floor.

type SchemaOutput

type SchemaOutput struct {
	Schema  map[string]any `json:"schema" jsonschema:"the JSON Schema for a Saga descriptor"`
	Version string         `json:"draugrVersion" jsonschema:"the Draugr build this schema came from"`
	Hint    string         `json:"hint"`
}

SchemaOutput carries the descriptor's JSON Schema.

Schema is a decoded object rather than raw bytes so a client receives the schema itself: MCP validates a tool's output against the schema derived from this type, and a []byte field derives as an array, which the schema document then fails to be.

func GetSchema

func GetSchema() (SchemaOutput, error)

GetSchema returns the schema embedded in this binary. The one that will actually be enforced, as opposed to whatever is published on the web for some other version.

type SummarizeInput

type SummarizeInput struct {
	Path string `json:"path" jsonschema:"path to the results.sarif draugr scan wrote; report.json beside it holds the verdict and no findings"`
	// MinPriority narrows the list the way --min-priority does on the CLI.
	MinPriority string `json:"minPriority,omitempty" jsonschema:"only return findings at this priority or above: p1, p2, p3 or p4"`
	// Limit caps how many findings come back. Context is the scarce resource here.
	Limit int `json:"limit,omitempty" jsonschema:"maximum findings to return; defaults to 20"`
}

SummarizeInput points at a report already on disk.

type SummarizeOutput

type SummarizeOutput struct {
	Total int `json:"total" jsonschema:"findings the report judged, before any priority filter; excludes suppressed"`
	// Suppressed is reported rather than hidden: an assistant that cannot see a decision was
	// made cannot tell an accepted risk from one nobody has looked at.
	Suppressed int        `json:"suppressed,omitempty" jsonschema:"findings a recorded decision took out of the ranking; not part of total"`
	Returned   int        `json:"returned"`
	Counts     Counts     `json:"counts"`
	Findings   []Finding  `json:"findings"`
	Accepted   []Accepted `` /* 172-byte string literal not displayed */
	// Feeds is empty when no exploitability data was loaded, which is the answer to "was this
	// checked against KEV" and not an omission.
	Feeds []Feed `` /* 135-byte string literal not displayed */
	Next  string `json:"next" jsonschema:"what to do with this result"`
	Note  string `json:"note,omitempty"`
}

SummarizeOutput is the ranked answer to "what should I fix?".

func SummarizeReportTool

SummarizeReportTool reads a report from disk and returns it ranked.

type SurveyInput added in v0.98.0

type SurveyInput struct {
	// Surveys is a list because an application is rarely one surface. The repositories in an
	// organization and the images running in a namespace are the same application described twice,
	// and merging them into one descriptor is the point. Running them separately gives two
	// descriptors that each look complete.
	Surveys []SurveyRequest `json:"surveys" jsonschema:"the surveyors to run; results merge into one descriptor"`
	Name    string          `json:"name,omitempty" jsonschema:"project name for the descriptor"`
	Version string          `json:"version,omitempty" jsonschema:"release version for the descriptor; omitted when empty"`
}

SurveyInput asks one or more surveyors what is out there.

type SurveyOutput added in v0.98.0

type SurveyOutput struct {
	// Saga is the descriptor as YAML, for the caller to show, edit and write itself.
	Saga string `json:"saga" jsonschema:"the descriptor this survey produced, as YAML"`
	// Components names what was found, so a caller can say what it discovered without parsing.
	Components []string `json:"components,omitempty"`
	// Controls are the ones the discovered surface turned on.
	Controls []string `json:"controls,omitempty"`
	Note     string   `json:"note,omitempty"`
	// Warning carries what the survey could not reach. A survey that half worked and reads as
	// complete is the failure worth naming: the descriptor looks finished and is not.
	Warning string `json:"warning,omitempty"`
}

SurveyOutput is a descriptor to look at, not a file that appeared on disk.

type SurveyRequest added in v0.98.0

type SurveyRequest struct {
	Surveyor string `json:"surveyor" jsonschema:"which surveyor to run; list_surveyors names them"`
	Ref      string `` /* 136-byte string literal not displayed */
}

SurveyRequest is one surveyor and what to point it at.

type SurveyorInfo added in v0.98.0

type SurveyorInfo struct {
	Name     string   `json:"name"`
	Provides []string `json:"provides" jsonschema:"what it discovers: repositories, images, hosts"`
}

SurveyorInfo is one surveyor and what it finds.

type ToolStatus added in v0.39.0

type ToolStatus struct {
	Name      string `json:"name"`
	Installed bool   `json:"installed"`
	Version   string `json:"version,omitempty"`
	Path      string `json:"path,omitempty"`
	Category  string `json:"category,omitempty" jsonschema:"scanner (backs a control) or utility (supporting, e.g. git)"`
	Optional  bool   `json:"optional,omitempty" jsonschema:"absence of an optional tool is not a problem"`
	// Install is the command a person would run. Draugr will not run it for you.
	Install string `json:"install,omitempty"`
}

ToolStatus is one external tool Draugr would execute.

type UnreadFile added in v0.133.0

type UnreadFile struct {
	Component  string   `json:"component"`
	Repository string   `json:"repository,omitempty"`
	Path       string   `json:"path"`
	Reason     string   `json:"reason" jsonschema:"no lockfile, no pinned versions, no packages read, or modules not loaded"`
	Controls   []string `json:"controls" jsonschema:"the controls whose scanners did not read it"`
}

UnreadFile is a dependency file no scanner serving a control took packages from, or a file calling a Terraform module no scanner loaded.

type ValidateInput

type ValidateInput struct {
	Path    string `json:"path,omitempty" jsonschema:"path to a Saga descriptor on disk"`
	Content string `json:"content,omitempty" jsonschema:"the descriptor's YAML content, for validating an edit before writing it"`
}

ValidateInput accepts a descriptor either by path or inline.

type ValidateOutput

type ValidateOutput struct {
	Valid bool `json:"valid"`
	// Error is why it isn't, in the same words the CLI would use.
	Error string `json:"error,omitempty"`
	// Components and Controls describe what the descriptor actually asks for, which is how an
	// agent checks that a descriptor says what it intended rather than merely parsing.
	Components []string `json:"components,omitempty"`
	Controls   []string `json:"controls,omitempty"`
}

ValidateOutput reports whether the descriptor is usable.

func ValidateSagaTool

ValidateSagaTool validates a descriptor from a path or inline content.

Jump to

Keyboard shortcuts

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