Documentation
¶
Overview ¶
Package groups provides optional flat Groups, independent membership and exact role grants. It does not interpret tenant/org as Group identities.
Index ¶
- Constants
- Variables
- func Scope(id uuid.UUID) types.ScopeFilter
- type Config
- type Group
- type ManageCommand
- type ManageInput
- type Membership
- type Operation
- type Service
- func (s *Service) Create(ctx context.Context, actor types.ActorRef, name string) (*Group, error)
- func (s *Service) Discover(ctx context.Context, actor types.ActorRef) ([]Group, error)
- func (s *Service) Guard() (*scope.StrictGuard, error)
- func (s *Service) SetActive(ctx context.Context, actor types.ActorRef, id uuid.UUID, active bool) error
- func (s *Service) SetMember(ctx context.Context, actor types.ActorRef, id, principal uuid.UUID, ...) error
- func (s *Service) SetRole(ctx context.Context, actor types.ActorRef, id, principal, roleID uuid.UUID, ...) error
- func (s *Service) WithAuthorized(ctx context.Context, actor types.ActorRef, requested types.ScopeFilter, ...) error
Constants ¶
const ( ActionRead types.PolicyAction = "groups:read" ActionCreate types.PolicyAction = "groups:create" ActionManage types.PolicyAction = "groups:manage" ActionMembers types.PolicyAction = "groups:members:write" ActionRoles types.PolicyAction = "groups:roles:write" )
Variables ¶
var ErrDenied = errors.New("groups: authorization denied")
var ErrInvalid = errors.New("groups: invalid configuration or input")
Functions ¶
Types ¶
type Config ¶
type Config struct {
DB *bun.DB
Resolver types.ScopeResolver
Policy types.AuthorizationPolicy
CatalogScope types.ScopeFilter
Actions []types.PolicyAction
// RecordPolicy defaults to dropping metadata/IP, preserving identity and scope.
RecordPolicy *activity.RecordPolicy
}
Config is opt-in. CatalogScope addresses shared definitions, never assignment scope. Actions explicitly declares additional resource permission names.
type Group ¶
type Group struct {
bun.BaseModel `bun:"table:user_groups"`
ID uuid.UUID `bun:"id,pk,type:uuid"`
Name string `bun:"name,notnull"`
Active bool `bun:"active,notnull"`
CreatedAt time.Time `bun:"created_at,notnull"`
UpdatedAt time.Time `bun:"updated_at,notnull"`
}
Group has no tenant/org parent or implicit hierarchy.
type ManageCommand ¶
type ManageCommand struct {
// contains filtered or unexported fields
}
func NewManageCommand ¶
func NewManageCommand(service *Service) *ManageCommand
func (*ManageCommand) Execute ¶
func (c *ManageCommand) Execute(ctx context.Context, i ManageInput) error
func (*ManageCommand) Run ¶
func (c *ManageCommand) Run(ctx context.Context, i ManageInput) (*Group, error)
type ManageInput ¶
type ManageInput struct {
Actor types.ActorRef
GroupID uuid.UUID
PrincipalID uuid.UUID
RoleID uuid.UUID
Operation Operation
Name string
}
ManageInput exposes native mutation workflows to go-command-compatible transports. Run/Execute delegate authorization and transactions to Service.
func (ManageInput) Type ¶
func (ManageInput) Type() string
func (ManageInput) Validate ¶
func (i ManageInput) Validate() error
type Membership ¶
type Membership struct {
bun.BaseModel `bun:"table:user_group_memberships"`
GroupID uuid.UUID `bun:"group_id,pk,type:uuid"`
PrincipalID uuid.UUID `bun:"principal_id,pk,type:uuid"`
Active bool `bun:"active,notnull"`
CreatedAt time.Time `bun:"created_at,notnull"`
UpdatedAt time.Time `bun:"updated_at,notnull"`
}
Membership is independent of grants. PrincipalID is an opaque identifier and need not be a human user or a row in an authentication table.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func NewStrict ¶
NewStrict rejects absent/typed nil dependencies. No permissive constructor is provided for native Groups; legacy scope/service constructors remain unchanged.
func (*Service) Create ¶
Create requires explicit bootstrap policy authority and creates no memberships or grants. Initial authorities can be provisioned through trusted SQL/registry in a deployment transaction; routine mutations use this guarded service.
func (*Service) Discover ¶
Discover lists only active Groups in which the principal has active membership and an effective groups:read grant. Native state is evaluated on every call.
func (*Service) Guard ¶
func (s *Service) Guard() (*scope.StrictGuard, error)
Guard provides a built-in strict guard usable by existing commands/queries. Enforce checks current state, but only WithAuthorized orders the protected database work with concurrent Group revocations.
func (*Service) SetRole ¶
func (s *Service) SetRole(ctx context.Context, actor types.ActorRef, id, principal, roleID uuid.UUID, assign bool) error
SetRole reuses an existing catalog role. Membership is necessary but never sufficient for access; callers cannot delegate permissions they do not hold.
func (*Service) WithAuthorized ¶
func (s *Service) WithAuthorized(ctx context.Context, actor types.ActorRef, requested types.ScopeFilter, action types.PolicyAction, target uuid.UUID, fn func(context.Context, bun.Tx) error) error
WithAuthorized keeps authorization and protected database work in the same transaction/Group lock as member removal, archive and role revocation. Use tx for all callback writes; do not call this service recursively in a callback.