authz

package
v2.2.1 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package authz defines the permission vocabulary used by role-based access control. It is deliberately a leaf package: it knows nothing about users, roles, or storage. The catalogue of resources lives here so both editions share one source of truth, routes can be annotated with typed permissions, and the UI can render a permission matrix straight from the API.

A permission is "<resource>:<action>" where the resource is the plural kebab-case route collection segment ("llms", "data-catalogues") and the action is one of read, write, delete, execute, publish. write, delete, execute and publish each imply read. publish does not imply write: it is the workflow verb that makes an object live (activate, enable) and is offered only by resources that have such a switch.

Community Edition never evaluates these beyond "is the user an admin"; Enterprise Edition resolves a user's effective set from role bindings.

Index

Constants

View Source
const (
	CodeUnauthenticated    = "unauthenticated"
	CodePermissionDenied   = "permission_denied"
	CodeEnterpriseRequired = "enterprise_required"
	CodeSystemRole         = "system_role"
	CodeLastOwner          = "last_owner"
	CodeOwnerUserOnly      = "owner_user_only"
	CodeOwnerRequired      = "owner_required"
)

Error codes carried in the "code" field of an ErrorBody. The UI keys off these, never off the HTTP status alone, so it can tell "your role lacks this" apart from "this edition lacks this".

View Source
const ContextKey = "authz"

ContextKey is the gin context key under which the request's Context is stored by the API's rbacContext middleware.

View Source
const PluginResourcePrefix = "plugin:"

PluginResourcePrefix starts every plugin-contributed resource key. The umbrella rule in Set.Has grants all of them to holders of plugins:execute.

Variables

View Source
var ActionLabels = map[Action]string{
	ActionRead:    "Read",
	ActionWrite:   "Write",
	ActionDelete:  "Delete",
	ActionExecute: "Execute",
	ActionPublish: "Publish",
}

ActionLabels are the human labels the UI shows as matrix columns.

Actions lists every action in display order.

View Source
var Groups = []string{
	"Analytics",
	"Plugins",
	"LLM management",
	"Context management",
	"Community",
	"Access",
	"Governance",
	"Settings",
	"AI Portal",
	"Chat",
	"Catalogs",
}

Groups is the display order of catalogue groups, aligned with the admin navigation so an administrator recognises the matrix layout.

Functions

func Can

func Can(c *gin.Context, p Permission) bool

Can reports whether the request's user holds p.

With no Context on the request the route was registered outside the governed groups (or by a test that injects the user directly). The legacy rule then applies: a user flagged as administrator holds everything, anyone else nothing. Unauthenticated requests are always denied.

func CanAny

func CanAny(c *gin.Context, ps ...Permission) bool

CanAny reports whether the request's user holds at least one of ps.

func IsPluginResource

func IsPluginResource(key string) bool

IsPluginResource reports whether key belongs to a plugin.

func Publishable

func Publishable() []string

Publishable returns the keys of every resource offering ActionPublish.

func Register

func Register(r Resource)

Register adds a built-in resource to the catalogue. It panics on a duplicate key, an unknown group, a missing label, or an invalid action, so mistakes surface at boot (and in every test that imports the package). Plugin resources use Replace instead.

func Replace

func Replace(r Resource) error

Replace upserts a plugin resource. It returns an error instead of panicking because plugin manifests are user data, and it bumps Version so clients can refresh the catalogue.

func Unregister

func Unregister(key string) bool

Unregister removes a plugin resource. Built-in resources are never removed. It reports whether anything changed.

func UnregisterPlugin

func UnregisterPlugin(plugin string) int

UnregisterPlugin removes every resource the plugin contributed (its base resource and any sub-resources) and reports how many were removed.

func Version

func Version() uint64

Version counts dynamic catalogue changes since boot. It is sent with GET /api/v1/rbac/permissions so the UI can tell a stale copy apart.

func WithContext

func WithContext(c *gin.Context, x *Context)

WithContext stores x on the gin context.

Types

type Action

type Action string

Action is one of the four verbs a permission can carry.

const (
	// ActionRead covers list, get, search, status and history reads, and
	// downloading an already-produced artefact.
	ActionRead Action = "read"
	// ActionWrite covers create and update, including linking sub-resources,
	// activate/deactivate, approve/reject and rollback.
	ActionWrite Action = "write"
	// ActionDelete covers removing a resource or a sub-resource link.
	ActionDelete Action = "delete"
	// ActionExecute covers side-effecting operations that do not persist
	// configuration: test, call, reload, sync, re-process.
	ActionExecute Action = "execute"
	// ActionPublish covers making an object live: setting an LLM, tool,
	// datasource, app or agent active, enabling a plugin, activating a
	// metadata schema. It is separate from write so a role can create and
	// edit drafts without being able to release them, and an approver role
	// can release without editing. Publish implies read, not write.
	ActionPublish Action = "publish"
)

