mapper

package module
v0.0.0-...-efd6d04 Latest Latest
Warning

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

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

README

OpenFGA Mapper

Go Reference Release License Join our community X

A Go module for mapping JSON events into OpenFGA relationship tuples using a declarative YAML mapping language.

Table of Contents

About

OpenFGA is an open source Fine-Grained Authorization solution inspired by Google's Zanzibar paper. It was created by the FGA team at Auth0 based on Auth0 Fine-Grained Authorization (FGA), available under a permissive license (Apache-2) and welcomes community contributions.

This module turns JSON events into OpenFGA relationship tuples. A mapping is authored in a declarative YAML language, compiled once, and then evaluated against events. The engine is stateless — it produces tuples (and tuple filter operations for read-diff-write flows); it makes no OpenFGA API calls, leaving I/O to the consumer.

It is made up of two packages:

  • mapper (module root) — compiles validated mapping configurations into an executable Mapping and evaluates events against it.
  • language — parses and validates mapping YAML into a canonical MappingConfig. mapper depends on language, never the reverse.

Resources

Installation

go get github.com/openfga/mapper

Getting Started

Compile a mapping and evaluate an event against it:

package main

import (
	"context"
	"fmt"

	"github.com/openfga/mapper"
)

func main() {
	yaml := []byte(`
version: "1"
rules:
  - name: "grant membership on user creation"
    when: input.type == "user.created"
    tuples:
      - user: "user:{{ input.data.email }}"
        relation: "member"
        object: "org:{{ input.data.org_id }}"
`)

	m, err := mapper.Compile(yaml)
	if err != nil {
		panic(err)
	}

	result, err := m.Evaluate(context.Background(), map[string]any{
		"type": "user.created",
		"data": map[string]any{
			"email":  "alice@example.com",
			"org_id": "acme",
		},
	})
	if err != nil {
		panic(err)
	}

	for _, t := range result.Tuples {
		fmt.Printf("%s %s %s\n", t.User, t.Relation, t.Object)
	}
}

Compile is a one-shot convenience. To compile many sources with the same configuration, build a Compiler once with mapper.NewCompiler(opts...) and reuse it.

Documentation

Contributing

See CONTRIBUTING.md.

License

This project is licensed under the Apache-2.0 license. See the LICENSE file for more info.

Documentation

Overview

Package mapper compiles validated FGA mapping configurations into an executable Mapping and evaluates JSON events against it, producing OpenFGA relationship tuples.

Mapping configurations are defined in YAML with three core components:

  • Expr (github.com/expr-lang/expr) for conditional logic, data extraction, and variable binding
  • Expr interpolation ({{ expr }}) for constructing tuple field strings (user, relation, object)
  • Iterators for fan-out from a single event to multiple tuples

Basic usage:

m, err := mapper.Compile(yamlBytes)
result, err := m.Evaluate(ctx, event)

Compile is a one-shot convenience. To compile many sources with the same configuration, build a Compiler once and reuse it:

compiler := mapper.NewCompiler()
m, err := compiler.Compile(yamlBytes)
m, err = compiler.CompileFile("mapping.yaml")

The compiler enforces safety limits: an evaluation timeout, a maximum number of tuples per event, and a maximum number of rules per configuration file. The tunable limits are set via functional options passed to Compile or NewCompiler:

m, err := mapper.Compile(yamlBytes, mapper.WithTimeout(50*time.Millisecond), mapper.WithTrace(true))

Parsing and validation are delegated to the language package.

Index

Constants

View Source
const (
	// DefaultTimeout is the maximum duration for a single Evaluate() call.
	DefaultTimeout = 3 * time.Second

	// DefaultMaxTuples is the maximum number of tuples a single event can produce.
	DefaultMaxTuples = 40
)
View Source
const DefaultMaxIteratorItems = 1000

DefaultMaxIteratorItems is the default cap on the number of items an iterator source array may contain per evaluation. Override per-compile with WithMaxIteratorItems.

Variables

This section is empty.

Functions

This section is empty.

Types

type Category

type Category string

Category classifies which stage of the pipeline produced a diagnostic.

const (
	// CategoryValidation covers structural validation and YAML parse errors.
	CategoryValidation Category = "validation"
	// CategoryEval covers expression compilation and evaluation errors.
	CategoryEval Category = "eval"
	// CategoryConflict covers write/delete conflicts detected during evaluation.
	CategoryConflict Category = "conflict"
	// CategoryUnknown covers errors that could not be classified.
	CategoryUnknown Category = "unknown"
)

