Skip to content

HYPERFLEET-1274 - refactor: move list parameter parsing to handler layer#307

Open
kuudori wants to merge 1 commit into
openshift-hyperfleet:mainfrom
kuudori:HYPERFLEET-1274
Open

HYPERFLEET-1274 - refactor: move list parameter parsing to handler layer#307
kuudori wants to merge 1 commit into
openshift-hyperfleet:mainfrom
kuudori:HYPERFLEET-1274

Conversation

@kuudori

@kuudori kuudori commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Extract query parameter parsing from pkg/services/types.go into pkg/handlers/list_params.go, aligning with the handler-validates, service-executes pattern
  • Use go-playground/validator for struct-level validation with structured error details via ValidationWithDetails
  • Remove redundant defensive size checks from the service layer (generic.go) while keeping a Size <= 0 guard
  • Add comprehensive table-driven tests covering defaults, custom values, format errors, range errors, ref pairing, and edge cases

Test plan

  • make verify-all passes (vet + lint + unit tests)
  • make test-integration passes
  • Verify list endpoints return correct pagination defaults (page=1, size=20, order=created_time desc)
  • Verify validation errors return 400 with structured details array
  • Verify ?fields=name response includes id field automatically
  • Verify ?ref_type=dep without ?ref_target_id returns validation error

Extract query parameter parsing from pkg/services/types.go into
pkg/handlers/list_params.go. Use go-playground/validator for struct-level
validation and return structured error details via ValidationWithDetails.

Remove defensive size checks from generic.go service layer (now validated
at the handler boundary) while keeping a guard for Size <= 0.

Update stale mockgen example in docs/development.md.
@openshift-ci
openshift-ci Bot requested review from ciaranRoche and mliptak0 July 21, 2026 20:50
@openshift-ci

openshift-ci Bot commented Jul 21, 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 kuudori 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 Jul 21, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

List query parsing and validation move from pkg/services into pkg/handlers, including pagination, search, ordering, fields, and reference-pair validation. List endpoints use the new parser, and field filtering shares its normalization helpers. Services retain a parameterless default constructor, remove query parsing utilities, stop trimming search internally, and return early for non-positive sizes. Documentation updates the mock generation command.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ResourceHandler
  participant parseListParams
  participant sqlResourceService
  Client->>ResourceHandler: Send list request with query parameters
  ResourceHandler->>parseListParams: Parse and validate URL query
  parseListParams-->>ResourceHandler: Return services.ListArguments
  ResourceHandler->>sqlResourceService: Execute list operation
  sqlResourceService-->>ResourceHandler: Return list results
Loading

Suggested reviewers: ldornele

🚥 Pre-merge checks | ✅ 10 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
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 No non-test/non-example log statements contain token/password/credential/secret fields or interpolated strings; CWE-532 not observed.
No Hardcoded Secrets ✅ Passed No hardcoded credentials, private keys, embedded URL creds, or quoted base64 blobs were added in touched files; the only regex hit was a false positive. CWE-798/CWE-321.
No Weak Cryptography ✅ Passed No banned primitives, ECB, custom crypto, or secret comparisons appear in the diff; changes are limited to query parsing/listing.
No Injection Vectors ✅ Passed No CWE-89/78/79/502 sink introduced: touched files have no exec/template/yaml usage; order values are whitelisted in ArgsToOrder and kinds are registry-validated.
No Privileged Containers ✅ Passed No Kubernetes/OpenShift manifests, Helm templates, or Dockerfiles changed; touched files contain no privileged flags (CWE-732/CWE-284).
No Pii Or Sensitive Data In Logs ✅ Passed No new logging paths in the patch expose PII/raw bodies; touched logs emit only generic errors. CWE-532 not introduced.
Title check ✅ Passed The title accurately states the main change: moving list parameter parsing into the handler layer.
Description check ✅ Passed The description matches the changeset and describes the parsing, validation, service cleanup, and test updates.
✨ 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.

@hyperfleet-ci-bot

Copy link
Copy Markdown

Risk Score: 2 — risk/medium

Signal Detail Points
PR size 1031 lines (>500) +2
Sensitive paths none +0
Test coverage Tests cover changed packages +0

Computed by hyperfleet-risk-scorer

@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: 1

🧹 Nitpick comments (1)
pkg/handlers/list_params_test.go (1)

246-255: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage for the page upper bound.

Once Page gains a max (see pkg/handlers/list_params.go Line 20-21), add a range-error case (e.g. ?page=99999999999999999999) so the overflow guard is regression-locked. Error paths are otherwise well covered.

As per path instructions: "Error paths SHOULD be tested, not just happy paths".