func (Action) Valid

func (a Action) Valid() bool

Valid reports whether a is one of the four known actions.

type AdminFlagged

type AdminFlagged interface {
	AdminFlag() bool
}

AdminFlagged is implemented by the user model so this package can apply the legacy admin-or-not rule without importing it.

type Context

type Context struct {
	UserID  uint
	IsAdmin bool
	// contains filtered or unexported fields
}

Context carries the authenticated user's identity and a lazy resolver for their effective permission set. Resolution runs at most once per request; nothing touches the database until something asks.

func FromContext

func FromContext(c *gin.Context) (*Context, bool)

FromContext returns the request's Context, if the middleware set one.

func NewContext

func NewContext(userID uint, isAdmin bool, resolve func() (Set, error)) *Context

NewContext builds a Context for a user with the given resolver.

func (*Context) Can

func (x *Context) Can(p Permission) bool

Can reports whether the set satisfies p. Any resolution error fails closed.

func (*Context) Permissions

func (x *Context) Permissions() (Set, error)

Permissions resolves (once) and returns the effective set.

type Error

type Error struct {
	Title      string `json:"title"`
	Detail     string `json:"detail"`
	Code       string `json:"code,omitempty"`
	Permission string `json:"permission,omitempty"`
}

Error is one entry in the API error envelope. Title and Detail match the shape used by models.ErrorResponse so existing clients keep working.

type ErrorBody

type ErrorBody struct {
	Errors []Error `json:"errors"`
}

ErrorBody is the JSON envelope returned on authorization failures.

func Body

func Body(title, detail, code string) ErrorBody

Body builds an envelope with an arbitrary code.

func Denied

func Denied(p Permission) ErrorBody

Denied builds the 403 body for a missing permission. The title stays "Forbidden" because existing tests and clients look for that word.

func EnterpriseRequired

func EnterpriseRequired(detail string) ErrorBody

EnterpriseRequired builds the 402 body for management endpoints that are not available in this edition or licence.

func Unauthenticated

func Unauthenticated() ErrorBody

Unauthenticated builds the 401 body.

type Permission

type Permission string

Permission is a "<resource>:<action>" string, or one of the two sentinels.

const (
	// FullAdmin is the wildcard held only by the Owner and Administrator
	// system roles. It satisfies every permission check.
	FullAdmin Permission = "*"

	// AnyAdmin is a route annotation sentinel, never stored in a role. A
	// route annotated with it is open to any user who holds at least one
	// permission (i.e. anyone allowed onto the admin surface at all).
	AnyAdmin Permission = "_any"
)

func All

func All() []Permission

All returns every concrete permission in the catalogue, sorted.

func AllWithAction

func AllWithAction(a Action) []Permission

AllWithAction returns every concrete permission carrying the action.

func Delete

func Delete(resource string) Permission

func Execute

func Execute(resource string) Permission

func Filter

func Filter(keep func(Resource, Action) bool) []Permission

Filter returns the permissions from All() the predicate keeps.

func P

func P(resource string, a Action) Permission

P builds a permission from a resource key and action.

func Parse

func Parse(s string) (Permission, error)

Parse validates a raw permission string against the catalogue. FullAdmin is accepted; AnyAdmin is not (it is a route sentinel, not a grant).

func ParseStored

func ParseStored(s string) (Permission, error)

ParseStored validates a permission as stored on a role. It accepts everything Parse accepts plus a well-formed plugin permission whose resource is not currently registered (the plugin is uninstalled, disabled or not yet loaded), so a role keeps its plugin grants across plugin lifecycle changes and stays saveable. Evaluation still drops unregistered permissions (NewSetFromStrings); this only governs storage.

func Publish

func Publish(resource string) Permission

func Read

func Read(resource string) Permission

Read, Write, Delete and Execute are shorthand constructors used at route registration so annotations stay short and greppable.

func Write

func Write(resource string) Permission

func (Permission) Action

func (p Permission) Action() Action

Action returns the action, or "" for sentinels.

func (Permission) IsSentinel

func (p Permission) IsSentinel() bool

IsSentinel reports whether p is FullAdmin or AnyAdmin.

func (Permission) Resource

func (p Permission) Resource() string

Resource returns the resource key, or "" for sentinels.

func (Permission) String

func (p Permission) String() string

