Changelog v3.15.1 (2026-05-11)
Version 3.15.1 (2026-05-11)
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
{
"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:CookieHttpOnlyBoth 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 likeCooieNameare still caught for both example-named and custom-named schemes. - Cross-type keys (e.g.
JwtSecreton 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:
Errormode: warnings are fatal.--configprints them in red on stderr and exits 1 without dumping JSON.--validatereportsconfigValid: false.Warningmode (default): warnings are surfaced (yellow on stderr for--config, included in--validatetext/JSON output) but they don't fail the run.--configproceeds to dump the JSONC.--validatereportsconfigValid: true.Ignoremode: 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
{
"valid": true,
"configValid": true,
"validationMode": "Warning",
"warningsAreFatal": false,
"warnings": ["SomeUnknown:Key"],
"connectionTest": "ok"
}Behavior after the fix
npgsqlrest --validateagainst a config with a typo +ValidateConfigKeys: "Warning"exits 0; the typo is surfaced as a warning. SetValidateConfigKeys: "Error"(or pass--Config:ValidateConfigKeys=Error) to keep the old fail-fast behavior.npgsqlrest --configalways emits the JSONC dump unless the mode isErrorand 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.csexerciseFindUnknownConfigKeysdirectly: per-type validation for each example scheme name and custom names, cross-type rejection, typo detection, and missing/invalidTypehandling. - CLI tests in
NpgsqlRestTests/CliTests/CliCommandTests.cscover theIgnore/Warning/Errormatrix for both--configand--validate --json.