Abort startup on an unknown PIXA_ environment variable (closes #133)
check / check (push) Successful in 2m58s
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:
+5
-1
@@ -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 |
|
||||||
| ------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------- |
|
| ------------------------------------ | ------------------------------- | ---------------------------------------------------------------------------- |
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user