Documentation
¶
Overview ¶
Package fga holds OpenFGA domain helpers shared by the CLI commands and the TUI: parsing tuple shorthand and turning an authorization model into a graph.
Index ¶
- func ConditionRows(c *openfga.RelationshipCondition) [][2]string
- func ExpandTree(root *ResNode, rootRef string, expand Expander, ...)
- func FormatContextJSON(ctx map[string]any) string
- func FormatContextualTuple(k openfga.TupleKey) string
- func FormatTuple(k openfga.TupleKey) string
- func FormatUserset(object, relation, user string) string
- func MarkGranted(root *ResNode, user string, r GrantResolver) bool
- func ParseJSONObject(label, s string) (map[string]any, error)
- func ParseTuple(user, relation, object string) (openfga.TupleKey, error)
- func RenderResolution(root *ResNode, user, object, relation string) string
- func SplitObject(object string) (typ, id string)
- func Triple(args []string, userFlag, relationFlag, objectFlag string) (user, relation, object string, err error)
- func ValidateObjectRef(object string) error
- func ValidateUserRef(user string) error
- type DiagramEdge
- type Expander
- type GrantResolver
- type Graph
- type Relation
- type RelationEdge
- type ResNode
- type ResOp
- type TypeNode
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ConditionRows ¶
func ConditionRows(c *openfga.RelationshipCondition) [][2]string
ConditionRows renders a tuple's condition as label/value pairs for detail views: a "Condition" row with the name, and a "Condition Context" row with the context as compact JSON when present. Returns nil for an unconditioned tuple.
func ExpandTree ¶
func ExpandTree(root *ResNode, rootRef string, expand Expander, tupleset func(object, relation string) []string, maxDepth, maxNodes int)
ExpandTree recursively expands computed-userset and tuple-to-userset leaves in place, attaching each reference's own resolution subtree so nested branches appear instead of dead-end leaves — e.g. a `viewer` node that resolves through `owner` gains `owner`'s subtree (and, in turn, its users) as a child.
OpenFGA's Expand API resolves only one level, so this issues a fresh expand per referenced relation via the `expand` callback; `tupleset` lists the objects a tuple-to-userset points at. rootRef ("object#relation" of root) seeds cycle detection. maxDepth bounds recursion depth and maxNodes bounds the total number of expansions (i.e. extra API calls), so a deep or cyclic model can't fan out unbounded. Call this before MarkGranted.
func FormatContextJSON ¶
FormatContextJSON renders a context map as compact JSON, or "" when empty.
func FormatContextualTuple ¶
FormatContextualTuple renders a contextual tuple in userset shorthand, with a " [conditionName]" suffix when the tuple carries a condition.
func FormatTuple ¶
func FormatUserset ¶
FormatUserset renders a tuple's parts in userset shorthand: "object#relation@user". Taking parts rather than a typed key lets it serve both openfga.TupleKey and openfga.CheckRequestTupleKey (which lack a common interface).
func MarkGranted ¶
func MarkGranted(root *ResNode, user string, r GrantResolver) bool
MarkGranted annotates each node with whether it grants `user`. Direct-user leaves match the user string exactly, computed usersets resolve via a Check, and tuple-to-userset leaves read the tupleset then Check the computed relation on each related object. It returns the root's grant status.
func ParseJSONObject ¶
ParseJSONObject parses s as a JSON object into a map, returning nil for empty input. label names the field in the error message (e.g. "--context" or "context") so both the CLI and TUI can share one implementation.
func ParseTuple ¶
ParseTuple parses the canonical "user relation object" triple from three separate arguments and returns a TupleKey. Each part is validated lightly: user and object should look like "type:id" (user may also carry "#relation" or be a wildcard "type:*").
func RenderResolution ¶
RenderResolution draws the resolution rooted at object#relation as the playground-style node-link diagram. user is the queried user (its box is highlighted); nodes and connectors on the granting branch are tinted.
func SplitObject ¶
SplitObject splits "type:id" into its type and id components.
func Triple ¶
func Triple(args []string, userFlag, relationFlag, objectFlag string) (user, relation, object string, err error)
Triple resolves a user/relation/object triple from positional args and the --user/--relation/--object flags. Flags set the fields they name; the remaining positionals then fill the still-unset fields left to right. This means `--user user:anne viewer document:roadmap` reads the two positionals as relation and object (rather than shifting them by index). Extra positionals that can't fill an unset field are an error, so a flag and a positional never silently fight over the same field. It errors if any part is missing.
func ValidateObjectRef ¶
ValidateObjectRef checks that object is a concrete "type:id" (no wildcard, no userset), matching ParseTuple's object rules.
func ValidateUserRef ¶
ValidateUserRef checks that user is a "type:id", a wildcard "type:*", or a userset "type:id#relation" — the same shape ParseTuple accepts for the user position — so a swapped argument yields a friendly hint, not a raw 400.
Types ¶
type DiagramEdge ¶
type DiagramEdge struct {
From string `json:"from"`
To string `json:"to"`
Kind string `json:"kind"`
Via string `json:"via"`
}
DiagramEdge is a directed dependency between two object types: type From has a relation that can be satisfied by users (or usersets) of type To. Kind is "direct" or "ttu" (tuple-to-userset / inherited). Via names the relation the dependency flows through (the relation on From for direct edges, the tupleset relation for ttu edges).
type Expander ¶
Expander resolves an object#relation to its (single-level) Expand subtree, or nil when it can't be expanded (API error, or no such resolution).
type GrantResolver ¶
type GrantResolver struct {
Check func(user, relation, object string) bool
Tupleset func(object, relation string) []string
}
GrantResolver supplies the live lookups MarkGranted needs. Check reports whether `user` has `relation` on `object`. Tupleset returns the objects related to `object` via `relation` — the "user" side of matching tuples — and may be nil to skip tuple-to-userset resolution.
type Graph ¶
type Graph struct {
SchemaVersion string `json:"schema_version"`
Types []TypeNode `json:"types"`
// Edges are the inter-type dependencies used to draw the node-link diagram.
Edges []DiagramEdge `json:"edges"`
}
Graph is the parsed, render-ready view of an authorization model.
func ParseModel ¶
func ParseModel(m *openfga.AuthorizationModel) Graph
ParseModel converts an authorization model into a Graph by interpreting the relation rewrite rules and the directly-related-user-types metadata. Slices are initialized (never nil) so `--json` output serializes empty collections as [] rather than null.
func (Graph) RenderDiagram ¶
RenderDiagram draws the authorization model as a node-link diagram: one rounded card per object type (a colored header plus its relations) laid out left→right by dependency depth, with edges routed orthogonally around the cards (never through them) and colored by resolution kind. The result is a wide, multi-line string meant to be shown inside a scrollable/pannable viewport.
type Relation ¶
type Relation struct {
Name string `json:"name"`
Edges []RelationEdge `json:"edges"`
}
Relation is a single relation on a type with its resolution edges.
type RelationEdge ¶
type RelationEdge struct {
// Kind is "direct", "computed", or "ttu" (tuple-to-userset).
Kind string `json:"kind"`
// Label is a human-readable description of the edge target.
Label string `json:"label"`
}
RelationEdge describes one resolution path for a relation.
type ResNode ¶
type ResNode struct {
Name string // the "object#relation" this node resolves
Op ResOp // how Children combine (ResLeaf → no children)
Children []*ResNode // operands for union / intersection / exclusion
// Leaf payloads — at most one is populated when Op == ResLeaf:
Users []string // direct users/usersets, e.g. ["user:anne", "team:eng#member"]
Computed string // a computed userset, e.g. "document:roadmap#owner"
TTUFrom string // tuple-to-userset: the tupleset relation, e.g. "document:x#parent"
TTUTo []string // the computed usersets reached through that tupleset
Granted bool // set by MarkGranted: this node reaches the queried user
}
ResNode is one node of a Check resolution. Each node resolves a single object#relation, either as a leaf (direct users, a computed userset, or a tuple-to-userset) or as a boolean combination of child nodes.
func GrantedPath ¶
GrantedPath returns a pruned copy of the tree keeping only the branch(es) that reach the user — the ACL resolution path. It returns nil when nothing grants (e.g. a denied check). Call MarkGranted first.