Skip to content
Written with Claude

Changelog v3.15.1 (2026-05-11)

Version 3.15.1 (2026-05-11)

Full Changelog

Two bug fixes around config-key validation that together caused legitimate Auth:Schemes setups to fail startup under default settings. No new features; no library changes — both fixes live in NpgsqlRestClient (ConfigDefaults.cs, Program.cs).

Fix: named auth schemes are validated by Type, not by name

A configuration like

json
json
{
  "Auth": {
    "Schemes": {
      "short_session": {
        "Type": "Cookies",
        "CookieName": "my_app",
        "CookieHttpOnly": true
      }
    }
  }
}

produced startup errors:

code
[ERR] Unknown configuration key: Auth:Schemes:short_session:CookieName
[ERR] Unknown configuration key: Auth:Schemes:short_session:CookieHttpOnly

Both keys are documented per-type override keys for Cookies-type schemes (added in 3.15.0) and are read/applied normally at scheme registration time. The validator was flagging them because of a name collision with the docs-style example entries in Auth:Schemes defaults (short_session, api_token, admin_jwt).

Root cause

FindUnknownConfigKeys descended into the defaults schema by key name. When a user's scheme name matched one of the documented examples, the validator validated against that example's incomplete key set instead of treating the entry as an open-dictionary item. The same scheme renamed to anything not in the example set took the open-dict path and validated clean — so the bug surfaced only for users whose scheme names happened to match the documentation.

What changed

Validation under Auth:Schemes:<name> is now driven by the scheme's Type field, not its name. The validator reads Type from the actual config and selects one of three type-specific schemas:

  • Cookies: Type, Enabled, CookieValid, CookieName, CookiePath, CookieDomain, CookieMultiSessions, CookieHttpOnly, CookieSameSite, CookieSecure.
  • BearerToken: Type, Enabled, BearerTokenExpire, BearerTokenRefreshPath.
  • Jwt: Type, Enabled, JwtSecret, JwtIssuer, JwtAudience, JwtExpire, JwtRefreshExpire, JwtClockSkew, JwtValidateIssuer, JwtValidateAudience, JwtValidateLifetime, JwtValidateIssuerSigningKey, JwtRefreshPath.

When Type is missing or unrecognized, the validator skips that scheme silently — RegisterAuthSchemes already throws a clearer error at startup, so double-reporting buys nothing.

Behavior after the fix

  • Every named scheme — regardless of name — is validated against the same key set per its declared Type. Typos like CooieName are still caught for both example-named and custom-named schemes.
  • Cross-type keys (e.g. JwtSecret on a Cookies-type scheme) are now flagged where they previously slipped through under custom-named schemes via the open-dict shortcut.
  • Existing configurations using the docs-example names (short_session, api_token, admin_jwt) start cleanly with any combination of valid per-type override keys.

Fix: --config and --validate CLI commands now honor ValidateConfigKeys mode

The three call sites of ValidateConfigKeys() were inconsistent. Normal startup branched on the mode (only "Error" aborts; "Warning" logs and continues; "Ignore" skips entirely). The two CLI command paths did not — both treated any warning as a fatal validation failure regardless of mode.

For a user running npgsqlrest --validate with the default Config:ValidateConfigKeys: "Warning", this meant:

  • Exit code 1 on the first unknown key, even though the runtime would have started up normally with the same config.
  • --config (dump current configuration as JSONC) suppressed its JSON output and exited 1 instead, even when the only thing wrong was a typo that would have shown up as a warning at runtime.

What changed

Both CLI paths now read the validation mode and apply the same rule as normal startup:

  • Error mode: warnings are fatal. --config prints them in red on stderr and exits 1 without dumping JSON. --validate reports configValid: false.
  • Warning mode (default): warnings are surfaced (yellow on stderr for --config, included in --validate text/JSON output) but they don't fail the run. --config proceeds to dump the JSONC. --validate reports configValid: true.
  • Ignore mode: no warnings produced at all (unchanged — the validator short-circuits earlier).

--validate --json output gains a warningsAreFatal boolean derived from the mode, so machine consumers can decide for themselves what to do with the warnings array independent of how the binary chose to exit:

json
json
{
  "valid": true,
  "configValid": true,
  "validationMode": "Warning",
  "warningsAreFatal": false,
  "warnings": ["SomeUnknown:Key"],
  "connectionTest": "ok"
}

Behavior after the fix

  • npgsqlrest --validate against a config with a typo + ValidateConfigKeys: "Warning" exits 0; the typo is surfaced as a warning. Set ValidateConfigKeys: "Error" (or pass --Config:ValidateConfigKeys=Error) to keep the old fail-fast behavior.
  • npgsqlrest --config always emits the JSONC dump unless the mode is Error and an unknown key is present. Warnings still print to stderr so typos remain visible.
  • Normal startup is unchanged — it was already correct.

Tests

  • New unit tests in NpgsqlRestTests/ConfigTests/ConfigValidationTests.cs exercise FindUnknownConfigKeys directly: per-type validation for each example scheme name and custom names, cross-type rejection, typo detection, and missing/invalid Type handling.
  • CLI tests in NpgsqlRestTests/CliTests/CliCommandTests.cs cover the Ignore / Warning / Error matrix for both --config and --validate --json.

Comments