Documentation
¶
Overview ¶
Package boardstorage hosts the control-plane side of the board-storage feature (see #283/#284/#285): startup SQL, per-user PG role provisioning, vault static-role registration. Runtime data access happens directly between the R worker and PostgreSQL/vault; nothing in this package is on that path.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EnsureBlockyardAdmin ¶
EnsureBlockyardAdmin runs the idempotent startup SQL that creates the blockyard_admin role (and grants it ADMIN OPTION on blockr_user) when board storage is enabled. No-op if the role already exists.
Not a migration: the GRANT syntax is PG16-only, and operators may run on PG13/14/15 with board storage disabled. Migrations are dialect-sensitive but not version-sensitive; this sidesteps that by living in Go startup code guarded by the preflight.
func SetRoleLogin ¶
SetRoleLogin flips a per-user role between LOGIN and NOLOGIN. Called from the admin deactivation path: we don't DROP the role (that would fail once boards reference it as owner via the `owner_sub` FK-adjacent mapping), but flipping LOGIN has the same effect of blocking access while preserving ownership references.
Types ¶
type Provisioner ¶
type Provisioner struct {
DB *db.DB
Vault *integration.Client
VaultMount string // cfg.Database.VaultMount
VaultDBConnName string // cfg.Database.VaultDBConnection
VaultRotationPeriod time.Duration // cfg.Database.VaultRotationPeriod
// MountAccessor is the opaque accessor of the OIDC/JWT auth mount
// blockyard users log in through. Required for the entity lookup
// below; resolved once at startup via AuthMountAccessor and
// passed in at construction time.
MountAccessor string
}
Provisioner orchestrates the per-user side-effects at OIDC first login: resolve the vault entity ID for the user's sub, create the PG role named `user_<entity-id>`, register it with vault's database secrets engine, persist the role on the users row.
Every step is idempotent, and `users.pg_role` is written last — so a login interrupted between steps replays cleanly next time (CREATE ROLE IF NOT EXISTS, GRANT is a no-op when already granted, vault POST is upsert). The durable signal that provisioning completed is users.pg_role being non-NULL.
Entity-ID-based role naming (#285) replaces the earlier sub- normalization scheme: the templated per-user vault policy resolves `user_{{identity.entity.id}}` from the user's own token context, which only agrees with blockyard's role name if blockyard also uses the entity ID. Bridging two identifier spaces is how we'd get silent mismatches; using vault's own identifier for both sides removes the bridge.
func (*Provisioner) ProvisionUser ¶
func (p *Provisioner) ProvisionUser(ctx context.Context, sub string) error
ProvisionUser runs the first-login flow for `sub`. Fast-path: returns nil immediately if users.pg_role is already populated. Otherwise resolves the vault entity for this sub, derives the PG role name `user_<entity-id>`, executes the provisioning steps, and writes pg_role to the users row.
On any error, leaves users.pg_role NULL so the next login retries from scratch. Partial state (an orphan PG role or a vault static role without a matching users row) is tolerated because every step short-circuits on re-run.