Abort startup on an unknown PIXA_ environment variable (closes #133)
check / check (push) Successful in 3m15s

A variable whose name starts with PIXA_ but is neither a setting's
variable, from the list pairing each config key with its variable, nor
PIXA_CONFIG_PATH now aborts startup naming it, as an unknown config key
does. PIXA_PORT is named with a pointer to PORT. The check runs before
the config file loads, so the variables the file's env section sets are
not checked. README.md says so under Configuration.

Model: opus-5-5
This commit is contained in:
2026-09-28 13:24:46 +00:00
parent 1629ba1f5c
commit c7ef156ab5
3 changed files with 56 additions and 1 deletions
+5 -1
View File
@@ -161,7 +161,11 @@ process was started with and the file's own key. A variable's value is
parsed as the same text in the file would be. The three lists take parsed as the same text in the file would be. The three lists take
comma-separated entries, with the spaces around each trimmed; an empty comma-separated entries, with the spaces around each trimmed; an empty
variable is an empty list. A value that does not parse or is invalid aborts variable is an empty list. A value that does not parse or is invalid aborts
startup, naming the variable. startup, naming the variable. A variable whose name starts with `PIXA_` but
is not in the table below, such as a misspelled one or `PIXA_PORT`, aborts
startup naming it, as an unknown config key does. The one other accepted
name is `PIXA_CONFIG_PATH`, the config file's path (like `--config`). The
variables set by the file's `env:` section are not checked.
| Variable | Config key | Meaning | | Variable | Config key | Meaning |
| ------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------- | | ------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------- |
+7
View File
@@ -30,6 +30,13 @@ exhaustion
# Completed Steps # Completed Steps
- 2026-09-28 unknown `PIXA_` environment variables abort startup (closes
#133): a variable whose name starts with `PIXA_` but is neither a
setting's variable nor `PIXA_CONFIG_PATH` aborts startup naming it, as
an unknown config key does, and `PIXA_PORT` is named with a pointer to
`PORT`; the check runs before the config file loads, so the variables
the file's `env:` section sets are not checked; documented in
`README.md`.
- 2026-09-28 start on a fresh upaas volume (closes #129): the image - 2026-09-28 start on a fresh upaas volume (closes #129): the image
starts as root only to give `/var/lib/pixa` to `pixad` when `pixad` starts as root only to give `/var/lib/pixa` to `pixad` when `pixad`
does not own it (`deploy/docker-entrypoint.sh`), then runs the server does not own it (`deploy/docker-entrypoint.sh`), then runs the server
+44
View File
@@ -58,6 +58,7 @@ var (
errValueRequired = errors.New("a value is required") errValueRequired = errors.New("a value is required")
errValueEmpty = errors.New("value must not be empty") errValueEmpty = errors.New("value must not be empty")
errUnknownConfigKeys = errors.New("unknown config keys") errUnknownConfigKeys = errors.New("unknown config keys")
errUnknownEnvVars = errors.New("unknown environment variables")
errNotAString = errors.New("not a string") errNotAString = errors.New("not a string")
errNotAnInteger = errors.New("not an integer") errNotAnInteger = errors.New("not an integer")
errNotABoolean = errors.New("not a boolean") errNotABoolean = errors.New("not a boolean")
@@ -146,6 +147,11 @@ type Config struct {
func New(_ fx.Lifecycle, params Params) (*Config, error) { func New(_ fx.Lifecycle, params Params) (*Config, error) {
log := params.Logger.Get() log := params.Logger.Get()
err := validateKnownEnvVars()
if err != nil {
return nil, err
}
// Look for the config file under the project name (/etc/pixa/, // Look for the config file under the project name (/etc/pixa/,
// ~/.config/pixa/), matching the /var/lib/pixa state directory, // ~/.config/pixa/), matching the /var/lib/pixa state directory,
// not under the daemon name pixad. // not under the daemon name pixad.
@@ -377,6 +383,44 @@ func envVarNames() map[string]string {
} }
} }
// validateKnownEnvVars rejects environment variables whose names start
// with PIXA_ but that are neither a setting's variable nor
// PIXA_CONFIG_PATH, so a misspelled variable fails at startup instead of
// being silently ignored, as validateKnownKeys does for config file keys.
// New calls it before loading the config file, so the variables the
// file's env section sets are not checked, just as validateKnownKeys
// leaves that section's contents alone.
func validateKnownEnvVars() error {
known := map[string]bool{"PIXA_CONFIG_PATH": true}
for _, name := range envVarNames() {
known[name] = true
}
var unknown []string
for _, entry := range os.Environ() {
name, _, _ := strings.Cut(entry, "=")
switch {
case !strings.HasPrefix(name, "PIXA_") || known[name]:
continue
case name == "PIXA_PORT":
unknown = append(unknown, name+" (use PORT for the port)")
default:
unknown = append(unknown, name)
}
}
if len(unknown) > 0 {
sort.Strings(unknown)
return fmt.Errorf("%w: %s", errUnknownEnvVars, strings.Join(unknown, ", "))
}
return nil
}
// lookupValue returns the value set for key and whether one is set. The // lookupValue returns the value set for key and whether one is set. The
// key's environment variable wins when it is present, even when empty; // key's environment variable wins when it is present, even when empty;
// its value is a string, read exactly as the same text quoted in the // its value is a string, read exactly as the same text quoted in the