profile

package
v1.0.0-alpha.21 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package profile enforces the bounded subset of OpenFGA that Zitadel can compile into portable relational query plans (ADR 032 §2).

Supported: direct relations, computed usersets, union, userset references, and tuple-to-userset bounded by known hierarchy edges. Everything else is rejected at upload time with structured Diagnostics rather than failing or timing out during a check.

Contextual tuples are not validated here because they are a check-time API input, not part of an authorization model; the resolver rejects them on request hot paths.

Index

Constants

View Source
const SupportedSchemaVersion = "1.1"

SupportedSchemaVersion is the only OpenFGA schema version the profile accepts. Modular models (1.2) are not planned for the MVP.

Variables

View Source
var DefaultHierarchyTypes = []string{"app", "app_group", "project", "team", "user"}

DefaultHierarchyTypes are the object types a tuple-to-userset may traverse. Bounding traversal to known edges keeps a check's join depth predictable on both PostgreSQL and Spanner.

Functions

func Validate

func Validate(model authz.Model) error

Validate reports profile violations in model using the default hierarchy edges. It returns nil when the model compiles within the profile, and Diagnostics otherwise.

Types

type Code

type Code string

Code identifies a profile violation. Codes are stable so the schema upload API can render them inside details and clients can branch on them. They stay plain snake_case; the dotted authz.* prefix belongs on the outer [domain.Error] that wraps Diagnostics at the service boundary. Where OpenFGA already names the same condition (openfga/api ErrorCode), the code reuses that vocabulary.

const (
	// CodeUnsupportedSchemaVersion mirrors OpenFGA 2057: the model declares a
	// schema version we do not accept.
	CodeUnsupportedSchemaVersion Code = "unsupported_schema_version"
	// CodeTypeNotFound mirrors OpenFGA 2021: a restriction names a type the
	// model never defines.
	CodeTypeNotFound Code = "type_not_found"
	// CodeRelationNotFound mirrors OpenFGA 2022: a rewrite or restriction names
	// a relation the target type never defines.
	CodeRelationNotFound Code = "relation_not_found"
)

Codes reused from OpenFGA's own ErrorCode enum (openfga/api, openfga/v1/errors_ignore.proto). These name conditions OpenFGA itself rejects, so a customer who knows OpenFGA meets the same word here.

const (
	// CodeUnsupportedOperator: an `and` or `but not` expression. The profile
	// starts with union only.
	CodeUnsupportedOperator Code = "unsupported_operator"
	// CodeUnsupportedRewrite: a relation whose definition the IR could not
	// classify — a parser or profile gap rather than an authoring mistake.
	CodeUnsupportedRewrite Code = "unsupported_rewrite"
	// CodeUnsupportedWildcard: a `[type:*]` restriction, which has no bounded
	// expansion in a list predicate.
	CodeUnsupportedWildcard Code = "unsupported_wildcard"
	// CodeUnsupportedCondition: a caveat definition or a `with <condition>`
	// restriction, which would need attribute evaluation off the indexed path.
	CodeUnsupportedCondition Code = "unsupported_condition"
	// CodeUnboundedRecursion: a relation that resolves back to itself, so its
	// closure cannot be precomputed at upload time.
	CodeUnboundedRecursion Code = "unbounded_recursion"
	// CodeUnboundedTupleToUserset: a `<relation> from <tupleset>` whose tupleset
	// is not a plain direct assignment onto a known hierarchy edge.
	CodeUnboundedTupleToUserset Code = "unbounded_tuple_to_userset"
	// CodeMissingTypeRestriction: a direct assignment with no `[...]` list.
	// Distinct from OpenFGA's empty_relation_definition (2023), which is about a
	// relation carrying no definition at all.
	CodeMissingTypeRestriction Code = "missing_type_restriction"
	// CodeEmptyRelationDefinition: a union (or nested union) with no assignable
	// leaves — present in the catalog but never satisfiable. Crafted JSON can
	// produce this; the DSL grammar cannot.
	CodeEmptyRelationDefinition Code = "empty_relation_definition"
)

Codes specific to Zitadel's profile. OpenFGA accepts every construct below; we reject it because it cannot be compiled into a bounded, portable query plan (ADR 032 §2). OpenFGA's nearest concept, authorization_model_resolution_too_complex (2002), is a runtime complexity signal rather than an upload-time rejection, so it is deliberately not reused.

type Diagnostic

type Diagnostic struct {
	Code      Code
	Message   string
	Type      string
	Relation  string
	Condition string
}

Diagnostic is a single profile violation. Type, Relation, and Condition are set when the violation can be attributed to one of them.

func (Diagnostic) Error

func (d Diagnostic) Error() string

type Diagnostics

type Diagnostics []Diagnostic

Diagnostics is the full set of violations found in one model. Validation collects every violation instead of failing on the first, so an upload reports all problems at once.

func (Diagnostics) Error

func (d Diagnostics) Error() string

func (Diagnostics) Unwrap

func (d Diagnostics) Unwrap() []error

Unwrap exposes the individual diagnostics to errors.Is and errors.As. Diagnostic holds only comparable fields, so errors.Is matches a diagnostic by value — a caller can test for one exact violation without scanning the slice.

type Validator

type Validator struct {
	// HierarchyTypes bounds tuple-to-userset traversal.
	//   - nil: use [DefaultHierarchyTypes]
	//   - non-nil empty: allow no TTU edges (deny all hierarchy traversal)
	//   - non-empty: allow only the listed types
	HierarchyTypes []string
}

Validator checks a model against the supported profile.

func (Validator) Validate

func (v Validator) Validate(model authz.Model) error

Validate reports profile violations in model. It returns nil when the model compiles within the profile, and Diagnostics otherwise.

Jump to

Keyboard shortcuts

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