Documentation
¶
Overview ¶
Package security loads security risk pattern annotations from a YAML file and converts them into NodeSecurityPattern + EdgeHasSecurityPattern rows that fold into the main CKG graph.
Where pkg/policy answers "why does this code exist?" (governance, fork blocks, gas schedules), pkg/security answers "what could go wrong with this code?" — the curated list of reentrancy candidates, access-control gaps, Byzantine attack surfaces, integer overflow hotspots that domain experts have flagged. An LLM modifying a listed symbol sees the risk surface as part of the retrieval envelope instead of having to run a separate static analyser (slither / mythril / semgrep) and reconcile its findings.
See docs/PROJECT-BLUEPRINT-ALIGNMENT.md §4.2 P1 #5 for the design intent. The MVP is purely YAML-driven (operators curate the matches[] list); automated pattern detection (slither-style flow rules) is deferred to a follow-up — the data model here is the same either way.
Schema ¶
The YAML envelope:
security_patterns:
- id: "reentrancy.external_call_after_state_change"
name: "Reentrancy: external call after state change"
category: "reentrancy" # reentrancy | access-control | byzantine | overflow | …
severity: "high" # info | low | medium | high | critical
description: "..."
remediation: "..." # optional fix guidance
matches: # qnames of code symbols this pattern applies to
- "Vault.withdraw"
- "Token.transfer"
Every SecurityPattern node carries id → QualifiedName, name → Name, category → SubKind, description + remediation → DocComment. severity rides in the Signature field as "severity=<level>" so search snippets and post-filter ordering can use it without touching the attrs JSON blob.
Index ¶
Constants ¶
const ( SeverityInfo = "info" SeverityLow = "low" SeverityMedium = "medium" SeverityHigh = "high" SeverityCritical = "critical" )
Severity levels. Mirror the conventional ranking used by Slither, Semgrep, CodeQL et al. so consumers familiar with those tools can map findings directly without an enum translation layer.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Entry ¶
type Entry struct {
ID string `yaml:"id" json:"id"`
Name string `yaml:"name" json:"name"`
Category string `yaml:"category,omitempty" json:"category,omitempty"`
Severity string `yaml:"severity,omitempty" json:"severity,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Remediation string `yaml:"remediation,omitempty" json:"remediation,omitempty"`
Matches []string `yaml:"matches,omitempty" json:"matches,omitempty"`
}
Entry is one security pattern row from the YAML file.
type File ¶
type File struct {
SecurityPatterns []Entry `yaml:"security_patterns"`
}
File is the top-level YAML envelope. The single-key envelope mirrors pkg/policy.File — explicit, editor-friendly, room to grow envelope- level metadata (source-of-truth URL, last-reviewed date) without breaking existing consumers.
func LoadFromFile ¶
LoadFromFile reads, parses, and validates a security pattern YAML. Hard errors:
- I/O / parse failure (wrapped underlying error)
- Empty id (would collide on the SecurityPattern node PK)
- Duplicate id (same collision)
- Severity outside the closed enum (loose strings would let typos past the boundary and surface as silent under/over-counts in downstream "severity ≥ high" filters)
Empty / absent security_patterns key is NOT an error; the result has zero entries — useful when an operator wants to land the file before populating it.
type ResolveResult ¶
type ResolveResult struct {
Nodes []types.Node
Edges []types.Edge
Warnings []ResolveWarning
}
ResolveResult bundles the rows Resolve produced and any matching warnings (matches[] qnames that found no code node).
func Resolve ¶
func Resolve(f *File, codeNodes []types.Node, yamlPath string) ResolveResult
Resolve builds NodeSecurityPattern nodes + EdgeHasSecurityPattern edges to fold into the main graph.
- One NodeSecurityPattern per entry. QualifiedName = ID, Name = Name, SubKind = Category. DocComment merges Description and Remediation (blank line between them when both are present).
- One EdgeHasSecurityPattern per (matched qname, pattern) pair. Direction = at-risk code symbol → pattern node so the natural query "what risks does X exhibit?" is a single FK lookup.
O(P + N) overall: a single qname → id index built from codeNodes drives the matches[] hot loop. Missing references emit a ResolveWarning rather than failing — security annotation is strictly additive metadata.
type ResolveWarning ¶
ResolveWarning records a matches[] entry that didn't find a target in the parsed graph. Surfaced verbatim so editors of the YAML can spot stale references (renamed functions, moved fields).