processor

package
v0.7.1 Latest Latest
Warning

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

Go to latest
Published: Jun 25, 2026 License: AGPL-3.0 Imports: 26 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ChangeSourceHuman  = "human"
	ChangeSourceSystem = "system"
)

ChangeSource constants for activity classification.

View Source
const (
	ActorTypeUser       = "user"
	ActorTypeSystem     = "system"
	ActorTypeController = "controller"
)

ActorType constants for actor classification.

View Source
const (
	TenantTypePlatform     = types.TenantTypePlatform
	TenantTypeOrganization = types.TenantTypeOrganization
	TenantTypeProject      = types.TenantTypeProject
	TenantTypeUser         = types.TenantTypeUser
)

Re-export tenant type constants for use within the processor package.

Variables

View Source
var (
	// ErrKindResolution indicates a failure to resolve a resource name to its Kind.
	// Example: resolving "deployments" -> "Deployment" via API discovery.
	ErrKindResolution = errors.New("kind resolution failed")

	// ErrActivityBuild indicates a failure to build an Activity from the input.
	// This wraps errors from link conversion, kind resolution during activity building, etc.
	ErrActivityBuild = errors.New("activity build failed")
)

Sentinel errors for error classification.

Functions

func ClassifyChangeSource

func ClassifyChangeSource(user authnv1.UserInfo) string

ClassifyChangeSource determines whether an activity was initiated by a human or by the system (controllers, service accounts, etc.). System accounts always use a "system:" prefix for the username.

func ConvertLinks(celLinks []cel.Link, resolveKind KindResolver) ([]v1alpha1.ActivityLink, error)

ConvertLinks converts CEL links to Activity links. If resolveKind is provided, it will be used to resolve plural resource names to Kind. Returns error if kind resolution fails.

func ExtractTenant

func ExtractTenant(user authnv1.UserInfo) v1alpha1.ActivityTenant

ExtractTenant extracts tenant information from user extra fields.

func ExtractTenantFromAnnotations

func ExtractTenantFromAnnotations(eventMap map[string]any) v1alpha1.ActivityTenant

ExtractTenantFromAnnotations reads scope annotations from event metadata and returns the corresponding ActivityTenant. Falls back to platform scope when the type annotation is absent or empty.

func GetNestedString

func GetNestedString(m map[string]any, keys ...string) string

GetNestedString extracts a string from a map, supporting nested access with multiple keys.

func IsHumanActor

func IsHumanActor(actor v1alpha1.ActivityActor) bool

IsHumanActor returns true if the actor represents a human user.

func IsSystemActor

func IsSystemActor(actor v1alpha1.ActivityActor) bool

IsSystemActor returns true if the actor represents a system component.

func NewRESTMapperFromConfig

func NewRESTMapperFromConfig(config *rest.Config) (meta.ResettableRESTMapper, error)

NewRESTMapperFromConfig creates a ResettableRESTMapper from a Kubernetes rest.Config. Uses a cached discovery client for efficient API group/resource lookups.

func ResolveActor

func ResolveActor(user authnv1.UserInfo) v1alpha1.ActivityActor

ResolveActor extracts actor information from the audit user field.

Actor types:

  • user: Human users authenticated via OIDC or other providers
  • system: Kubernetes controllers, service accounts, and other system components

Types

type ActivityBuilder

type ActivityBuilder struct {
	// Resource information from the policy
	APIGroup string
	Kind     string
}

ActivityBuilder contains the common fields needed to build an Activity.

func (*ActivityBuilder) BuildFromAudit

func (b *ActivityBuilder) BuildFromAudit(
	audit *auditv1.Event,
	summary string,
	links []cel.Link,
	resolveKind KindResolver,
) (*v1alpha1.Activity, error)

BuildFromAudit constructs an Activity from an audit event. If resolveKind is provided, it will be used to resolve resource names to Kind in links. Returns error if link conversion fails.

func (*ActivityBuilder) BuildFromEvent

func (b *ActivityBuilder) BuildFromEvent(
	eventMap map[string]interface{},
	summary string,
	links []cel.Link,
	resolveKind KindResolver,
) (*v1alpha1.Activity, error)

BuildFromEvent constructs an Activity from a Kubernetes event. If resolveKind is provided, it will be used to resolve resource names to Kind in links. Returns error if link conversion fails.

type AuditPolicyLookup

type AuditPolicyLookup interface {
	// MatchAudit looks up matching audit rules for the given resource and
	// evaluates them against the provided audit map.
	// Returns the first matching result, or nil if no policy matched.
	MatchAudit(apiGroup, resource string, auditMap map[string]any) (*MatchedPolicy, error)
}

