github gofr-dev/gofr v1.63.0

2 hours ago

Release v1.63.0

๐Ÿš€ Features

๐Ÿ”’ Redact query arguments

SQL bind arguments and Redis keys/values โ€” often PII or tokens โ€” are written to query logs and Redis spans by default. These switches mask them instead. Values are masked rather than dropped, so the argument count stays visible and the log shape is unchanged.

Config Description Default
DB_REDACT_ARGS Mask each SQL argument as ***** in the query log, for queries and inside transactions false
REDIS_REDACT_ARGS Mask Redis arguments in the query log and drop db.statement from Redis spans false

๐Ÿ”Œ Redis URL & pool tuning

Point GoFr at a managed Redis with a single REDIS_URL (rediss:// turns on TLS and verifies the host). The URL wins: when set, it alone decides host, port, credentials, DB and TLS, and any overlapping REDIS_HOST/REDIS_PORT/โ€ฆ are ignored with a warning. The tuning variables work with or without the URL.

Config Description Default
REDIS_URL Full connection URL (redis:// or rediss://) โ€”
REDIS_POOL_SIZE Maximum connections in the pool go-redis default
REDIS_MIN_IDLE_CONNS Minimum idle connections kept open go-redis default
REDIS_DIAL_TIMEOUT Timeout for establishing a connection go-redis default
REDIS_READ_TIMEOUT Timeout for reads from the socket go-redis default
REDIS_WRITE_TIMEOUT Timeout for writes to the socket go-redis default

๐Ÿ” Richer HTTP retries

service.RetryConfig used to retry immediately, replay POST, and ignore Retry-After โ€” one slow upstream could turn into a retry storm. These optional fields fix that. Every field's zero value keeps today's behavior, so a config that sets only MaxRetries is unchanged.

Field Description
Backoff Constant or exponential backoff, with full jitter
RetryOn Which errors and statuses to retry (StandardRetryable provided)
RespectRetryAfter / MaxRetryAfter Honor Retry-After on 429/503, capped
Methods / IdempotencyKeyHeader Retry only safe or idempotency-keyed methods
PerAttemptTimeout Bound the time each attempt waits for response headers
Budget Cap retries per service over a sliding window

๐Ÿ›ก๏ธ RBAC role arrays & permissions mode

A token whose claim is an array of roles ("roles": ["admin","viewer"]) now grants every role's permissions โ€” previously the array matched nothing and returned 403. Permissions mode authorizes straight from the token: a string claim is split on spaces, an array is read entry by entry. Role names with spaces stay intact and are never split.

Config (rbac.json) Description
jwtClaimPath Claim holding the role(s); now accepts a single role or a role array
permissionsClaimPath Claim holding permissions to authorize from directly (e.g. scope)

โœ… RBAC startup route check

configs/rbac.json is a hand-kept copy of the route table, so a single typo can silently leave a route served with no role check. At startup GoFr now compares the rules against the real routes and reports three problems: a rule that matches no route, a route no rule covers, and a route only partly covered.

Config Values Default
GOFR_RBAC_ROUTE_CHECK warn (log and start) ยท fail (refuse to start) ยท off warn

โฑ๏ธ DB connect timeout

A connect attempt to an unresponsive database had no time limit. Postgres, Supabase and CockroachDB cap the whole attempt via connect_timeout, while MySQL caps the TCP dial.

Config Description Default
DB_CONNECT_TIMEOUT Bound a database connect attempt, in whole seconds 0 (off)

๐Ÿ“Š Unmatched-metric cap

Scanner traffic (/.env, /wp-json, โ€ฆ) creates a new metric series per path, and across many short-lived instances these pile up at the backend. The cap collapses the overflow to __unmatched__. It can only lower the budget, never raise it, so it cannot reopen the cardinality blow-up it guards against.

Config Description Default
METRICS_UNMATCHED_LIMIT Max distinct unmatched (path, method, status) label sets per process 500

๐Ÿ› ๏ธ Fixes

HTTP & services

  • 405 Method Not Allowed (not 404) for a known path with the wrong method
  • Reuse the OAuth token instead of fetching one per request
  • Auth and DefaultHeaders options no longer mutate the caller's header map
  • Redis rate limiter keeps fractional refill and sub-second windows
  • Invalid rate-limiter config logs instead of panicking
  • Validate ACCESS_CONTROL_MAX_AGE and ALLOW_CREDENTIALS at startup

SQL & Redis

  • Cloud SQL connects to Postgres over IAM without resolving the instance name
  • Log a missing DB_DIALECT and keep container SQL nil when uninitialized
  • Keep container Redis nil when uninitialized
  • dbresolver skips a replica whose connection failed to initialize
  • DB.Close waits for its background goroutines
  • Report migrations below the last applied version that never ran
  • Mock container validates a Select before filling the response

NoSQL, search & messaging

  • Dgraph reports the real HealthCheck cause, and ends spans + records latency on failures
  • ArangoDB registers metrics and returns not-connected errors on a failed Connect
  • SurrealDB stays disconnected when Connect fails after dialing
  • NATS detects an existing stream with errors.Is, not error text
  • OpenTSDB returns errInvalidParam for every wrong-argument type

Files

  • CommonFileSystem connection state is safe for concurrent use
  • FTP no longer desyncs on concurrent or overlapping operations
  • SFTP reads JSON arrays and objects on every Go version

CLI, auth & observability

  • cmd preserves = in parameter values and exits non-zero on a handler error
  • Reject empty basic-auth credentials
  • Datasource health checks honor the caller's context
  • Metrics warn when the environment sets service.name, and guard a nil Logger
  • RBAC logs an inheritsFrom role that matches no defined role
  • Log discarded JSON encode errors in panic recovery and MCP responses

Submodule note: ArangoDB's generated gomock mocks moved into _test.go files โ€” import them from tests only.

Full Changelog: v1.62.0...v1.63.0

Don't miss a new gofr release

NewReleases is sending notifications on new releases.