moduleseed

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: 7 Imported by: 0

Documentation

Overview

Package moduleseed — ПРИМЕНИТЕЛЬ раздела `seed` манифеста модуля (задача продукта #2452).

Чей это предмет и почему он появился

Раздел `seed` объявляет то, что установка модуля заводит в службе доступа: личность модуля, его группы, выдачи и вступления в чужие группы. До этой задачи применителя у раздела не было НИ ОДНОГО: строки заводила применённая миграция службы, а раздел с ними лишь сверялся (`internal/moduleseedparity`).

Цена того устройства измерена и названа в задаче #2452: миграция применяется ВЕЗДЕ, включая установку, где платформы нет вовсе, — и самостоятельная служба доступа заводила пять служебных ЛИЧНОСТЕЙ чужого продукта. Теперь строки заводит применитель, а условием служит ДОСТАВКА манифеста: каталог доставки кладёт зонтичный чарт платформы и не кладёт чарт самостоятельной службы. Условность выражена тем, что объявила установка, а не догадкой кода.

Что применитель НЕ делает

Он не читает каталог доставки (это `loadDeliveredManifests`) и не судит форму манифеста (это валидатор связности `internal/manifest`). Ему приезжают уже разобранные и уже проверенные манифесты, и он приводит базу к тому, что в них написано.

Он не СНИМАЕТ строк. Снятие модуля из доставки — отдельный предмет с отдельной ценой: снятая личность уносит с собой права, а её отсутствие снаружи неотличимо от «право не выдали». Применитель, снимающий молча, был бы отзывом без решения. Это ОСТАТОК, названный вслух, а не забытая половина.

Идемпотентность выражена ОПЕРАТОРОМ, а не сравнением в коде

Каждая запись кладётся `ON CONFLICT … DO NOTHING` либо `DO UPDATE … WHERE <строка отличается>`. «Прочитать и сравнить» дало бы окно между чтением и записью (ban #10): под конкуренцией два применения увидели бы одну и ту же строку отсутствующей.

Index

Constants

This section is empty.

Variables

View Source
var ErrGrantFormEmpty = errors.New("moduleseed: access binding names neither roleId nor grantedRelation")

ErrGrantFormEmpty — выдача не назвала НИ РОЛИ, НИ ОТНОШЕНИЯ.

Формы взаимоисключающи, и валидатор связности требует ровно одну ещё до применителя. Отказ здесь всё равно свой, а не оставленный базе: та отвергла бы строку ограничением `access_bindings_grant_form_ck`, и оператор прочёл бы имя ограничения вместо имени поля манифеста, которое надо править.

View Source
var ErrUnknownSubjectType = errors.New("moduleseed: unknown access binding subject type")

ErrUnknownSubjectType — субъект выдачи назван формой, которой применитель не знает. Отказ, а не пропуск: см. перечень выше.

Functions

This section is empty.

Types

type Applier

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

Applier — применитель. Держит только исполнителя транзакций: решать ему нечего сверх того, что написано в манифесте.

func NewApplier

func NewApplier(tx TxRunner) *Applier

NewApplier собирает применитель над исполнителем транзакций.

func (*Applier) ApplyAll

func (a *Applier) ApplyAll(ctx context.Context, manifests []*manifest.Manifest) (Census, error)

ApplyAll приводит базу к состоянию, объявленному разделами `seed` доставленных манифестов, и отдаёт перепись — ВСЕГДА, независимо от исхода.

Отказ на любом модуле прекращает применение: половина применённого посева ýже объявленного, и отличить её от исполненного можно только вызовом. Отказ называет модуль — иначе оператор ищет причину во всей доставке сразу.

type Census

type Census struct {
	// Manifests — доставленных манифестов прочитано.
	Manifests int
	// Seeding — из них объявили раздел `seed`. Ноль здесь законен и означает
	// «модули посева не объявили», а НЕ «применять не стали».
	Seeding int
	// Reports — по модулю на каждый объявивший.
	Reports []Report
}

Census — перепись всего применения.

func (Census) String

func (c Census) String() string

func (Census) Totals

func (c Census) Totals() (declared, written int)

Totals — суммы по подразделам: объявлено и записано.

type Report

type Report struct {
	// Module — модуль манифеста.
	Module string
	// Declared — объявлено разделом `seed` по каждому подразделу.
	DeclaredAccounts, DeclaredGroups, DeclaredJoins, DeclaredGrants int
	// Written — строк заведено либо приведено.
	WrittenAccounts, WrittenGroups, WrittenJoins, WrittenGrants int
}

Report — перепись применения одного модуля. Числами, потому что «применено» без чисел неотличимо от «прошло мимо»: применитель, не нашедший ни одной своей строки, молчит ровно так же уверенно, как записавший все.

func (Report) String

func (r Report) String() string

type Subject

type Subject struct {
	// Kind — форма субъекта из закрытого перечня выше.
	Kind string
	// Account — аккаунт, в котором живёт субъект.
	Account string
	// Name — имя субъекта в этом аккаунте.
	Name string
}

Subject — получатель выдачи, адресованный ПАРОЙ (аккаунт, имя): так он уникален в продукте. Идентификатор сюда не входит — его производит хранилище, и требовать от манифеста воспроизвести его значило бы требовать воспроизвести частность записи.

func (Subject) String

func (s Subject) String() string

type TxRunner

type TxRunner interface {
	RunInWriteTx(ctx context.Context, fn func(context.Context, Writer) error) error
}

TxRunner — «исполни это под одной писательской транзакцией».

Транзакция берётся НА МОДУЛЬ, а не на строку: личность модуля и её членства ложатся вместе либо не ложатся вовсе. Членство, доехавшее без личности, нарушило бы ссылочный триггер; личность без членства выглядела бы исправной и молча не давала бы модулю читать пределы.

type Writer

type Writer interface {
	// UpsertServiceAccount заводит личность модуля либо приводит её назначение.
	UpsertServiceAccount(ctx context.Context, account, name, description string) (changed bool, err error)
	// UpsertGroup заводит группу модуля.
	UpsertGroup(ctx context.Context, account, name, description string) (changed bool, err error)
	// JoinGroup вводит служебную запись в группу.
	JoinGroup(ctx context.Context, saAccount, saName, groupAccount, groupName string) (changed bool, err error)
	// GrantRelation выдаёт субъекту ИМЕНОВАННОЕ ОТНОШЕНИЕ на якоре области.
	GrantRelation(ctx context.Context, subject Subject, relation, scopeKind, scopeID string) (changed bool, err error)
	// GrantRole выдаёт субъекту РОЛЬ на якоре области.
	GrantRole(ctx context.Context, subject Subject, roleID, scopeKind, scopeID string) (changed bool, err error)
}

Writer — то, что применителю нужно от хранилища, и ничего сверх.

Каждый глагол отвечает ИЗМЕНИЛОСЬ ЛИ состояние: «применено шесть манифестов, изменений ноль» и «применено ноль манифестов» — разные утверждения о платформе, а молчание у них одно и то же.

Jump to

Keyboard shortcuts

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