AuditPolicyLookup is the interface used by AuditProcessor to look up and evaluate activity policies against audit log events.

type DLQConfig

type DLQConfig struct {
	// Enabled controls whether failed events are published to the DLQ.
	Enabled bool

	// StreamName is the NATS JetStream stream name for the DLQ.
	StreamName string

	// SubjectPrefix is the subject prefix for DLQ messages.
	// Messages are published to: <prefix>.<event_type>.<api_group>.<kind>
	SubjectPrefix string
}

DLQConfig contains configuration for the dead-letter queue.

func DefaultDLQConfig

func DefaultDLQConfig() DLQConfig

DefaultDLQConfig returns the default DLQ configuration.

type DLQPublisher

type DLQPublisher interface {
	// PublishAuditFailure publishes a failed audit event to the DLQ.
	// policyVersion should be the policy.Generation when available, or 0 if no policy.
	// Returns nil if the DLQ is disabled.
	PublishAuditFailure(ctx context.Context, payload json.RawMessage, policyName string, policyVersion int64, ruleIndex int, errorType ErrorType, err error, resource *DeadLetterResource, tenant *DeadLetterTenant) error

	// PublishEventFailure publishes a failed Kubernetes event to the DLQ.
	// policyVersion should be the policy.Generation when available, or 0 if no policy.
	// Returns nil if the DLQ is disabled.
	PublishEventFailure(ctx context.Context, payload json.RawMessage, policyName string, policyVersion int64, ruleIndex int, errorType ErrorType, err error, resource *DeadLetterResource, tenant *DeadLetterTenant) error
}

DLQPublisher publishes failed events to the dead-letter queue.

func NewDLQPublisher

func NewDLQPublisher(js nats.JetStreamContext, config DLQConfig) DLQPublisher

NewDLQPublisher creates a new DLQ publisher. Returns nil if the DLQ is disabled.

type DeadLetterEvent

type DeadLetterEvent struct {
	// Type identifies whether this is an audit log or Kubernetes event.
	Type EventType `json:"type"`

	// OriginalPayload contains the raw event JSON that failed processing.
	OriginalPayload json.RawMessage `json:"originalPayload"`

	// Error contains the error message from the failed processing attempt.
	Error string `json:"error"`

	// ErrorType classifies the type of error (cel_match, cel_summary, unmarshal).
	ErrorType ErrorType `json:"errorType"`

	// PolicyName is the name of the ActivityPolicy that failed evaluation.
	PolicyName string `json:"policyName"`

	// PolicyVersion is the policy.Generation when the failure occurred.
	// Used to trigger immediate retry when the policy is updated.
	PolicyVersion int64 `json:"policyVersion"`

	// RuleIndex is the index of the rule within the policy that failed.
	// -1 indicates the error occurred before rule evaluation.
	RuleIndex int `json:"ruleIndex"`

	// Timestamp is when the failure occurred.
	Timestamp metav1.Time `json:"timestamp"`

	// Tenant contains multi-tenancy information if available.
	Tenant *DeadLetterTenant `json:"tenant,omitempty"`

	// Resource contains information about the target resource.
	Resource *DeadLetterResource `json:"resource,omitempty"`

	// RetryCount tracks how many times this event has been retried.
	RetryCount int `json:"retryCount"`

	// LastRetryAt is when the last retry attempt occurred.
	LastRetryAt *metav1.Time `json:"lastRetryAt,omitempty"`

	// NextRetryAfter is when the event becomes eligible for the next retry.
	// Nil means the event has not been retried yet.
	NextRetryAfter *metav1.Time `json:"nextRetryAfter,omitempty"`
}

DeadLetterEvent wraps a failed event with error context for debugging.

type DeadLetterResource

type DeadLetterResource struct {
	// APIGroup is the API group of the resource (empty for core resources).
	APIGroup string `json:"apiGroup,omitempty"`
	// Kind is the kind of the resource.
	Kind string `json:"kind,omitempty"`
	// Name is the name of the resource.
	Name string `json:"name,omitempty"`
	// Namespace is the namespace of the resource (empty for cluster-scoped).
	Namespace string `json:"namespace,omitempty"`
}

DeadLetterResource contains resource information for a dead-lettered event.

type DeadLetterTenant

type DeadLetterTenant struct {
	// Type is the tenant type (platform, organization, project).
	Type string `json:"type,omitempty"`
	// Name is the tenant name.
	Name string `json:"name,omitempty"`
}

DeadLetterTenant contains tenant information for a dead-lettered event.

func NewDeadLetterTenantFromActivity

func NewDeadLetterTenantFromActivity(tenantType, tenantName string) *DeadLetterTenant

NewDeadLetterTenantFromActivity creates a DeadLetterTenant from an ActivityTenant. Returns nil if the input tenant has default/empty values.

