protocol

package
v3.90.1 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: AGPL-3.0 Imports: 1 Imported by: 0

Documentation

Overview

Package protocol is the Language Server Protocol subset the Vulnetix server speaks, plus the vulnetix/* extension methods.

Hand-written rather than generated or imported. The options were:

  • golang.org/x/tools/gopls/internal/protocol lives under an internal/ directory, so Go's own rules make it unimportable from here. Not a trade-off, a hard block.
  • go.lsp.dev/protocol last released in 2021 against LSP 3.16, so it has no inlay hints, no pull diagnostics and no positionEncoding, and it pulls in a logging framework this binary has no other use for.
  • github.com/tliron/glsp is complete and current, but it owns the process: its own context type, its own logging, its own stdio loop. This server specifically needs to control stdio, because cmd/ writes to os.Stdout in 144 places and a single stray byte desynchronises the framing.

So the transport is github.com/sourcegraph/jsonrpc2 (framing, request correlation, concurrent write serialisation) and the types are here. Only what is used is defined; the spec is large and most of it is a language server's job rather than a security scanner's.

Index

Constants

View Source
const (
	MethodInitialize  = "initialize"
	MethodInitialized = "initialized"
	MethodShutdown    = "shutdown"
	MethodExit        = "exit"
	MethodSetTrace    = "$/setTrace"
	MethodCancel      = "$/cancelRequest"
	MethodProgress    = "$/progress"

	MethodDidOpen   = "textDocument/didOpen"
	MethodDidChange = "textDocument/didChange"
	MethodDidSave   = "textDocument/didSave"
	MethodDidClose  = "textDocument/didClose"

	MethodPublishDiagnostics = "textDocument/publishDiagnostics"

	MethodLogMessage             = "window/logMessage"
	MethodShowMessage            = "window/showMessage"
	MethodWorkDoneProgressCreate = "window/workDoneProgress/create"

	MethodConfiguration          = "workspace/configuration"
	MethodDidChangeConfiguration = "workspace/didChangeConfiguration"
	MethodDidChangeWatchedFiles  = "workspace/didChangeWatchedFiles"

	// Vulnetix extensions. One namespace, so a client can discover them and a
	// reader can tell at a glance what is standard and what is ours.
	MethodServerInfo    = "vulnetix/serverInfo"
	MethodScanWorkspace = "vulnetix/scanWorkspace"
	MethodScanStatus    = "vulnetix/scanStatus"
	MethodFindings      = "vulnetix/findings"
)
View Source
const (
	CodeParseError     = -32700
	CodeInvalidRequest = -32600
	CodeMethodNotFound = -32601
	CodeInvalidParams  = -32602
	CodeInternalError  = -32603

	CodeServerNotInitialized = -32002
	CodeRequestCancelled     = -32800
	CodeContentModified      = -32801
)

JSON-RPC and LSP error codes. RequestCancelled is the one that matters most here: a cancelled scan must be distinguishable from a failed one, or the client reports an error for something the user asked to stop.

View Source
const (
	SyncNone        = 0
	SyncFull        = 1
	SyncIncremental = 2
)

TextDocumentSyncKind values. The server advertises Full.

Incremental sync would mean applying ranged edits to a local copy of every open document. The rule engine needs whole-file text anyway, so incremental buys nothing and adds a class of bug where the server's copy silently drifts from the editor's. Files are capped at 1 MiB, so the transfer cost is not worth that risk.

View Source
const (
	SeverityError       = 1
	SeverityWarning     = 2
	SeverityInformation = 3
	SeverityHint        = 4
)

Severity values. Vulnetix maps critical and high to Error, medium to Warning, and low and info to Information or Hint depending on a setting.

View Source
const (
	TagUnnecessary = 1
	TagDeprecated  = 2
)

Diagnostic tags. Deprecated is used for end-of-life packages, which the editor renders with a strikethrough: exactly the right signal for a dependency that is not going to get fixed because it is not maintained.

View Source
const (
	MessageError   = 1
	MessageWarning = 2
	MessageInfo    = 3
	MessageLog     = 4
)

MessageType values, matching pipeline.Level without translation.

View Source
const (
	FileCreated = 1
	FileChanged = 2
	FileDeleted = 3
)

FileChangeType values.

View Source
const ProtocolVersion = 1

ProtocolVersion is the contract version for the vulnetix/* extension methods.

The client requires an exact match. Bump it ONLY on a breaking change to a vulnetix/* method's params or result: a field removed, renamed, or changed in type or meaning.

Adding a field does NOT bump it. Every params and result type is an object for exactly this reason, so a server can grow a field and an older client ignores it, while a newer client reading a missing field gets a zero value it can handle.

The extension declares the same integer in its package.json under "vulnetix.lspProtocolVersion", and an integration test asserts the two agree. `vulnetix lsp --version` prints it so the client can check before connecting.

View Source
const ServerName = "vulnetix"

ServerName is reported in the initialize result and in log messages.

Variables

This section is empty.

Functions

This section is empty.

Types

type AnchorConfidence

type AnchorConfidence string

AnchorConfidence describes how precisely a finding was placed. Rendered as a subtle indicator so an approximate position is not presented as an exact one.

const (
	AnchorExact   AnchorConfidence = "exact"
	AnchorSnippet AnchorConfidence = "snippet"
	AnchorLine    AnchorConfidence = "line"
	AnchorFile    AnchorConfidence = "file"
)

type CancelParams

type CancelParams struct {
	// ID is a request id, which JSON-RPC allows to be a number or a string.
	ID json.RawMessage `json:"id"`
}

type Client

type Client struct {
	Name    string `json:"name"`
	Version string `json:"version,omitempty"`
}

type ClientCaps

type ClientCaps struct {
	Workspace struct {
		Configuration          bool `json:"configuration,omitempty"`
		WorkspaceFolders       bool `json:"workspaceFolders,omitempty"`
		DidChangeConfiguration struct {
			DynamicRegistration bool `json:"dynamicRegistration,omitempty"`
		} `json:"didChangeConfiguration"`
	} `json:"workspace"`
	TextDocument struct {
		PublishDiagnostics struct {
			RelatedInformation bool `json:"relatedInformation,omitempty"`
			DataSupport        bool `json:"dataSupport,omitempty"`
			TagSupport         struct {
				ValueSet []int `json:"valueSet,omitempty"`
			} `json:"tagSupport"`
		} `json:"publishDiagnostics"`
	} `json:"textDocument"`
	Window struct {
		WorkDoneProgress bool `json:"workDoneProgress,omitempty"`
	} `json:"window"`
	General struct {
		// PositionEncodings is the client's preference order. The server
		// advertises utf-16 regardless, because that is what rangefix produces.
		PositionEncodings []string `json:"positionEncodings,omitempty"`
	} `json:"general"`
}

ClientCaps is the subset of client capabilities the server branches on. Everything else is ignored rather than modelled: a field nobody reads is a field that drifts.

type CodeDescription

type CodeDescription struct {
	Href string `json:"href"`
}

CodeDescription links a diagnostic code to its documentation, so the code in the Problems panel becomes a link to the rule page.

type ConfigurationItem

type ConfigurationItem struct {
	// ScopeURI is the folder the setting is being asked about. Requesting per
	// folder rather than once at startup is what makes a folder-scoped
	// vulnetix.scan.exclude take effect in a multi-root workspace.
	ScopeURI string `json:"scopeUri,omitempty"`
	Section  string `json:"section,omitempty"`
}

type ConfigurationParams

type ConfigurationParams struct {
	Items []ConfigurationItem `json:"items"`
}

type ContentChange

type ContentChange struct {
	Range       *Range `json:"range,omitempty"`
	RangeLength *int   `json:"rangeLength,omitempty"`
	Text        string `json:"text"`
}

ContentChange carries the whole document, because the server advertises full sync. Range and RangeLength are accepted and ignored, so a client that sends incremental changes anyway is detected rather than silently misapplied.

type Diagnostic

type Diagnostic struct {
	Range    Range  `json:"range"`
	Severity int    `json:"severity,omitempty"`
	Code     string `json:"code,omitempty"`
	// CodeDescription turns Code into a link. Omitted when the rule has no
	// documentation page rather than pointing at a 404.
	CodeDescription *CodeDescription `json:"codeDescription,omitempty"`
	// Source names the scanner family, which is what the Problems panel groups
	// and filters by: vulnetix-sca, vulnetix-sast, vulnetix-secrets and so on.
	Source             string                         `json:"source,omitempty"`
	Message            string                         `json:"message"`
	Tags               []int                          `json:"tags,omitempty"`
	RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"`
	// Data round-trips to the client untouched. Carries the finding id, the
	// anchor confidence and whether a fix exists, so a code action can be
	// resolved without a second lookup.
	Data json.RawMessage `json:"data,omitempty"`
}

type DiagnosticRelatedInformation

type DiagnosticRelatedInformation struct {
	Location Location `json:"location"`
	Message  string   `json:"message"`
}

type DidChangeConfigurationParams

type DidChangeConfigurationParams struct {
	Settings json.RawMessage `json:"settings"`
}

type DidChangeParams

type DidChangeParams struct {
	TextDocument   VersionedTextDocumentIdentifier `json:"textDocument"`
	ContentChanges []ContentChange                 `json:"contentChanges"`
}

type DidChangeWatchedFilesParams

type DidChangeWatchedFilesParams struct {
	Changes []FileEvent `json:"changes"`
}

type DidCloseParams

type DidCloseParams struct {
	TextDocument TextDocumentIdentifier `json:"textDocument"`
}

type DidOpenParams

type DidOpenParams struct {
	TextDocument TextDocumentItem `json:"textDocument"`
}

type DidSaveParams

type DidSaveParams struct {
	TextDocument TextDocumentIdentifier `json:"textDocument"`
	Text         *string                `json:"text,omitempty"`
}

type ExecuteCommandOptions

type ExecuteCommandOptions struct {
	Commands []string `json:"commands"`
}

type FileEvent

type FileEvent struct {
	URI  string `json:"uri"`
	Type int    `json:"type"`
}

type Finding

type Finding struct {
	// ID is the fingerprint for a code finding, or tool:vuln:purl for a
	// dependency one. Stable across scans, which is what lets a client keep
	// selection and expansion state through a rescan.
	ID   string `json:"id"`
	Tool string `json:"tool"`

	RuleID   string `json:"ruleId,omitempty"`
	RuleName string `json:"ruleName,omitempty"`
	Title    string `json:"title,omitempty"`
	Message  string `json:"message"`

	Severity string `json:"severity"`
	Level    string `json:"level,omitempty"`

	Location         FindingLocation   `json:"location"`
	RelatedLocations []RelatedLocation `json:"relatedLocations,omitempty"`

	Package *PackageInfo `json:"package,omitempty"`
	Vuln    *VulnInfo    `json:"vuln,omitempty"`

	Status      string           `json:"status,omitempty"`
	Vex         *VexInfo         `json:"vex,omitempty"`
	Suppression *SuppressionInfo `json:"suppression,omitempty"`

	HelpURI      string `json:"helpUri,omitempty"`
	FixAvailable bool   `json:"fixAvailable,omitempty"`
	Snippet      string `json:"snippet,omitempty"`
}

Finding is the one shape every view binds to, unioning the SARIF and SCA worlds so a tree, a panel and a diagnostic all read the same object.

type FindingLocation

type FindingLocation struct {
	URI              string           `json:"uri"`
	Range            Range            `json:"range"`
	AnchorConfidence AnchorConfidence `json:"anchorConfidence,omitempty"`
}

type FindingsFilter

type FindingsFilter struct {
	Tools      []string `json:"tools,omitempty"`
	Severities []string `json:"severities,omitempty"`
	Statuses   []string `json:"statuses,omitempty"`
	Path       string   `json:"path,omitempty"`
	Query      string   `json:"query,omitempty"`
}

type FindingsParams

type FindingsParams struct {
	Folder  string          `json:"folder,omitempty"`
	Filter  *FindingsFilter `json:"filter,omitempty"`
	GroupBy string          `json:"groupBy,omitempty"`
	Cursor  string          `json:"cursor,omitempty"`
	Limit   int             `json:"limit,omitempty"`
}

FindingsParams is paginated. A large repository produces thousands of findings and serialising them all into one message stalls the client for seconds before it can draw anything.

type FindingsResult

type FindingsResult struct {
	ProtocolVersion int       `json:"protocolVersion"`
	Items           []Finding `json:"items"`
	Total           int       `json:"total"`
	// NextCursor is empty on the last page.
	NextCursor string `json:"nextCursor,omitempty"`
}

type Folder

type Folder struct {
	URI  string `json:"uri"`
	Name string `json:"name"`
}

type GateResult

type GateResult struct {
	Breached bool     `json:"breached"`
	Reasons  []string `json:"reasons,omitempty"`
}

type InitializeParams

type InitializeParams struct {
	ProcessID  *int    `json:"processId"`
	RootURI    string  `json:"rootUri,omitempty"`
	ClientInfo *Client `json:"clientInfo,omitempty"`
	// InitializationOptions carries settings the client wants applied before
	// the first workspace/configuration round trip.
	InitializationOptions json.RawMessage `json:"initializationOptions,omitempty"`
	Capabilities          ClientCaps      `json:"capabilities"`
	WorkspaceFolders      []Folder        `json:"workspaceFolders,omitempty"`
	Trace                 string          `json:"trace,omitempty"`
}

type InitializeResult

type InitializeResult struct {
	Capabilities ServerCaps  `json:"capabilities"`
	ServerInfo   *ServerInfo `json:"serverInfo,omitempty"`
}

type Location

type Location struct {
	URI   string `json:"uri"`
	Range Range  `json:"range"`
}

Location is a range within a document.

type LogMessageParams

type LogMessageParams struct {
	Type    int    `json:"type"`
	Message string `json:"message"`
}

type PackageInfo

type PackageInfo struct {
	Purl        string `json:"purl"`
	Name        string `json:"name"`
	Version     string `json:"version"`
	Ecosystem   string `json:"ecosystem"`
	Direct      bool   `json:"direct"`
	Scope       string `json:"scope,omitempty"`
	IsEOL       bool   `json:"isEol,omitempty"`
	IsMalicious bool   `json:"isMalicious,omitempty"`
	// PathCount is how many dependency paths introduce this package. More than
	// one is the usual reason a transitive cannot simply be upgraded.
	PathCount int `json:"pathCount,omitempty"`
}

PackageInfo describes the dependency a finding is about, when it is about one.

type Position

type Position struct {
	Line      int `json:"line"`
	Character int `json:"character"`
}

Position is zero-based. Character is measured in UTF-16 code units, which is the LSP default and what this server advertises. See internal/lsp/rangefix for why that distinction is load-bearing.

type ProgressParams

type ProgressParams struct {
	Token string          `json:"token"`
	Value json.RawMessage `json:"value"`
}

type PublishDiagnosticsParams

type PublishDiagnosticsParams struct {
	URI     string       `json:"uri"`
	Version *int         `json:"version,omitempty"`
	Diags   []Diagnostic `json:"diagnostics"`
}

type Range

type Range struct {
	Start Position `json:"start"`
	End   Position `json:"end"`
}

Range is a half-open interval.

type RelatedLocation

type RelatedLocation struct {
	URI     string `json:"uri"`
	Range   Range  `json:"range"`
	Message string `json:"message,omitempty"`
}

type SaveOptions

type SaveOptions struct {
	IncludeText bool `json:"includeText"`
}

type ScanArtifacts

type ScanArtifacts struct {
	SBOM   string `json:"sbom,omitempty"`
	SARIF  string `json:"sarif,omitempty"`
	Memory string `json:"memory,omitempty"`
}

type ScanCounts

type ScanCounts struct {
	BySeverity map[string]int `json:"bySeverity,omitempty"`
	ByTool     map[string]int `json:"byTool,omitempty"`
	Total      int            `json:"total"`
}

type ScanFeatures

type ScanFeatures struct {
	SCA        *bool `json:"sca,omitempty"`
	SAST       *bool `json:"sast,omitempty"`
	Secrets    *bool `json:"secrets,omitempty"`
	IAC        *bool `json:"iac,omitempty"`
	Containers *bool `json:"containers,omitempty"`
	License    *bool `json:"license,omitempty"`
	Malscan    *bool `json:"malscan,omitempty"`
}

ScanFeatures toggles analysis families for one run. A nil pointer means "server default", which is what lets the client send only what the user actually changed rather than a full set it has to keep in sync.

type ScanStatusParams

type ScanStatusParams struct {
	ScanID      string `json:"scanId"`
	Phase       string `json:"phase"`
	Stage       string `json:"stage,omitempty"`
	Percent     *int   `json:"percent,omitempty"`
	Cancellable bool   `json:"cancellable"`
}

ScanStatusParams complements $/progress with data a tree view can bind to. $/progress renders a bar; this says which phase, how far, and whether it can still be cancelled, which is what a sidebar needs to show useful state.

type ScanWorkspaceParams

type ScanWorkspaceParams struct {
	// Folders to scan. Empty means every folder the client has registered.
	Folders  []string      `json:"folders,omitempty"`
	Features *ScanFeatures `json:"features,omitempty"`
	// Refresh bypasses the vulnerability-data disk cache.
	Refresh bool `json:"refresh,omitempty"`
	// GitHistory walks git history for secrets. Defaults to false in the
	// server even though the CLI defaults it true, because it walks hundreds
	// of commits and thousands of file versions: a CI job, not an editor one.
	GitHistory bool `json:"gitHistory,omitempty"`
}

type ScanWorkspaceResult

type ScanWorkspaceResult struct {
	ProtocolVersion int           `json:"protocolVersion"`
	ScanID          string        `json:"scanId"`
	DurationMS      int64         `json:"durationMs"`
	Counts          ScanCounts    `json:"counts"`
	Artifacts       ScanArtifacts `json:"artifacts,omitempty"`
	Gate            *GateResult   `json:"gate,omitempty"`

	// Degradations names what did not run to completion. Always populated when
	// something was skipped, because "no findings" and "did not look" must
	// never be indistinguishable to the person reading the result.
	Degradations []string `json:"degradations,omitempty"`
}

type ServerCaps

type ServerCaps struct {
	PositionEncoding string                   `json:"positionEncoding,omitempty"`
	TextDocumentSync *TextDocumentSyncOptions `json:"textDocumentSync,omitempty"`
	Workspace        *WorkspaceCaps           `json:"workspace"`
	ExecuteCommand   *ExecuteCommandOptions   `json:"executeCommandProvider,omitempty"`
}

type ServerInfo

type ServerInfo struct {
	Name    string `json:"name"`
	Version string `json:"version,omitempty"`
}

type ServerInfoResult

type ServerInfoResult struct {
	ProtocolVersion int    `json:"protocolVersion"`
	CLIVersion      string `json:"cliVersion"`
	Commit          string `json:"commit,omitempty"`
	BuildDate       string `json:"buildDate,omitempty"`
	GoVersion       string `json:"goVersion,omitempty"`
	Platform        string `json:"platform,omitempty"`

	// Capabilities names the analysis families this build supports.
	Capabilities []string `json:"capabilities"`

	// RulesEmbedded and RuleKinds describe the compiled-in corpus, which is
	// what the client shows as "evaluated N rules" instead of an opaque wait.
	RulesEmbedded int            `json:"rulesEmbedded"`
	RuleKinds     map[string]int `json:"ruleKinds,omitempty"`
}

ServerInfoResult is the handshake. The client checks ProtocolVersion for an exact match and CLIVersion against its declared range, then uses Capabilities to hide UI for anything this build cannot do, rather than offering it and failing at call time.

type SetTraceParams

type SetTraceParams struct {
	Value string `json:"value"`
}

type ShowMessageParams

type ShowMessageParams struct {
	Type    int    `json:"type"`
	Message string `json:"message"`
}

type SuppressionInfo

type SuppressionInfo struct {
	// Kind is nosec, cli or console: an inline comment, a recorded local
	// suppression, or one synced from the organisation.
	Kind      string `json:"kind,omitempty"`
	Reason    string `json:"reason,omitempty"`
	ExpiresAt string `json:"expiresAt,omitempty"`
}

type TextDocumentIdentifier

type TextDocumentIdentifier struct {
	URI string `json:"uri"`
}

type TextDocumentItem

type TextDocumentItem struct {
	URI        string `json:"uri"`
	LanguageID string `json:"languageId"`
	Version    int    `json:"version"`
	Text       string `json:"text"`
}

type TextDocumentSyncOptions

type TextDocumentSyncOptions struct {
	OpenClose bool         `json:"openClose"`
	Change    int          `json:"change"`
	Save      *SaveOptions `json:"save,omitempty"`
}

type VersionedTextDocumentIdentifier

type VersionedTextDocumentIdentifier struct {
	URI     string `json:"uri"`
	Version int    `json:"version"`
}

type VexInfo

type VexInfo struct {
	Status          string `json:"status,omitempty"`
	Justification   string `json:"justification,omitempty"`
	ActionStatement string `json:"actionStatement,omitempty"`
}

type VulnInfo

type VulnInfo struct {
	ID      string   `json:"id"`
	Aliases []string `json:"aliases,omitempty"`

	CVSS *float64 `json:"cvss,omitempty"`
	EPSS *float64 `json:"epss,omitempty"`
	SSVC string   `json:"ssvc,omitempty"`
	CWSS *float64 `json:"cwss,omitempty"`

	InCisaKev bool `json:"inCisaKev,omitempty"`
	InEuKev   bool `json:"inEuKev,omitempty"`
	// ExploitMaturity is none, poc, functional or weaponized.
	ExploitMaturity string `json:"exploitMaturity,omitempty"`

	CWEs []int `json:"cwes,omitempty"`
	// Reachability is reachable, not_reachable, not_assessable or unassessed.
	// The distinction between not_reachable and unassessed matters: one is an
	// answer and the other is the absence of one.
	Reachability string `json:"reachability,omitempty"`
}

VulnInfo carries the exploit picture alongside the score, because a critical CVSS on something nobody exploits is different work from a high with a working exploit, and a client that only sees severity cannot tell them apart.

type WorkDoneProgressBegin

type WorkDoneProgressBegin struct {
	Kind        string `json:"kind"` // "begin"
	Title       string `json:"title"`
	Cancellable bool   `json:"cancellable,omitempty"`
	Message     string `json:"message,omitempty"`
	Percentage  *int   `json:"percentage,omitempty"`
}

type WorkDoneProgressCreateParams

type WorkDoneProgressCreateParams struct {
	Token string `json:"token"`
}

type WorkDoneProgressEnd

type WorkDoneProgressEnd struct {
	Kind    string `json:"kind"` // "end"
	Message string `json:"message,omitempty"`
}

type WorkDoneProgressReport

type WorkDoneProgressReport struct {
	Kind        string `json:"kind"` // "report"
	Cancellable bool   `json:"cancellable,omitempty"`
	Message     string `json:"message,omitempty"`
	Percentage  *int   `json:"percentage,omitempty"`
}

type WorkspaceCaps

type WorkspaceCaps struct {
	WorkspaceFolders *WorkspaceFoldersCaps `json:"workspaceFolders,omitempty"`
}

type WorkspaceFoldersCaps

type WorkspaceFoldersCaps struct {
	Supported           bool `json:"supported"`
	ChangeNotifications bool `json:"changeNotifications,omitempty"`
}

Jump to

Keyboard shortcuts

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