HYPERFLEET-1375 - fix: validate typed search fields and close DB column leaks#308
HYPERFLEET-1375 - fix: validate typed search fields and close DB column leaks#308mliptak0 wants to merge 2 commits into
Conversation
…mn leaks Search values for generation/created_time/updated_time/deleted_time reached Postgres without type validation, leaking raw pq: driver errors and SQLSTATE codes as 500s instead of clean 400s. Add type validation to FieldNameWalk, the shared search-to-SQL translation layer used by both /resources and typed entity search. Also remove the dead "properties." field mapping, a leftover alias from before the resources table's JSONB column was renamed to "spec" — it pointed at a nonexistent column and produced the same class of raw pq: leak. Also cap the label-key length check at the actual resource_labels.key DB column size (255) instead of the Kubernetes spec's own limit (317), so a spec-valid-but-oversized key is rejected with a clean 400 during request validation instead of a 500 during resource conversion. Co-Authored-By: Claude <noreply@anthropic.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
📝 WalkthroughWalkthroughSearch field mapping now rejects the legacy Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant SearchEndpoint
participant FieldNameWalk
participant Database
Client->>SearchEndpoint: Search query
SearchEndpoint->>FieldNameWalk: Parse and map fields
FieldNameWalk-->>SearchEndpoint: Validation error or SQL expression
SearchEndpoint->>Database: Execute validated query
Database-->>SearchEndpoint: Results
SearchEndpoint-->>Client: HTTP response
Suggested reviewers: 🚥 Pre-merge checks | ✅ 11✅ Passed checks (11 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
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. Comment |
Risk Score: 1 —
|
| Signal | Detail | Points |
|---|---|---|
| PR size | 391 lines (>200) | +1 |
| Sensitive paths | none | +0 |
| Test coverage | Tests cover changed packages | +0 |
Computed by hyperfleet-risk-scorer
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
test/integration/search_field_mapping_test.go (1)
919-925: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDuplicate
assertCleanBadRequestclosure across two test functions.Identical helper defined in both
TestSearchTypedFieldValidationandTestSearchPropertiesFieldRejected. Extract to a package-level test helper (witht.Helper()) to avoid drift.Also applies to: 1020-1026
🤖 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 `@test/integration/search_field_mapping_test.go` around lines 919 - 925, Extract the duplicated assertCleanBadRequest closure from TestSearchTypedFieldValidation and TestSearchPropertiesFieldRejected into a package-level test helper. Give the helper a *testing.T parameter, call t.Helper(), and preserve the existing status-code and response-body assertions; update both tests to use it.
🤖 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.
Inline comments:
In `@pkg/db/sql_helpers.go`:
- Around line 585-613: Update validateTypedFieldValues to detect tracked typed
fields on either operand of a binary expression, not only when n.Left is the
identifier. When the right operand is the field, validate the left operand
against that field’s expected kind; preserve the existing left-field validation
and recursive traversal behavior.
---
Nitpick comments:
In `@test/integration/search_field_mapping_test.go`:
- Around line 919-925: Extract the duplicated assertCleanBadRequest closure from
TestSearchTypedFieldValidation and TestSearchPropertiesFieldRejected into a
package-level test helper. Give the helper a *testing.T parameter, call
t.Helper(), and preserve the existing status-code and response-body assertions;
update both tests to use it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Central YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: 48ef8c1d-eca3-4934-ab97-893befeb4aba
📒 Files selected for processing (6)
pkg/db/sql_helpers.gopkg/db/sql_helpers_test.gopkg/handlers/validation.gopkg/handlers/validation_test.gopkg/services/generic_test.gotest/integration/search_field_mapping_test.go
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
openshift-hyperfleet/architecture(manual)openshift-hyperfleet/hyperfleet-api(manual)openshift-hyperfleet/hyperfleet-sentinel(manual)openshift-hyperfleet/hyperfleet-adapter(manual)openshift-hyperfleet/hyperfleet-broker(manual)
… side validateTypedFieldValues only checked the field-on-left form (field = value), so field-on-right comparisons like 'not-a-date' < created_time or 'abc' = generation skipped validation and reached Postgres unvalidated, reintroducing the pq:/SQLSTATE leak this PR is meant to close. Also collapses the per-type error-message switch into a single lookup map for a simpler, still field-type-aware error message. Co-Authored-By: Claude <noreply@anthropic.com>
Summary
What
generation(INTEGER) andcreated_time/updated_time/deleted_time(TIMESTAMPTZ) — so a mismatched search value (e.g.generation='abc',created_time='not-a-date') is rejected before it reaches Postgres, on both operand orders (generation='abc'and'abc'=generation).properties.xxxsearch field mapping, a leftover alias from before the resources table's JSONB column was renamed tospec— it pointed at a nonexistent column and produced the same class of rawpq:leak.resource_labels.keyDB column size (255) instead of the Kubernetes spec's own limit (317), so a spec-valid-but-oversized key is rejected with a clean 400 during request validation instead of a 500 during resource conversion. Could turn the sql column into text to be able to use 317char limit, but since it's not typical case, chosed to not proceed with this change at the moment.Why
Callers should get a consistent, actionable
HYPERFLEET-VAL-*400 error for bad search input — never a raw Postgres error message or SQLSTATE code. This was a coverage gap found while validating Generic Resources CRUD journeys.Test Plan
make test-allpassesmake lintpassesmake test-helm(if applicable)Manually verified against a live dev cluster: valid/invalid
generationandcreated_time/updated_time/deleted_timesearches on both operand orders,INlists, date-literal-for-timestamp,properties.xxxrejection on/clustersand/resources, an oversized-but-K8s-valid label key on cluster create, and a malformed TSL query — all returned cleanHYPERFLEET-VAL-*400s with nopq:/SQLSTATEleakage.