type ErrorType

type ErrorType string

ErrorType classifies the type of error that caused DLQ routing.

const (
	// ErrorTypeCELMatch indicates the CEL match expression failed to evaluate.
	// Example: A match expression like "audit.verb == 'create'" fails due to
	// missing fields or type mismatches in the audit event.
	ErrorTypeCELMatch ErrorType = "cel_match"

	// ErrorTypeCELSummary indicates the CEL summary template failed to render.
	// Example: A summary template like "{{ actor }} created {{ resource.name }}"
	// fails because "resource.name" doesn't exist or has an unexpected type.
	ErrorTypeCELSummary ErrorType = "cel_summary"

	// ErrorTypeUnmarshal indicates the event JSON could not be parsed.
	// Example: Malformed JSON in the NATS message payload, or unexpected
	// structure that doesn't match the expected audit event schema.
	ErrorTypeUnmarshal ErrorType = "unmarshal"

	// ErrorTypeKindResolve indicates the resource-to-kind resolution failed.
	// Example: An audit event references resource "widgets" but no CRD or
	// built-in resource with that plural name exists in the API discovery cache.
	ErrorTypeKindResolve ErrorType = "kind_resolve"
)

type EvaluationResult

type EvaluationResult struct {
	// Activity is the generated activity, or nil if no rule matched
	Activity *v1alpha1.Activity

	// MatchedRuleIndex is the index of the rule that matched, or -1 if none matched
	MatchedRuleIndex int

	// MatchedRuleType is "audit" or "event" depending on which rule matched
	MatchedRuleType string

	// MatchedRuleName is the name of the matched rule from the policy spec
	MatchedRuleName string
}

EvaluationResult contains the result of evaluating policy rules against an input.

func EvaluateAuditRules

func EvaluateAuditRules(
	spec *v1alpha1.ActivityPolicySpec,
	audit *auditv1.Event,
	resolveKind KindResolver,
) (*EvaluationResult, error)

EvaluateAuditRules evaluates audit rules against an audit log input. Returns the generated Activity if a rule matches, or nil if no rule matched. If resolveKind is provided, it will be used to resolve resource names to Kind in links.

func EvaluateEventRules

func EvaluateEventRules(
	spec *v1alpha1.ActivityPolicySpec,
	eventData interface{},
	resolveKind KindResolver,
) (*EvaluationResult, error)

EvaluateEventRules evaluates event rules against a Kubernetes event input. Returns the generated Activity if a rule matches, or nil if no rule matched. If resolveKind is provided, it will be used to resolve resource names to Kind in links.

type EventPolicyLookup

type EventPolicyLookup interface {
	// MatchEvent looks up matching event rules for the given resource and
	// evaluates them against the provided event map.
	// Returns the first matching result, or nil if no policy matched.
	MatchEvent(apiGroup, kind string, eventMap map[string]any) (*MatchedPolicy, error)
}

EventPolicyLookup is the interface used by EventProcessor to look up and evaluate activity policies against Kubernetes events. activityprocessor.PolicyCache provides an adapter that satisfies this interface.

type EventProcessor

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

EventProcessor processes Kubernetes events from a NATS JetStream pull consumer and generates Activity records via ActivityPolicy event rules.

func NewEventProcessor

func NewEventProcessor(
	js nats.JetStreamContext,
	streamName string,
	consumerName string,
	activityPrefix string,
	policyLookup EventPolicyLookup,
	workers int,
	batchSize int,
	dlqPublisher DLQPublisher,
) *EventProcessor

NewEventProcessor creates a new event processor. js is the JetStream context used for both consuming events and publishing activities. streamName is the NATS stream to consume from (e.g., "EVENTS"). consumerName is the durable pull consumer name. activityPrefix is the subject prefix for publishing generated activities. policyLookup is used to evaluate events against ActivityPolicy event rules. dlqPublisher is used to publish failed events to the dead-letter queue.

func (*EventProcessor) Run

func (p *EventProcessor) Run(ctx context.Context) error

Run starts the event processor workers and blocks until ctx is cancelled.

type EventType

type EventType string

EventType identifies the type of event that failed processing.

const (
	// EventTypeAudit indicates an audit log event.
	EventTypeAudit EventType = "audit"
	// EventTypeK8sEvent indicates a Kubernetes event.
	EventTypeK8sEvent EventType = "k8s-event"
)

type KindResolver

type KindResolver func(apiGroup, resource string) (string, error)

KindResolver resolves a plural resource name to its Kind using API discovery. Returns error if resolution fails.

func NewKindResolver

func NewKindResolver(mapper meta.ResettableRESTMapper) KindResolver

