fix(referrer): apply default page size when request has no pagination#3023
Conversation
The ReferrerService.DiscoverPrivate and DiscoverPublicShared endpoints were unbounded when clients sent an empty request. The helper referrerPaginationOptsFromProto returned (nil, nil) for a nil pagination field, and the data layer interpreted nil CursorOptions as "return every reference". A container image that had been attested many times would accumulate hundreds of SBOMs/SARIF referrers, all returned in a single response. Apply the existing defaultReferrerPageSize (20) whenever no pagination is supplied or the limit is zero. Clients that already send pagination are unaffected. The CLI already sends a non-nil pagination request with a default limit of 20, so no client-side change is needed. Fixes: chainloop-dev#2890 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Vibhav Bobade <vibhav.bobde@gmail.com>
99b794c to
d5df1d7
Compare
|
@jiparis @migmartri Ready for review. Fixes #2890 (referrer Discover* endpoints returning unbounded references). Self-reviewed and hardened after feedback — the PR now addresses the bug at two layers for defense in depth:
Why two defaults (20 vs 10)? The service-layer 20 is a UX choice for this RPC; the data-layer 10 is a safety backstop that shouldn't encode API-surface knowledge. Commented inline to explain. Tests: 7 table-driven cases on the helper covering nil / empty / zero / negative / 1 / 50 / 100 limits. All pass. |
migmartri
left a comment
There was a problem hiding this comment.
Thanks for the contribution, my understanding is that I fixed this issue in this PR #2896 but forgot to link it to the issue (sorry)
I might have missed something though, what issue is exactly this fixing that the original PR didn't?
|
Thanks @migmartri — #2896 absolutely did add the cursor-pagination plumbing (proto, biz, data, CLI), and the CLI path is bounded by the default Post-#2896 code on ```go // app/controlplane/pkg/data/referrer.go A caller that omits This PR closes that gap at two layers for defense in depth:
Let me know if you'd rather have only one layer changed, or want the default consolidated into |
|
Thanks! |
Summary
Fixes #2890.
The
ReferrerService.DiscoverPrivateandDiscoverPublicSharedendpoints return an unbounded number of direct references (SBOMs, SARIF reports, …) when a client sends an empty pagination field. A container image that is attested repeatedly accumulates these references over time, so a single call can return hundreds of items.Root cause
referrerPaginationOptsFromProtoinapp/controlplane/internal/service/referrer.goreturned(nil, nil)whenever the request's pagination was nil, and the data layer treatednil *CursorOptionsas "skip pagination entirely":```go
// app/controlplane/pkg/data/referrer.go (unchanged)
if p != nil {
q = q.Limit(p.Limit + 1)
// …
}
```
This was intentional "backward compatibility" per the helper's comment, but it is the bug the issue describes.
Fix
Always return
*pagination.CursorOptionswith the existingdefaultReferrerPageSize = 20:Limit: 0→ default page sizeLimit: N→ honored as-is (still capped at 100 by the proto validation rule)The biz-layer traversal is still bounded by
maxTraverseLevels = 1(app/controlplane/pkg/data/referrer.go:196), so level-0 refs are now bounded and nothing deeper needs a change.Client impact
app/cli/cmd/referrer_discover.goalready sends a non-nil pagination request withDefaultLimit: 20.pagination.limitexplicitly (up to 100) or page through withpagination.cursor. This is a behavior change but it is the fix the issue asks for.Test plan
go test ./internal/service/... -run TestReferrerPaginationOptsFromProto -v— 5 subtests covering nil / empty / zero / explicit / boundary limitgo test ./internal/service/...— full service package passesgo vet ./internal/service/...cleangofmt -lclean