type Compiler

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

Compiler holds configuration policy and compiles mapping YAML into Mappings.

func NewCompiler

func NewCompiler(opts ...Option) *Compiler

NewCompiler creates a Compiler with default settings, applying any options.

func (*Compiler) Compile

func (c *Compiler) Compile(data []byte) (*Mapping, error)

Compile parses and validates a YAML mapping configuration, returning an immutable Mapping ready for evaluation.

func (*Compiler) CompileFile

func (c *Compiler) CompileFile(path string) (*Mapping, error)

CompileFile reads a YAML mapping file from disk and compiles it.

func (*Compiler) CompileReader

func (c *Compiler) CompileReader(r io.Reader) (*Mapping, error)

CompileReader reads a YAML mapping from r and compiles it. It is a convenience over reading the stream into memory and calling Compile.

func (*Compiler) Err

func (c *Compiler) Err() error

Err returns any configuration errors recorded while applying options (e.g. a non-positive limit), or nil if the Compiler is well-configured. It lets callers detect misconfiguration before attempting a Compile; Compile returns the same error.

type Conflict

type Conflict struct {
	User     string
	Relation string
	Object   string
}

Conflict describes an unsatisfiable set of desired states on a single (User, Relation, Object) key.

type ConflictError

type ConflictError struct {
	Conflict
	Condition string // write/delete conflicts: the write tuple's condition, if any
	Kind      ConflictKind
}

ConflictError represents a runtime conflict on a single relationship (URO). OpenFGA identifies a relationship by (user, relation, object) only, so any URO carrying more than one incompatible desired state produces an invalid Write batch and is rejected here instead.

func (*ConflictError) Error

func (e *ConflictError) Error() string

type ConflictKind

type ConflictKind int

ConflictKind classifies why a set of desired states on one URO cannot be satisfied in a single OpenFGA Write batch.

const (
	// ConflictWriteDelete is a write and a delete targeting the same URO.
	ConflictWriteDelete ConflictKind = iota
	// ConflictCompetingWrites is two writes on the same URO whose condition or
	// context differ, i.e. two incompatible desired states for one relationship.
	ConflictCompetingWrites
)

type Diagnostic

type Diagnostic struct {
	Severity Severity          `json:"severity"`
	Category Category          `json:"category"`
	Field    string            `json:"field,omitempty"`   // YAML field path or tuple field name
	Message  string            `json:"message"`           // human-readable description
	Position language.Position `json:"position,omitzero"` // zero value = unknown, omitted from JSON
}

Diagnostic is a structured representation of a single error suitable for rendering in any consumer (CLI, IDE, browser editor, API response).

type Diagnostics

type Diagnostics []Diagnostic

Diagnostics is a named slice of Diagnostic values. It satisfies fmt.Stringer, so fmt.Println(diags) and fmt.Sprintf("%v", diags) produce the grouped human-readable output rather than Go's default slice representation. JSON marshalling is unaffected — it encodes as a JSON array.

func DiagnosticsFrom

func DiagnosticsFrom(err error) Diagnostics

DiagnosticsFrom extracts all structured diagnostics from an error tree. Handles errors.Join trees, wrapped errors, and all mapper error types. Returns nil for nil errors.

func (Diagnostics) String

func (d Diagnostics) String() string

String renders diagnostics as a human-readable multi-line string grouped by category, satisfying fmt.Stringer.

type EvalError

type EvalError struct {
	Expression string
	RuleName   string            // populated during evaluation before wrapping; empty if unknown
	Field      string            // tuple field name ("user", "relation", "object"); set for compile-time interpolation errors
	Position   language.Position // source location; set for compile-time interpolation errors; zero = unknown
	Err        error
}

EvalError represents an Expr expression evaluation error.

func (*EvalError) Error

func (e *EvalError) Error() string

func (*EvalError) Unwrap

func (e *EvalError) Unwrap() error

type FilteredTestRun

type FilteredTestRun struct {
	// Results contains outcomes for tests that were executed.
	Results []TestResult
	// Filtered is the number of tests skipped because they did not match the --run filter.
	Filtered int
	// Skipped is the number of matching tests that were not run because fail-fast triggered.
	Skipped int
}

FilteredTestRun holds the outcome of a filtered test execution.

func (FilteredTestRun) NotRun

func (r FilteredTestRun) NotRun() int