NewKindResolver creates a KindResolver that uses a ResettableRESTMapper. On cache miss, it resets the discovery cache and retries to handle newly registered CRDs.

type MatchedPolicy

type MatchedPolicy struct {
	// PolicyName is the name of the matching policy.
	PolicyName string
	// Generation is the policy generation (version) that produced this match.
	Generation int64
	// APIGroup is the API group of the target resource.
	APIGroup string
	// Kind is the kind of the target resource.
	Kind string
	// Summary is the generated activity summary.
	Summary string
	// Links contains clickable references extracted from link() calls in the summary template.
	Links []cel.Link
}

MatchedPolicy contains the result of matching an event against policy rules.

type NATSDLQPublisher

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

NATSDLQPublisher implements DLQPublisher using NATS JetStream.

func (*NATSDLQPublisher) PublishAuditFailure

func (p *NATSDLQPublisher) PublishAuditFailure(ctx context.Context, payload json.RawMessage, policyName string, policyVersion int64, ruleIndex int, errorType ErrorType, err error, resource *DeadLetterResource, tenant *DeadLetterTenant) error

PublishAuditFailure publishes a failed audit event to the DLQ.

func (*NATSDLQPublisher) PublishEventFailure

func (p *NATSDLQPublisher) PublishEventFailure(ctx context.Context, payload json.RawMessage, policyName string, policyVersion int64, ruleIndex int, errorType ErrorType, err error, resource *DeadLetterResource, tenant *DeadLetterTenant) error

PublishEventFailure publishes a failed Kubernetes event to the DLQ.

type PolicyEvaluationError

type PolicyEvaluationError struct {
	PolicyName string
	RuleIndex  int
	Err        error
}

PolicyEvaluationError wraps an error with policy context for DLQ routing.

func NewPolicyEvaluationError

func NewPolicyEvaluationError(policyName string, ruleIndex int, err error) *PolicyEvaluationError

NewPolicyEvaluationError creates a new PolicyEvaluationError.

func (*PolicyEvaluationError) Error

func (e *PolicyEvaluationError) Error() string

func (*PolicyEvaluationError) Unwrap

func (e *PolicyEvaluationError) Unwrap() error

type PolicyRule

type PolicyRule interface {
	// IsValid returns true if the rule compiled successfully.
	IsValid() bool
	// EvaluateEventMatch evaluates the match expression against an event map.
	EvaluateEventMatch(eventMap map[string]any) (bool, error)
	// EvaluateAuditMatch evaluates the match expression against an audit map.
	EvaluateAuditMatch(auditMap map[string]any) (bool, error)
	// EvaluateSummary evaluates the summary template with the given variables.
	// Returns the rendered summary, any links collected via link() calls, and any error.
	EvaluateSummary(vars map[string]any) (string, []cel.Link, error)
}

PolicyRule represents a compiled activity policy rule for CEL evaluation. This is the minimal interface that EventProcessor and AuditProcessor need to match events/audit records against policy rules. The activityprocessor package provides concrete implementations of this interface.

type PolicySpec

type PolicySpec struct {
	// Name is the policy name.
	Name string
	// APIGroup is the target resource's API group.
	APIGroup string
	// Kind is the target resource's kind.
	Kind string
	// Resource is the plural resource name.
	Resource string
	// ResourceVersion is used for cache invalidation.
	ResourceVersion string
	// AuditRules are the CEL match/summary rule pairs for audit events.
	AuditRules []RuleSpec
	// EventRules are the CEL match/summary rule pairs for Kubernetes events.
	EventRules []RuleSpec
}

PolicySpec contains the minimal information needed to add a policy to the cache.

type PolicyUpdater

type PolicyUpdater interface {
	// AddPolicy adds a policy to the cache.
	AddPolicy(policy *PolicySpec) error
	// UpdatePolicy updates a policy in the cache.
	UpdatePolicy(oldPolicy, newPolicy *PolicySpec) error
	// RemovePolicy removes a policy from the cache.
	RemovePolicy(policy *PolicySpec)
}

PolicyUpdater is the interface used by the Processor to update the policy cache when ActivityPolicy resources change.

type ResourceResolver

type ResourceResolver func(apiGroup, kind string) (string, error)

ResourceResolver resolves a Kind to its plural resource name using API discovery.

func NewResourceResolver

func NewResourceResolver(mapper meta.ResettableRESTMapper) ResourceResolver

NewResourceResolver creates a ResourceResolver that uses a ResettableRESTMapper. On cache miss, it resets the discovery cache and retries.

type RuleSpec

type RuleSpec struct {
	Match   string
	Summary string
}

RuleSpec contains a match/summary rule pair.

Jump to

Keyboard shortcuts

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