String implements fmt.Stringer.

func (Permission) Valid

func (p Permission) Valid() bool

Valid reports whether p is a sentinel or a concrete permission present in the catalogue (the resource exists and offers the action).

func (Permission) WellFormedPlugin

func (p Permission) WellFormedPlugin() bool

WellFormedPlugin reports whether p is "plugin:<key>[:<sub>]:<action>" with a known action, regardless of whether the resource is registered.

type Resource

type Resource struct {
	// Key is the permission resource slug: plural, kebab-case, matching the
	// route collection segment ("llms", "data-catalogues").
	Key string `json:"key"`
	// Label is the human name, matching the admin navigation where one exists.
	Label string `json:"label"`
	// Group is the navigation group the resource belongs to; see Groups.
	Group string `json:"group"`
	// Sensitive marks a data class (transcripts, logs, secrets) that is split
	// out so read can be withheld independently. The UI shows a shield.
	Sensitive bool `json:"sensitive"`
	// Privileged marks resources whose write/delete can escalate access
	// (users, groups, roles, identity providers, plugins). The UI warns.
	Privileged bool `json:"privileged"`
	// Actions lists the actions this resource offers, in display order.
	Actions []Action `json:"actions"`
	// Description is optional help text for the role editor.
	Description string `json:"description,omitempty"`
	// Plugin is the permission key of the plugin that contributed this
	// resource ("plugin:<manifest id>"), or "" for built-in resources. The
	// role editor groups plugin resources under their plugin.
	Plugin string `json:"plugin,omitempty"`
	// PluginLabel is the display name of the contributing plugin.
	PluginLabel string `json:"plugin_label,omitempty"`
	// Dynamic marks a resource registered at runtime (plugins) rather than
	// in init(); dynamic resources can be replaced and unregistered.
	Dynamic bool `json:"dynamic,omitempty"`
}

Resource is one row of the permission catalogue.

func Catalogue

func Catalogue() []Resource

Catalogue returns a copy of every resource, sorted by group order, then built-in resources by label, then plugin resources by plugin label with each plugin's base resource ahead of its sub-resources. This is the payload of GET /api/v1/rbac/permissions.

func Lookup

func Lookup(p Permission) (Resource, bool)

Lookup returns the resource for a concrete permission, and whether the resource offers that action.

func PluginResources

func PluginResources(plugin string) []Resource

PluginResources returns the resources contributed by one plugin, sorted with the base resource (key == plugin) first.

func ResourceByKey

func ResourceByKey(key string) (Resource, bool)

ResourceByKey returns the resource with the given key.

type Set

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

Set is an effective permission set: either the wildcard, or a concrete set of permissions. It implements the implied-read rule: holding any action on a resource satisfies a read check for that resource.

func NewSet

func NewSet(perms ...Permission) Set

NewSet builds a concrete set. Sentinels are ignored except FullAdmin, which turns the set into the wildcard.

func NewSetFromStrings

func NewSetFromStrings(raw []string) Set

NewSetFromStrings builds a set from stored strings, skipping any that do not parse. Use this when loading role definitions from the database so a permission removed from the catalogue does not break evaluation.

func Permissions

func Permissions(c *gin.Context) (Set, error)

Permissions returns the request user's effective set. With no Context it returns an empty set and no error.

func Wildcard

func Wildcard() Set

Wildcard returns the full-admin set.

func (Set) Has

func (s Set) Has(p Permission) bool

Has reports whether the set satisfies p. FullAdmin is satisfied only by the wildcard. AnyAdmin is satisfied by any non-empty set.

func (Set) HasAll

func (s Set) HasAll(ps ...Permission) bool

HasAll reports whether every permission is satisfied.

func (Set) HasAny

func (s Set) HasAny(ps ...Permission) bool

HasAny reports whether at least one permission is satisfied.

func (Set) HasPluginGrant

func (s Set) HasPluginGrant() bool

HasPluginGrant reports whether the set grants anything on a plugin resource: the wildcard, plugins:execute, or an explicit "plugin:*" entry. The UI uses it to decide whether plugin configuration pages are reachable.

func (Set) IsEmpty

func (s Set) IsEmpty() bool

IsEmpty reports whether the set grants nothing at all.

func (Set) IsFullAdmin

func (s Set) IsFullAdmin() bool

IsFullAdmin reports whether the set is the wildcard.

func (Set) List

func (s Set) List() []string

List returns the sorted permission strings; ["*"] for the wildcard.

func (Set) Union

func (s Set) Union(o Set) Set

Union returns a new set containing both.

Jump to

Keyboard shortcuts

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