group

package
v0.2.0 Latest Latest
Warning

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

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

Documentation

Overview

Package group — GroupService + member-management.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AddMemberInput

type AddMemberInput struct {
	GroupID    domain.GroupID
	MemberType domain.SubjectType
	MemberID   domain.SubjectID
}

type AddMemberUseCase

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

func NewAddMemberUseCase

func NewAddMemberUseCase(r Repo, opsRepo operations.Repo) *AddMemberUseCase

func (*AddMemberUseCase) Execute

type CreateGroupUseCase

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

func NewCreateGroupUseCase

func NewCreateGroupUseCase(r Repo, opsRepo operations.Repo) *CreateGroupUseCase

func (*CreateGroupUseCase) Execute

func (*CreateGroupUseCase) WithObjectReconciler

func (u *CreateGroupUseCase) WithObjectReconciler(r ObjectReconciler) *CreateGroupUseCase

WithObjectReconciler wires the post-commit synchronous per-object materializer (rbac-contract-a-fix, C-01b). nil-safe.

func (*CreateGroupUseCase) WithRelationStore

func (u *CreateGroupUseCase) WithRelationStore(relations clients.RelationStore, logger *slog.Logger) *CreateGroupUseCase

WithRelationStore wires the group→account hierarchy-tuple writer.

type DeleteGroupUseCase

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

func NewDeleteGroupUseCase

func NewDeleteGroupUseCase(r Repo, opsRepo operations.Repo) *DeleteGroupUseCase

func (*DeleteGroupUseCase) Execute

type GetGroupUseCase

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

func NewGetGroupUseCase

func NewGetGroupUseCase(r Repo) *GetGroupUseCase

func (*GetGroupUseCase) Execute

func (u *GetGroupUseCase) Execute(ctx context.Context, id domain.GroupID) (domain.Group, error)

Execute — sync read.

Authz (Design B, D-6/D-9): the caller must hold `v_get` on iam_group:<id> OR be a cluster-admin. Otherwise (incl. anonymous) → NotFound (hide existence; no enumeration). Replaces the legacy owner-only gate that denied a delegate granted `iam.group.get`.

func (*GetGroupUseCase) WithRelationStore

func (u *GetGroupUseCase) WithRelationStore(relations clients.RelationStore) *GetGroupUseCase

WithRelationStore wires the FGA client authorizing the read via the verb-bearing `v_get` relation on iam_group:<id> (+ cluster-admin short-circuit). Without it a non-cluster-admin Get fails closed.

type Handler

type Handler struct {
	iamv1.UnimplementedGroupServiceServer
	// contains filtered or unexported fields
}

func (*Handler) AddMember

func (*Handler) Create

func (*Handler) Delete

func (*Handler) Get

func (h *Handler) Get(ctx context.Context, req *iamv1.GetGroupRequest) (*iamv1.Group, error)

func (*Handler) List

List — sync read with pagination.

Формат страницы судится по СЫРОМУ запросу первым стейтментом: сужение int64→int32 ниже насыщающее, и отрицательный page_size превратился бы в 0 («умолчание») до того, как его кто-либо увидит.

func (*Handler) ListMembers

func (*Handler) RemoveMember

func (*Handler) Update

func (*Handler) WithListOperations

func (h *Handler) WithListOperations(uc *shared.ListOperationsUseCase) *Handler

WithListOperations wires the per-resource operation-listing use-case.

type ListGroupsUseCase

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

func NewListGroupsUseCase

func NewListGroupsUseCase(r Repo) *ListGroupsUseCase

func (*ListGroupsUseCase) Execute

func (*ListGroupsUseCase) WithListScanRecorder

func (u *ListGroupsUseCase) WithListScanRecorder(rec shared.ListScanRecorder) *ListGroupsUseCase

