config

package
v0.0.1-alpha.30 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package config loads and validates all runtime configuration from environment variables. All other packages receive a *Config value — they never read os.Getenv directly. This makes configuration explicit and testable.

Index

Constants

View Source
const DefaultEFSNFSImage = "registry.k8s.io/sig-storage/nfs-provisioner@sha256:c825f3d5e28bde099bd7a3daace28772d412c9157ad47fa752a9ad0baafc118d"

DefaultEFSNFSImage is the digest-pinned NFS-Ganesha image used for mount-target exports when OVERCAST_EFS_NFS is on. Pinned rather than floating so an upstream retag cannot change what a mount target runs.

The image is Kubernetes SIG-Storage's NFS provisioner build; Overcast uses it only as a carrier for ganesha.nfsd and its VFS FSAL, replacing the entrypoint with its own configuration. It is multi-arch (amd64, arm64, ppc64le, s390x) and runs unprivileged.

View Source
const TLSModeAuto = "auto"

TLSModeAuto is the OVERCAST_TLS value that mints a certificate from the local Overcast CA at startup.

Variables

View Source
var WildcardDNSDomains = []string{
	"localhost.overcast.sh",
	"localhost.localstack.cloud",
	"localhost.floci.io",
}

WildcardDNSDomains are the public domains whose every subdomain resolves to 127.0.0.1, so an SDK-generated hostname reaches Overcast with no hosts-file edit. They are "split horizon": inside containers Overcast starts, the same names are remapped to its container address via /etc/hosts, so one URL is dialable from both sides of the container boundary.

This is the single source of truth for the set. internal/middleware reads it for S3 virtual-hosted addressing — adding plain "localhost", which is not a public domain and so belongs only there — and internal/containerendpoint reads it for the /etc/hosts mapping. They were previously two hand-maintained lists and they drifted: containerendpoint knew localhost.floci.io while the S3 matcher did not, so a bucket was unreachable on a domain Overcast itself advertises.

Extend per-deployment with OVERCAST_SPLIT_HORIZON_HOSTS rather than editing this list.

Functions

func AllServices

func AllServices() []string

AllServices returns the canonical list of supported service names in declaration order. The result is a copy, so callers cannot mutate package state through it.

These are the names OVERCAST_STATE_<SERVICE> is keyed by, and cmd/capgen generates the service-name table in docs/README.md from this list, which is what keeps the documented names from drifting away from the real ones when a service is added or renamed.

func SQLiteSupported

func SQLiteSupported() bool

SQLiteSupported reports whether this binary was built with SQLite support (i.e. not built with -tags nosqlite). Exported so callers outside this package — e.g. tests that need to skip a hybrid/persistent/wal-specific assertion under a nosqlite build — can check it without reaching into unexported internals.

func ServiceNamespacePrefix

func ServiceNamespacePrefix(service string) string

ServiceNamespacePrefix returns the canonical mapping from a config service name (as used in OVERCAST_STATE_<SERVICE> and allServices) to the storage-namespace prefix that service actually writes under — the segment before the first ":" in namespaces like "cfn:stacks" or "sqs:queues".

Most services use their config name as their namespace prefix unchanged (e.g. "sqs" → "sqs"), but a few historical namespace prefixes are shorter than the config name:

cloudformation → cfn
apigateway     → apigw
eventbridge    → eb

This function is the single source of truth for that mapping. It is used by both the per-service storage override routing in cmd/overcast's serve command and the /_debug endpoints in internal/router — state.NamespacedStore (internal/state/namespaced.go) routes purely on namespace prefix, not on config service name, so any caller that keys a NamespacedStore route map (or unwraps one) by config service name instead of this prefix will build an override that silently never takes effect.

"dynamodbstreams" is intentionally left identity-mapped here — it must NOT be remapped to "dynamodb". cfg.ServiceStates is an unordered map: if both OVERCAST_STATE_DYNAMODB and OVERCAST_STATE_DYNAMODBSTREAMS were ever set to different modes, remapping dynamodbstreams to "dynamodb" would make both resolve to the same route-map key and collide, nondeterministically redirecting real DynamoDB item/table storage depending on map iteration order. It's also moot: dynamodbstreams.New (internal/services/dynamodbstreams/service.go) takes no state.Store parameter at all — it's a store-less facade over the dynamodb service, so an override for it can never have any effect regardless of prefix. See ServiceOverrideIneffective, which documents this (and a few other services) as a known no-op override.

func ServiceOverrideIneffective

func ServiceOverrideIneffective(service string) (reason string, ok bool)

ServiceOverrideIneffective reports whether an OVERCAST_STATE_<SERVICE> override for service is accepted by config validation but has no observable effect, and if so, a short human-readable reason why.

These services fall into two groups, both of which mean the service never reads or writes through the store instance that a per-service override would substitute:

  • "dynamodbstreams": a store-less facade over the dynamodb service. dynamodbstreams.New(ddb DynamoDBService, logger *zap.Logger) — see internal/services/dynamodbstreams/service.go — takes no state.Store parameter; all persisted data actually lives under the dynamodb service's own store.
  • "sts": STS session state is written under the IAM namespace, not "sts" — see internal/services/sts/handler.go, which calls `h.st.Set(ctx, "iam:sessions", accessKeyID, ...)`. An OVERCAST_STATE_STS override builds a store that is registered under the "sts" prefix, but NamespacedStore.storeFor never routes "iam:sessions" there.
  • "bedrock": a stateless stub. bedrock.New's state.Store parameter is the blank identifier (see internal/services/bedrock/service.go) — the service struct holds no store field and never persists anything.
  • "organizations": a stateless stub. organizations.New accepts a state.Store parameter but never assigns or otherwise uses it (see internal/services/organizations/service.go) — the service struct holds no store field.

