Documentation
¶
Overview ¶
Package episodic provides namespace encoding/decoding helpers and OPA policy integration for the namespaced episodic memory system.
Index ¶
- Constants
- func BuiltinDefaultKindVersion(ctx context.Context) (model.MemoryKindVersion, error)
- func CompileKindProjection(ctx context.Context, src string) (*rego.PreparedEvalQuery, error)
- func DecodeNamespace(encoded string) ([]string, error)
- func EncodeNamespace(segments []string, maxDepth int) (string, error)
- func EvaluateKindProjection(ctx context.Context, pq *rego.PreparedEvalQuery, namespace []string, ...) (map[string]interface{}, error)
- func ImportKindVersions(ctx context.Context, store registryepisodic.EpisodicStore, dir string) error
- func MatchesSuffix(encoded string, suffix []string) bool
- func NamespacePrefixPattern(prefixEncoded string) string
- func NamespaceTruncate(encoded string, depth int) string
- func ParseCanonicalKindName(name string) (family, version string, err error)
- func ParseKindSelector(sel string) (family, canonicalName string, isExact bool)
- func ResolveSortFieldType(field string, exactVersion string, versions KindVersionList) (string, error)
- func ValidateAndNormalizeCallerFilterValues(fieldName, op, fieldType string, rawValues []interface{}) ([]interface{}, error)
- func ValidateAndNormalizeKindProjection(result map[string]interface{}, declaredTypes map[string]string) (map[string]interface{}, error)
- func ValidateCallerFilterField(fieldName, op, exactVersion string, versions KindVersionList) error
- func ValidateKindAttributeTypes(types map[string]string) error
- func ValidateKindSelector(sel string) error
- type AttributeType
- type AuthzDecision
- type KindImportManifest
- type KindIntersection
- type KindVersionList
- type PolicyContext
- type PolicyEngine
- func (e *PolicyEngine) EvaluateAuthz(ctx context.Context, operation string, namespace []string, key string, ...) (AuthzDecision, error)
- func (e *PolicyEngine) InjectFilter(ctx context.Context, nsPrefix []string, filter map[string]interface{}, ...) ([]string, map[string]interface{}, error)
- func (e *PolicyEngine) InjectFilterParts(ctx context.Context, nsPrefix []string, filter map[string]interface{}, ...) ([]string, map[string]interface{}, error)
- func (e *PolicyEngine) InjectFilterPartsWithKind(ctx context.Context, nsPrefix []string, filter map[string]interface{}, ...) (effectivePrefix []string, policyFilter map[string]interface{}, ...)
- func (e *PolicyEngine) IsAllowed(ctx context.Context, operation string, namespace []string, key string, ...) (bool, error)
Constants ¶
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
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 ¶
DecodeNamespace decodes a storage string back into a []string namespace.
func EncodeNamespace ¶
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 ¶
MatchesSuffix returns true if the decoded namespace ends with each segment in suffix.
func NamespacePrefixPattern ¶
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 ¶
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
ParseCanonicalKindName parses and validates "family/version". Returns family, version, and nil error on success.
func ParseKindSelector ¶ added in v0.2.0
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
ValidateKindAttributeTypes checks that every key/value in the declared type map is valid.
func ValidateKindSelector ¶ added in v0.2.0
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 ¶
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
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
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:
- Authz policy — controls read/write/delete access per (namespace, key).
- 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.