api
May 19, 2026 · View on GitHub
import "github.com/vilaca/portal/internal/api"
Package api defines the load-bearing interfaces and DTOs that Portal modules communicate through. It is the only package depended on by every other internal package; nothing in api may import from internal/admission, internal/audit, internal/network, internal/actions, internal/engine, internal/expr, internal/sink, internal/lookup, or internal/rule.
The only external dependencies allowed are k8s.io/apimachinery (for GVK and Unstructured, which travel through Context) and Go's standard library.
Index
- func ContextBuilders() map[string]func() ContextBuilder
- func RegisterAction(typ string, ctor func() Action)
- func RegisterContextBuilder(name string, ctor func() ContextBuilder)
- func RegisterEngine(name string, ctor func() ExpressionEngine)
- func RegisterSink(name string, ctor func() OutputSink)
- func Sinks() map[string]func() OutputSink
- type Action
- type ActionDispatcher
- type ActionSpec
- type AdmissionRequest
- type Context
- type ContextBuilder
- type Decision
- type DepEntry
- type DepRecorder
- type EnforcementAction
- type EventMeta
- type EventSource
- type ExpressionEngine
- type IdempotencyStore
- type Lookup
- type Matcher
- type Mode
- type NamespaceSelector
- type ObjectRef
- type OutputSink
- type Program
- type RateLimiter
- type Rule
- type RuleEngine
- type RuleIndex
- type RuleLoader
- type RuleSource
- type Severity
- type UserInfo
- type Violation
- type ViolationSource
func ContextBuilders
func ContextBuilders() map[string]func() ContextBuilder
ContextBuilders returns a snapshot of every registered builder factory, in no particular order. The engine queries each in turn via Supports(gvk).
func RegisterAction
func RegisterAction(typ string, ctor func() Action)
RegisterAction adds an Action factory.
func RegisterContextBuilder
func RegisterContextBuilder(name string, ctor func() ContextBuilder)
RegisterContextBuilder adds a ContextBuilder factory.
func RegisterEngine
func RegisterEngine(name string, ctor func() ExpressionEngine)
RegisterEngine adds an ExpressionEngine factory. Last writer wins.
func RegisterSink
func RegisterSink(name string, ctor func() OutputSink)
RegisterSink adds an OutputSink factory.
func Sinks
func Sinks() map[string]func() OutputSink
Sinks returns a snapshot of every registered sink factory.
type Action
Action is one response capability — label, annotate, evict, patch-NP, revoke-SA-token, alertmanager. Adding a new action type is one struct + one Register call.
type Action interface {
Type() string
Execute(ctx context.Context, v Violation, params map[string]any) error
Idempotent() bool
DefaultRateLimit() time.Duration
}
func ActionFor
func ActionFor(typ string) Action
ActionFor returns a constructed Action by type, or nil if absent.
type ActionDispatcher
ActionDispatcher routes Violations to enabled Actions. It is non-blocking, applies rate-limiting per (rule, target) tuple, and consults an IdempotencyStore so re-emissions within the action's idempotency window are dropped rather than re-executed.
type ActionDispatcher interface {
Dispatch(ctx context.Context, v Violation)
// Drain blocks until in-flight dispatches finish or ctx is cancelled.
Drain(ctx context.Context) error
}
type ActionSpec
ActionSpec is one entry in Rule.Actions.
type ActionSpec struct {
Type string `json:"type" yaml:"type"`
On []Mode `json:"on,omitempty" yaml:"on,omitempty"`
RateLimit string `json:"rateLimit,omitempty" yaml:"rateLimit,omitempty"`
Params map[string]any `json:"params,omitempty" yaml:",inline"`
}
type AdmissionRequest
AdmissionRequest is the subset of AdmissionReview.Request that rules can read.
type AdmissionRequest struct {
Operation string
UserInfo UserInfo
DryRun bool
OldObject *unstructured.Unstructured
}
type Context
Context is the evaluation environment a rule sees. It carries three layers:
- Object: always populated. The raw resource as *unstructured.Unstructured, exposed to expr-lang as nested maps. Anything reachable in the K8s schema is reachable here — this is the universal escape hatch.
- Env: the rendered expr-lang environment (a map[string]any). Pod-shaped sugar lives here under the keys "container", "spec", "securityContext", "metadata", "object", "request". Non-pod GVKs get only "object", "metadata", "request".
- Request: admission-only request metadata (Operation, UserInfo, DryRun, OldObject).
type Context struct {
GVK schema.GroupVersionKind
Object *unstructured.Unstructured
Env map[string]any
Request *AdmissionRequest
}
type ContextBuilder
ContextBuilder converts a raw unstructured resource into an evaluation Context. One ContextBuilder is responsible for one GVK family — the pod-shaped builder covers Pod plus any GVK whose spec embeds PodTemplateSpec; a fallback builder handles everything else with only Object/Env(object,metadata,request).
type ContextBuilder interface {
Supports(gvk schema.GroupVersionKind) bool
Build(obj *unstructured.Unstructured) (Context, error)
}
type Decision
Decision is the admission-time aggregate response across all rules that fired for one AdmissionReview request.
type Decision struct {
Allowed bool
Message string
Warnings []string
// Violations is the full list this request produced, for PolicyReport + metrics.
Violations []Violation
}
type DepEntry
DepEntry is an (rule, observed-object) pair recorded as depending on some referenced object.
type DepEntry struct {
Rule string
Observed ObjectRef
}
type DepRecorder
DepRecorder is the write side of the reverse-dependency index. The lookup implementation records (rule, object) → (referenced) edges; the audit loop queries the inverse on resource-change events to enqueue re-evaluation.
type DepRecorder interface {
Record(rule string, observed, referenced ObjectRef)
Dependents(referenced ObjectRef) []DepEntry
}
type EnforcementAction
EnforcementAction controls how admission responds to a violation.
type EnforcementAction string
const (
EnforceDeny EnforcementAction = "deny"
EnforceWarn EnforcementAction = "warn"
EnforceDryRun EnforcementAction = "dryrun"
)
type EventMeta
EventMeta describes one event flowing through the engine. It is what EventSource produces and what ActionDispatcher / OutputSink consume alongside Violations.
type EventMeta struct {
Source string // "admission", "audit", "network", "api-audit-log" (v2)
EventID string // unique per event; used as the idempotency seed
At time.Time
DryRun bool
Operation string // create/update/delete; "audit" or "network" outside admission
}
type EventSource
EventSource produces evaluation events. The admission webhook, the audit informer loop, and the NetworkPolicy analyser each implement EventSource and feed the same RuleEngine + ActionDispatcher pipeline.
type EventSource interface {
Name() string
// Start blocks until ctx is cancelled or the source errors fatally. onEvent
// is invoked for each event; the source is responsible for any internal
// goroutines (informers, HTTP handlers).
Start(ctx context.Context, onEvent func(Context, EventMeta)) error
Stop(ctx context.Context) error
}
type ExpressionEngine
ExpressionEngine compiles rule expressions into evaluable Programs. expr-lang is the default implementation; CEL/Rego/starlark can be added in v3 without touching the rule schema.
type ExpressionEngine interface {
// Name is "expr", "cel", "rego" — used in metrics and the Rule's selector.
Name() string
// Compile parses one rule expression. Diagnostics include line/column when
// available so PortalClusterRule.status.parseError is human-readable.
Compile(expression string) (Program, error)
}
func Engine
func Engine(name string) ExpressionEngine
Engine returns a constructed ExpressionEngine by name, or nil if absent.
type IdempotencyStore
IdempotencyStore remembers recently-dispatched (rule,gvk,ns,name,actionType) tuples. Default impl is an in-memory LRU; v2 may swap in a persistent store.
type IdempotencyStore interface {
// Seen returns true if the key has been observed within ttl, otherwise
// records it and returns false.
Seen(key string, ttl time.Duration) bool
}
type Lookup
Lookup is exposed to rule expressions as `cluster.<gvk>.byName(ns, name)` and `cluster.<gvk>.list(ns, selector)`. Backed by audit's shared informer caches at runtime; pluggable for tests.
type Lookup interface {
// ByName fetches a single object from the cache. Returns nil if absent.
ByName(gvk schema.GroupVersionKind, namespace, name string) (*unstructured.Unstructured, error)
// List returns every object of gvk in namespace matching selector. Empty
// namespace means cluster-wide.
List(gvk schema.GroupVersionKind, namespace string, selector map[string]string) ([]*unstructured.Unstructured, error)
// Watched reports the set of GVKs this Lookup currently has informers for.
Watched() []schema.GroupVersionKind
}
type Matcher
Matcher narrows the set of resources a rule applies to.
type Matcher struct {
GVK []schema.GroupVersionKind `json:"gvk" yaml:"gvk"`
Namespaces NamespaceSelector `json:"namespaces,omitempty" yaml:"namespaces,omitempty"`
}
type Mode
Mode names a rule-evaluation loop. A rule may opt in to multiple modes.
type Mode string
const (
ModeAdmission Mode = "admission"
ModeAudit Mode = "audit"
ModeNetwork Mode = "network"
ModeRuntime Mode = "runtime" // v2
)
type NamespaceSelector
NamespaceSelector is the include/exclude shape used by Rule.Match.Namespaces.
type NamespaceSelector struct {
Include []string `json:"include,omitempty" yaml:"include,omitempty"`
Exclude []string `json:"exclude,omitempty" yaml:"exclude,omitempty"`
}
type ObjectRef
ObjectRef identifies one cluster object for the dep index.
type ObjectRef struct {
GVK schema.GroupVersionKind
Namespace string
Name string
}
type OutputSink
OutputSink writes violations somewhere visible. AlertManager, PolicyReport, Prometheus, stdout/JSON all implement this. Each sink is independently enable-able and must be safe for concurrent Emit calls.
type OutputSink interface {
Name() string
Emit(ctx context.Context, v Violation) error
Close() error
}
type Program
Program is a compiled, reusable rule expression. It MUST be safe for concurrent Eval calls.
type Program interface {
Eval(ctx Context) (bool, error)
}
type RateLimiter
RateLimiter limits dispatch frequency per opaque key. Returning false means "drop"; the dispatcher counts these into portal_actions_total{result="ratelimited"}.
type RateLimiter interface {
Allow(key string, window time.Duration) bool
}
type Rule
Rule is the canonical parsed shape of a Portal rule, regardless of whether it originated from a folder YAML file or a PortalClusterRule / PortalRule CR.
type Rule struct {
Name string `json:"name" yaml:"name"`
Enabled bool `json:"enabled" yaml:"enabled"`
Severity Severity `json:"severity,omitempty" yaml:"severity,omitempty"`
Mode []Mode `json:"mode,omitempty" yaml:"mode,omitempty"`
EnforcementAction EnforcementAction `json:"enforcementAction,omitempty" yaml:"enforcementAction,omitempty"`
Match Matcher `json:"match" yaml:"match"`
Expression string `json:"rule" yaml:"rule"`
Alert string `json:"alert,omitempty" yaml:"alert,omitempty"`
Actions []ActionSpec `json:"actions,omitempty" yaml:"actions,omitempty"`
// Source identifies where this rule came from; used by status reporting and tests.
Source RuleSource `json:"-" yaml:"-"`
}
func (Rule) HasMode
func (r Rule) HasMode(m Mode) bool
HasMode reports whether the rule opts into the given evaluation mode.
type RuleEngine
RuleEngine dispatches a Context to every rule indexed under that GVK and returns the produced Violations.
type RuleEngine interface {
Evaluate(ctx Context, meta EventMeta) []Violation
}
type RuleIndex
RuleIndex is the read-only view of the rule store that the engine consults. Loaders (folder, CR) write into a concrete index that implements this.
type RuleIndex interface {
// ForGVK returns the rules whose Match.GVK includes gvk, filtered by enabled.
ForGVK(gvk schema.GroupVersionKind) []Rule
// All returns every enabled rule. Used for static dependency extraction.
All() []Rule
}
type RuleLoader
RuleLoader feeds parsed Rules into a central index. The folder loader walks a directory and watches it via fsnotify; the CR loader watches the two PortalClusterRule / PortalRule CRDs. Both produce the same Rule shape.
type RuleLoader interface {
Name() string
Start(ctx context.Context, onUpdate func(snapshot []Rule)) error
Stop(ctx context.Context) error
}
type RuleSource
RuleSource records the origin of a Rule for diagnostics.
type RuleSource struct {
Origin string // "folder", "PortalClusterRule", "PortalRule"
Path string // file path or CR name/namespace
UID string // CR UID when applicable
Generated bool // true if produced by migrate-rules
}
type Severity
Severity classifies a rule for downstream routing and alerting.
type Severity string
const (
SeverityInfo Severity = "info"
SeverityLow Severity = "low"
SeverityMedium Severity = "medium"
SeverityHigh Severity = "high"
SeverityCritical Severity = "critical"
)
type UserInfo
UserInfo identifies the requester at admission.
type UserInfo struct {
Username string
UID string
Groups []string
Extra map[string][]string
}
type Violation
Violation is the cross-cutting DTO emitted by rule evaluation. Every output channel (admission response, PolicyReport, AlertManager, Prometheus, action dispatcher) consumes Violations.
type Violation struct {
Rule string // Rule.Name
Severity Severity // copied from Rule
GVK schema.GroupVersionKind // resource that violated
Namespace string
Name string
Mode Mode // which loop produced this violation (admission/audit/network)
Message string // human-readable reason
At time.Time // creation timestamp
// EnforcementAction tells admission how to respond. Empty outside admission.
EnforcementAction EnforcementAction
// Actions is the rule's action list, copied verbatim so the dispatcher
// doesn't need to re-read the rule store. Pre-merged with the `alert:`
// shorthand.
Actions []ActionSpec
// Source carries enough metadata for sinks to render context-rich messages
// without re-fetching the object.
Source ViolationSource
}
type ViolationSource
ViolationSource captures the originating event for downstream rendering.
type ViolationSource struct {
EventID string // unique per emission, used for idempotency
Operation string // admission operation, if any
Username string // admission requester, if any
Container string // when the violating context was a specific container in a multi-container Pod
}
Generated by gomarkdoc