WithRelationStore wires the FGA ListObjects client (паритет с account/project/service_account/role List). WithListScanRecorder провязывает съём стоимости страницы (#653).

func (*ListGroupsUseCase) WithRelationStore

func (u *ListGroupsUseCase) WithRelationStore(relations clients.RelationQueries) *ListGroupsUseCase

type ListMembersInput

type ListMembersInput struct {
	GroupID   domain.GroupID
	PageSize  int64
	PageToken string
}

ListMembersInput — one page of a group's membership.

type ListMembersOutput

type ListMembersOutput struct {
	Members       []domain.GroupMember
	NextPageToken string
}

ListMembersOutput — the page plus the continuation token, empty on the last page.

type ListMembersUseCase

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

func NewListMembersUseCase

func NewListMembersUseCase(r Repo) *ListMembersUseCase

func (*ListMembersUseCase) Execute

Execute returns one page of the membership.

page_size is validated HERE, before the storage is touched: an out-of-range value is a refusal, never a clamp (a clamped page makes the caller believe it received everything it asked for), and the refusal must not depend on how far down the call the storage happens to check. The adapter keeps its own check as the authoritative backstop.

Then the group NAMED IN THE REQUEST is re-asked about, on `v_list` — the same relation the front door requires of this RPC, so a caller admitted there is admitted here. Both sibling reads of this resource already do it (`Get` on `v_get`, `List` through the per-object page filter); this one did not, and it is also the only one of the three whose name the List-surface analyser cannot see. A denial is the resource's own miss, verbatim, so it cannot be told from the group not existing; a model that could not be ASKED is an outage, never a miss.

func (*ListMembersUseCase) WithRelationStore

func (u *ListMembersUseCase) WithRelationStore(relations authzguard.RelationChecker) *ListMembersUseCase

WithRelationStore wires the relation-Check port. Unwired, the roster is served to nobody: a read whose remaining authorization lives one layer up must not quietly become a read with none.

type ObjectReconciler

type ObjectReconciler interface {
	// ReconcileObjectForward is the ADDITIVE forward fast-path for the freshly-created
	// group-AS-OBJECT (iam.group): it materializes ONLY that new group's per-object
	// owner/admin tuples across the matching bindings while holding NO advisory lock at
	// all (neither EXCLUSIVE nor SHARE, no O(scope) recompute), the throughput fix for the owner-tuple
	// materialization lag under a parallel group-create burst. It transparently delegates
	// to the FULL ReconcileObject if the object already has members (delete-stale guard).
	ReconcileObjectForwardNoStale(ctx context.Context, objectType, objectID string) error
	// ReconcileObjectForward — СТОРОЖЕВОЙ вход того же прохода: он сперва читает,
	// есть ли у объекта члены, и при непустом наборе уходит на полный проход ради
	// снятия устаревших. Пути СОЗДАНИЯ он не нужен (доказательство — выше), но
	// остаётся в порту: его зовёт правка того же пакета, где прежние факты есть
	// и снятие устаревших — как раз предмет.
	ReconcileObjectForward(ctx context.Context, objectType, objectID string) error
	// ReconcileObject is the FULL EXCLUSIVE object-fan-out (async at-least-once backstop —
	// delete-stale / audit / sweep), driven by the reconcile worker off the co-committed
	// reconcile-outbox event, not the create hot-path.
	ReconcileObject(ctx context.Context, objectType, objectID string) error
}

ObjectReconciler — narrow port (rbac-contract-a-fix, C-01b): SYNCHRONOUSLY materialize the per-object access of every binding whose selector matches a freshly-created iam-native object, right after Create commits. Under the flat rights model (Contract-A) the `<rel> from account` ACCESS cascade on iam leaf types is gone, so the owner's / account-admin's per-object admin/v_* tuple is materialized per-object by the reconciler — and the async event drain races a client that GETs the object right after the Operation reports done. The sync call closes that race. Implemented by reconcile.Reconciler (the SAME single materialization path the worker drives). nil-safe: when unwired the co-committed reconcile event + periodic sweep still materialize it, just not synchronously.

type Reader

type Reader = kanamerepo.Reader

type RemoveMemberInput

type RemoveMemberInput struct {
	GroupID    domain.GroupID
	MemberType domain.SubjectType
	MemberID   domain.SubjectID
}

type RemoveMemberUseCase

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

func NewRemoveMemberUseCase

func NewRemoveMemberUseCase(r Repo, opsRepo operations.Repo) *RemoveMemberUseCase

func (*RemoveMemberUseCase) Execute

type Repo

type Repo = kanamerepo.Repository

type UpdateGroupInput

type UpdateGroupInput struct {
	ID          domain.GroupID
	Name        *domain.GroupName
	Description *domain.Description
	Labels      domain.Labels
	UpdateMask  []string
}

type UpdateGroupUseCase

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

func NewUpdateGroupUseCase

func NewUpdateGroupUseCase(r Repo, opsRepo operations.Repo) *UpdateGroupUseCase

func (*UpdateGroupUseCase) Execute

func (*UpdateGroupUseCase) WithObjectReconciler

func (u *UpdateGroupUseCase) WithObjectReconciler(r ObjectReconciler, logger *slog.Logger) *UpdateGroupUseCase

WithObjectReconciler wires the post-commit per-object materializer used on a LABEL change (parity with the cross-service RegisterResource re-register path — see doUpdate). Optional; nil keeps the queue-only behaviour. The logger is used only to report a failed pass (the durable event + sweep still re-converge).

type Writer

type Writer = kanamerepo.Writer

Jump to

Keyboard shortcuts

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