tenant

package
v0.1.125 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package tenant stores the multi-tenant registry for a subrouter server. Each tenant owns an isolated account pool under <state-dir>/tenants/<id>/ that mirrors the single-tenant layout (codex/accounts/*.json, codex/claude/, sessions.json). Tenant keys look like srt_<32 hex>; only SHA-256 hashes are stored, so a key is shown once at creation and cannot be recovered later.

Index

Constants

View Source
const KeyPrefix = "srt_"
View Source
const MaxLegacyCredentialGrace = 90 * 24 * time.Hour

Variables

View Source
var ErrTenantRetired = errors.New("tenant is retired")

Functions

func DeriveKey added in v0.1.52

func DeriveKey(secret []byte, namespace, externalID string) (string, error)

DeriveKey deterministically maps an external tenant identity to a valid tenant key. The secret stays on the server; only the derived srt_ key is returned to the authenticated client.

func HashKey

func HashKey(key string) string

func ValidExternalID added in v0.1.52

func ValidExternalID(value string) bool

ValidExternalID permits lowercase identity-provider IDs as directory names while rejecting separators, traversal, and case-folding collisions.

func ValidKeyFormat

func ValidKeyFormat(value string) bool

ValidKeyFormat reports whether value is shaped like a tenant key (srt_ followed by 32 lowercase hex chars).

Types

type Capability added in v0.1.55

type Capability string
const (
	CapabilityUse            Capability = "use"
	CapabilityManageAccounts Capability = "manage_accounts"
)

type Key

type Key struct {
	Hash         string       `json:"hash"`
	Prefix       string       `json:"prefix"`
	CreatedAt    time.Time    `json:"createdAt"`
	Restricted   bool         `json:"restricted,omitempty"`
	Capabilities []Capability `json:"capabilities,omitempty"`
}

func (Key) Allows added in v0.1.55

func (k Key) Allows(capability Capability) bool

type Registry

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

Registry reads and writes tenants.json under a server state dir. Reads are cached on file modtime+size so the per-request key resolution is one stat.

func NewRegistry

func NewRegistry(stateDir string) *Registry

func (*Registry) AcquireExclusiveUse added in v0.1.53

func (r *Registry) AcquireExclusiveUse(id string) (*UseLock, error)

AcquireExclusiveUse waits until every active request has released its shared tenant-use lock, then holds the deletion lock.

func (*Registry) AcquireUse added in v0.1.53

func (r *Registry) AcquireUse(id string) (*UseLock, error)

func (*Registry) Create

func (r *Registry) Create(name string) (Tenant, string, error)

Create registers a new tenant, provisions its state dir, and returns the tenant plus its first key in plaintext (the only time it is available).

func (*Registry) CreateKey

func (r *Registry) CreateKey(tenantID string) (Tenant, string, error)

CreateKey mints an additional key for an existing tenant and returns it in plaintext.

func (*Registry) DeleteRetired added in v0.1.53

func (r *Registry) DeleteRetired(id string) (bool, error)

DeleteRetired permanently removes a retired tenant's credential-bearing state. A durable tombstone prevents a still-valid Stack token from recreating the tenant in the interval before the owning identity is deleted. The caller must hold the tenant's exclusive use lock.

func (*Registry) Dir

func (r *Registry) Dir(id string) string

Dir returns the tenant's isolated state dir.

func (*Registry) EnsureExternal added in v0.1.52

func (r *Registry) EnsureExternal(id, name, plaintextKey string) (Tenant, error)

EnsureExternal creates or updates the tenant owned by an external identity provider. plaintextKey must be a deterministic key derived by the caller, so repeated logins return the same client configuration without accumulating registry keys.

func (*Registry) EnsureExternalRestricted added in v0.1.55

func (r *Registry) EnsureExternalRestricted(
	id,
	name,
	plaintextKey string,
	capabilities []Capability,
) (Tenant, error)

EnsureExternalRestricted creates or updates an externally owned tenant key whose authority is limited to the supplied capabilities.

func (*Registry) EnsureLegacyCredentialCutoff added in v0.1.56

func (r *Registry) EnsureLegacyCredentialCutoff(
	now time.Time,
	grace time.Duration,
) (time.Time, error)

EnsureLegacyCredentialCutoff creates one durable deadline for credentials issued by the pre-broker Stack exchange. Repeated starts and overlapping worker generations read the original deadline instead of extending it.

func (*Registry) Find

func (r *Registry) Find(ref string) (Tenant, bool, error)

Find matches a tenant by exact ID or case-insensitive name.

func (*Registry) HasTenants

func (r *Registry) HasTenants() bool

HasTenants reports whether at least one tenant exists.

func (*Registry) List

func (r *Registry) List() ([]Tenant, error)

func (*Registry) Path

func (r *Registry) Path() string

func (*Registry) PendingDeletionIDs added in v0.1.53

func (r *Registry) PendingDeletionIDs() ([]string, error)

PendingDeletionIDs lists retired registry entries and crash-recovery markers that need credential-state deletion after active requests drain.

func (*Registry) Resolve

func (r *Registry) Resolve(key string) (Tenant, bool, error)

Resolve maps a plaintext tenant key to its tenant. A revoked or unknown key returns ok=false.

func (*Registry) ResolveCredential added in v0.1.55

func (r *Registry) ResolveCredential(key string) (Tenant, Key, bool, error)

func (*Registry) ResolveFresh added in v0.1.53

func (r *Registry) ResolveFresh(key string) (Tenant, bool, error)

ResolveFresh bypasses the metadata cache after a request has acquired its shared use lock. This closes the cross-process race with tenant retirement.

func (*Registry) ResolveFreshCredential added in v0.1.55

func (r *Registry) ResolveFreshCredential(key string) (Tenant, Key, bool, error)

func (*Registry) RetireExternal added in v0.1.53

func (r *Registry) RetireExternal(id string) (bool, error)

RetireExternal revokes every key and records deletion intent under one interprocess registry lock. This prevents a first exchange from creating an absent tenant between retirement and deletion. It is idempotent while active requests drain.

func (*Registry) RevokeKey

func (r *Registry) RevokeKey(tenantID, keyRef string) (int, error)

RevokeKey removes the key whose display prefix exactly matches keyRef, or whose hash matches when keyRef is a full plaintext key, and returns how many keys were revoked. Exact matching only: a loose prefix like "srt_" must not wipe every key on the tenant.

func (*Registry) TenantsDir

func (r *Registry) TenantsDir() string

func (*Registry) TryAcquireExclusiveUse added in v0.1.53

func (r *Registry) TryAcquireExclusiveUse(id string) (*UseLock, bool, error)

type Tenant

type Tenant struct {
	ID        string    `json:"id"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"createdAt"`
	Keys      []Key     `json:"keys,omitempty"`
	Retired   bool      `json:"retired,omitempty"`
}

type UseLock added in v0.1.53

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

UseLock coordinates live tenant requests with permanent tenant deletion across supervisor worker generations.

func (*UseLock) Close added in v0.1.53

func (l *UseLock) Close() error

Jump to

Keyboard shortcuts

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