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

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 after
the config file loads, so the variables the file's env section sets are
checked too. README.md says so under Configuration.

Model: opus-5-5
This commit is contained in:
2026-09-28 13:53:27 +00:00
parent 3bcb2cd6e5
commit 09c627bf8b
3 changed files with 57 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 checked the same way.
| 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 after the config file loads, so the variables
the file's `env:` section sets are checked too; 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
+45
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")
@@ -154,6 +155,13 @@ func New(_ fx.Lifecycle, params Params) (*Config, error) {
return nil, err return nil, err
} }
// Loading the config file sets the variables in its env section,
// so this also checks their names.
err = validateKnownEnvVars()
if err != nil {
return nil, err
}
if sc == nil { if sc == nil {
log.Info("no config file found, using environment variables and defaults") log.Info("no config file found, using environment variables and defaults")
} }
@@ -377,6 +385,43 @@ 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 after loading the config file, so the variables the
// file's env section sets are checked too.
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