🤖 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 `@pkg/handlers/list_params_test.go` around lines 246 - 255, Add a table-driven
test case in the list-parameter validation tests covering a page value above the
`Page` maximum, such as an excessively large numeric page query, and assert the
expected range-validation error. Keep the existing valid large-page case
unchanged and use the current error assertion pattern.

Source: Path instructions

🤖 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/handlers/list_params.go`:
- Around line 20-21: Cap Page or explicitly validate its multiplication with
Size before loadList computes the offset and calls Fetch. Update the Page
validation in list parameters and ensure (args.Page-1)*int(args.Size) cannot
overflow into a negative offset, while preserving valid pagination behavior.

---

Nitpick comments:
In `@pkg/handlers/list_params_test.go`:
- Around line 246-255: Add a table-driven test case in the list-parameter
validation tests covering a page value above the `Page` maximum, such as an
excessively large numeric page query, and assert the expected range-validation
error. Keep the existing valid large-page case unchanged and use the current
error assertion pattern.
🪄 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: 15f509e2-4d57-4412-9603-b9ad8c7ae08f

📥 Commits

Reviewing files that changed from the base of the PR and between 99c22d1 and aa6578b.

📒 Files selected for processing (11)
  • docs/development.md
  • pkg/handlers/framework.go
  • pkg/handlers/list_params.go
  • pkg/handlers/list_params_test.go
  • pkg/handlers/resource_handler.go
  • pkg/handlers/resource_status_handler.go
  • pkg/handlers/root_resource_handler.go
  • pkg/services/generic.go
  • pkg/services/resource.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)
💤 Files with no reviewable changes (1)
  • pkg/services/types_test.go

Comment on lines +20 to +21
Size int64 `validate:"min=1,max=100"`
Page int `validate:"min=1"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

go-playground/validator v10 numeric max tag on int field

💡 Result:

In the go-playground/validator v10 library, the max tag behaves differently depending on the type of the field being validated [1][2]. When applied to an integer (int) field, the max tag ensures that the value of the integer is less than or equal to the parameter specified in the tag [1][2]. Example: type User struct { Age int validate:"max=100" } In this example, the validator will return an error if the Age field is greater than 100 [1][2]. Key points regarding the max tag: - Numeric comparison: For numbers (including various int sizes, uint, and float types), it performs a direct numeric comparison [1][2]. - Other types: The max tag is polymorphic. For strings, it checks the character length (number of characters); for slices, arrays, and maps, it validates the number of items [1][2]. - Order of operations: If multiple validation tags are used on the same field, they are processed in the order they are defined [1][2]. - Potential issues: Ensure that the validation tag is placed correctly. In some complex scenarios—such as when using custom types or specific struct-backed fields—improper ordering or unsupported types can lead to unexpected behavior or panics [3]. Always ensure your data types are compatible with the library's expected input formats [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files 'pkg/handlers/list_params.go' 'pkg/services/generic.go'

echo "== list_params.go =="
cat -n pkg/handlers/list_params.go

echo "== generic.go relevant slices =="
rg -n "loadList|args\.Page|args\.Size|offset|limit" pkg/services/generic.go
sed -n '240,320p' pkg/services/generic.go

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 8786


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== list-related call sites =="
rg -n "Fetch\(|Offset\(|Limit\(|Count\(" pkg | sed -n '1,200p'

echo "== DAO fetch implementation =="
rg -n "type GenericDao|func .*Fetch\(" pkg

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 1979


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Probe Go int overflow behavior for the offset expression shape.
python3 - <<'PY'
import sys
max_int = 2**63 - 1
size = 100
page = max_int // size + 2  # first page value that makes (page-1)*size overflow 64-bit signed
offset = (page - 1) * size
wrapped = ((offset + 2**63) % 2**64) - 2**63
print("page =", page)
print("exact offset =", offset)
print("wrapped int64 =", wrapped)
print("negative =", wrapped < 0)
PY

Repository: openshift-hyperfleet/hyperfleet-api

Length of output: 286


pkg/handlers/list_params.go:21 / pkg/services/generic.go:275 — Cap Page before computing the list offset. loadList multiplies (args.Page-1)*int(args.Size); with only min=1, a large valid page can overflow into a negative offset (CWE-190). Add an upper bound or explicit overflow check before Fetch.

🤖 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 `@pkg/handlers/list_params.go` around lines 20 - 21, Cap Page or explicitly
validate its multiplication with Size before loadList computes the offset and
calls Fetch. Update the Page validation in list parameters and ensure
(args.Page-1)*int(args.Size) cannot overflow into a negative offset, while
preserving valid pagination behavior.

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.

1 participant