Documentation
¶
Overview ¶
Package tenancy is the one tenant model and how a request carries it.
A tenant reaches the rest of the program through the context: HTTP middleware resolves the host to a Tenant and calls WithTenant, and kit/db reads it back to scope the transaction. Nothing else may derive a tenant from anywhere.
Index ¶
- Variables
- func ActorFrom(ctx context.Context) (uuid.UUID, bool)
- func WithActor(ctx context.Context, userID uuid.UUID) context.Context
- func WithPrincipal(ctx context.Context, p Principal) context.Context
- func WithTenant(ctx context.Context, t Tenant) context.Context
- type Grant
- type Principal
- type SystemToken
- type Tenant
Constants ¶
This section is empty.
Variables ¶
var ErrNoSuchHost = errors.New("tenancy: no tenant at this host")
ErrNoSuchHost is what a tenant loader returns when it looked and there is no site at that host. It is the one loader failure that is an answer rather than an outage: the HTTP layer turns it into 404 and everything else into 503, so a database the loader cannot reach never reads as "these hosts do not exist".
Functions ¶
func ActorFrom ¶
ActorFrom returns the user ctx carries, if any. The nil UUID is not an actor: a zero principal must not read as somebody.
func WithActor ¶
WithActor returns a copy of ctx carrying the user who is making the request.
It lives here, beside the tenant, because the two are one thing: the identity of a request is which customer it is about and who is asking. kit/httpx calls it once, immediately after Options.Authenticate recognises the caller, and kit/events reads it back so that every event an operation writes carries the person who caused it without any module remembering to pass it along.
Work with no person behind it — a job, the relay, an event handler — leaves it unset, and that is the honest answer rather than a sentinel: the outbox column is null and the audit row says the system did it.
func WithPrincipal ¶
WithPrincipal returns a copy of ctx carrying p.
Types ¶
type Grant ¶
Grant is a permission question: which token, and whether that token is one only the operator's own tenant may exercise.
It is a struct rather than a string because "may this caller do X" and "is this a tenant entitled to X at all" are two questions and the second is asked first. It lives beside Tenant because both halves of the answer are here.
type Principal ¶
type Principal struct {
// UserID identifies the person or machine account.
UserID uuid.UUID
// Roles are the roles the credential carries, for an authorizer that wants
// them without a second lookup.
Roles []string
}
Principal is who is making a request, established once per request by the HTTP layer's identity hook and never derived again.
It lives here, beside Tenant and the actor, because the three are one thing. It used to live in kit/httpx, and the cost was a module's contracts/ package naming the HTTP kernel to describe its own caller — which linked huma and chi into the build graph of anything that only wanted to name a Session.
There is no tenant on it: the hook runs inside the resolved tenant's own transaction, so a credential belonging to another is a row row-level security does not show, and the principal that would have had to be refused is never built.
type SystemToken ¶
type SystemToken = syscap.SystemToken
SystemToken is a capability that lets kernel runners open cross-tenant work. It is an interface whose only implementation and only constructor live in kit/internal/syscap, so packages outside kit/ can name a token but can neither mint nor implement one: the compiler enforces that modules never bypass tenancy.
Resolving a host to a tenant is a query, so it needs a transaction; the interface for it is httpx.TenantLoader, declared where both kit/db and this package are already imported.
type Tenant ¶
type Tenant struct {
ID uuid.UUID
Slug string
Name string
// Operator says this tenant is the installation's own, the one whose
// administrators may reach the control plane. A customer's administrator
// holds "may do everything in my tenant", which must not become the power
// to list, create and suspend the tenants beside them. The column is
// written by the bootstrap and by nothing else; see Grant and docs/adr/0006.
Operator bool
}
Tenant is one customer of the platform.