Help us shape the future of Go! Take the 2026 Go Developer Survey

config

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: AGPL-3.0 Imports: 13 Imported by: 0

Documentation

Overview

Package config loads configuration from YAML, environment, and flags (R-271).

Index

Constants

View Source
const (
	OTLPHTTP = "http/protobuf"
	OTLPGRPC = "grpc"
)

Metrics protocols.

View Source
const DefaultMetricsInterval = time.Minute

DefaultMetricsInterval is Metrics.Interval's default, and the OpenTelemetry SDKs' own.

View Source
const LetsEncryptDirectory = "https://acme-v02.api.letsencrypt.org/directory"

LetsEncryptDirectory is ACME.DirectoryURL's default.

View Source
const PolicyEnvPrefix = "PANDO_POLICY_"

PolicyEnvPrefix is how a host policy field is set from the environment: PANDO_POLICY_MIN_SECURITY_SCORE sets min_security_score.

View Source
const RegistryAdapterID = "image_registry"

RegistryAdapterID is the ID of the image registry adapter PANDO_REGISTRY_* declares.

Variables

This section is empty.

Functions

This section is empty.

Types

type ACME

type ACME struct {
	// DirectoryURL is the CA's ACME directory. Let's Encrypt's production
	// directory by default; an organization's own ACME CA, or a test CA such
	// as Pebble, otherwise.
	DirectoryURL string `` /* 150-byte string literal not displayed */

	// CAFile is a PEM bundle of certificates trusted, beside the system's,
	// when connecting to the directory: for a private ACME server whose own
	// TLS certificate no public root signs. Empty trusts the system roots.
	CAFile string `` /* 185-byte string literal not displayed */
}

ACME is the certificate authority the edge's certificates are ordered from when Pando issues them itself — the Kubernetes edge (O-49, R-169).

type AdapterDecl

type AdapterDecl struct {
	ID       string `json:"id"`
	Category string `json:"category"`
	Kind     string `json:"kind"`
	Name     string `json:"name"`
	Default  bool   `json:"is_default"`
	Enabled  bool   `json:"enabled"`

	// Config is the adapter's own settings, as it would be stored in
	// adapter_configs.config. Never a credential.
	Config map[string]any `json:"-"`

	// Credentials name where each credential is read from at startup. The
	// value itself is never in the file (R-190).
	Credentials map[string]CredentialRef `json:"-"`

	// Functions are the AI functions this adapter handles, for an AI adapter.
	Functions []FunctionDecl `json:"functions,omitempty"`

	Source Source `json:"source"`
}

AdapterDecl is one adapter declared in the config file.

type Apps

type Apps struct {
	CPUMillis   int   `` /* 139-byte string literal not displayed */
	MemoryBytes int64 `mapstructure:"memory_bytes" desc:"The memory each new app may use, in bytes. An app can override its own. 0 means 512 MiB."`
	DiskBytes   int64 `mapstructure:"disk_bytes" desc:"The disk each new app may use, in bytes. An app can override its own. 0 means 10 GiB."`

	// DockerCredentials pulls a private image with the Docker login on the
	// Pando server — `docker login`, the config.json it writes and any
	// credential helper it names, found through DOCKER_CONFIG or
	// ~/.docker — when the app has no registry credential of its own (issue
	// #41). Off by default: it lends every app on the install whatever the
	// server's login can read, so it is an operator's decision, made where
	// only an operator can make it.
	DockerCredentials bool `` /* 235-byte string literal not displayed */
}

Apps holds the resource limits every new app inherits (R-240).

R-240 says these are set at the host. They were constants: one CPU, 512 MiB and 10 GiB for every app, with nothing that could change them, so a 12-CPU host refused its thirteenth app however idle the first twelve were (issue #55). Zero means the shipped default (spec.StandardDefaults); an app still overrides its own with app.resources.override (R-241).

func (Apps) Resources

func (a Apps) Resources(shipped spec.Resources) spec.Resources

Resources lays the configured limits over the shipped ones.

type Bootstrap

type Bootstrap struct {
	// AdminPassword is the first administrator's initial password, empty to
	// have the first person to reach the console set the administrator up
	// there (R-046).
	//
	// The one credential in this struct, and the reason nothing logs a Config
	// wholesale. It exists because the generated password is shown once, in a
	// log line, and a server container recreated before anyone read it leaves
	// an account nobody can sign in to.
	//
	// Ignored once the install has any account. It is a bootstrap input, not a
	// way to set a password: the account must still change it at first sign-in,
	// because an environment variable is in the Compose file, in
	// `docker inspect`, and inherited by every child process.
	AdminPassword string `` /* 268-byte string literal not displayed */
}

Bootstrap is what first run needs, and is read on no other run.

type Config

type Config struct {
	Server     Server     `mapstructure:"server"`
	Bootstrap  Bootstrap  `mapstructure:"bootstrap"`
	Database   Database   `mapstructure:"database"`
	Log        Log        `mapstructure:"log"`
	Reconciler Reconciler `mapstructure:"reconciler"`
	Apps       Apps       `mapstructure:"apps"`
	Work       Work       `mapstructure:"work"`
	Retention  Retention  `mapstructure:"retention"`
	Registry   Registry   `mapstructure:"registry"`
	ACME       ACME       `mapstructure:"acme"`
	Metrics    Metrics    `mapstructure:"metrics"`

	// File is the config file read at startup, or empty when there was none.
	File string `mapstructure:"-"`

	// Settings is every non-secret setting with its effective value and where
	// it came from, for GET /config. Policy is the host policy fields set at
	// startup, which override the stored policy (see sources.go).
	Settings []Setting       `mapstructure:"-"`
	Policy   []PolicySetting `mapstructure:"-"`

	// Adapters are the adapters declared in the config file, with the AI
	// functions each handles (adapters.go).
	Adapters []AdapterDecl `mapstructure:"-"`
}

Config is Pando's configuration, from YAML, environment, and flags (R-271).

Adapters usually live in the database (adapter_configs), so they can be changed through the API. An install kept as code may declare them in the file instead (Adapters, see adapters.go), and those are read-only elsewhere while declared.

func Load

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

Load reads configuration. Precedence, lowest to highest: defaults, config file, environment, flags.

type CredentialRef

type CredentialRef struct {
	Env  string
	File string
}

CredentialRef is where a declared credential is read from: an environment variable, or a file such as a mounted Docker or Kubernetes secret.

type Database

type Database struct {
	// URL is the connection string. The bundled Compose file supplies it; an
	// operator pointing Pando at an existing Postgres sets PANDO_DATABASE_URL.
	//
	// Whatever it names, the account must be able to manage Pando's restricted
	// application role — see design 00 §1.1. Pando verifies this at startup and
	// refuses to run if the audit log would be rewritable.
	URL            string        `` /* 192-byte string literal not displayed */
	ConnectTimeout time.Duration `mapstructure:"connect_timeout" desc:"How long Pando keeps trying to reach Postgres at startup before giving up."`

	// PasswordFile names a file holding the password for URL's user, which
	// URL then leaves out (issue #130). The bundled Compose file generates
	// one on first start rather than defaulting to a known password, and
	// hands it to Postgres and Pando as a file, so it is in neither the
	// Compose file nor `docker inspect`. Load writes it into URL.
	PasswordFile string `` /* 178-byte string literal not displayed */

	// MaxConns caps this replica's pool of connections as the application
	// role. pgx's own default is the CPU count, at least four, which a
	// reconciler holding a connection per app it is converging, plus the
	// leader's held lock, could use up on a small host and then wait on
	// forever (issue #72). Postgres's max_connections must allow MaxConns
	// for every replica, plus a few for each one's bootstrap.
	MaxConns int32 `` /* 172-byte string literal not displayed */
}

type FunctionDecl

type FunctionDecl struct {
	Function string `json:"function"`
	Model    string `json:"model,omitempty"`
	Source   Source `json:"source"`
}

FunctionDecl is one AI function a declared adapter handles.

type Log

type Log struct {
	Level       string `mapstructure:"level" desc:"The least severe log level written: debug, info, warn or error."`
	Development bool   `mapstructure:"development" desc:"Write logs as colored, human-readable lines rather than JSON."`
}

type Metrics

type Metrics struct {
	// OTLPEndpoint is the collector: http://otel-collector:4318 for OTLP over
	// HTTP, or http://otel-collector:4317 for gRPC. http:// sends in the
	// clear, https:// over TLS. Over HTTP, a URL with no path has
	// /v1/metrics added, as the OpenTelemetry SDKs do.
	OTLPEndpoint string `` /* 182-byte string literal not displayed */

	// OTLPProtocol is http/protobuf (the default) or grpc.
	OTLPProtocol string `mapstructure:"otlp_protocol" desc:"The OTLP protocol: http/protobuf or grpc."`

	// OTLPHeaders are sent with every export, written as
	// OTEL_EXPORTER_OTLP_HEADERS writes them: key=value pairs separated by
	// commas, values URL-encoded. Usually an API key, so never reported
	// (sources.go) or logged (R-194).
	OTLPHeaders string `` /* 192-byte string literal not displayed */

	// Interval is how often metrics are pushed. Default: a minute.
	Interval time.Duration `mapstructure:"interval" desc:"How often metrics are pushed."`
}

Metrics is where Pando pushes metrics about itself, over OTLP (R-399, issue #126). Empty OTLPEndpoint: nothing is exported.

func (Metrics) Enabled

func (m Metrics) Enabled() bool

Enabled reports whether metrics are exported at all.

func (Metrics) Headers

func (m Metrics) Headers() (map[string]string, error)

Headers parses OTLPHeaders.

type PolicySetting

type PolicySetting struct {
	Key    string `json:"key"`
	Value  any    `json:"value"`
	Source Source `json:"source"`
}

PolicySetting is a host policy field set at startup (a `policy:` section in the config file, or PANDO_POLICY_<FIELD>). It overrides the stored policy and cannot be changed from the console, the API or the CLI while it is set. The value is as given — a string from the environment, a typed value from the file — and is checked against the policy document by the policy package.

type Reconciler

type Reconciler struct {
	// Backoff is the retry schedule, indexed by consecutive failures, as a
	// comma-separated list of durations: "0s,5s,15s,60s,5m".
	Backoff string `` /* 262-byte string literal not displayed */

	// FailureThreshold is how many failures inside FailureWindow before an app
	// is given up on and left failed (R-150).
	FailureThreshold int `` /* 137-byte string literal not displayed */

	// FailureWindow is measured from the last failure, so a slow crash loop
	// still reaches the threshold rather than resetting forever.
	FailureWindow time.Duration `mapstructure:"failure_window" desc:"The window failures are counted in, measured from the last failure. 0 means 30 minutes."`

	// GCInterval is how often garbage collection runs. Zero means the shipped
	// hour. Short intervals are wasteful rather than dangerous — nothing the
	// collector does is urgent — so unlike the backoff this gets no warning.
	GCInterval time.Duration `mapstructure:"gc_interval" desc:"How often garbage collection runs. 0 means an hour."`
}

Reconciler tunes R-149's retry backoff and R-150's give-up rule.

Present because the acceptance test for R-151 has to wait out the real schedule, and at the shipped numbers that is forty minutes. Leave these unset in production: the defaults are the requirement, and Pando says so at startup if they are set faster.

func (Reconciler) BackoffSchedule

func (r Reconciler) BackoffSchedule() ([]time.Duration, error)

BackoffSchedule parses Backoff, returning nil when it is unset.

type Registry

type Registry struct {
	// URL is the registry and an optional path prefix:
	// https://registry.internal:5000, or the organization's registry such as
	// 123456789012.dkr.ecr.us-east-1.amazonaws.com/pando.
	URL string `` /* 307-byte string literal not displayed */

	// Username and Password are the one credential Pando pushes and pulls
	// with (O-36). The password may be given as a file instead
	// (PasswordFile), so it need not be in the environment.
	Username     string `mapstructure:"username" desc:"The registry username. With kind ecr, the AWS access key ID."`
	Password     string `` /* 171-byte string literal not displayed */
	PasswordFile string `mapstructure:"password_file" desc:"A file holding the registry password, in place of password."`

	// Kind is basic (the default) or ecr, where Username and Password are an
	// AWS access key ID and its secret.
	Kind string `mapstructure:"kind" desc:"How Pando signs in to the registry: basic (a username and password) or ecr (an AWS access key)."`

	// Layout is per_app (the default) or single.
	Layout string `` /* 176-byte string literal not displayed */

	// Insecure permits plain HTTP (O-35). Off by default.
	Insecure bool `mapstructure:"insecure" desc:"Allow plain HTTP to the registry."`

	// Always sends every build through the registry, even for a runtime that
	// can import it. Off by default.
	Always bool `mapstructure:"always" desc:"Send every build through the registry, even when the runtime could import it directly."`
}

Registry is the startup shorthand for declaring the install's image registry adapter (R-252, issue #153): PANDO_REGISTRY_URL and the variables beside it, or registry: in the config file. It becomes the adapter declaration image_registry (registry.go), read-only while it is set (R-271), as one written under adapters: would be. Empty URL: no registry, which single-host Docker does not need (O-34).

type Retention

type Retention struct {
	DeploymentsPerApp int           `mapstructure:"deployments_per_app" desc:"How many deployments are kept for each app. 0 means 50."`
	Scans             time.Duration `mapstructure:"scans" desc:"How long security scans are kept. 0 means 90 days."`
	Sessions          time.Duration `mapstructure:"sessions" desc:"How long expired or revoked sessions are kept. 0 means 30 days."`
	IdempotencyKeys   time.Duration `mapstructure:"idempotency_keys" desc:"How long idempotency keys are kept. 0 means a day."`
	SSOFlows          time.Duration `mapstructure:"sso_flows" desc:"How long expired sign-in flows are kept. 0 means a day."`
	Events            time.Duration `mapstructure:"events" desc:"How long the event outbox is kept. 0 means 30 days."`
	DeletedApps       time.Duration `mapstructure:"deleted_apps" desc:"How long a deleted app's detection and backup records are kept. 0 means 30 days."`
}

Retention is how long the retention job keeps each kind of row it removes (issue #72, R-224). Zero means the shipped default for each, listed in retention.Settings: 50 deploys per app, scans 90 days, expired or revoked sessions 30 days, idempotency keys a day, expired sign-in flows a day, the event outbox 30 days, a deleted app's detection and backup record 30 days.

type Server

type Server struct {
	Addr            string        `` /* 139-byte string literal not displayed */
	ShutdownTimeout time.Duration `mapstructure:"shutdown_timeout" desc:"How long Pando waits for requests in flight to finish when it is stopped."`

	// ProxyUpstream is the address routing adapters are told to send traffic
	// to (R-023). It must be reachable from wherever an adapter's data plane
	// runs, which is not necessarily where Pando runs.
	ProxyUpstream string `` /* 227-byte string literal not displayed */

	// Issuer is the `iss` claim in every assertion, and identifies this
	// install to the apps it fronts.
	Issuer string `` /* 140-byte string literal not displayed */

	// ExternalURL is how a browser reaches this installation, and exists
	// because Pando usually does not terminate its own TLS (O-19).
	//
	// Behind a TLS-terminating reverse proxy — the topology SECURITY.md
	// describes — every request arrives over plain HTTP, so `r.TLS` is nil and
	// Pando cannot tell an encrypted browser connection from an unencrypted
	// one. Session cookies then go out without `Secure`, and a single plaintext
	// request to the hostname puts one on the wire.
	//
	// The operator states the scheme rather than Pando guessing it from a
	// header. `X-Forwarded-Proto` is the usual answer and is rejected here for
	// the same reason R-053 strips inbound `X-Pando-*`: any client that can
	// reach Pando directly can also set it, so trusting it without a
	// trusted-proxy list trades one hole for another, and with one it becomes a
	// second thing to get wrong.
	//
	// Empty is correct for the two topologies where the request already tells
	// the truth: Pando serving TLS itself, and the plain-HTTP localhost install
	// the README documents.
	ExternalURL string `` /* 275-byte string literal not displayed */

	// TrustedProxies are the proxies whose X-Forwarded-For names the client
	// in the audit log (R-380, design 12 §3.2): addresses and CIDRs, separated
	// by commas. Empty, the default, records the connecting peer. It decides
	// the audited address and nothing else — not Secure, which ExternalURL
	// decides, and not rate limits (O-19).
	TrustedProxies string `` /* 217-byte string literal not displayed */

	// RoutingMode is how apps are addressed — "subdomain" or "path" (design 03
	// §4.1). Neither is a global setting in the spec sense; this is the
	// install's default shape, and each app's spec still names its own mode.
	RoutingMode spec.RoutingMode `` /* 199-byte string literal not displayed */

	// BaseDomain is what a per-app subdomain is carved out of, so an app
	// called "notes" is reached at notes.example.com. Only used in subdomain
	// mode; empty is correct for an install addressing apps by path, which is
	// the default and needs no DNS at all (R-002 — setup cost is paid once).
	BaseDomain string `` /* 172-byte string literal not displayed */

	// PortRangeStart and PortRangeEnd bound the ports handed to apps in
	// port-mode routing — the loopback adapter's only mode, and so the laptop
	// default. [P]: the requirements do not specify a range (O-15).
	PortRangeStart int `mapstructure:"port_range_start" desc:"The first host port given to an app when apps are reached by port."`
	PortRangeEnd   int `mapstructure:"port_range_end" desc:"The last host port given to an app when apps are reached by port."`

	// WorkDir is where a DR bundle is assembled before it is encrypted and
	// streamed out (R-212). It needs room for a database dump plus every app
	// volume, which is why it is configurable and does not default to the
	// system temporary directory — that is often a small tmpfs, and running out
	// of space partway through a backup is how an install discovers it has no
	// backups.
	WorkDir string `` /* 165-byte string literal not displayed */

	// AuditArchiveDir is where Pando keeps audit archives itself, when host
	// policy's audit_archive is keep, the default (R-347). Beside the rest
	// of Pando's data, on the same volume, so the archives are on the disk
	// R-224 is about rather than somewhere nobody counts.
	AuditArchiveDir string `` /* 126-byte string literal not displayed */

	// TokenKeyPath is the file holding the key API tokens are stored under,
	// as HMAC-SHA-256 (R-063). Generated on first start. Outside the database
	// so a dump alone cannot test a guess at a token; every replica must read
	// the same file, which is why it defaults to the shared /var/lib/pando
	// beside the secrets key, and a DR bundle carries it (R-212).
	TokenKeyPath string `` /* 193-byte string literal not displayed */

	// AdvertiseURL is where the other Pando replicas reach this one, for the
	// one request that has to go to a particular replica: a deploy's live log
	// (issue #72). Empty means http://<hostname><port of addr>, which is right
	// on a Compose network; in Kubernetes, set it to the pod's address, such
	// as http://$(POD_IP):8080. With one replica nothing reads it.
	AdvertiseURL string `` /* 257-byte string literal not displayed */
}

func (Server) Advertise

func (s Server) Advertise(hostname string) string

Advertise is AdvertiseURL, or the default built from hostname.

func (Server) External

func (s Server) External() (*url.URL, error)

External parses ExternalURL, returning nil when it is unset.

Checked at startup rather than at the first sign-in, because the symptom of getting it wrong is a cookie attribute nobody looks at until it matters.

func (Server) Trusted

func (s Server) Trusted() (clientaddr.Trusted, error)

Trusted parses TrustedProxies. Checked at startup: a list Pando cannot read, or one trusting most of the internet, is refused before the first request.

type Setting

type Setting struct {
	Key    string `json:"key"`
	Value  any    `json:"value"`
	Source Source `json:"source"`

	// Env is the variable that sets it, whether or not it is set — so a
	// setting still at its default can say how to change it.
	Env string `json:"env"`
}

Setting is one startup setting, its effective value and where it came from.

type SettingDoc

type SettingDoc struct {
	Env         string `json:"env"`
	Key         string `json:"key"`
	Type        string `json:"type"`
	Default     string `json:"default"`
	Description string `json:"description"`
	Group       string `json:"group"`
	Secret      bool   `json:"secret"`
}

SettingDoc is one startup setting as docs/config.json publishes it: the variable and key that set it, its type and default, and what it does.

Read from Config itself — the mapstructure key, the desc tag beside it, the default Load starts from and the variable Load binds — so the reference cannot name a setting Pando does not read, or miss one it does (R-271).

func Reference

func Reference() []SettingDoc

Reference is every setting in Config, sorted by key.

type Source

type Source struct {
	// Kind is "env", "file" or "default".
	Kind string `json:"kind"`
	// Name is the environment variable, or the config file's path.
	Name string `json:"name,omitempty"`
	// Key is the key inside the config file.
	Key string `json:"key,omitempty"`
}

Source is where a value came from.

type Work

type Work struct {
	// Deploys is the older name for host policy's max_concurrent_deploys
	// (issue #93). Set, it fixes that policy field unless the policy key is
	// set too (policyOf); nothing reads it from here.
	Deploys int `` /* 159-byte string literal not displayed */

	// Detections is how many detections this replica runs at once. Default:
	// one per CPU, at least two.
	Detections int `mapstructure:"detections" desc:"How many detections this replica runs at once. 0 means one per CPU, and at least two."`

	// Backups is how many rolling backups the leader takes at once.
	// Default: two.
	Backups int `mapstructure:"backups" desc:"How many rolling backups the leader takes at once. 0 means two."`

	// AutoDeploy is how many apps the leader checks for new commits at
	// once. Default: eight.
	AutoDeploy int `mapstructure:"auto_deploy" desc:"How many apps the leader checks for new commits at once. 0 means eight."`
}

Work bounds the background work one replica does at once (issue #72). Zero means the shipped default for each.

Jump to

Keyboard shortcuts

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