Skip to content

HYPERFLEET-1241 - fix: pagination parameter validation#232

Open
ldornele wants to merge 4 commits into
openshift-hyperfleet:mainfrom
ldornele:HYPERFLEET-1241
Open

HYPERFLEET-1241 - fix: pagination parameter validation#232
ldornele wants to merge 4 commits into
openshift-hyperfleet:mainfrom
ldornele:HYPERFLEET-1241

Conversation

@ldornele

Copy link
Copy Markdown
Contributor

Summary

Fixes pagination and ordering query parameter validation issues identified in code review.

Changes

  • Fix: Implement missing order parameter validation (asc/desc only)
  • Fix: Use int64 parsing for pageSize (was platform-dependent)
  • Fix: Trim whitespace when applying order direction to prevent malformed orderBy
  • Tests: Added validation and behavior tests for order parameter
  • Docs: Updated api-resources.md with ordering behavior examples

Testing

✅ All unit tests passing
✅ Added test coverage for order parameter edge cases

Related

  • Issue: HYPERFLEET-1241

@openshift-ci openshift-ci Bot requested review from jsell-rh and kuudori June 22, 2026 01:39
@openshift-ci

openshift-ci Bot commented Jun 22, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign ldornele for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: e492eafd-f0e4-4dcd-8f5f-2d5cd2260308

📥 Commits

Reviewing files that changed from the base of the PR and between 84f339a and e2482d3.

📒 Files selected for processing (1)
  • pkg/services/types.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)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/services/types.go

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Added strict validation for pagination and ordering query parameters across list endpoints; invalid values now return 400 Bad Request using RFC 9457 Problem Details.
    • Enforced page >= 1 and pageSize/size within 1–100, plus order limited to asc/desc; handlers now fail fast when query argument parsing errors.
    • Updated orderBy/order direction behavior per documented precedence and defaults.
  • Documentation
    • Revised API docs with concrete defaults, constraints, and ordering rules.
  • Tests
    • Expanded validation and ordering/normalization test coverage to match new behavior.

Walkthrough

NewListArguments in pkg/services/types.go changes from *ListArguments to (*ListArguments, *errors.ServiceError), now validating page (≥ 1), pageSize (1–100 via new MaxPageSize constant), and order (strictly asc or desc). Violations return RFC 9457–formatted 400 Bad Request errors. All seven handlers (ClusterHandler.List, ClusterNodePoolsHandler.List, ClusterStatusHandler.List, applyFieldFilter, NodePoolHandler.List, NodePoolStatusHandler.List, ResourceHandler.List, ResourceHandler.ListByOwner) capture and propagate the error. Existing tests update to destructure (listArgs, err) and assert err == nil for valid inputs; TestNewListArguments_OrderBy expands to cover direction inference and parsing edge cases. New TestNewListArguments_Validation provides table-driven validation error coverage. API docs specify concrete constraints and error format.

Security-Critical Checklist

CWE-20 (Improper Input Validation)

  • page and pageSize parse failures: range_9b43503cccf0 must cover non-numeric strings, empty strings, 0, negative, and over-max values. Confirm range_2b8ef60aa377 rejects all invalid Atoi/ParseInt results explicitly, not with silent defaults or clamping.
  • order whitelist: Verify range_2b8ef60aa377 accepts only asc and desc (case-sensitive, no variants like "ASC", "ascending"). Confirm all other values trigger 400 error.

CWE-703 (Improper Check or Handling of Exceptional Conditions)

  • Handler error propagation: All ranges range_bc539efd7e90, range_3b8f3f058612, range_ec77c1943639, range_96b610c27c9e, range_410f146355fb, range_a11495d20845, range_3b4ca4ea8dd0, range_30bfab7a3e4d must return NewListArguments errors immediately to the HTTP response layer. Confirm error is not swallowed, silently logged, or converted to 500.

CWE-89 (SQL Injection) / Ordering Direction Injection

  • Downstream orderBy consumption: When range_2b8ef60aa377 appends order direction to orderBy field strings (e.g., "field asc"), verify that Sentinel, Adapter, Broker packages consuming ListArguments.OrderBy use parameterized query or enum-based ordering whitelist, not raw SQL string interpolation. Grep ListArguments.OrderBy usage in all packages—do not rely on suffix validation alone.

Contract Break (Compile-time enforcement)

  • Signature change of NewListArguments is a hard break. Confirm no additional unmarked call sites exist in Sentinel, Adapter, Broker, or other packages. Unmarked sites fail to compile; they do not panic silently.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 10 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (10 passed)
