Skip to content

feat(databases): pass through arbitrary PostgreSQL query params#415

Merged
flemzord merged 2 commits intomainfrom
feat/postgres-passthrough-query-params
Mar 6, 2026
Merged

feat(databases): pass through arbitrary PostgreSQL query params#415
flemzord merged 2 commits intomainfrom
feat/postgres-passthrough-query-params

Conversation

@flemzord
Copy link
Copy Markdown
Member

@flemzord flemzord commented Mar 4, 2026

Summary

  • Preserve arbitrary query parameters from PostgreSQL Settings URIs in the final POSTGRES_URI environment variable. Previously only disableSSLMode and secret were handled; all other params were silently dropped.
  • This unblocks deployments on managed PostgreSQL providers (Google Cloud SQL, Azure Database, etc.) that require params like sslmode=require or tcpKeepAlive=true.
  • Full backward compatibility: disableSSLMode=true still produces sslmode=disable, secret is still consumed for credentials and filtered out.

Changes

File Change
internal/resources/databases/env.go Preserve arbitrary query params, filter only disableSSLMode and secret
internal/resources/databases/env_test.go 7 table-driven unit tests for GetPostgresEnvVars
internal/resources/databases/mock_test.go Mock types for unit testing
docs/09-Configuration reference/01-Settings.md Document pass-through behavior in Postgres URI format section
docs/05-Infrastructure services/01-PostgreSQL.md Add Option 3 example for managed PostgreSQL with custom params

Test plan

  • go test ./internal/resources/databases/... — all 7 new unit tests pass
  • go vet ./... — no issues
  • go build ./... — compiles cleanly
  • CI pipeline passes

Previously, GetPostgresEnvVars() reconstructed POSTGRES_URI from scratch
and only supported two internal query params (disableSSLMode and secret).
All other query parameters were silently dropped, blocking deployments
on managed PostgreSQL providers like Google Cloud SQL that require params
such as sslmode=require or tcpKeepAlive=true.

Now all query parameters from the Settings URI are preserved in the final
POSTGRES_URI, except for the operator-internal ones (disableSSLMode and
secret) which are still consumed and filtered out. Backward compatibility
is fully maintained: disableSSLMode=true still produces sslmode=disable.
@flemzord flemzord requested a review from a team as a code owner March 4, 2026 14:29
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 4, 2026

Walkthrough

This change centralizes PostgreSQL URI query parameter handling by introducing a helper function that filters internal parameters while preserving custom ones. Documentation is updated to explain parameter forwarding and internal parameter handling behavior.

Changes

Cohort / File(s) Summary
Documentation
docs/05-Infrastructure services/01-PostgreSQL.md, docs/09-Configuration reference/01-Settings.md
Updated PostgreSQL configuration guidance to document that extra URI query parameters are forwarded to POSTGRES_URI, with examples using sslmode and tcpKeepAlive. Added notes explaining that secret and disableSSLMode are consumed internally and won't appear in the final connection string.
Implementation
internal/resources/databases/env.go
Introduced new public function BuildPostgresQueryString(rawQuery url.Values) string that centralizes query parameter handling. The function copies all parameters, removes internal ones (disableSSLMode, secret), conditionally sets sslmode=disable when disableSSLMode is true, and returns the encoded query string for POSTGRES_URI construction.
Testing
internal/resources/databases/env_test.go
Added comprehensive test suite for GetPostgresEnvVars validating various query parameter scenarios: no parameters, disableSSLMode handling, custom sslmode preservation, multiple parameter preservation, secret filtering, and parameter override behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A helper hops in, parameters in tow,
Filtering secrets and SSL in a row,
Custom ones dance, internal ones hide,
Connection strings built with rabbit-blessed pride! 🔗✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: passing through arbitrary PostgreSQL query parameters that were previously dropped.
Description check ✅ Passed The description is directly related to the changeset, explaining the purpose of preserving query parameters, the business motivation, backward compatibility, and listing affected files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/postgres-passthrough-query-params

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/09-Configuration` reference/01-Settings.md:
- Around line 98-100: Add a fenced-code language specifier to the block
containing the PostgreSQL connection URL (the
``postgresql://user:pass@host:5432?sslmode=require&tcpKeepAlive=true`` example)
so markdownlint MD040 is satisfied; replace the opening ``` with a language
token such as ```text (or another appropriate language) to explicitly mark the
block's language.

In `@internal/resources/databases/mock_test.go`:
- Around line 30-55: The file has formatting drift causing pre-commit/CI
failures; run gofmt (or `gofmt -w`) on internal/resources/databases/mock_test.go
to normalize formatting and then re-stage the file; ensure the changes cover the
mockManager method block (e.g., GetClient, GetScheme, GetAPIReader, Elected,
Start, etc.) so that the entire file is properly formatted before committing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 21ec4392-7768-4363-af84-d0d30620f712

📥 Commits

Reviewing files that changed from the base of the PR and between eb8d126 and f6522a6.

📒 Files selected for processing (5)
  • docs/05-Infrastructure services/01-PostgreSQL.md
  • docs/09-Configuration reference/01-Settings.md
  • internal/resources/databases/env.go
  • internal/resources/databases/env_test.go
  • internal/resources/databases/mock_test.go

Comment on lines +30 to +55
func (m *mockManager) GetClient() client.Client { return m.client }
func (m *mockManager) GetScheme() *runtime.Scheme { return m.scheme }
func (m *mockManager) GetAPIReader() client.Reader { return m.client }
func (m *mockManager) GetCache() cache.Cache { return nil }
func (m *mockManager) GetConfig() *rest.Config { return nil }
func (m *mockManager) GetEventRecorderFor(string) record.EventRecorder { return nil }
func (m *mockManager) GetLogger() logr.Logger { return logr.Discard() }
func (m *mockManager) GetRESTMapper() meta.RESTMapper { return nil }
func (m *mockManager) GetFieldIndexer() client.FieldIndexer { return nil }
func (m *mockManager) GetHTTPClient() *http.Client { return nil }
func (m *mockManager) GetWebhookServer() webhook.Server { return nil }
func (m *mockManager) GetMetricsServer() server.Server { return nil }
func (m *mockManager) GetControllerOptions() config.Controller { return config.Controller{} }
func (m *mockManager) GetPlatform() core.Platform { return core.Platform{} }
func (m *mockManager) Add(manager.Runnable) error { return nil }
func (m *mockManager) Elected() <-chan struct{} {
ch := make(chan struct{})
close(ch)
return ch
}
func (m *mockManager) SetFields(interface{}) error { return nil }
func (m *mockManager) AddMetricsExtraHandler(string, interface{}) error { return nil }
func (m *mockManager) AddMetricsServerExtraHandler(string, http.Handler) error { return nil }
func (m *mockManager) AddHealthzCheck(string, healthz.Checker) error { return nil }
func (m *mockManager) AddReadyzCheck(string, healthz.Checker) error { return nil }
func (m *mockManager) Start(context.Context) error { return nil }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Pre-commit failure points to formatting drift in this file.

CI reports unstaged changes for internal/resources/databases/mock_test.go; please run gofmt on this file and re-stage to unblock the pipeline.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/resources/databases/mock_test.go` around lines 30 - 55, The file has
formatting drift causing pre-commit/CI failures; run gofmt (or `gofmt -w`) on
internal/resources/databases/mock_test.go to normalize formatting and then
re-stage the file; ensure the changes cover the mockManager method block (e.g.,
GetClient, GetScheme, GetAPIReader, Elected, Start, etc.) so that the entire
file is properly formatted before committing.

Dav-14
Dav-14 previously approved these changes Mar 4, 2026
Copy link
Copy Markdown
Contributor

@Dav-14 Dav-14 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to mock all the client ?. Can you just export the business part we need and use the existing integration test ?

Address PR #415 review feedback:
- Extract URI query param logic into exported BuildPostgresQueryString()
- Simplify tests to call pure function directly (no fake k8s client)
- Remove mock_test.go (no longer needed)
- Fix markdown lint: add language identifier to fenced code block
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/resources/databases/env.go`:
- Around line 63-64: The formatted string `f` built for the Postgres URI can
contain percent signs from BuildPostgresQueryString(database.Status.URI.Query())
which will be interpreted as format directives when later used with
core.ComputeEnvVar (which calls fmt.Sprintf); fix by escaping percent signs in
the encoded query (replace "%" with "%%") before concatenating into `f` or by
moving the query portion out of the format template passed to ComputeEnvVar so
the query is appended after fmt.Sprintf; update the logic around the `f`
construction (where `f += "?" + encoded`) and ensure ComputeEnvVar is called
with a safe format string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 55b36659-9a55-4815-be2a-2246f97edcc5

📥 Commits

Reviewing files that changed from the base of the PR and between f6522a6 and d826106.

📒 Files selected for processing (3)
  • docs/09-Configuration reference/01-Settings.md
  • internal/resources/databases/env.go
  • internal/resources/databases/env_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/09-Configuration reference/01-Settings.md
  • internal/resources/databases/env_test.go

Comment on lines +63 to +64
if encoded := BuildPostgresQueryString(database.Status.URI.Query()); encoded != "" {
f += "?" + encoded
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== ComputeEnvVar definition ==\n'
rg -n -A20 -B2 'func ComputeEnvVar\('

printf '\n== Formatting calls near ComputeEnvVar ==\n'
rg -n -C4 'fmt\.(Sprintf|Errorf|Fprintf)\('

printf '\n== POSTGRES_URI assembly site ==\n'
rg -n -A6 -B4 'BuildPostgresQueryString|POSTGRES_URI|ComputeEnvVar\(' internal/resources/databases/env.go

Repository: formancehq/operator

Length of output: 50375


Escape percent signs in encoded query strings before passing to fmt.Sprintf.

At lines 63-64, the encoded query string is appended to f which is then passed to core.ComputeEnvVar. Since ComputeEnvVar uses fmt.Sprintf(format, ...) with f as the format string, any percent-encoded characters from url.Values.Encode() (e.g., %20, %40) will be misinterpreted as format directives, causing POSTGRES_URI corruption or runtime errors. Either escape % to %% in the encoded query string before concatenating, or append the query string outside the format template passed to ComputeEnvVar.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/resources/databases/env.go` around lines 63 - 64, The formatted
string `f` built for the Postgres URI can contain percent signs from
BuildPostgresQueryString(database.Status.URI.Query()) which will be interpreted
as format directives when later used with core.ComputeEnvVar (which calls
fmt.Sprintf); fix by escaping percent signs in the encoded query (replace "%"
with "%%") before concatenating into `f` or by moving the query portion out of
the format template passed to ComputeEnvVar so the query is appended after
fmt.Sprintf; update the logic around the `f` construction (where `f += "?" +
encoded`) and ensure ComputeEnvVar is called with a safe format string.

@flemzord flemzord merged commit 441f929 into main Mar 6, 2026
6 checks passed
@flemzord flemzord deleted the feat/postgres-passthrough-query-params branch March 6, 2026 15:02
@flemzord flemzord mentioned this pull request Mar 10, 2026
2 tasks
flemzord added a commit that referenced this pull request Mar 13, 2026
The awsRole query parameter is an internal operator parameter (legacy
mechanism for IAM role configuration) that should not be forwarded to
PostgreSQL. Since #415 introduced arbitrary query param pass-through,
awsRole was being sent to PostgreSQL which rejects it with
"unrecognized configuration parameter".
flemzord added a commit that referenced this pull request Mar 13, 2026
…ugh (#424)

The awsRole query parameter is an internal operator parameter (legacy
mechanism for IAM role configuration) that should not be forwarded to
PostgreSQL. Since #415 introduced arbitrary query param pass-through,
awsRole was being sent to PostgreSQL which rejects it with
"unrecognized configuration parameter".
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants