Skip to content

fix(config): escape LIKE wildcards in registration search filter - #720

Merged
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
fix/719-registrations-like-escape
May 27, 2026
Merged

cristim merged 2 commits into
feat/multicloud-web-frontendfrom
fix/719-registrations-like-escape

Conversation

@cristim

@cristim cristim commented May 25, 2026 •

Copy link
Copy Markdown
Member

Closes #719. Surfaced by the full-codebase SQL injection audit (audit found zero SQLi but one suspicious LIKE wildcard escape gap).

internal/config/store_postgres_registrations.go:101-107 was binding filter.Search as $N (so not SQLi), but %/_/\\ were not escaped — a search like %@gmail.com matched every gmail address instead of literally containing %@gmail.com. Now mirrors the working pattern at store_postgres.go:1974 (ListCloudAccounts): strings.NewReplacer escapes the wildcards before wrapping, and ESCAPE '\\' is appended to all three ILIKE clauses.

Tests

  • New TestPGXMock_ListAccountRegistrations_SearchEscapesPercent — %foo input binds \\%foo to the DB parameter
  • New TestPGXMock_ListAccountRegistrations_SearchEscapesUnderscore — foo_bar input binds foo\\_bar
  • Both assert the SQL contains ESCAPE
  • 504 tests pass total

Summary by CodeRabbit

  • Bug Fixes
    • Improved search functionality to properly handle special characters (%, _, and backslash) as literal text when searching, ensuring accurate and consistent results.

Review Change Stack

@cristim cristim added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/this-quarter Within the quarter impact/few Limited audience effort/xs Trivial / one-liner type/bug Defect labels May 25, 2026
@coderabbitai

coderabbitai Bot commented May 25, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8fc6d95d-f3ee-427a-9983-5c8f5e6e54ea

📥 Commits

Reviewing files that changed from the base of the PR and between fad51d6 and bb34bf9.

📒 Files selected for processing (1)
  • internal/config/store_postgres_pgxmock_test.go

📝 Walkthrough

Walkthrough

The PR adds SQL LIKE wildcard escaping to the registration search filter to prevent unintended pattern matching, mirroring existing security handling in ListCloudAccounts. It escapes %, _, and \ characters in user input and adds an ESCAPE clause to the query. Three new tests verify escaping behavior for each wildcard type.

Changes

Search Filter Wildcard Escaping

Layer / File(s) Summary
Search filter wildcard escaping implementation
internal/config/store_postgres_registrations.go
Updated ListAccountRegistrations query to escape %, _, and \ in filter.Search before wrapping with the %...% pattern, and added ESCAPE '\\' clause to the ILIKE condition to treat escaped characters as literals instead of wildcards.
Test helpers and search escaping verification
internal/config/store_postgres_pgxmock_test.go
Added registrationCols() and minimalRegRow() helper functions to support row construction in pgxmock tests. Added TestPGXMock_ListAccountRegistrations_SearchEscapesPercent, TestPGXMock_ListAccountRegistrations_SearchEscapesUnderscore, and TestPGXMock_ListAccountRegistrations_SearchEscapesBackslash to verify that each wildcard character is properly escaped in the bound argument and that the resulting query includes the ESCAPE clause.

🎯 2 (Simple) | ⏱️ ~10 minutes

🐰 A hop and a skip to fix the search,
Backslash, percent, underscore—no more lurch!
ESCAPE clauses bind our hearts so tight,
Three little tests make everything right. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(config): escape LIKE wildcards in registration search filter' accurately describes the main change: escaping wildcard characters in the registration search filter to fix a security gap.
Linked Issues check ✅ Passed The PR fully addresses the requirements from #719: escapes '%', '_', and '\' characters in the registration search filter, adds ESCAPE clause to ILIKE queries, and includes comprehensive regression tests for all three escaped characters.
Out of Scope Changes check ✅ Passed All changes are scoped to addressing the LIKE wildcard escape gap in registration search filters; no unrelated modifications were introduced.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/719-registrations-like-escape

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

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
internal/config/store_postgres_pgxmock_test.go (1)

1545-1595: ⚡ Quick win

Add regression coverage for backslash (\) escaping.

The implementation escapes \ too, but tests currently assert only % and _. Adding one test here closes the remaining escape-path gap.

✅ Suggested test addition
+func TestPGXMock_ListAccountRegistrations_SearchEscapesBackslash(t *testing.T) {
+	mock := newMock(t)
+	store := storeWith(mock)
+	ctx := context.Background()
+
+	rawSearch := `foo\bar`
+	escapedArg := `foo\\bar`
+
+	rows := pgxmock.NewRows(registrationCols()).
+		AddRow(minimalRegRow("reg-3", `foo\bar LLC`, "foo@example.com")...)
+	mock.ExpectQuery(`ESCAPE`).
+		WithArgs("%" + escapedArg + "%").
+		WillReturnRows(rows)
+
+	filter := AccountRegistrationFilter{Search: rawSearch}
+	regs, err := store.ListAccountRegistrations(ctx, filter)
+	require.NoError(t, err)
+	assert.Len(t, regs, 1)
+	assert.Equal(t, "reg-3", regs[0].ID)
+	assert.NoError(t, mock.ExpectationsWereMet())
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/config/store_postgres_pgxmock_test.go` around lines 1545 - 1595, Add
a new unit test (e.g.,
TestPGXMock_ListAccountRegistrations_SearchEscapesBackslash) mirroring the
existing percent/underscore tests that verifies backslash escaping: create mock
:= newMock(t), store := storeWith(mock), ctx := context.Background(), set
rawSearch to include a backslash (for example "foo\\bar") and set escapedArg to
the expected escaped form (e.g., `foo\\bar`), prepare rows :=
pgxmock.NewRows(registrationCols()).AddRow(minimalRegRow("reg-3", "foo\\bar
Inc", "foo\\bar@example.com")...), set
mock.ExpectQuery(`ESCAPE`).WithArgs("%"+escapedArg+"%").WillReturnRows(rows),
call store.ListAccountRegistrations(ctx, AccountRegistrationFilter{Search:
rawSearch}) and assert no error, one result with ID "reg-3", and
mock.ExpectationsWereMet(); use the same helper symbols (newMock, storeWith,
ListAccountRegistrations, AccountRegistrationFilter, minimalRegRow,
registrationCols) so the test integrates with the others.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/config/store_postgres_pgxmock_test.go`:
- Around line 1545-1595: Add a new unit test (e.g.,
TestPGXMock_ListAccountRegistrations_SearchEscapesBackslash) mirroring the
existing percent/underscore tests that verifies backslash escaping: create mock
:= newMock(t), store := storeWith(mock), ctx := context.Background(), set
rawSearch to include a backslash (for example "foo\\bar") and set escapedArg to
the expected escaped form (e.g., `foo\\bar`), prepare rows :=
pgxmock.NewRows(registrationCols()).AddRow(minimalRegRow("reg-3", "foo\\bar
Inc", "foo\\bar@example.com")...), set
mock.ExpectQuery(`ESCAPE`).WithArgs("%"+escapedArg+"%").WillReturnRows(rows),
call store.ListAccountRegistrations(ctx, AccountRegistrationFilter{Search:
rawSearch}) and assert no error, one result with ID "reg-3", and
mock.ExpectationsWereMet(); use the same helper symbols (newMock, storeWith,
ListAccountRegistrations, AccountRegistrationFilter, minimalRegRow,
registrationCols) so the test integrates with the others.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fb6c3118-420f-4b4c-83ca-74dc3232a66c

📥 Commits

Reviewing files that changed from the base of the PR and between 5abf40b and fad51d6.

📒 Files selected for processing (2)
  • internal/config/store_postgres_pgxmock_test.go
  • internal/config/store_postgres_registrations.go

@cristim

cristim commented May 25, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 26, 2026

Copy link
Copy Markdown
Member Author

Addressed in bb34bf9. Added TestPGXMock_ListAccountRegistrations_SearchEscapesBackslash at lines 1598-1625 of internal/config/store_postgres_pgxmock_test.go, mirroring the existing percent/underscore tests. The test confirms that foo\bar is bound as %foo\\bar% and that the query contains ESCAPE. All 505 tests in ./internal/config/... pass, go vet and gofmt clean, golangci-lint exit 0.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

@cristim: Great — adding the backslash test rounds out coverage for all three escapable characters (%, _, \). Triggering a review of the latest commit now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim

cristim commented May 27, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit 5c15dd3 into feat/multicloud-web-frontend May 27, 2026
4 checks passed
@cristim
cristim deleted the fix/719-registrations-like-escape branch May 27, 2026 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/xs Trivial / one-liner impact/few Limited audience priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant