episodic

package
v0.2.2 Latest Latest
Warning

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

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

Documentation

Overview

Package episodic provides namespace encoding/decoding helpers and OPA policy integration for the namespaced episodic memory system.

Index

Constants

View Source
const (
	DefaultKindName   = "default/v1"
	DefaultKindFamily = "default"
)

Well-known schema name constants.

Variables

This section is empty.

Functions

func BuiltinDefaultKindVersion added in v0.2.0

func BuiltinDefaultKindVersion(ctx context.Context) (model.MemoryKindVersion, error)

BuiltinDefaultKindVersion returns the immutable default/v1 definition used to seed every primary datastore. The manifest and Rego source are embedded files so all datastore implementations use one canonical definition.

func CompileKindProjection added in v0.2.0

func CompileKindProjection(ctx context.Context, src string) (*rego.PreparedEvalQuery, error)

CompileKindProjection compiles and validates a projection Rego source. Returns a PreparedEvalQuery ready for evaluation. Results are cached by source text so repeated calls for the same immutable schema version do not recompile.

func DecodeNamespace

func DecodeNamespace(encoded string) ([]string, error)

DecodeNamespace decodes a storage string back into a []string namespace.

func EncodeNamespace

func EncodeNamespace(segments []string, maxDepth int) (string, error)

EncodeNamespace encodes a []string namespace into a single storage string. Each segment is percent-encoded (url.PathEscape), then joined with \x1e (RS). Returns an error if any segment is empty or if depth > maxDepth.

func EvaluateKindProjection added in v0.2.0

func EvaluateKindProjection(ctx context.Context, pq *rego.PreparedEvalQuery, namespace []string, key string, value map[string]interface{}, index map[string]string) (map[string]interface{}, error)

EvaluateKindProjection evaluates a projection Rego program over replay inputs. Returns the raw result map (not yet validated against declared types).

func ImportKindVersions added in v0.2.0

func ImportKindVersions(ctx context.Context, store registryepisodic.EpisodicStore, dir string) error

ImportKindVersions recursively examines every *.yaml and *.yml document in a policy import directory and imports only documents whose kind is "memory-kind". Existing identical versions are idempotent. Conflicting content is logged and never overwrites the immutable database record. A directory with no memory-kind documents is valid because it may contain other policy types.

func MatchesSuffix

func MatchesSuffix(encoded string, suffix []string) bool

MatchesSuffix returns true if the decoded namespace ends with each segment in suffix.

func NamespacePrefixPattern

func NamespacePrefixPattern(prefixEncoded string) string

NamespacePrefixPattern returns the SQL LIKE pattern that matches namespaces under the given prefix. The pattern matches the prefix exactly or any descendant, using the RS separator as the delimiter so "users\x1ealice" never matches "users\x1ealiced".

func NamespaceTruncate

func NamespaceTruncate(encoded string, depth int) string

NamespaceTruncate returns the first depth segments of the encoded namespace, re-encoded. If depth >= actual depth, returns the encoded namespace unchanged.

func ParseCanonicalKindName added in v0.2.0

func ParseCanonicalKindName(name string) (family, version string, err error)

ParseCanonicalKindName parses and validates "family/version". Returns family, version, and nil error on success.

func ParseKindSelector added in v0.2.0

func ParseKindSelector(sel string) (family, canonicalName string, isExact bool)

ParseKindSelector parses a search/list kind selector:

  • "family/version" → exact canonical name (IsExact == true)
  • "family" → family selector (IsExact == false)
  • "" → empty selector (callers interpret this as all kinds)

func ResolveSortFieldType added in v0.2.0

func ResolveSortFieldType(field string, exactVersion string, versions KindVersionList) (string, error)

ResolveSortFieldType resolves the declared attribute type for a sort field across the supplied list of regular schema versions.

Rules per Enhancement 115 §Sort:

  • versions == nil / empty → returns ("", nil) — callers use untyped sort.
  • Exactly one version supplied (exact canonical selector): field must be declared, returns its type; returns error if absent.
  • Multiple versions (family/all selector): field must be declared in at least one version; all declaring versions must agree on type; conflict → error. Returns error when versions exist but none declares the field.

func ValidateAndNormalizeCallerFilterValues added in v0.2.0

func ValidateAndNormalizeCallerFilterValues(fieldName, op, fieldType string, rawValues []interface{}) ([]interface{}, error)

