Documentation
¶
Index ¶
- Constants
- func DevAuthBypass(msg proto.Message) bool
- func Load(cmd *cobra.Command, msg proto.Message) error
- func LoadInto(cmd *cobra.Command, msg proto.Message) error
- func LoadTyped[T proto.Message](cmd *cobra.Command) (T, error)
- func RegisterFlags(cmd *cobra.Command, msg proto.Message) error
- func RegisterFlagsFor(flags *pflag.FlagSet, msg proto.Message) error
- func Validate(msg proto.Message) error
- type RuntimeMode
Constants ¶
const ConfigFlag = "config"
ConfigFlag is the name of the always-registered persistent flag that points the loader at a config file. RegisterFlags registers it unconditionally.
const ConfigPathEnv = "FORGE_CONFIG"
ConfigPathEnv is the documented environment variable that supplies the config-file path when the --config flag is not set. The flag, when set, takes precedence over this env var. Set FORGE_CONFIG to load a config file without passing --config (e.g. in a container entrypoint).
Variables ¶
This section is empty.
Functions ¶
func DevAuthBypass ¶
DevAuthBypass reports whether this server runs with NO real auth: authn passthrough + authz allow-all + synthetic dev claims.
It is an EXPLICIT, two-factor opt-in and is NEVER implied by the mode field alone: development mode gives dev ergonomics but KEEPS auth enforced. To actually bypass auth you must ALSO set AUTH_DEV_MODE=true. In production the bypass is impossible — Mode is never dev there.
func Load ¶
Load populates msg in place from cobra flags > environment variables > proto defaults, for every field carrying a (forge.v1.config) option. It is the cobra-facing alias of LoadInto. cmd may be nil (env + defaults only). Sensitive fields resolve from env / Secret mount only.
func LoadInto ¶
LoadInto populates msg in place using the full forge config precedence — later layers OVERRIDE earlier ones:
defaults → config file → environment → flags
(earliest) (wins)
- defaults: every annotated field's proto default (sensitive fields get
none — an inline secret default would be a leak).
- config file: when a path is EXPLICITLY given via the --config flag or
the FORGE_CONFIG env var, the file is proto-native unmarshaled INTO msg,
overlaying the defaults (see filelayer.go). A missing/invalid explicit
file is a LOUD error — never a silent fallback. With no path given this
layer is simply skipped (normal precedence, not a fallback).
- environment: each field's env var overrides the file/default value.
- flags: a flag changed on THIS invocation overrides everything.
It is the runtime, descriptor-driven loader: empty-env handling, required- field errors, and per-kind parsing all key off the (forge.v1.config) field options. cmd may be nil (file via FORGE_CONFIG + env + defaults only), so LoadInto works from non-cobra entrypoints too.
Durations: declare a duration-shaped field as google.protobuf.Duration in the config proto — env/flag layers parse the Go-duration string ("5s") into the message, and consumers read it with .AsDuration(). (A plain string field stays a string; the descriptor has no name heuristic.)
The companion semantics — Mode/DevAuthBypass (role=MODE) and Validate (TLS/CORS roles + allowed_values) — live in this package too (semantic.go), as FREE FUNCTIONS over the message. There is no parallel generated struct: a project holds the proto config type and calls these directly.
func LoadTyped ¶
LoadTyped is the generic convenience: it allocates a fresh T, loads it, and returns it typed. T must be a pointer proto message type (e.g. *configv1.AppConfig). Usage:
cfg, err := config.LoadTyped[*configv1.AppConfig](cmd)
It mirrors the generated Load(cmd) (*Config, error) signature shape so a project can drop the generated loader and call this directly.
func RegisterFlags ¶
RegisterFlags registers one cobra flag per config-bound field of msg that carries a non-empty flag annotation, using the annotated name, default, and description. Sensitive fields are skipped (env/Secret only). It is the cobra-facing form of RegisterFlagsFor and is generic over ANY config message — no per-field codegen.
It ALSO registers a persistent --config <path> flag (ConfigFlag) — always, for every config message. This is the first-class config-FILE layer's entry point: it is on, not dormant. Load resolves the file from this flag (or the FORGE_CONFIG env var) and unmarshals it as the layer between defaults and env. Registering it persistent means it is also visible to subcommands. The flag is registered idempotently so re-registering on the same command (or a parent that already has it) is safe.
func RegisterFlagsFor ¶
RegisterFlagsFor walks msg's fields and registers one cobra/pflag flag per field that carries a non-empty (forge.v1.config).flag. The flag's type matches the proto field kind (string/int32/int64/bool/float; duration messages register as a string flag — LoadInto parses "5s" → Duration), and its default is the proto option's DefaultValue.
It is the pflag-level primitive; the cobra-facing RegisterFlags(cmd, msg) in semantic.go wraps it. It recurses into nested config blocks.
Fields without a flag (typically secrets sourced only from env / Secret mounts) are intentionally skipped — defense-in-depth against shell-history / `ps` exposure of credentials.
func Validate ¶
Validate runs the cross-field and closed-set config invariants that cannot be expressed as per-field defaults, failing fast (before the listener binds) on the known misconfiguration classes. It is the annotation/TYPE-driven replacement for the deleted name-matched validators (CORS-wildcard / TLS-pair / log-format):
- allowed_values: a string field carrying a closed value set is a string ENUM; a resolved value outside the set is rejected. (True proto enum fields need no check — protoreflect enforces their domain. The empty value is always allowed: an unset, non-required field.)
- TLS keypair: the fields tagged role=TLS_CERT and role=TLS_KEY are both-or-neither. Exactly one set is an error (the server would silently serve plaintext).
- CORS: a wildcard origin ("*") in the role=CORS_ORIGINS field combined with role=CORS_ALLOW_CREDENTIALS=true is spec-invalid and rejected.
Every check keys off the ANNOTATION, never the field name — renaming a field never silently drops its guard. Validate recurses into nested config blocks so a block can carry its own allowed_values fields. The cross-field TLS/CORS checks operate per message level (the role fields of the same message), which is where those pairs naturally live.
Types ¶
type RuntimeMode ¶
type RuntimeMode int
RuntimeMode is the typed runtime mode. The zero value is ModeProduction: a message with no role=MODE field (or one whose mode field is empty) always reports production — dev permissiveness is never the default.
const ( // ModeProduction is the zero value: authz enforced, auth required. ModeProduction RuntimeMode = iota // ModeDevelopment enables local-dev permissiveness. Never set in // deployed environments. ModeDevelopment )
func Mode ¶
func Mode(msg proto.Message) RuntimeMode
Mode derives the runtime mode from msg's role=MODE field: "development"/"dev" (case-insensitive) → ModeDevelopment, anything else (including no role field) → ModeProduction. Deriving — rather than caching — means a hand-built message in tests can never disagree with its own mode value.
func (RuntimeMode) IsDev ¶
func (m RuntimeMode) IsDev() bool
IsDev reports whether the mode is ModeDevelopment. It gates NON-SECURITY dev ergonomics only (permissive CORS, verbose errors, dev DB defaults). It MUST NOT gate auth — see DevAuthBypass.