NotRun returns the total number of tests that did not execute (filtered + skipped).

func (FilteredTestRun) Stopped

func (r FilteredTestRun) Stopped() bool

Stopped reports whether fail-fast actually prevented matching tests from running.

type Mapping

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

Mapping is a compiled mapping configuration ready to evaluate events. It is immutable and safe for concurrent use across multiple goroutines. Each Evaluate() call operates independently with its own evaluation state.

func Compile

func Compile(src []byte, opts ...Option) (*Mapping, error)

Compile is a one-shot convenience that builds a Compiler with the given options and compiles src in a single call. Use NewCompiler directly when compiling multiple sources with the same configuration.

func (*Mapping) Evaluate

func (m *Mapping) Evaluate(ctx context.Context, event map[string]any) (*Result, error)

Evaluate runs all rules against the given event and returns the result.

For each rule:

  1. Evaluate variables (sequential, with access to input and prior variables)
  2. Evaluate rule when guard (skip rule if false)
  3. Fan-out via iterator (or single pass if no iterator), rendering tuples per item

After all rules:

  1. Deduplicate tuples and detect write/delete conflicts
  2. Enforce maxTuples limit

func (*Mapping) RuleCount

func (m *Mapping) RuleCount() int

RuleCount returns the number of rules in the compiled mapping.

func (*Mapping) Rules

func (m *Mapping) Rules() []RuleSummary

Rules returns a read-only summary of each rule's tuple templates for static analysis (e.g., model validation). The returned values are copies — callers cannot mutate the compiled mapping's internal state.

func (*Mapping) RunTests

func (m *Mapping) RunTests(ctx context.Context) []TestResult

RunTests executes the embedded test cases from the mapping configuration and returns results for each case.

func (*Mapping) RunTestsFiltered

func (m *Mapping) RunTestsFiltered(ctx context.Context, filter string, failFast bool) FilteredTestRun

RunTestsFiltered executes embedded test cases with optional name filtering and fail-fast support.

filter is a case-sensitive substring; empty string runs all tests. If failFast is true, execution stops after the first failure or error.

func (*Mapping) TestCount

func (m *Mapping) TestCount() int

TestCount returns the number of embedded test cases in the compiled mapping.

func (*Mapping) Version

func (m *Mapping) Version() string

Version returns the schema version declared in the mapping file.

type Option

type Option func(*Compiler)

Option configures a Compiler. Options are applied by NewCompiler and by the one-shot Compile facade. An option that receives an invalid value records the error on the Compiler; that error is surfaced from Compile rather than panicking.

func WithMaxIteratorItems

func WithMaxIteratorItems(n int) Option

WithMaxIteratorItems overrides the default cap on the number of items an iterator source array may contain per evaluation. The count must be positive; a non-positive value is recorded as an error and surfaced from Compile.

func WithMaxRules

func WithMaxRules(n int) Option

WithMaxRules overrides the default cap on the number of rules a single mapping file may declare, enforced during validation (within Compile). The count must be positive; a non-positive value is recorded as an error and surfaced from Compile.

func WithMaxTuples

func WithMaxTuples(n int) Option

WithMaxTuples overrides the default maximum tuples per event. The count must be positive; a non-positive value is recorded as an error and surfaced from Compile.

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout overrides the default evaluation timeout per Evaluate() call. The duration must be positive; a non-positive value is recorded as an error and surfaced from Compile.

func WithTrace

func WithTrace(enabled bool) Option

WithTrace enables execution tracing in the compiled Mapping.

type Position

type Position = language.Position

Position is a source location within a mapping file. It is an alias for language.Position so SDK callers handling the mapper error path (EvalError, Diagnostic) can name it without importing the language package; the two are the same type.

type PostProcessResult

type PostProcessResult struct {
	RemovedTuples []Tuple    // the duplicate tuples that were removed
	Conflicts     []Conflict // all write/delete conflicts detected (empty if none)
}

PostProcessResult holds metadata from tuple post-processing (dedup + conflict detection). Populated on the Trace only when tracing is enabled.

type Result

type Result struct {
	Tuples                []Tuple                `json:"tuples"`
	TupleFilterOperations []TupleFilterOperation `json:"tuple_filter_operations,omitempty"`
	Trace                 *Trace                 `json:"trace,omitempty"` // nil unless tracing is enabled on the Compiler
}

Result is the output of Mapping.Evaluate.

type RuleStatus

type RuleStatus string

RuleStatus represents the outcome of evaluating a single rule.

const (
	// RuleMatched indicates the rule's when guard evaluated to true and the rule produced tuples.
	RuleMatched RuleStatus = "matched"
	// RuleSkipped indicates the rule's when guard evaluated to false and the rule was skipped.
	RuleSkipped RuleStatus = "skipped"
	// RuleErrored indicates an error occurred while evaluating the rule.
	RuleErrored RuleStatus = "error"
)

type RuleSummary

type RuleSummary struct {
	Name           string
	Tuples         []TupleTemplate
	IteratorTuples []TupleTemplate
	TupleFilters   []TupleFilterTemplate
}

RuleSummary is a read-only view of a rule's tuple templates for static analysis. It carries mapper-owned template types (not the language package's parse structs), exposing only the fields needed to validate a mapping against an authorization model — no source positions or other internal parse state leak through.

type RuleTrace

type RuleTrace struct {
	Name     string
	Status   RuleStatus
	Error    error // populated only when Status == RuleErrored
	EmittedN int
	FilterN  int // number of rendered tuple filters (0 if rule has no tuple_filters)
}

RuleTrace records evaluation details for a single rule.

type Severity

type Severity string

Severity represents the severity of a diagnostic.

const (
	// SeverityError indicates a fatal error that prevents compilation or evaluation.
	SeverityError Severity = "error"
)

type TestResult

type TestResult struct {
	Name   string
	Passed bool
	// Expected is the set of tuples the test case declared.
	Expected []language.Tuple
	// Actual is the set of tuples evaluation produced.
	Actual []language.Tuple
	// ExpectedTupleFilters is the set of tuple filters the test case declared.
	ExpectedTupleFilters []language.TupleFilter
	// ActualTupleFilters is the set of tuple filters evaluation produced.
	ActualTupleFilters []language.TupleFilter
	// Error is populated if the test failed due to an evaluation error.
	Error error
	// Duration is the wall time taken to evaluate this test case.
	Duration time.Duration
	// Trace holds rule-level execution details; nil unless the mapping was compiled with WithTrace(true).
	Trace *Trace
	// Input is the event that was evaluated, preserved for display in verbose failure output.
	Input map[string]any
}

TestResult captures the outcome of a single embedded test case.

type Trace

type Trace struct {
	Rules       []RuleTrace
	Duration    time.Duration
	PostProcess *PostProcessResult // nil unless dedup or conflicts occurred
}

Trace holds execution trace data for debugging rule evaluation. Populated only when WithTrace(true) is set on the Compiler.

type Tuple

type Tuple = language.Tuple

Tuple is an OpenFGA relationship tuple produced by evaluation. It is an alias for language.Tuple so SDK callers can name it without a second import; the two are the same type.

type TupleFilter

type TupleFilter = language.TupleFilter

TupleFilter is a rendered tuple filter produced by evaluation. It is an alias for language.TupleFilter so SDK callers can name it without a second import; the two are the same type.

type TupleFilterOperation

type TupleFilterOperation struct {
	Filters []TupleFilter `json:"filters"`
	Tuples  []Tuple       `json:"tuples"`
}

TupleFilterOperation groups a rule's rendered filters with its desired-state tuples. One per rule that has tuple_filters. The consumer uses these to drive read-diff-write against FGA.

type TupleFilterTemplate

type TupleFilterTemplate struct {
	User     string
	Relation string
	Object   string
}

TupleFilterTemplate is the pre-render shape of a tuple filter for static analysis. Empty fields are wildcards; interpolated fields cannot be validated statically.

type TupleTemplate

type TupleTemplate struct {
	User      string
	Relation  string
	Object    string
	Condition string            // FGA condition name (empty if none)
	Context   map[string]string // FGA context keys → interpolation templates (nil if none)
}

TupleTemplate is the pre-render shape of a tuple, exposing only the fields a static analyzer needs to check a mapping against an authorization model. The User, Relation, and Object fields may still contain {{ }} interpolation; a fully interpolated field cannot be validated statically and is skipped by the analyzer.

type ValidationError

type ValidationError = language.ValidationError

ValidationError is a structural validation error carrying a source Position. It is an alias for language.ValidationError so SDK callers can branch on the mapper error surface (alongside EvalError and ConflictError) without a second import; the two are the same type.

Directories

Path Synopsis
Package language parses and validates FGA mapping configurations.
Package language parses and validates FGA mapping configurations.

Jump to

Keyboard shortcuts

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