Check name Status Explanation
Title check ✅ Passed Title directly addresses the main change: pagination parameter validation fixes across the codebase with consistent error handling implementation.
Description check ✅ Passed Description clearly relates to the changeset, detailing pagination/ordering validation fixes, int64 parsing, whitespace handling, and test coverage additions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sec-02: Secrets In Log Output ✅ Passed All log statements in the PR changes (handlers and services/types.go) contain only parameter names, numeric pagination values, and system constants—no tokens, passwords, credentials, or secrets are...
No Hardcoded Secrets ✅ Passed No hardcoded secrets, API keys, tokens, passwords, private keys, base64 strings, or embedded credentials found in any of the 10 modified files.
No Weak Cryptography ✅ Passed PR introduces no banned cryptographic primitives (md5, des, rc4, SHA1), custom crypto implementations, or insecure secret comparisons. String comparisons for "asc"/"desc" are database ordering dire...
No Injection Vectors ✅ Passed No injection vectors detected. PR validates query parameters (page, pageSize, order) with hardcoded error strings using parsed numeric values or constants—never raw user input. No SQL concatenation...
No Privileged Containers ✅ Passed PR contains only Go source files and API documentation—no Kubernetes manifests, Helm templates, or Dockerfiles that could contain privileged container configurations.
No Pii Or Sensitive Data In Logs ✅ Passed PR logging statements log only error codes, HTTP status codes, and validated integer pagination parameters—no PII, session IDs, raw bodies, or credential-bearing hostnames exposed.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/api-resources.md`:
- Around line 688-691: The documented default value for the `orderBy` parameter
in the API resources table shows `created_time`, but the actual runtime default
from `NewListArguments` is `created_time desc`. Update the `orderBy` row in the
documentation table to change the default value from `created_time` to
`created_time desc` to align the documentation with the actual implementation
behavior.

In `@pkg/services/types.go`:
- Around line 111-120: The orderBy field processing loop in the section where
listArgs.OrderBy is modified does not filter out empty tokens, allowing
malformed entries like " asc" to be created when empty values are passed (e.g.,
"name,,created_time"). Add a validation check after trimming each field to skip
empty tokens and prevent them from being processed with the order direction
applied. Specifically, after creating trimmedField via strings.TrimSpace, check
if the length is zero and continue to the next iteration if so, ensuring only
non-empty fields receive the direction suffix.
🪄 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: Enterprise

Run ID: 11340d16-364f-4c4c-ae7e-44e94e0e0cfd

📥 Commits

Reviewing files that changed from the base of the PR and between 24ec42b and 19669a7.

📒 Files selected for processing (10)
  • docs/api-resources.md
  • pkg/handlers/cluster.go
  • pkg/handlers/cluster_nodepools.go
  • pkg/handlers/cluster_status.go
  • pkg/handlers/framework.go
  • pkg/handlers/node_pool.go
  • pkg/handlers/nodepool_status.go
  • pkg/handlers/resource_handler.go
  • pkg/services/types.go
  • pkg/services/types_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)

Comment thread docs/api-resources.md Outdated
Comment thread pkg/services/types.go Outdated
@hyperfleet-ci-bot

hyperfleet-ci-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown

Risk Score: 2 — risk/medium

Signal Detail Points
PR size 418 lines (>200) +1
Sensitive paths none +0
Test coverage Missing tests for: pkg/handlers +1

Computed by hyperfleet-risk-scorer

@rafabene

Copy link
Copy Markdown
Contributor

Bug (nit)pkg/services/types.go:108-136

order without orderBy is validated but silently ignored. ?order=asc passes validation at line 110, but the normalization loop (117-130) iterates over an empty OrderBy slice, so it's a no-op. Then line 134 always sets created_time desc.

This means ?order=asc alone produces created_time desc — the user's intent is dropped.

Consider applying the order direction to the default (around line 133):

// Set default sorting — respect order param if provided
if len(listArgs.OrderBy) == 0 {
    defaultDir := "desc"
    if v := strings.Trim(params.Get("order"), " "); v == "asc" || v == "desc" {
        defaultDir = v
    }
    listArgs.OrderBy = []string{"created_time " + defaultDir}
}

Comment thread pkg/services/types.go
Comment on lines +102 to +104
if trimmed := strings.TrimSpace(field); trimmed != "" {
listArgs.OrderBy = append(listArgs.OrderBy, trimmed)
}

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.

Inconsistent whitespace normalization: without order, TrimSpace preserves internal multi-spaces ("name asc" stays as-is). With order, strings.Fields + strings.Join normalizes them ("name asc""name asc").

Consider normalizing in the initial parsing:

Suggested change
if trimmed := strings.TrimSpace(field); trimmed != "" {
listArgs.OrderBy = append(listArgs.OrderBy, trimmed)
}
if trimmed := strings.TrimSpace(field); trimmed != "" {
listArgs.OrderBy = append(listArgs.OrderBy, strings.Join(strings.Fields(trimmed), " "))
}

Comment thread pkg/handlers/framework.go
// If fields are specified, it filters the resource and returns only the requested fields.
func applyFieldFilter(r *http.Request, presented interface{}) (interface{}, *errors.ServiceError) {
listArgs := services.NewListArguments(r.URL.Query())
listArgs, err := services.NewListArguments(r.URL.Query())

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.

applyFieldFilter only uses the Fields from ListArguments, but now validates pagination params too. On single-resource GETs (e.g., GET /clusters/{id}?fields=name&page=abc), this returns 400 for an irrelevant parameter.

This is defensively correct ("validate at boundaries"), but could surprise clients. Consider extracting field parsing separately, or documenting this as intentional.

@rafabene

Copy link
Copy Markdown
Contributor

Improvement (nit)pkg/services/types.go:24 / pkg/services/generic.go:292

MaxListSize (65500) is still defined and used in generic.go:292, but is now unreachable since NewListArguments caps at MaxPageSize (100). Consider removing the dead guard in generic.go, or adding a comment explaining the dual-layer validation intent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants