Skip to content

config

import "github.com/neochaotic/leoflow/internal/config"

Package config loads Leoflow configuration from defaults, an optional config file, and LEOFLOW_* environment variables, with flags taking precedence.

Index

func DefaultConfigFile

func DefaultConfigFile() (string, error)

DefaultConfigFile returns the default configuration file path, \~/.leoflow/config.yaml.

type AuthSection

AuthSection configures authentication.

type AuthSection struct {
    Provider string     `mapstructure:"provider"`
    JWT      JWTSection `mapstructure:"jwt"`
    // DevNoAuth disables authentication entirely, treating every request as an
    // admin. It exists ONLY for `leoflow dev` (local, unsandboxed). It is false by
    // default and the server logs a prominent warning when it is on. NEVER set
    // this in production (LEOFLOW_AUTH_DEV_NO_AUTH).
    DevNoAuth bool `mapstructure:"dev_no_auth"`
    // LoginRateLimitPerMinute caps failed /auth/token attempts per client IP per
    // minute (anti-brute-force). Only failures count, so a successful login never
    // consumes budget. Lite raises this well above the production default because
    // it is a local single-user tool where lockouts are pure friction.
    LoginRateLimitPerMinute int `mapstructure:"login_rate_limit_per_minute"`
}

type CORSSection

CORSSection configures cross-origin access.

type CORSSection struct {
    AllowedOrigins []string `mapstructure:"allowed_origins"`
}

type Config

Config holds the developer CLI configuration.

type Config struct {
    // ServerURL is the control plane base URL used by push and auth create-token.
    ServerURL string `mapstructure:"server_url"`
    // LogLevel is reserved for CLI log verbosity (not yet wired).
    LogLevel string `mapstructure:"log_level"`
    // Registry is reserved for the image registry used by image build (ADR 0003).
    Registry string `mapstructure:"registry"`
    // ParserCmd is the command used to invoke the Python parser from compile.
    ParserCmd string `mapstructure:"parser_cmd"`

    // Lite-edition settings written by `leoflow setup` and read by `leoflow lite`.
    // Workspace is the default directory holding the user's DAG projects.
    Workspace string `mapstructure:"workspace"`
    // LiteExecutor is the chosen executor: "subprocess" (local) or "k8s" (mini-cluster).
    LiteExecutor string `mapstructure:"lite_executor"`
    // LitePort is the UI/API port for the Lite control plane.
    LitePort int `mapstructure:"lite_port"`
    // AdminEmail is the Lite admin login created at bootstrap.
    AdminEmail string `mapstructure:"admin_email"`
    // AdminPasswordHash is the bcrypt hash of the generated admin password; the
    // plaintext is shown once at setup and never stored (Lite only).
    AdminPasswordHash string `mapstructure:"admin_password_hash"`
    // JWTSecret is the per-install Lite JWT signing secret, generated by
    // `leoflow setup` (random, 64 hex chars) and persisted alongside the admin
    // hash. Rotating it on every fresh install invalidates browser tokens from a
    // prior install โ€” so a reinstall greets the user with the login screen and
    // the freshly printed credentials actually do something (#121). Empty on
    // legacy installs; the lite runner falls back to the dev-only constant with
    // a warning so the upgrade does not break existing setups.
    JWTSecret string `mapstructure:"jwt_secret"`
}

func Load

func Load(configFile string, flags *pflag.FlagSet) (*Config, error)

Load assembles configuration from defaults, the given file (when non-empty), LEOFLOW_* environment variables, and the provided flag set, in increasing order of precedence. A nil flag set or empty file path is ignored.

type DatabaseSection

DatabaseSection configures the Postgres connection pool.

type DatabaseSection struct {
    URL          string `mapstructure:"url"`
    MaxOpenConns int    `mapstructure:"max_open_conns"`
    MaxIdleConns int    `mapstructure:"max_idle_conns"`
}

type DispatchSection

DispatchSection sizes the BufferedDispatcher (#127). BufferSize=0 keeps the scheduler tick synchronous with the inner dispatcher โ€” the right shape for Lite (subprocess fork is microseconds). BufferSize>0 enables the worker pool โ€” the right shape for Pro (Kubernetes API calls add real latency). The defaults are set per-edition by configsetup so the user does not have to think about this; an operator can still tune the knobs.

type DispatchSection struct {
    // BufferSize is the depth of the queued-dispatches channel. 0 disables the
    // pool (synchronous passthrough). A full channel returns ErrAtCapacity to
    // the scheduler, which leaves the TI scheduled for the next tick.
    BufferSize int `mapstructure:"buffer_size"`
    // Workers is the number of goroutines draining the queue. Ignored when
    // BufferSize <= 0; otherwise floored to 1.
    Workers int `mapstructure:"workers"`
}

type ExecutorSection

ExecutorSection configures how tasks are executed.

type ExecutorSection struct {
    HTTP HTTPExecutorSection `mapstructure:"http"`
    // Type selects the pod-path executor: "kubernetes" (default, pod-per-task) or
    // "subprocess" (dev only, runs the agent on the host without isolation, used
    // by `leoflow dev`).
    Type string `mapstructure:"type"`
    // AgentPath is the leoflow-agent binary the subprocess executor runs (dev only).
    AgentPath string `mapstructure:"agent_path"`
    // SubprocessWorkDir is the working directory the subprocess executor runs the
    // agent in, so it can import the project's dag.py (dev only). Empty keeps the
    // server's working directory.
    SubprocessWorkDir string `mapstructure:"subprocess_workdir"`
    // AgentControlPlaneAddr is the gRPC address task pods dial back to. Empty
    // falls back to server.grpc_addr; in a local k3d/kind cluster set it to a
    // host-reachable address such as host.k3d.internal:9091.
    AgentControlPlaneAddr string `mapstructure:"agent_control_plane_addr"`
    // AgentTLSCAConfigMap names a ConfigMap (key ca.crt) mounted into task pods so
    // the agent verifies the control plane's gRPC TLS cert (issue #58). Empty =
    // agents use the insecure channel (dev).
    AgentTLSCAConfigMap string `mapstructure:"agent_tls_ca_configmap"`
    // TaskSecretName names a Kubernetes Secret mounted (read-only) into every task
    // pod at TaskSecretMountPath. It lets a task read a credential that lives in
    // the cluster's secret store (e.g. a GCP service-account key) referenced by a
    // connection's key_path โ€” so Leoflow never stores the key itself (ADR 0035).
    // Empty = no secret mounted.
    TaskSecretName string `mapstructure:"task_secret_name"`
    // TaskSecretMountPath is where TaskSecretName is mounted in the task pod.
    TaskSecretMountPath string `mapstructure:"task_secret_mount_path"`
    // Defaults holds per-cluster task defaults applied at dispatch to fill gaps the
    // DAG artifact left empty (ADR 0023, layer L0). They never override a value
    // baked into dag.json, keeping the artifact portable across clusters.
    Defaults PlatformDefaultsSection `mapstructure:"defaults"`
}

type HTTPExecutorSection

HTTPExecutorSection configures the inline http_api execution path (ADR 0002).

type HTTPExecutorSection struct {
    // InlineMaxDurationSeconds caps how long an inline http_api task may run; a
    // task declaring a longer execution_timeout_seconds must use execution_mode: pod.
    InlineMaxDurationSeconds int `mapstructure:"inline_max_duration_seconds"`
    // InlineConcurrencyLimit bounds the number of in-flight inline goroutines.
    InlineConcurrencyLimit int `mapstructure:"inline_concurrency_limit"`
    // UserAgent is the User-Agent header sent on inline http_api requests.
    UserAgent string `mapstructure:"user_agent"`
}

type JWTSection

JWTSection configures JWT issuance and validation.

type JWTSection struct {
    Secret          string `mapstructure:"secret"`
    TokenTTLSeconds int    `mapstructure:"token_ttl_seconds"`
}

type LogsSection

LogsSection configures task log shipping.

type LogsSection struct {
    // Dir is the root directory for the disk log sink.
    Dir string `mapstructure:"dir"`
}

type OTelSection

OTelSection configures OpenTelemetry export.

type OTelSection struct {
    Enabled  bool   `mapstructure:"enabled"`
    Endpoint string `mapstructure:"endpoint"`
}

type ObservabilitySection

ObservabilitySection configures logging, metrics, and tracing.

type ObservabilitySection struct {
    OTel      OTelSection `mapstructure:"otel"`
    LogLevel  string      `mapstructure:"log_level"`
    LogFormat string      `mapstructure:"log_format"`
}

type PlatformDefaultsSection

PlatformDefaultsSection configures the lowest-precedence (L0) task defaults, applied at dispatch to fill gaps the DAG left empty (ADR 0023).

type PlatformDefaultsSection struct {
    // StagingSize/StagingStorageClass default the per-run staging volume when the
    // DAG enabled staging without pinning them (e.g. the cluster's RWX class).
    StagingSize         string `mapstructure:"staging_size"`
    StagingStorageClass string `mapstructure:"staging_storage_class"`
    // StagingAccessMode is the PVC access mode for the staging volume. Defaults to
    // ReadWriteMany (multi-node prod); single-node dev (k3d local-path, no RWX)
    // sets ReadWriteOnce, which is sufficient for a run's sequential same-node pods.
    StagingAccessMode string `mapstructure:"staging_access_mode"`
    // ResourcesCPU/ResourcesMemory default a task's request when neither the task
    // override nor the DAG set any (Kubernetes quantities, e.g. "250m"/"256Mi").
    ResourcesCPU    string `mapstructure:"resources_cpu"`
    ResourcesMemory string `mapstructure:"resources_memory"`
}

type RedisSection

RedisSection configures the Redis connection.

type RedisSection struct {
    URL string `mapstructure:"url"`
    // CAFile is the absolute path to a PEM CA bundle the client trusts when
    // negotiating TLS to a `rediss://` URL (#312). Required to reach managed
    // Redis (Memorystore SERVER_AUTHENTICATION, ElastiCache in-transit
    // encryption, Azure Cache for Redis) whose server cert is signed by a
    // provider / per-instance CA that is not in the container's system
    // roots. Empty falls back to the SDK default โ€” system roots only.
    // The Helm chart sets this via LEOFLOW_REDIS_CA_FILE when
    // `redis.caConfigMap` is configured, pointing at the mounted ConfigMap.
    CAFile string `mapstructure:"ca_file"`
}

type SchedulerSection

SchedulerSection configures the scheduler loop.

type SchedulerSection struct {
    LoopIntervalMS int             `mapstructure:"loop_interval_ms"`
    Enabled        bool            `mapstructure:"enabled"`
    Dispatch       DispatchSection `mapstructure:"dispatch"`
}

type ServerConfig

ServerConfig is the full configuration for the leoflow-server control plane. It mirrors the nested YAML described in the Phase 2 prompt.

type ServerConfig struct {
    Server        ServerSection        `mapstructure:"server"`
    Database      DatabaseSection      `mapstructure:"database"`
    Redis         RedisSection         `mapstructure:"redis"`
    Auth          AuthSection          `mapstructure:"auth"`
    Scheduler     SchedulerSection     `mapstructure:"scheduler"`
    Executor      ExecutorSection      `mapstructure:"executor"`
    Logs          LogsSection          `mapstructure:"logs"`
    Observability ObservabilitySection `mapstructure:"observability"`
    UI            UISection            `mapstructure:"ui"`
    // SecretKey (LEOFLOW_SECRET_KEY) is the 32-byte key encrypting connection
    // secrets at rest (ADR 0019). Raw 32 chars, 64-char hex, or base64. Empty
    // disables connection writes.
    SecretKey string `mapstructure:"secret_key"`
}

func LoadServer

func LoadServer(configFile string, flags *pflag.FlagSet) (*ServerConfig, error)

LoadServer assembles the server configuration from defaults, the given file, LEOFLOW_* environment variables, and flags, in increasing precedence.

func (*ServerConfig) Validate

func (c *ServerConfig) Validate() error

Validate reports configuration errors that must abort startup.

type ServerSection

ServerSection configures the HTTP, metrics, and agent gRPC listeners.

type ServerSection struct {
    HTTPAddr    string      `mapstructure:"http_addr"`
    MetricsAddr string      `mapstructure:"metrics_addr"`
    GRPCAddr    string      `mapstructure:"grpc_addr"`
    CORS        CORSSection `mapstructure:"cors"`
    // GRPCTLSCert/GRPCTLSKey enable TLS on the agent gRPC listener (issue #58).
    // When both are set the channel is encrypted; empty means plaintext (dev).
    GRPCTLSCert string `mapstructure:"grpc_tls_cert"`
    GRPCTLSKey  string `mapstructure:"grpc_tls_key"`
}

type UISection

UISection configures the embedded Airflow UI.

type UISection struct {
    // InstanceName is shown in the UI navbar (Airflow's instance_name). Empty
    // falls back to "Leoflow"; `leoflow lite` sets it to mark the environment.
    InstanceName string `mapstructure:"instance_name"`
    // AutoRefreshIntervalSeconds is the SPA's polling cadence for DAG /
    // DagRun / task-instance state refresh (Airflow's auto_refresh_interval).
    // Zero (the default) falls back to api.DefaultUIAutoRefreshIntervalSeconds
    // (30s, production-safe). `leoflow lite` sets it to 1s for a snappy inner
    // loop so the SPA reflects state changes almost immediately during dev.
    AutoRefreshIntervalSeconds int `mapstructure:"auto_refresh_interval_seconds"`
    // Edition marks the running edition; "lite" shows the silver LITE badge and
    // "pro" shows the gold PRO badge in the UI shell (independent of the auth
    // mode). Empty/any other value shows no badge โ€” Demo intentionally renders
    // without an edition pill.
    Edition string `mapstructure:"edition"`
    // Workspace is the DAG project directory the Lite web editor edits (ADR 0025).
    // Empty disables the editor (Production, or Lite without one).
    Workspace string `mapstructure:"workspace"`
    // MonacoDir is where the pinned Monaco bundle was fetched by `leoflow setup`;
    // the editor page is served Monaco from it. Empty shows a setup hint.
    MonacoDir string `mapstructure:"monaco_dir"`
}

Generated by gomarkdoc