config

package
v0.2.2 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	Server struct {
		Host            string        `mapstructure:"host"`
		Port            int           `mapstructure:"port"`
		ShutdownTimeout time.Duration `mapstructure:"shutdownTimeout"`
		// InferenceRelayURL is the CF Worker URL for free-tier inference relay (Epic 26).
		// When set, ListModels remaps free-tier opencode models to providerID=opencode-relay.
		InferenceRelayURL string `mapstructure:"inferenceRelayURL"`
	} `mapstructure:"server"`

	// Use the shared Kubernetes config
	Kubernetes k8sconfig.KubernetesConfig `mapstructure:"kubernetes"`

	Database struct {
		Host            string        `mapstructure:"host"`
		Port            int           `mapstructure:"port"`
		User            string        `mapstructure:"user"`
		Password        string        `mapstructure:"password"`
		Database        string        `mapstructure:"database"`
		SSLMode         string        `mapstructure:"sslMode"`
		MaxOpenConns    int           `mapstructure:"maxOpenConns"`
		MaxIdleConns    int           `mapstructure:"maxIdleConns"`
		ConnMaxLifetime time.Duration `mapstructure:"connMaxLifetime"`
	} `mapstructure:"database"`

	Redis struct {
		Host     string `mapstructure:"host"`
		Port     int    `mapstructure:"port"`
		Password string `mapstructure:"password"`
		DB       int    `mapstructure:"db"`
		PoolSize int    `mapstructure:"poolSize"`
	} `mapstructure:"redis"`

	Auth struct {
		JWTSecret string `mapstructure:"jwtSecret"`
		// JWTPreviousSecrets is the list of previous JWT signing keys
		// retained for VALIDATION ONLY. Tokens signed with any entry
		// here are still accepted; new tokens are always signed with
		// JWTSecret. Operators rotate by:
		//   1. Move current JWTSecret to head of JWTPreviousSecrets.
		//   2. Set JWTSecret to a fresh random string.
		//   3. Restart API; old sessions stay valid until they
		//      expire (TokenDuration), at which point the entry can
		//      be removed.
		// Closes F1.7.5 (Epic 17). Set via env
		// LLMSAFESPACES_AUTH_JWTPREVIOUSSECRETS as a comma-separated
		// list, OR via the YAML key `jwtPreviousSecrets: [...]`.
		JWTPreviousSecrets  []string      `mapstructure:"jwtPreviousSecrets"`
		TokenDuration       time.Duration `mapstructure:"tokenDuration"`
		APIKeyPrefix        string        `mapstructure:"apiKeyPrefix"`
		CookieName          string        `mapstructure:"cookieName"`
		RememberMeDuration  time.Duration `mapstructure:"rememberMeDuration"`
		RegistrationEnabled bool          `mapstructure:"registrationEnabled"`
		LockoutEnabled      bool          `mapstructure:"lockoutEnabled"`
		LockoutAttempts     int           `mapstructure:"lockoutAttempts"`
		LockoutDuration     time.Duration `mapstructure:"lockoutDuration"`
		APIKeyDEKTTL        time.Duration `mapstructure:"apiKeyDEKTTL"`
	} `mapstructure:"auth"`

	Security struct {
		AllowedOrigins       []string `mapstructure:"allowedOrigins"`
		AllowCredentials     bool     `mapstructure:"allowCredentials"`
		RootKeyProvider      string   `mapstructure:"rootKeyProvider"`
		SealedKeyPath        string   `mapstructure:"sealedKeyPath"`
		PassphrasePath       string   `mapstructure:"passphrasePath"`
		SkipMasterKeyWarning bool     `mapstructure:"skipMasterKeyWarning"`
	} `mapstructure:"security"`

	Logging struct {
		Level       string `mapstructure:"level"`
		Development bool   `mapstructure:"development"`
		Encoding    string `mapstructure:"encoding"`
	} `mapstructure:"logging"`

	RateLimiting struct {
		Enabled       bool          `mapstructure:"enabled"`
		DefaultLimit  int           `mapstructure:"defaultLimit"`
		DefaultWindow time.Duration `mapstructure:"defaultWindow"`
		BurstSize     int           `mapstructure:"burstSize"`
		Strategy      string        `mapstructure:"strategy"`
	} `mapstructure:"rateLimiting"`

	Proxy struct {
		RequestBufferSizePerWorkspace int `mapstructure:"requestBufferSizePerWorkspace"`
		RequestBufferTimeoutSeconds   int `mapstructure:"requestBufferTimeoutSeconds"`
	} `mapstructure:"proxy"`

	// Billing holds Stripe configuration for org subscriptions (Epic 43).
	// When SecretKey is empty, a NoopCheckoutProvider is used and the webhook
	// endpoint rejects all deliveries — development/test mode.
	Billing struct {
		SecretKey          string            `mapstructure:"secretKey"`
		WebhookSecret      string            `mapstructure:"webhookSecret"`
		CheckoutSuccessURL string            `mapstructure:"checkoutSuccessUrl"`
		CheckoutCancelURL  string            `mapstructure:"checkoutCancelUrl"`
		PortalReturnURL    string            `mapstructure:"portalReturnUrl"`
		PlanPrices         map[string]string `mapstructure:"planPrices"`
		Meters             map[string]string `mapstructure:"meters"`
	} `mapstructure:"billing"`

	// Email holds outbound email configuration (US-43.2 invitations). When
	// Provider is empty or "noop", NoopProvider logs to stderr — no AWS
	// dependency. "ses" requires AWS credentials via IRSA or env.
	Email struct {
		Provider    string `mapstructure:"provider"`
		SESRegion   string `mapstructure:"sesRegion"`
		FromAddress string `mapstructure:"fromAddress"`
		BaseURL     string `mapstructure:"baseUrl"`
	} `mapstructure:"email"`

	// OIDC holds SSO login wiring (US-43.10, D17). RedirectBaseURL is the
	// origin the IdP redirects back to after authentication; the full callback
	// is {RedirectBaseURL}/api/v1/auth/sso/:orgSlug/callback. When empty the
	// start endpoint derives it from the incoming request. FrontendRedirectURL
	// is where the browser lands after a successful or failed SSO callback.
	OIDC struct {
		RedirectBaseURL     string `mapstructure:"redirectBaseUrl"`
		FrontendRedirectURL string `mapstructure:"frontendRedirectUrl"`
		// StateCookieName is the signed PKCE/state cookie name.
		StateCookieName string `mapstructure:"stateCookieName"`
	} `mapstructure:"oidc"`

	// OrgSubdomainRouting holds Epic 54 (US-54.1) email-led login discovery
	// config. When BaseDomain is non-empty, POST /auth/lookup redirects found
	// users to https://<orgSlug>.<baseDomain>. When empty (subdomain routing
	// disabled — the default), the lookup falls back to the direct SSO start
	// URL (/api/v1/auth/sso/<slug>/start), which works regardless of chart
	// config. CookieDomain is the value set on the lsp_session cookie's
	// Domain attribute so the session survives root→subdomain redirects; it
	// is consumed by the auth cookie setter (US-54.3 wires it through Helm).
	OrgSubdomainRouting struct {
		BaseDomain   string `mapstructure:"baseDomain"`
		CookieDomain string `mapstructure:"cookieDomain"`
	} `mapstructure:"orgSubdomainRouting"`

	// Turnstile is Cloudflare's CAPTCHA. When Enabled, the /register
	// middleware validates the client-supplied cf-turnstile-response
	// token against SecretKey using VerifyURL. When Enabled but SecretKey
	// is empty, /register 500s at startup — fail-closed, don't run in
	// a state where the operator thinks Turnstile is on but it isn't.
	//
	// When Enabled is false, the middleware is a no-op and /register
	// accepts requests without a token. All chart-side wiring flows
	// through Enabled+SecretKey+SiteKey; there's no partial-config state.
	//
	// Wired via ops-prod cluster-config → chart values → env:
	//   LLMSAFESPACES_TURNSTILE_ENABLED     ("true" | unset)
	//   LLMSAFESPACES_TURNSTILE_SECRETKEY   (secretKeyRef; never in ConfigMap)
	//   LLMSAFESPACES_TURNSTILE_VERIFYURL   (defaults to Cloudflare production)
	Turnstile struct {
		Enabled   bool   `mapstructure:"enabled"`
		SecretKey string `mapstructure:"secretKey"`
		VerifyURL string `mapstructure:"verifyURL"`
	} `mapstructure:"turnstile"`

	// Workspace holds Helm-managed workspace defaults. Currently only
	// DefaultStorageClass is exposed here: when non-empty the API pins the
	// `workspace.defaultStorageClass` instance setting via SetHelmOverrides
	// so admins cannot override it via the settings UI (Tier 1). When
	// empty, the setting stays admin-mutable (Tier 2) with its DB-backed
	// value (which itself defaults to "" — meaning "use cluster default SC").
	//
	// This pathway exists so operators running LLMSafeSpaces on clusters
	// with dedicated low-durability StorageClasses (e.g. Longhorn 2-replica
	// pools) can declare that choice in the Helm chart rather than having
	// to remember to set it in the admin UI after every install/re-install.
	//
	// Wired via: values.yaml `workspace.defaultStorageClass` → API
	// ConfigMap `workspace.defaultStorageClass` → this field → app.go
	// SetHelmOverrides → workspace service Create path.
	Workspace struct {
		DefaultStorageClass string `mapstructure:"defaultStorageClass"`
	} `mapstructure:"workspace"`
}

Config represents the application configuration

func Load

func Load(path string) (*Config, error)

Load loads configuration from file and environment variables

Jump to

Keyboard shortcuts

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