ValidateAndNormalizeCallerFilterValues validates and normalizes the values for a single caller filter condition against the resolved attribute type and operator.

Rules per Enhancement 115 §CallerFilter:

  • $exists: values must be empty (no value expected).
  • string: each value must be a string.
  • number: each value must be a finite float64 or json.Number convertible to one.
  • boolean: each value must be a bool.
  • timestamp $eq/$in: each value must be parseable as RFC3339/RFC3339Nano and is rewritten to canonicalTimestampLayout ("2006-01-02T15:04:05.000000000Z") in UTC.
  • string[]: values are treated as strings (same rule as string).

Returns the normalized values (a new slice) or an error. When fieldType == "" (untyped — legacy or no schema), returns values unchanged.

func ValidateAndNormalizeKindProjection added in v0.2.0

func ValidateAndNormalizeKindProjection(result map[string]interface{}, declaredTypes map[string]string) (map[string]interface{}, error)

ValidateAndNormalizeKindProjection checks the projection result against declared types and normalizes timestamp fields to canonical UTC form.

func ValidateCallerFilterField added in v0.2.0

func ValidateCallerFilterField(fieldName, op, exactVersion string, versions KindVersionList) error

ValidateCallerFilterField validates that a single filter condition is legal for the supplied set of regular schema versions.

Policy-injected security filters (policyFilter) must NOT be passed here — the built-in namespace/sub fields are always valid.

Rules:

  • exactVersion is a non-empty canonical name → field must be declared; operator must be supported for the declared type.
  • exactVersion == "" (family / all selector) → field must be declared in at least one version; all must agree on type; conflict → error; string[] + range operators → error.

func ValidateKindAttributeTypes added in v0.2.0

func ValidateKindAttributeTypes(types map[string]string) error

ValidateKindAttributeTypes checks that every key/value in the declared type map is valid.

func ValidateKindSelector added in v0.2.0

func ValidateKindSelector(sel string) error

ValidateKindSelector validates a user-supplied kind selector string. Valid values are: "" (empty = all kinds), a family name (e.g. "default"), or a canonical exact name (e.g. "default/v1"). Returns an error if the selector is non-empty but malformed.

Types

type AttributeType added in v0.2.0

type AttributeType string

AttributeType is one of the supported declared attribute types.

const (
	AttributeTypeString    AttributeType = "string"
	AttributeTypeNumber    AttributeType = "number"
	AttributeTypeBoolean   AttributeType = "boolean"
	AttributeTypeTimestamp AttributeType = "timestamp"
	AttributeTypeStringArr AttributeType = "string[]"
)

type AuthzDecision

type AuthzDecision struct {
	Allow  bool   `json:"allow"`
	Reason string `json:"reason,omitempty"`
}

AuthzDecision is the structured authz policy result.

type KindImportManifest added in v0.2.0

type KindImportManifest struct {
	Kind               string            `json:"kind"`
	Name               string            `json:"name"`
	Attributes         map[string]string `json:"attributes"`
	ProjectionRego     string            `json:"projectionRego,omitempty"`
	ProjectionRegoFile string            `json:"projectionRegoFile,omitempty"`
	Writable           *bool             `json:"writable,omitempty"`
}

KindImportManifest is a file-backed bootstrap definition for an immutable database-backed MemoryKindVersion. The database remains authoritative after import; changing content requires a new canonical name.

type KindIntersection added in v0.2.0

type KindIntersection struct {
	Selector string
	Empty    bool
}

KindIntersection is the typed result of IntersectKindSelectors. Empty=true means the caller and policy selectors are incompatible and no memories can possibly match. Callers must check Empty before querying the store and return an empty result set immediately without any store query. When Empty=false, Selector is the effective kind selector to pass to the store (empty string means "all kinds").

func IntersectKindSelectors added in v0.2.0

func IntersectKindSelectors(callerSel, policySel string) KindIntersection

IntersectKindSelectors computes the narrowing intersection of a caller kind selector and a policy kind selector.

Both inputs must already be trimmed and valid. Callers should validate the caller selector with ValidateKindSelector before calling this function.

Rules (policy never broadens):

  • callerSel == "" && policySel == "" → {Selector: "", Empty: false} (no restriction)
  • callerSel == "" && policySel != "" → {policySel, false} (policy restricts caller)
  • callerSel != "" && policySel == "" → {callerSel, false} (no policy restriction)
  • equal strings → {callerSel, false}
  • both exact, same string → {callerSel, false}
  • both exact, different → {Empty: true}
  • callerSel exact, policySel family: caller family == policy → {callerSel, false} different → {Empty: true}
  • callerSel family, policySel exact: policy family == caller → {policySel, false} different → {Empty: true}
  • both family, equal → {callerSel, false}
  • both family, different → {Empty: true}

type KindVersionList added in v0.2.0

type KindVersionList []struct {
	Name           string
	AttributeTypes map[string]string
}

KindVersionList is a slice of MemoryKindVersion-like structs used by sort/filter helpers. It is defined as a local type to avoid an import cycle with registry/episodic.

type PolicyContext

type PolicyContext struct {
	UserID    string                 `json:"user_id"`
	ClientID  string                 `json:"client_id"`
	JWTClaims map[string]interface{} `json:"jwt_claims"`
}

PolicyContext contains the caller's identity for OPA policy evaluation.

type PolicyEngine

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

PolicyEngine evaluates the two immutable OPA policies for episodic memory:

  1. Authz policy — controls read/write/delete access per (namespace, key).
  2. Search filter injection policy — narrows namespace_prefix + adds attribute_filter constraints.

Attribute projection is now handled per-memory by the stored MemoryKindVersion and is not part of the global PolicyEngine.

func NewPolicyEngine

func NewPolicyEngine(ctx context.Context, policyImportDir string) (*PolicyEngine, error)

NewPolicyEngine creates a PolicyEngine. A policy import directory may contain both authz.rego and filter.rego at its root to replace the built-in global policies. When neither file is present, the built-in policies are used. Other Rego files are assets for manifest-based policy types and are not loaded here.

func (*PolicyEngine) EvaluateAuthz

func (e *PolicyEngine) EvaluateAuthz(ctx context.Context, operation string, namespace []string, key string, value map[string]interface{}, index map[string]string, kind string, pc PolicyContext) (AuthzDecision, error)

EvaluateAuthz evaluates the authz policy and returns the decision. kind is the resolved exact canonical memory kind (e.g. "default/v1"). It is passed as input.kind so authz policies can restrict access by kind. For read/update it is the kind stored on the row; for write it is the resolved write kind (before persistence).

func (*PolicyEngine) InjectFilter

func (e *PolicyEngine) InjectFilter(ctx context.Context, nsPrefix []string, filter map[string]interface{}, pc PolicyContext) ([]string, map[string]interface{}, error)

InjectFilter evaluates the search filter injection policy and returns the effective namespace_prefix and merged attribute_filter to use for search.

func (*PolicyEngine) InjectFilterParts

func (e *PolicyEngine) InjectFilterParts(ctx context.Context, nsPrefix []string, filter map[string]interface{}, pc PolicyContext) ([]string, map[string]interface{}, error)

InjectFilterParts evaluates the search filter injection policy and returns the effective namespace_prefix plus policy-supplied attribute_filter without merging it into the caller filter. The caller kind selector is not passed through this variant; use InjectFilterPartsWithKind when kind restriction is needed.

func (*PolicyEngine) InjectFilterPartsWithKind added in v0.2.0

func (e *PolicyEngine) InjectFilterPartsWithKind(ctx context.Context, nsPrefix []string, filter map[string]interface{}, callerKind string, pc PolicyContext) (effectivePrefix []string, policyFilter map[string]interface{}, ki KindIntersection, err error)

InjectFilterPartsWithKind evaluates the search filter injection policy and returns:

  • effectivePrefix: narrowed namespace prefix
  • policyFilter: policy-injected attribute_filter (not yet merged with caller)
  • ki: KindIntersection of callerKind and the optional policy kind output

filter.rego may include a "kind" field in its output document; if present it must be a valid kind selector string and is intersected with callerKind using IntersectKindSelectors. A non-string or malformed policy kind output returns an internal error. The built-in default policy does not output "kind", so ki.Selector == callerKind and ki.Empty == false for all built-in policy users.

func (*PolicyEngine) IsAllowed

func (e *PolicyEngine) IsAllowed(ctx context.Context, operation string, namespace []string, key string, pc PolicyContext) (bool, error)

IsAllowed evaluates the authz policy and returns true if the operation is allowed.

Jump to

Keyboard shortcuts

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