setup

package
v0.37.0 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package setup provides a first-run setup flow for self-hosted GoFastr apps. An operator deploying a binary against an empty database gets a guided bootstrap: create the initial admin, verify adapter health, and any other step the app declares — either headlessly (all values in env) or through an SSR wizard.

The package exports Config, Field, Step, and constructors for shipped steps (AdminStep, HealthStep). A Config becomes a Runner via New; the Runner implements framework.SetupRunner and is wired onto an App via framework.WithSetup.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Steps []Step

	// Complete reports whether setup has already finished (e.g. "at
	// least one user exists"). This is a DERIVED check — never a marker
	// file — so a crash mid-setup re-enters setup on next boot. Required.
	Complete func(ctx context.Context) (bool, error)

	// DisableToken opts out of the one-time setup token. Use only on
	// trusted networks where the first operator to reach /setup is
	// guaranteed to be authorised.
	DisableToken bool

	// Title overrides the wizard page title. Defaults to "Setup".
	Title string

	// HostName overrides the host in the setup URL printed at boot.
	// Defaults to the bound listen address.
	HostName string

	// Theme supplies the shared design tokens (--color-* / --font-*)
	// the wizard renders from. When zero, the framework DefaultTheme
	// is used. Pass the same theme the app uses for a coherent look.
	Theme style.Theme
}

Config is the top-level setup configuration.

type Field

type Field struct {
	// Name is the form field name AND the default env-var suffix
	// (prefixed with GOFASTR_). e.g. "ADMIN_EMAIL" → form name
	// "ADMIN_EMAIL", env GOFASTR_ADMIN_EMAIL.
	Name string
	// Label is the human-readable label shown in the wizard.
	Label string
	// EnvVar is the full environment variable name (e.g.
	// "GOFASTR_ADMIN_EMAIL"). Empty means the field cannot be resolved
	// from env — it can only come through the wizard.
	EnvVar string
	// Secret renders as a password input. Secret values are never
	// pre-filled from env (the wizard shows an empty password field even
	// when GOFASTR_ADMIN_PASSWORD is set) and never logged.
	Secret bool
	// Validate optionally checks the value before the step's Run fires.
	// Returning an error aborts the step and re-renders the field with
	// the message.
	Validate func(value string) error
}

Field describes one input the operator provides during setup.

type Runner

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

Runner implements framework.SetupRunner. Construct via New.

func New

func New(cfg Config) *Runner

New constructs a Runner from cfg. Panics if cfg.Complete is nil — without a Complete predicate the framework can't tell whether setup is done, and a derived check (not a marker file) is the contract.

func (*Runner) CanRunHeadless

func (r *Runner) CanRunHeadless(_ context.Context) (bool, error)

CanRunHeadless reports whether every field across all steps resolves from the environment. A field resolves when its EnvVar is non-empty AND the variable is actually set.

func (*Runner) Handler

func (r *Runner) Handler(swap func(), healthz, readyz http.HandlerFunc) http.Handler

Handler implements framework.SetupRunner.Handler. It returns the interactive setup surface: the wizard + /healthz + /readyz; every other path returns 503 with a short "setup required" body.

The returned handler owns:

  • Token exchange: GET /setup?token=<t> sets a cookie and redirects to /setup; wrong/missing token → 403.
  • Wizard navigation: GET /setup renders the current step; POST /setup validates, runs the step, and advances or re-renders on error.
  • Atomic exit: when the final step succeeds, swap() is called to switch to the real app handler. Step execution is serialized and Complete is re-checked under the mutex so two racing submissions can't both run the steps.

func (*Runner) Incomplete

func (r *Runner) Incomplete(ctx context.Context) (bool, error)

Incomplete reports whether setup has not yet finished.

func (*Runner) RunSteps

func (r *Runner) RunSteps(ctx context.Context) error

RunSteps resolves all fields from env and runs every step in order. An error names the step that failed.

func (*Runner) SetupURL

func (r *Runner) SetupURL(addr string) string

SetupURL returns the operator-facing setup URL for the startup banner.

type Step

type Step struct {
	Name   string
	Fields []Field
	// Run executes the step with the resolved field values. Called once
	// per step in order. An error aborts the flow (headless) or
	// re-renders the step (interactive).
	Run func(ctx context.Context, values map[string]string) error
}

Step is one unit of the setup flow.

func AdminStep

func AdminStep(m *auth.AuthManager, db *sql.DB, usersTable string) (Step, func(context.Context) (bool, error))

AdminStep builds the "create initial admin" step plus the Complete predicate ("at least one user exists").

The step collects an email + password, validates the password against the auth battery's strength policy (RecommendedMinPasswordBytes), hashes it with the same bcrypt hasher the battery uses, and creates a user with roles ["admin"].

The Complete predicate probes the users table directly — auth.UserStore has no count/list surface and the brief forbids adding methods to battery/auth. The narrowest exported surface is the *sql.DB the host already holds (the same one passed to auth.NewEntityUserStore).

usersTable MUST match the table name passed to auth.NewEntityUserStore (typically "auth_users"). The identifier is validated with query.SafeIdent and quoted with query.QuoteIdent since it can't be parameterized. An empty or unsafe name panics — fail loud, never silently fall back to a hardcoded default.

EnvVars: GOFASTR_ADMIN_EMAIL / GOFASTR_ADMIN_PASSWORD.

func HealthStep

func HealthStep(app *framework.App) Step

HealthStep builds a "verify adapters" step with no fields. Its Run executes the app's registered readiness checks via the exported RunReadinessChecks method and fails with a per-check, actionable error list. In the wizard this renders as a "verify adapters" step.

Jump to

Keyboard shortcuts

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