Callers that build per-service storage overrides (cmd/overcast's serve command) should still build and route the override store for these services when configured — it's harmless — but should log a warning so the no-op isn't silently misread as "the override took effect".

Types

type Config

type Config struct {
	// Host is the hostname or IP address to bind to.
	// Equivalent to LocalStack's LOCALSTACK_HOST.
	// Use "127.0.0.1" to restrict to localhost only.
	// Defaults to "0.0.0.0" (all interfaces).
	Host string

	// Port is the TCP port the HTTP server listens on.
	Port int

	// Hostname is the externally-reachable hostname or IP that services embed
	// in URLs returned to clients (e.g. SQS QueueUrl, SNS UnsubscribeURL,
	// RDS Endpoint.Address). When empty, defaults to "localhost".
	// Set OVERCAST_HOSTNAME when Overcast runs in Docker Compose alongside
	// app containers that need to reach it by its service name.
	Hostname string

	// SplitHorizonHosts are extra hostnames that resolve to 127.0.0.1 in public
	// DNS and are remapped to Overcast's address inside containers Overcast
	// starts, so one URL is dialable from both the host and a sibling container.
	// Appended to the built-in set (localhost.overcast.sh,
	// localhost.localstack.cloud, localhost.floci.io) — see
	// internal/containerendpoint.
	SplitHorizonHosts []string

	// TestOnlyServiceSubset restricts which services router.New registers.
	// nil — the normal case, and the only case any production path produces —
	// registers every service.
	//
	// Load never populates this: there is no environment variable for it and
	// no way for a user to set it. It exists because a handful of router tests
	// need a server where nothing but the service under test is registered.
	// S3's bucket/object routes are deliberately broad, so proving that no
	// modeled operation falls through to them, or that an S3 bucket whose name
	// collides with another service's REST literal stays reachable, requires
	// removing the other claimants — there is no way to assert it against a
	// fully-registered router. See tests/integration/router and
	// docs/plans/host-routing-precedence.md.
	TestOnlyServiceSubset map[string]bool

	// State controls the global storage backend used for all services. This
	// is always a concrete backend (memory, persistent, hybrid, or wal) —
	// when OVERCAST_STATE is unset or "auto", it holds the *resolved* value
	// (see resolveAutoState); the raw configured value ("auto" or whatever
	// the user set) is preserved separately in StateConfigured.
	// Individual services may override this via ServiceStates.
	State StateBackend

	// StateConfigured is the raw value of OVERCAST_STATE as configured, or
	// "auto" if the variable was unset (auto is also the default). Unlike
	// State, this is never resolved — it exists so /_health and startup logs
	// can report what was actually configured, not just what it resolved to.
	StateConfigured string

	// StateSource reports whether State was chosen explicitly (OVERCAST_STATE
	// set to a concrete backend) or resolved by the OVERCAST_STATE=auto
	// heuristic. Drives the actionable variant of the memory-mode advisory
	// (internal/router/advisories.go checkMemoryMode) and the startup log
	// line below.
	StateSource StateSource

	// StateAutoReason is a short, human-readable explanation of why
	// resolveAutoState chose State. Empty when StateSource is "explicit".
	StateAutoReason string

	// StateAutoSignal is the stable code identifying which auto-detection
	// signal fired: "mountpoint", "explicit-data-dir", "existing-database",
	// or "" when none fired (State resolved to memory). Empty when
	// StateSource is "explicit". Safe to key tests off of, unlike
	// StateAutoReason's free text.
	StateAutoSignal string

	// ServiceStates overrides the global State for individual services.
	// Keys are lowercase service names ("s3", "sqs", "dynamodb", etc.).
	// Entries missing from the map inherit the global State.
	ServiceStates map[string]StateBackend

	// HybridFlushInterval controls how often the hybrid store flushes
	// in-memory state to disk. Only meaningful when State or a per-service
	// mode is "hybrid".
	HybridFlushInterval time.Duration

	// HybridSyncMode controls fsync policy for the hybrid store's pending
	// log. Valid values: always, interval, never. Corresponds to
	// state.WALSyncMode (the hybrid pending log reuses the same sync-mode
	// mechanism as the WAL backend).
	HybridSyncMode string

	// HybridSyncInterval controls periodic fsync cadence for the hybrid
	// pending log when HybridSyncMode is "interval".
	HybridSyncInterval time.Duration

	// HybridDirtyEntryThreshold triggers an early, out-of-band hybrid flush
	// once this many unflushed pending-log operations have accumulated,
	// ahead of the next HybridFlushInterval tick. A value <= 0 disables the
	// entry-count trigger (the byte threshold still applies unless it is
	// also disabled).
	HybridDirtyEntryThreshold int

	// HybridDirtyByteThreshold triggers an early, out-of-band hybrid flush
	// once the approximate byte size of unflushed writes exceeds this many
	// bytes. A value <= 0 disables the byte-size trigger.
	HybridDirtyByteThreshold int64

	// HybridMaintenanceInterval controls how often the hybrid store's
	// background loop runs routine SQLite housekeeping (a passive WAL
	// checkpoint plus a conditional incremental vacuum — see
	// docs/plans/storage-plan.md item 3.5). Never runs on the request path.
	HybridMaintenanceInterval time.Duration

	// WALFsyncMode controls fsync policy for the WAL backend.
	// Valid values: always, interval, never.
	WALFsyncMode string

	// WALFsyncInterval controls periodic fsync cadence when WALFsyncMode is
	// set to interval.
	WALFsyncInterval time.Duration

	// WALMaxLogBytes triggers log compaction when the append log grows past
	// this size.
	WALMaxLogBytes int64

	// DataDir is the root directory for the SQLite file and any
	// on-disk state (analogous to LocalStack's DATA_DIR).
	DataDir string

	// Region is the default AWS region reported in ARNs and responses.
	Region string

	// AccountID is the fake AWS account ID embedded in ARNs.
	AccountID string

	// EKSMode controls whether the EKS service stays metadata-only (`mock`) or
	// enables the live k3s-backed control plane path (`live`).
	EKSMode EKSMode

	// EFSMode controls whether the EFS service backs each file system with a
	// named Docker volume (`live`, the default) or stays metadata-only
	// (`mock`). Live mode needs no Docker to be safe: it falls back to
	// metadata-only whenever a daemon is unreachable.
	EFSMode EFSMode

	// RDSMode controls whether the RDS service starts a real engine container
	// per DB instance (`live`, the default) or stays metadata-only (`mock`).
	// Mock mode makes an instance reach `available` in a moment rather than in
	// the tens of seconds a real engine takes, at the cost of nothing listening
	// on the endpoint it reports.
	RDSMode RDSMode

	// SigV4Validate enables SigV4 signature verification.
	SigV4Validate bool

	// EnforceIAM enables opt-in IAM authorization enforcement middleware.
	// Default false.
	EnforceIAM bool

	// EnforceAPIGatewayThrottle turns API Gateway usage-plan throttle and
	// quota limits from evaluate-and-report into actual rejection: an
	// over-limit request gets AWS's 429 instead of being served. Usage is
	// always measured and readable through GetUsage regardless — only the
	// rejection is gated, so a stack that works today keeps working.
	// Default false. Corresponds to env var
	// OVERCAST_ENFORCE_APIGATEWAY_THROTTLE.
	EnforceAPIGatewayThrottle bool

	// ProtocolStrict restores strict rejection of "claimed-but-undeclared"
	// wire protocols: when a request's identified protocol isn't one a
	// service's SupportedProtocols() lists, the service returns 415
	// UnsupportedProtocol instead of attempting the decode anyway. Default
	// false (lenient): the emulator logs a "protocol drift" warning and
	// attempts dispatch regardless, since AWS SDKs may switch a service's
	// wire protocol without notice (see docs/plans/level2-codegen.md
	// Track 1.2). Corresponds to env var OVERCAST_PROTOCOL_STRICT.
	ProtocolStrict bool

	// CFNSyncWait is the bounded time CloudFormation waits for fast stack
	// create/update/delete provisioning to reach a terminal state before returning.
	// A zero value disables the wait and restores fully asynchronous behaviour.
	// Corresponds to env var OVERCAST_CFN_SYNC_WAIT_MS. Default 1000ms.
	CFNSyncWait time.Duration

	// StepFunctionsExecutionTimeout is the ceiling on how long one Step
	// Functions execution may run. It is a runaway guard, not a request
	// timeout: StartExecution accepts and returns while the execution is still
	// RUNNING, so this never sits on the wire and is set high enough not to
	// rule out ordinary Wait states. A state machine's own top-level
	// TimeoutSeconds can lower the budget but never raise it. Exceeding it
	// ends the execution TIMED_OUT with AWS's States.Timeout.
	// Corresponds to env var OVERCAST_STEPFUNCTIONS_EXECUTION_TIMEOUT.
	// Default 15m; values below 1s are raised to 1s.
	StepFunctionsExecutionTimeout time.Duration

	// ShutdownTimeout is how long the server waits for in-flight
	// requests to complete before forcibly closing.
	ShutdownTimeout time.Duration

	// LogLevel controls log verbosity: "trace", "debug", "info", "warn", "error"
	// (case-insensitive). "trace" is Overcast-specific — it sits below zap's
	// built-in "debug" and covers periodic machine chatter (health-check and
	// /_debug/* request logs, flush/checkpoint/maintenance/sweep cycle logs,
	// pool internals); see serviceutil.ParseLevel and CONTRIBUTING.md § Log
	// levels. Default "info".
	LogLevel string

	// LambdaDockerSocket is the path to the Docker daemon socket used to
	// manage Lambda container siblings. Defaults to the platform Docker socket
	// (/var/run/docker.sock on Linux/macOS, npipe:////./pipe/docker_engine on Windows).
	LambdaDockerSocket string

	// LambdaNetwork is the Docker network name that Lambda containers are
	// attached to. Must be reachable from the Overcast container.
	// Defaults to "overcast_lambda".
	LambdaNetwork string

	// LambdaRuntimeAPIPort is the port on which Overcast exposes the Lambda
	// Runtime API to containers. Each container connects back on this port.
	// Defaults to 9001.
	LambdaRuntimeAPIPort int

	// LambdaDockerMaxConcurrentStarts bounds concurrent Docker-backed Lambda
	// environment starts. This is local Docker backpressure, not an AWS-facing
	// Lambda concurrency quota. Corresponds to env var
	// LAMBDA_DOCKER_MAX_CONCURRENT_STARTS. 0 (the default) means unset: the
	// Lambda runtime derives a value from the Docker host's CPU count —
	// clamp(NCPU/2, 2, 8), because every start bursts to ~2 CPUs during INIT —
	// falling back to 4 when Docker /info is unavailable.
	LambdaDockerMaxConcurrentStarts int

	// LambdaMaxInstances bounds how many Lambda containers Overcast runs at
	// once across all functions — warm and executing combined. When the limit
	// is reached, a new invocation first reclaims the least-recently-used idle
	// container; if none can be reclaimed it queues until the function's
	// timeout and is then throttled. This protects the host, it is not an
	// emulation of the AWS account concurrency quota. Corresponds to env var
	// LAMBDA_MAX_INSTANCES. 0 (the default) means unset: the Lambda runtime
	// derives a value from the Docker host's memory —
	// clamp(MemTotal*0.65 / 256 MiB, 4, 32) — falling back to 25 when Docker
	// /info is unavailable.
	LambdaMaxInstances int

	// LambdaMaxInstancesPerFunction bounds concurrent containers for a single
	// function, independent of any AWS reserved concurrency the function has.
	// Clamped to LambdaMaxInstances. Corresponds to env var
	// LAMBDA_MAX_INSTANCES_PER_FUNCTION. 0 (the default) means unset: the
	// Lambda runtime derives clamp(maxInstances/2, 2, maxInstances) from the
	// effective global limit, falling back to 10 when Docker /info is
	// unavailable.
	LambdaMaxInstancesPerFunction int

	// LambdaMaxMemoryMB bounds the aggregate memory of live Lambda containers,
	// in MB: Σ MemorySize over warm and executing containers. Each container is
	// hard-capped at its function's MemorySize with swap disabled, so this is a
	// real bound on what Lambda can take from the host, not an estimate. When
	// the budget is exhausted a new invocation reclaims idle containers, then
	// queues, then throttles at the function's timeout — the same ladder as
	// LambdaMaxInstances. Corresponds to env var LAMBDA_MAX_MEMORY_MB. 0 (the
	// default) means unset: the Lambda runtime derives 65% of the Docker host's
	// MemTotal, or leaves the budget unlimited when Docker /info is unavailable.
	LambdaMaxMemoryMB int

	// LambdaMaxWarmInstances bounds how many idle containers one function keeps
	// after a concurrency burst. Surplus instances are destroyed on release
	// rather than waiting out the 15-minute idle sweep. A provisioned
	// concurrency allocation raises this floor for that function. Corresponds
	// to env var LAMBDA_MAX_WARM_INSTANCES. Default 10.
	LambdaMaxWarmInstances int

	// LambdaSeedRuntimeImages controls whether Overcast pre-pulls every known
	// managed Lambda runtime image when the Docker runtime starts. Disabled by
	// default to avoid Docker Desktop/containerd pressure during frequent restarts;
	// runtime images are still pulled lazily on first use.
	// Corresponds to env var LAMBDA_SEED_RUNTIME_IMAGES. Default false.
	LambdaSeedRuntimeImages bool

	// LambdaInitTimeout is the maximum time to wait for a Docker-backed Lambda
	// runtime to finish INIT and poll the Runtime API for its first invocation.
	// This is separate from the function invocation timeout. Corresponds to env
	// var LAMBDA_INIT_TIMEOUT_SECONDS. Default 10s.
	LambdaInitTimeout time.Duration

	// LambdaKeepContainers controls whether Docker containers are removed when
	// a Lambda instance expires (idle timeout) or the function is deleted.
	// Set to true to keep stopped containers for post-mortem inspection.
	// Corresponds to env var LAMBDA_KEEP_CONTAINERS. Default false.
	LambdaKeepContainers bool

	// LambdaTarCacheMB bounds the in-memory cache of pre-built cold-start
	// artifacts (code and layer tars), in megabytes. 0 disables the cache.
	// Corresponds to env var LAMBDA_TAR_CACHE_MB. Default 256.
	LambdaTarCacheMB int

	// LambdaProactiveInit pre-initializes one execution environment after a
	// function's configuration settles, mirroring AWS's documented proactive
	// initialization, so the next request lands warm. Corresponds to env var
	// LAMBDA_PROACTIVE_INIT. Default false while the feature beds in.
	LambdaProactiveInit bool

	// LambdaHotReload enables bind-mount based source reload for functions that
	// opt in via the overcast:hot-reload-path function tag.
	// Corresponds to env var OVERCAST_LAMBDA_HOT_RELOAD. Default false.
	LambdaHotReload bool

	// LambdaFetchRemoteLayers enables downloading layer content from real AWS
	// when a layer ARN is not found locally. Requires valid AWS credentials.
	// Downloaded layers are cached on disk and have /opt/extensions/ stripped
	// (extensions can't run locally without the full Lambda platform).
	// Corresponds to env var LAMBDA_FETCH_REMOTE_LAYERS. Default false.
	LambdaFetchRemoteLayers bool

	// LambdaLayerCacheDir overrides the directory used to look up and cache
	// layer zip files. When empty, defaults to {DataDir}/layers (typically
	// /data/layers in the standard Docker image).
	// Users can pre-download layers and mount this directory to avoid needing
	// AWS credentials at runtime. Files are named {sha256(arn)}.zip.
	// Corresponds to env var LAMBDA_LAYER_CACHE_DIR.
	LambdaLayerCacheDir string

	// LambdaRemoteAWSAccessKeyID is the AWS access key used for fetching
	// remote layers. Read from LAMBDA_REMOTE_AWS_ACCESS_KEY_ID.
	LambdaRemoteAWSAccessKeyID string

	// LambdaRemoteAWSSecretAccessKey is the AWS secret key used for fetching
	// remote layers. Read from LAMBDA_REMOTE_AWS_SECRET_ACCESS_KEY.
	LambdaRemoteAWSSecretAccessKey string

	// LambdaRemoteAWSSessionToken is the optional session token for fetching
	// remote layers. Read from LAMBDA_REMOTE_AWS_SESSION_TOKEN.
	LambdaRemoteAWSSessionToken string

	// ECSDockerSocket is the path to the Docker daemon socket used to manage
	// ECS task containers. Defaults to the same value as LambdaDockerSocket.
	ECSDockerSocket string

	// ECSNetwork is the Docker network name that ECS task containers are
	// attached to. Defaults to "overcast_ecs".
	ECSNetwork string

	// ECSKeepContainers controls whether Docker containers are removed when
	// an ECS task stops. Set to true for post-mortem inspection.
	// Corresponds to env var ECS_KEEP_CONTAINERS. Default false.
	ECSKeepContainers bool

	// RDSDockerSocket is the path to the Docker daemon socket used to manage
	// RDS database containers. Defaults to the same value as LambdaDockerSocket.
	RDSDockerSocket string

	// RDSNetwork is the Docker network name that RDS database containers are
	// attached to. Defaults to "overcast_rds".
	RDSNetwork string

	// RDSPortBase is the starting host port for RDS database containers.
	// Each DB instance gets a sequential port starting from this base.
	// Defaults to 33060.
	RDSPortBase int

	// RDSKeepContainers controls whether Docker containers are removed when
	// an RDS instance is deleted. Set to true for post-mortem inspection.
	// Corresponds to env var RDS_KEEP_CONTAINERS. Default false.
	RDSKeepContainers bool

	// ElastiCacheDockerSocket is the path to the Docker daemon socket used to
	// manage ElastiCache Redis/Valkey containers. Defaults to the same value as
	// LambdaDockerSocket.
	ElastiCacheDockerSocket string

	// ElastiCacheNetwork is the Docker network name that ElastiCache containers
	// are attached to. Defaults to "overcast_elasticache".
	ElastiCacheNetwork string

	// ElastiCachePortBase is the starting host port for ElastiCache containers.
	// Each cache cluster gets a sequential port starting from this base.
	// Defaults to 63790.
	ElastiCachePortBase int

	// ElastiCacheKeepContainers controls whether Docker containers are removed
	// when a cache cluster is deleted. Set to true for post-mortem inspection.
	// Corresponds to env var ELASTICACHE_KEEP_CONTAINERS. Default false.
	ElastiCacheKeepContainers bool

	// MSKDockerSocket is the path to the Docker daemon socket for MSK Redpanda containers.
	MSKDockerSocket string

	// MSKNetwork is the Docker network name for MSK containers.
	MSKNetwork string

	// MSKPortBase is the starting host port for MSK containers.
	MSKPortBase int

	// MSKKeepContainers controls whether Docker containers are removed on delete.
	MSKKeepContainers bool

	// EKSDockerSocket is the path to the Docker daemon socket used to manage
	// EKS live-mode control-plane containers. Defaults to the same value as
	// LambdaDockerSocket.
	EKSDockerSocket string

	// EKSNetwork is the Docker network name that EKS live-mode containers are
	// attached to. Defaults to "overcast_eks".
	EKSNetwork string

	// EFSDockerSocket is the path to the Docker daemon socket used to manage
	// EFS live-mode volumes. Defaults to the same value as LambdaDockerSocket.
	EFSDockerSocket string

	// EFSNFSExport opts into the NFS data plane: in live mode each mount
	// target starts an NFS-Ganesha container exporting its file system's
	// volume. Off by default — the volume mounts Lambda and ECS use need no
	// NFS hop, and an export costs a container plus a published port per
	// mount target. Corresponds to OVERCAST_EFS_NFS.
	EFSNFSExport bool

	// EFSNFSPortBase is the starting host port for NFS-Ganesha export
	// containers. Each mount target publishes container port 2049 on the
	// first free port at or above this.
	EFSNFSPortBase int

	// EFSNFSImage is the NFS-Ganesha image used for mount-target exports,
	// pinned by digest. Override to run a different build.
	EFSNFSImage string

	// EFSNetwork is the Docker network mount-target export containers are
	// attached to, so a containerized Overcast and sibling NFS clients can
	// reach them without going through a published host port. Defaults to
	// "overcast_efs"; unused unless EFSNFSExport is on.
	EFSNetwork string

	// EC2VPCNetworkStrategy selects the policy used to map stored VPCs onto
	// Docker networks. Docker bridges share one host address space, so two
	// VPCs with overlapping CIDRs cannot both back real networks. Valid
	// values:
	//
	//   shared   (default) — overlapping VPCs share one Docker network.
	//                        Fastest, isolation leaks between sharers.
	//   strict              — reject overlapping CIDRs at CreateVpc; startup
	//                        tolerates existing overlaps. (future)
	//   remapped            — allocate a shadow CIDR from 100.64.0.0/10
	//                        when the requested range collides. (future)
	//   netns               — per-VPC Linux netns for true overlap. (future)
	//
	// Values other than "shared" currently fall back to "shared" with a
	// startup warning. Corresponds to env var OVERCAST_EC2_VPC_STRATEGY.
	EC2VPCNetworkStrategy string

	// Debug enables the /_debug/* endpoint namespace.
	// These endpoints expose internal state and should never be enabled
	// in shared or production environments.
	Debug bool

	// TLSCertFile is the path to the TLS certificate file.
	// When set (together with TLSKeyFile), the server uses HTTPS.
	TLSCertFile string

	// TLSKeyFile is the path to the TLS private key file.
	TLSKeyFile string

	// TLSMode selects how TLS is provisioned (OVERCAST_TLS). Empty means
	// plain HTTP unless TLSCertFile/TLSKeyFile are set; TLSModeAuto mints a
	// server certificate from Overcast's local CA at startup and serves both
	// the API and the web UI over HTTPS (which also unlocks browser HTTP/2
	// via ALPN). Mutually exclusive with TLSCertFile/TLSKeyFile.
	TLSMode string

	// SMTPMock enables the built-in SMTP capture server. When true, all
	// outbound SNS email/email-json notifications are delivered to the local
	// capture server and are browseable in the web UI under /mail.
	// Automatically set to false when SMTPHost is configured.
	SMTPMock bool

	// SMTPPort is the TCP port the mock SMTP server listens on, and also the
	// default port the mailer dials when SMTPHost is unset.
	SMTPPort int

	// SMTPHost is the hostname of an external SMTP relay. When set, SMTPMock
	// is automatically false and the built-in capture server is not started.
	SMTPHost string

	// SMTPFrom is the envelope From address used when sending SNS email notifications.
	SMTPFrom string

	// SMTPUsername and SMTPPassword are the credentials for SMTP AUTH PLAIN
	// when connecting to an external relay. Leave empty for no authentication.
	SMTPUsername string
	SMTPPassword string

	// SMTPTLS enables implicit TLS (port 465). For STARTTLS (port 587) leave
	// this false — Go's net/smtp client upgrades automatically.
	SMTPTLS bool

	// SMTPInboxMax is the maximum number of messages the capture store retains.
	// When exceeded, the oldest message is evicted.
	SMTPInboxMax int

	// InitEnabled controls whether init hook scripts are executed.
	// Defaults to true.
	InitEnabled bool

	// InitDirs is the list of base directories to scan for init hook scripts.
	// Each directory should contain stage subdirs: boot.d/, start.d/, ready.d/,
	// shutdown.d/. Scripts are executed in the order directories appear, then
	// alphabetically within each directory.
	// Defaults to ["/etc/localstack/init", "/etc/overcast/init"].
	InitDirs []string

	// InitTimeout is the maximum time allowed for each individual init script.
	// Defaults to 30s.
	InitTimeout time.Duration

	// Version is the build version string, injected via -ldflags at build time.
	// Not loaded from environment — set by the caller after Load().
	Version string

	// PublishedPort is the host port the API is actually reachable on, which
	// differs from Port only when Overcast runs in a container that remaps it
	// (`docker run -p 4580:4566`). A container cannot see its own port mapping
	// from the inside, so this is recovered by asking Docker about our own
	// container; it is 0 when there is nothing to recover — a native binary, no
	// Docker socket, or a 1:1 mapping.
	//
	// Consumers use it wherever an address has to make sense *outside* the
	// container: the port the web UI hands the browser, and the origins
	// containerendpoint recognises as Overcast's own when rewriting URLs a
	// host-side deploy minted.
	//
	// Not loaded from environment — set by the caller after Load().
	PublishedPort int

	// DNSEnabled turns on the resolver that serves Overcast's split-horizon
	// hostnames to the containers it starts (OVERCAST_DNS, default true).
	//
	// It exists because /etc/hosts is an exact-match table: it can shadow
	// localhost.overcast.sh but not bucket.s3.localhost.overcast.sh, and the
	// URLs AWS SDKs build are overwhelmingly subdomains. See internal/dns.
	DNSEnabled bool

	// DNSPort is the port the resolver listens on (OVERCAST_DNS_PORT, default
	// 53). Docker's --dns cannot express a port, so anything other than 53 is
	// only useful for tests.
	DNSPort int

	// DNSListening reports that the resolver actually bound, which is what
	// makes it safe to point containers at it: a container told to use a
	// resolver that is not there loses all name resolution. Binding port 53
	// needs privilege outside a container, so this is false more often than
	// DNSEnabled is.
	//
	// Not loaded from environment — set by the caller after Load().
	DNSListening bool

	// MCPReplayLimit bounds in-memory MCP notification replay history for
	// Last-Event-ID reconnect support. A value of 0 disables replay retention.
	// Default: 256.
	MCPReplayLimit int

	// MCPRemoteExposure explicitly enables remote/runtime MCP exposure mode.
	// When true, MCPAuthToken must be configured.
	MCPRemoteExposure bool

	// MCPAuthToken is the bearer token required for HTTP access to runtime MCP
	// when MCPRemoteExposure is enabled.
	MCPAuthToken string
}

Config holds all runtime configuration for the emulator. Zero value is not valid — always construct via Load().

func Load

func Load() (*Config, error)

Load reads configuration from environment variables and returns a validated Config. Returns an error if any required value is invalid.

Environment variables (all optional, defaults shown):

OVERCAST_HOST                      0.0.0.0
OVERCAST_HOSTNAME                  (empty — defaults to localhost in URLs)
OVERCAST_SPLIT_HORIZON_HOSTS       (empty — extra names remapped to Overcast
                                           inside containers, comma-separated)
OVERCAST_PORT                      4566
OVERCAST_STATE                     auto    (auto | memory | persistent | hybrid | wal)
                                           auto resolves to hybrid when the data directory
                                           is a mounted volume/bind mount, OVERCAST_DATA_DIR
                                           was explicitly set, or an existing database is
                                           found there — otherwise memory. See
                                           resolveAutoState (state_auto.go).
OVERCAST_STATE_<SERVICE>           <mode>  (per-service override, e.g. OVERCAST_STATE_S3=memory;
                                           does not accept "auto")
OVERCAST_DATA_DIR_SOURCE           (empty) internal provenance marker — the Docker image sets this
                                           to "image" alongside its baked-in OVERCAST_DATA_DIR=/data,
                                           so the auto-state resolver doesn't mistake the image
                                           default for user intent. Not for end users to set.
OVERCAST_HYBRID_FLUSH_INTERVAL     5s
OVERCAST_HYBRID_SYNC                interval (always | interval | never)
OVERCAST_HYBRID_SYNC_INTERVAL       100ms
OVERCAST_HYBRID_DIRTY_ENTRY_THRESHOLD 10000
OVERCAST_HYBRID_DIRTY_BYTE_THRESHOLD  8388608
OVERCAST_HYBRID_MAINTENANCE_INTERVAL  5m
OVERCAST_WAL_FSYNC                 interval (always | interval | never)
OVERCAST_WAL_FSYNC_INTERVAL        100ms
OVERCAST_WAL_MAX_LOG_BYTES         67108864
OVERCAST_DATA_DIR                  ~/.overcast/data
OVERCAST_DEFAULT_REGION             us-east-1
OVERCAST_ACCOUNT_ID                000000000000
OVERCAST_EKS_MODE                  mock    (mock | live)
OVERCAST_EFS_MODE                  live    (mock | live; live is inert without Docker)
OVERCAST_RDS_MODE                  live    (mock | live; mock starts no engine container)
OVERCAST_SIGV4_VALIDATE            false
OVERCAST_ENFORCE_IAM              false
OVERCAST_ENFORCE_APIGATEWAY_THROTTLE false
OVERCAST_CFN_SYNC_WAIT_MS          1000
OVERCAST_LOG_LEVEL                 info    (trace | debug | info | warn | error)
OVERCAST_SHUTDOWN_TIMEOUT          5s
OVERCAST_LAMBDA_NODE_BIN           node
OVERCAST_LAMBDA_HOT_RELOAD         false
OVERCAST_DEBUG                     false
OVERCAST_TLS                       ""    (auto = mint from the local overcast CA; serves API + web UI over HTTPS/h2)
OVERCAST_TLS_CERT                  ""
OVERCAST_TLS_KEY                   ""
LAMBDA_DOCKER_MAX_CONCURRENT_STARTS (auto) derived from Docker host CPUs: clamp(NCPU/2, 2, 8);
                                           4 when Docker /info is unavailable
LAMBDA_MAX_INSTANCES               (auto)  derived from Docker host memory:
                                           clamp(MemTotal*0.65 / 256MiB, 4, 32); 25 when /info is unavailable
LAMBDA_MAX_INSTANCES_PER_FUNCTION  (auto)  clamp(maxInstances/2, 2, maxInstances); 10 when /info is unavailable
LAMBDA_MAX_MEMORY_MB               (auto)  aggregate Σ MemorySize budget for live containers, in MB;
                                           derived as MemTotal*0.65; unlimited when /info is unavailable
LAMBDA_MAX_WARM_INSTANCES          10
LAMBDA_INIT_TIMEOUT_SECONDS       10
LAMBDA_KEEP_CONTAINERS             false (true = keep stopped containers after expiry/delete)
LAMBDA_FETCH_REMOTE_LAYERS         false (true = download missing layers from real AWS)
ECS_DOCKER_SOCKET                  <LAMBDA_DOCKER_SOCKET> (default: same as Lambda)
ECS_NETWORK                        overcast_ecs
ECS_KEEP_CONTAINERS                false
RDS_DOCKER_SOCKET                  <LAMBDA_DOCKER_SOCKET> (default: same as Lambda)
RDS_NETWORK                        overcast_rds
RDS_PORT_BASE                      33060
RDS_KEEP_CONTAINERS                false
ELASTICACHE_DOCKER_SOCKET          <LAMBDA_DOCKER_SOCKET> (default: same as Lambda)
ELASTICACHE_NETWORK                overcast_elasticache
ELASTICACHE_PORT_BASE              63790
ELASTICACHE_KEEP_CONTAINERS        false
MSK_DOCKER_SOCKET                  <LAMBDA_DOCKER_SOCKET>
MSK_NETWORK                        overcast_msk
MSK_PORT_BASE                      49092
MSK_KEEP_CONTAINERS                false
EKS_DOCKER_SOCKET                  <LAMBDA_DOCKER_SOCKET>
EKS_NETWORK                        overcast_eks
EFS_DOCKER_SOCKET                  <LAMBDA_DOCKER_SOCKET>
OVERCAST_EFS_NFS                   false (true = one NFS-Ganesha export container per mount target, live mode only)
EFS_NFS_PORT_BASE                  22049
EFS_NFS_IMAGE                      registry.k8s.io/sig-storage/nfs-provisioner@sha256:c825f3d5… (digest-pinned)
EFS_NETWORK                        overcast_efs (export containers; unused unless OVERCAST_EFS_NFS is on)
OVERCAST_SMTP_MOCK                 true  (false when SMTP_HOST is set)
OVERCAST_SMTP_PORT                 1025
OVERCAST_SMTP_HOST                 ""    (set to use an external relay)
OVERCAST_SMTP_FROM                 overcast@localhost
OVERCAST_SMTP_USERNAME             ""
OVERCAST_SMTP_PASSWORD             ""
OVERCAST_SMTP_TLS                  false
OVERCAST_SMTP_INBOX_MAX            500
OVERCAST_INIT_ENABLED              true  (set false to disable init hooks)
OVERCAST_INIT_DIRS                 /etc/localstack/init,/etc/overcast/init
OVERCAST_INIT_TIMEOUT              30s   (per-script timeout)
OVERCAST_MCP_REPLAY_LIMIT          256
OVERCAST_MCP_REMOTE_EXPOSURE       false
OVERCAST_MCP_AUTH_TOKEN            "" (required when OVERCAST_MCP_REMOTE_EXPOSURE=true)

func (*Config) Addr

func (c *Config) Addr() string

Addr returns the "host:port" string for the server to listen on.

func (*Config) ExternalBaseURL

func (c *Config) ExternalBaseURL() string

ExternalBaseURL returns the base URL for client-facing links, e.g. "http://localhost:4566" or "http://overcast:4566".

func (*Config) ExternalHostname

func (c *Config) ExternalHostname() string

ExternalHostname returns the hostname that should appear in client-facing URLs. Returns Hostname if set, otherwise "localhost".

func (*Config) TLSAuto

func (c *Config) TLSAuto() bool

TLSAuto returns true when OVERCAST_TLS=auto: the server certificate is minted from Overcast's local CA at startup.

func (*Config) TLSAutoSANs

func (c *Config) TLSAutoSANs() []string

TLSAutoSANs returns every subject alternative name the auto-minted server certificate must cover: the loopback names and addresses, each wildcard DNS domain (apex, one-level wildcard, and the "*.s3." level used by S3 virtual-hosted addressing), any extra split-horizon hosts, and the configured hostname.

One-level wildcards are a TLS constraint, not a choice: "*.<base>" matches exactly one label, so deeper host-routed names with a variable middle (e.g. "{id}.execute-api.{region}.<base>") cannot be enumerated here and are not covered. The S3 level is included explicitly because "{bucket}.s3.<base>" is the common two-label shape.

func (*Config) TLSEnabled

func (c *Config) TLSEnabled() bool

TLSEnabled returns true when the server should serve HTTPS — either via an explicitly configured cert/key pair or via the auto-minted local CA leaf.

type EFSMode

type EFSMode string

EFSMode identifies how the EFS service behaves.

const (
	// EFSModeMock keeps EFS metadata-only: file systems have no backing storage.
	// An explicit opt-out — the default is live.
	EFSModeMock EFSMode = "mock"

	// EFSModeLive backs each file system with a named Docker volume so
	// emulated compute (Lambda, ECS) can share real file data. The default,
	// because it costs nothing where it cannot be used: volume operations run
	// only while a Docker daemon is reachable, and without one live mode
	// behaves exactly like mock.
	EFSModeLive EFSMode = "live"
)

type EKSMode

type EKSMode string

EKSMode identifies how the EKS service behaves.

const (
	// EKSModeMock keeps EKS metadata-only and does not start a Kubernetes API server.
	EKSModeMock EKSMode = "mock"

	// EKSModeLive enables the future live k3s-backed control plane path.
	EKSModeLive EKSMode = "live"
)

type RDSMode

type RDSMode string

RDSMode identifies how the RDS service behaves.

const (
	// RDSModeMock keeps RDS metadata-only: instances move through the status
	// model on a timer and no engine container is ever started, so nothing
	// listens on the reported endpoint. An explicit opt-out — the default is
	// live — for environments that have a Docker daemon but cannot afford the
	// tens of seconds a real engine takes to accept its first connection.
	RDSModeMock RDSMode = "mock"

	// RDSModeLive runs a real engine container per DB instance, which is what
	// makes the endpoint connectable. The default. Live mode needs no Docker to
	// be safe: without a reachable daemon it behaves exactly like mock.
	RDSModeLive RDSMode = "live"
)

type StateBackend

type StateBackend string

StateBackend identifies which storage implementation to use.

const (
	// StateBackendMemory stores all state in-process. Fastest; nothing persists
	// across restarts. Best for unit tests and CI pipelines.
	StateBackendMemory StateBackend = "memory"

	// StateBackendPersistent writes every mutation synchronously to SQLite.
	// Slowest; fully durable. Previously named "sqlite" (still accepted as alias).
	StateBackendPersistent StateBackend = "persistent"

	// StateBackendHybrid serves all reads from an in-memory map and flushes
	// writes to SQLite asynchronously at a configurable interval. Fast reads,
	// durable across restarts, with a small window of potential data loss on
	// unclean exit. This is the default — best for general local development.
	StateBackendHybrid StateBackend = "hybrid"

	// StateBackendWAL uses the append-log WALStore (memory reads, write-ahead
	// durability with replay on startup and periodic compaction).
	StateBackendWAL StateBackend = "wal"
)

type StateSource

type StateSource string

StateSource identifies whether the effective storage backend (Config.State) was chosen explicitly by the user (OVERCAST_STATE set to a concrete backend name) or resolved by the OVERCAST_STATE=auto heuristic (also the default when OVERCAST_STATE is unset — see resolveAutoState).

This is internal provenance for logging and diagnostics (the startup log line, the memory-mode advisory, and /_health's storage.configured field) — not itself a user-facing configuration knob.

const (
	// StateSourceExplicit means OVERCAST_STATE was set to a concrete backend
	// name (memory, hybrid, persistent, wal, or the sqlite alias).
	StateSourceExplicit StateSource = "explicit"

	// StateSourceAuto means OVERCAST_STATE was unset or set to "auto", and
	// Config.State was resolved by resolveAutoState.
	StateSourceAuto StateSource = "auto"
)

Jump to

Keyboard shortcuts

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