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
- Variables
- func Can(c *gin.Context, p Permission) bool
- func CanAny(c *gin.Context, ps ...Permission) bool
- func IsPluginResource(key string) bool
- func Publishable() []string
- func Register(r Resource)
- func Replace(r Resource) error
- func Unregister(key string) bool
- func UnregisterPlugin(plugin string) int
- func Version() uint64
- func WithContext(c *gin.Context, x *Context)
- type Action
- type AdminFlagged
- type Context
- type Error
- type ErrorBody
- type Permission
- func All() []Permission
- func AllWithAction(a Action) []Permission
- func Delete(resource string) Permission
- func Execute(resource string) Permission
- func Filter(keep func(Resource, Action) bool) []Permission
- func P(resource string, a Action) Permission
- func Parse(s string) (Permission, error)
- func ParseStored(s string) (Permission, error)
- func Publish(resource string) Permission
- func Read(resource string) Permission
- func Write(resource string) Permission
- type Resource
- type Set
Constants ¶
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".
const ContextKey = "authz"
ContextKey is the gin context key under which the request's Context is stored by the API's rbacContext middleware.
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 ¶
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.
var Actions = []Action{ActionRead, ActionWrite, ActionDelete, ActionExecute, ActionPublish}
Actions lists every action in display order.
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 ¶
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 ¶
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 ¶
Unregister removes a plugin resource. Built-in resources are never removed. It reports whether anything changed.
func UnregisterPlugin ¶
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 ¶
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" )
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 ¶
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 ¶
FromContext returns the request's Context, if the middleware set one.
func NewContext ¶
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 ¶
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 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 ¶
EnterpriseRequired builds the 402 body for management endpoints that are not available in this edition or licence.
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 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) 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 ¶
PluginResources returns the resources contributed by one plugin, sorted with the base resource (key == plugin) first.
func ResourceByKey ¶
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 ¶
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 ¶
Permissions returns the request user's effective set. With no Context it returns an empty set and no error.
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 ¶
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) IsFullAdmin ¶
IsFullAdmin reports whether the set is the wildcard.