Skip to content

Conversation

@JivusAyrus
Copy link
Member

@JivusAyrus JivusAyrus commented Dec 22, 2025

Summary by CodeRabbit

  • New Features

    • Added pagination (limit/offset and total counts) across many list endpoints and client-side pagination on the API Keys page.
    • Added pagination/range support for proposals, cache warmer, webhooks, operations, and related endpoints.
  • Bug Fixes / Improvements

    • Defaulted and clamped list limits/offsets to sensible ranges instead of returning errors.
    • Enforced a 200 API-key maximum per organization.
    • Improved API Keys UI messages, validation and dialog feedback.
  • Tests

    • Updated tests to validate clamped-limit behavior and pagination results.

✏️ Tip: You can customize this high-level summary in your review settings.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/cosmo-docs.
  • I have read the Contributors Guide.

@coderabbitai
Copy link

coderabbitai bot commented Dec 22, 2025

Walkthrough

Adds pagination (limit/offset) and total-count fields to protobufs and handlers, replaces hard-limit errors with clamped defaults across many server endpoints, adds API-key creation pre-check (200 limit), updates repository queries for pagination/count, and enables client-side pagination in the API keys UI.

Changes

Cohort / File(s) Summary
Protobufs & generated types
proto/wg/cosmo/platform/v1/platform.proto, connect/src/wg/cosmo/platform/v1/platform_pb.ts
Added limit/offset to many request messages and count (and related fields) to responses; regenerated TypeScript protobufs reflect these additions.
API key services
controlplane/src/core/bufservices/api-key/createAPIKey.ts, controlplane/src/core/bufservices/api-key/getAPIKeys.ts
Added pre-check to refuse creating ≥200 API keys per org; getAPIKeys now clamps/defaults limit, accepts offset, returns paginated keys and total count.
Repository (API keys)
controlplane/src/core/repositories/ApiKeyRepository.ts
getAPIKeys now accepts { organizationID, limit, offset }, applies conditional .limit()/.offset(), and added getAPIKeysCount({ organizationID }).
Checks / federated-graph / operations services
controlplane/src/core/bufservices/check/getCheckOperations.ts, controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts, controlplane/src/core/bufservices/federated-graph/getCompositions.ts, controlplane/src/core/bufservices/check/*
Replaced explicit "invalid limit" error paths with clamp-based defaults (commonly default 10) and allowed clamped offsets; preserved downstream logic.
Organization / proposal / audit services
controlplane/src/core/bufservices/organization/getAuditLogs.ts, controlplane/src/core/bufservices/proposal/getProposalChecks.ts, controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
Introduced clamp/default limits (default 10, clamped typically to [1,50]) and offset clamping; responses updated to include counts where applicable.
Cache-warmer / webhook / proposal-related services & protos
proto/... , controlplane/src/core/bufservices/*
Added pagination, range/date parameters, count/flag fields and corresponding service handling for cache-warmer operations, webhook history/delivery, proposals, and related endpoints.
Frontend — API keys page
studio/src/pages/[organizationSlug]/apikeys.tsx
Client-side pagination: derive pageNumber/limit from router; pass limit/offset to getAPIKeys; render Pagination; UpdateAPIKey now accepts onOpenChange prop; minor UI/text adjustments.
Tests
controlplane/test/fetch-checks-by-federated-graph.test.ts
Updated tests to exercise clamped-limit behavior (expecting clamped responses, e.g., >50 → 50) and added test data to validate counts.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • Consistency of clamp defaults and numeric ranges across endpoints.
    • Correctness and efficiency of new count queries in repositories (ensure proper indexing and query shapes).
    • Race-condition semantics of the API-key create pre-check (enforcement at 200).
    • Frontend pagination: offset calculation, query-sync with router, and dialog open-state changes.

Possibly related PRs

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add pagination and limit handling for API keys' directly and clearly describes the main change: adding pagination support and limit constraints for API keys across multiple services and the UI.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31657a5 and 0a66ea3.

📒 Files selected for processing (1)
  • controlplane/src/core/bufservices/api-key/getAPIKeys.ts
🧰 Additional context used
🧬 Code graph analysis (1)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)
controlplane/src/db/schema.ts (1)
  • apiKeys (1175-1205)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build-router
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: Analyze (go)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: build_test
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
🔇 Additional comments (2)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (2)

22-25: LGTM! Input validation is well-implemented.

The clamping logic correctly handles edge cases and prevents invalid pagination parameters. The bounds are appropriate:

  • Limit [1, 50] with default 10 balances usability and prevents bulk enumeration
  • Offset [0, 1000] with default 0 provides a defensive upper bound

This follows the same pattern used in other paginated endpoints across the codebase (getAuditLogs, getCompositions, getChecks).


27-35: LGTM! Pagination implementation is correct and follows established patterns.

The paginated query and count retrieval work together to provide complete pagination support:

  • Limit and offset are correctly passed to the repository
  • Total count enables client-side pagination UI
  • Response structure matches the protobuf schema changes

The two-query pattern (data + count) is standard and consistent with other paginated endpoints in the codebase. Given the 200 API key limit, the performance impact is negligible.

Also applies to: 42-42


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

@codecov
Copy link

codecov bot commented Dec 22, 2025

Codecov Report

❌ Patch coverage is 23.78378% with 141 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.94%. Comparing base (e15b640) to head (0a66ea3).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
studio/src/pages/[organizationSlug]/apikeys.tsx 0.00% 130 Missing ⚠️
...plane/src/core/bufservices/api-key/createAPIKey.ts 41.66% 7 Missing ⚠️
.../src/core/bufservices/organization/getAuditLogs.ts 0.00% 2 Missing ⚠️
...rolplane/src/core/repositories/ApiKeyRepository.ts 90.00% 2 Missing ⚠️

❌ Your patch check has failed because the patch coverage (23.78%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2430       +/-   ##
===========================================
- Coverage   61.35%   35.94%   -25.42%     
===========================================
  Files         229      943      +714     
  Lines       23814   123006    +99192     
  Branches        0     4879     +4879     
===========================================
+ Hits        14612    44210    +29598     
- Misses       7970    77258    +69288     
- Partials     1232     1538      +306     
Files with missing lines Coverage Δ
...olplane/src/core/bufservices/api-key/getAPIKeys.ts 100.00% <100.00%> (ø)
...e/src/core/bufservices/check/getCheckOperations.ts 71.42% <100.00%> (ø)
...bufservices/check/getChecksByFederatedGraphName.ts 86.95% <100.00%> (ø)
...ore/bufservices/federated-graph/getCompositions.ts 88.60% <100.00%> (ø)
...src/core/bufservices/proposal/getProposalChecks.ts 78.94% <100.00%> (ø)
...fservices/proposal/getProposalsByFederatedGraph.ts 77.50% <100.00%> (ø)
.../src/core/bufservices/organization/getAuditLogs.ts 2.73% <0.00%> (ø)
...rolplane/src/core/repositories/ApiKeyRepository.ts 82.75% <90.00%> (ø)
...plane/src/core/bufservices/api-key/createAPIKey.ts 85.10% <41.66%> (ø)
studio/src/pages/[organizationSlug]/apikeys.tsx 0.00% <0.00%> (ø)

... and 707 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link

github-actions bot commented Dec 22, 2025

Router-nonroot image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-38a70977903b66cd445d39c8ccf28532b1b6d397-nonroot

@JivusAyrus JivusAyrus changed the title feat: add pagination and limit handling for API keys. feat: add pagination and limit handling for API keys Dec 22, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts (1)

73-85: Add validation for lower bounds of limit and offset.

The code validates that limit <= 50 but doesn't check if limit is at least 1, nor does it validate that offset >= 0. Negative or zero limit values could bypass intended constraints; negative offset values could cause unexpected database behavior.

🧹 Nitpick comments (6)
controlplane/src/core/bufservices/organization/getAuditLogs.ts (1)

57-58: Consider using nullish coalescing operator.

The logical OR (||) operator treats all falsy values (including 0) as missing. While unlikely to cause issues in this context, the nullish coalescing operator (??) is generally preferred for defaulting, as it only treats undefined and null as missing values.

🔎 Proposed refactor
-req.limit = req.limit || 50;
+req.limit = req.limit ?? 50;
controlplane/src/core/bufservices/check/getCheckOperations.ts (2)

76-77: Default limit handling looks good.

The logic correctly sets a default limit of 200 when not provided, preventing the validation error on line 79 from triggering unexpectedly.

Optional: Consider using nullish coalescing and a local variable

The || operator will treat explicit 0 as falsy and override it to 200. While this is unlikely to be a practical issue (0 doesn't make sense for pagination), the nullish coalescing operator (??) would be more precise. Additionally, using a local variable avoids mutating the request object:

-    req.limit = req.limit || 200;
+    const limit = req.limit ?? 200;

Then update the validation and usage:

-    if (req.limit > 200) {
+    if (limit > 200) {

And at line 97:

-      limit: req.limit,
+      limit: limit,

79-93: Consider improving the error message clarity.

The validation logic is correct, but the error message "Invalid limit" could be more descriptive to help API consumers understand the constraint.

Optional: More descriptive error message
-          details: 'Invalid limit',
+          details: 'Limit must not exceed 200',
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)

22-32: Pagination validation implemented correctly.

The defaulting and validation logic is sound. The function correctly defaults limit to 50 and validates it doesn't exceed 50.

Optional: Add validation for negative or zero limits

While the current defaulting prevents negative limits in practice, you could add an explicit check for completeness:

 req.limit = req.limit || 50;
-if (req.limit > 50) {
+if (req.limit <= 0 || req.limit > 50) {
   return {
     response: {
       code: EnumStatusCode.ERR,
       details: 'Invalid limit',
     },
     apiKeys: [],
     count: 0,
   };
 }
studio/src/pages/[organizationSlug]/apikeys.tsx (2)

714-725: Pagination query setup implemented correctly.

The page number and limit extraction from router query is well-implemented, with appropriate defaults and client-side limit capping.

Optional: Specify radix in parseInt

For clarity and to avoid edge cases, consider explicitly specifying the radix:

-const pageNumber = router.query.page ? parseInt(router.query.page as string) : 1;
+const pageNumber = router.query.page ? parseInt(router.query.page as string, 10) : 1;

769-769: Consider handling empty non-first pages.

The condition apiKeys.length === 0 && pageNumber === 1 correctly shows the empty state only on the first page. However, if a user navigates to a page that becomes empty (e.g., after deletion), they'll see an empty table rather than being redirected to a valid page.

This is acceptable current behavior, but you could enhance UX by redirecting to the last valid page when the current page is empty and pageNumber > 1:

useEffect(() => {
  if (apiKeys.length === 0 && pageNumber > 1 && noOfPages > 0) {
    router.push({
      pathname: router.pathname,
      query: { ...router.query, page: noOfPages },
    });
  }
}, [apiKeys.length, pageNumber, noOfPages, router]);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea29fed and 878e652.

⛔ Files ignored due to path filters (1)
  • connect-go/gen/proto/wg/cosmo/platform/v1/platform.pb.go is excluded by !**/*.pb.go, !**/gen/**
📒 Files selected for processing (12)
  • connect/src/wg/cosmo/platform/v1/platform_pb.ts
  • controlplane/src/core/bufservices/api-key/createAPIKey.ts
  • controlplane/src/core/bufservices/api-key/getAPIKeys.ts
  • controlplane/src/core/bufservices/check/getCheckOperations.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
  • controlplane/src/core/bufservices/federated-graph/getCompositions.ts
  • controlplane/src/core/bufservices/organization/getAuditLogs.ts
  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
  • controlplane/src/core/repositories/ApiKeyRepository.ts
  • proto/wg/cosmo/platform/v1/platform.proto
  • studio/src/pages/[organizationSlug]/apikeys.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-10T11:15:52.157Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/ProposalRepository.ts:562-572
Timestamp: 2025-09-10T11:15:52.157Z
Learning: The getLatestCheckForProposal function in controlplane/src/core/repositories/ProposalRepository.ts is only called during proposal creation or updates, so proposal match error checking (hasProposalMatchError) is not needed since the proposal is being modified itself rather than being matched against.

Applied to files:

  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
🧬 Code graph analysis (3)
controlplane/src/core/repositories/ApiKeyRepository.ts (4)
controlplane/src/types/index.ts (1)
  • APIKeyDTO (317-326)
controlplane/src/db/schema.ts (1)
  • apiKeys (1175-1205)
controlplane/src/core/repositories/SubgraphRepository.ts (1)
  • count (818-853)
controlplane/src/core/repositories/FederatedGraphRepository.ts (1)
  • count (557-572)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)
controlplane/src/db/schema.ts (1)
  • apiKeys (1175-1205)
studio/src/pages/[organizationSlug]/apikeys.tsx (7)
studio/src/components/group-select.tsx (1)
  • GroupSelect (8-70)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)
  • getAPIKeys (9-52)
controlplane/src/core/repositories/ApiKeyRepository.ts (1)
  • getAPIKeys (111-153)
controlplane/src/core/util.ts (1)
  • checkUserAccess (284-291)
controlplane/src/db/schema.ts (1)
  • apiKeys (1175-1205)
connect/src/wg/cosmo/platform/v1/platform_pb.ts (1)
  • Pagination (5857-5895)
connect-go/gen/proto/wg/cosmo/platform/v1/platform.pb.go (3)
  • Pagination (7076-7083)
  • Pagination (7098-7098)
  • Pagination (7113-7115)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build-router
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: build_test
  • GitHub Check: integration_test (./events)
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (13)
controlplane/src/core/bufservices/organization/getAuditLogs.ts (1)

57-69: LGTM! Default limit and validation implemented correctly.

The implementation properly defaults the limit to 50 when not provided and enforces the maximum bound, which aligns with the PR's DOS prevention objectives.

controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts (2)

98-99: LGTM: Default limit handling.

The default limit of 50 is correctly applied before validation, ensuring consistent pagination behavior when no limit is specified.


112-159: Include totalProposalsCount in the pagination response.

The getProposalChecks handler returns totalChecksCount for pagination support, but getProposalsByFederatedGraph omits a total count despite supporting paginated requests (limit/offset). The ProposalRepository.countByFederatedGraphId method exists and is used elsewhere (createProposal), so it should be called here to match pagination patterns across handlers and support client-side pagination calculations.

controlplane/src/core/bufservices/proposal/getProposalChecks.ts (2)

78-79: LGTM: Consistent default limit handling.

The default limit of 50 is correctly applied before validation, maintaining consistency with the pagination pattern used in getProposalsByFederatedGraph.


103-109: Good: Complete pagination response.

The response correctly includes totalChecksCount alongside the paginated results, enabling proper client-side pagination controls.

controlplane/src/core/bufservices/federated-graph/getCompositions.ts (1)

74-75: LGTM! Pagination defaults and validation added.

The defaulting of limit to 50 and the upper-bound validation are correctly implemented and consistent with the pagination pattern used throughout this PR.

proto/wg/cosmo/platform/v1/platform.proto (1)

1091-1099: LGTM! Pagination fields added to API Keys messages.

The protobuf definitions correctly add limit and offset to the request and count to the response, following standard pagination patterns.

controlplane/src/core/bufservices/api-key/createAPIKey.ts (1)

34-47: LGTM! API key limit enforcement added.

The pre-check correctly enforces a maximum of 200 API keys per organization, addressing the DoS risk mentioned in the PR objectives. The >= 200 check allows exactly 200 keys to be created while preventing the 201st, which is the intended behavior.

controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)

34-42: LGTM! Pagination implementation complete.

The function correctly fetches paginated API keys and the total count, returning both in the response as defined in the protobuf schema.

controlplane/src/core/repositories/ApiKeyRepository.ts (1)

155-165: LGTM! Total count method implemented correctly.

The getAPIKeysCount method is well-implemented, using the standard pattern of querying with count() and providing a sensible fallback.

studio/src/pages/[organizationSlug]/apikeys.tsx (2)

765-765: LGTM! Page count calculation is correct.

The calculation properly uses Math.ceil to handle partial pages and includes a fallback for undefined count.


931-935: LGTM! Pagination component integrated correctly.

The Pagination component is properly configured with the necessary props for page navigation.

connect/src/wg/cosmo/platform/v1/platform_pb.ts (1)

8175-8183: Generated code looks correct for pagination support.

This is auto-generated protobuf code, and the pagination fields (limit, offset on request; count on response) are correctly defined. The default value of 0 for limit means the service layer must handle this case by applying a sensible default limit to prevent unbounded queries.

Ensure the corresponding service implementation validates that limit > 0 (or applies a default) and that offset >= 0 before executing database queries.

Also applies to: 8228-8231

Copy link
Contributor

@wilsonrivera wilsonrivera left a comment

Choose a reason for hiding this comment

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

Can we clamp the limits instead of returning a failure? That way we can prevent negative values too

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)

25-33: Consider concurrent execution of queries.

The API keys fetch and count query execute sequentially. For better performance, consider running them concurrently using Promise.all.

🔎 Proposed optimization
-    const apiKeys = await apiKeyRepo.getAPIKeys({
-      organizationID: authContext.organizationId,
-      limit: req.limit,
-      offset: req.offset,
-    });
-
-    const count = await apiKeyRepo.getAPIKeysCount({
-      organizationID: authContext.organizationId,
-    });
+    const [apiKeys, count] = await Promise.all([
+      apiKeyRepo.getAPIKeys({
+        organizationID: authContext.organizationId,
+        limit: req.limit,
+        offset: req.offset,
+      }),
+      apiKeyRepo.getAPIKeysCount({
+        organizationID: authContext.organizationId,
+      }),
+    ]);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 878e652 and 377f77c.

📒 Files selected for processing (7)
  • controlplane/src/core/bufservices/api-key/getAPIKeys.ts
  • controlplane/src/core/bufservices/check/getCheckOperations.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
  • controlplane/src/core/bufservices/federated-graph/getCompositions.ts
  • controlplane/src/core/bufservices/organization/getAuditLogs.ts
  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • controlplane/src/core/bufservices/federated-graph/getCompositions.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
  • controlplane/src/core/bufservices/check/getCheckOperations.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-10T11:15:52.157Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/ProposalRepository.ts:562-572
Timestamp: 2025-09-10T11:15:52.157Z
Learning: The getLatestCheckForProposal function in controlplane/src/core/repositories/ProposalRepository.ts is only called during proposal creation or updates, so proposal match error checking (hasProposalMatchError) is not needed since the proposal is being modified itself rather than being matched against.

Applied to files:

  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
📚 Learning: 2025-08-29T10:28:04.846Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/SubgraphRepository.ts:1749-1751
Timestamp: 2025-08-29T10:28:04.846Z
Learning: In the controlplane codebase, authentication and authorization checks (including organization scoping) are handled at the service layer in files like unlinkSubgraph.ts before calling repository methods. Repository methods like unlinkSubgraph() in SubgraphRepository.ts can focus purely on data operations without redundant security checks.

Applied to files:

  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
🧬 Code graph analysis (3)
controlplane/src/core/bufservices/proposal/getProposalChecks.ts (1)
controlplane/src/core/util.ts (1)
  • clamp (543-545)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)
controlplane/src/db/schema.ts (1)
  • apiKeys (1175-1205)
controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts (1)
controlplane/src/core/util.ts (1)
  • clamp (543-545)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build-router
  • GitHub Check: build_test
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_test
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: image_scan
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
controlplane/src/core/bufservices/organization/getAuditLogs.ts (1)

12-12: LGTM! Unified limit handling.

The addition of the clamp utility import aligns with the PR objective to standardize limit handling across services.

controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts (1)

12-12: LGTM! Import addition supports new pagination logic.

The clamp import is correctly added to support the limit handling introduced on line 99.

controlplane/src/core/bufservices/proposal/getProposalChecks.ts (1)

11-11: LGTM! Import is necessary for the clamping logic.

The addition of the clamp import is correct and required for the limit handling introduced on line 79.

controlplane/src/core/bufservices/api-key/getAPIKeys.ts (3)

7-7: LGTM: Import added for clamp utility.

The clamp function import is correctly added to support the new limit validation logic.


23-23: LGTM: Limit clamping logic is correct.

The clamp implementation correctly defaults to 10 when no limit is provided and constrains the value between 1 and 50, preventing both empty results and excessive queries.


35-41: LGTM: Response structure correctly includes count.

The response properly returns both the paginated API keys and the total count, enabling proper pagination UI implementation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
controlplane/src/core/bufservices/organization/getAuditLogs.ts (1)

12-12: DoS prevention logic is sound; consider the mutation pattern.

The clamp-based limit handling effectively prevents DoS by defaulting to 10 and constraining to [1, 50]. The typo mentioned in the past review has been corrected.

However, the pattern of mutating req.limit directly (rather than using a local variable) persists. While this works in the current context, it could have unintended side effects if the request object is reused elsewhere. This pattern is consistent across the PR, so if you choose to refactor, consider applying the change uniformly.

📝 Example refactor using a local variable
-    // default to 10 if no limit is provided
-    req.limit = clamp(req.limit || 10, 1, 50);
+    // default to 10 if no limit is provided
+    const limit = clamp(req.limit || 10, 1, 50);

     const auditLogs = await auditLogRepo.getAuditLogs({
       organizationId: authContext.organizationId,
-      limit: req.limit,
+      limit,
       offset: req.offset,

Also applies to: 57-58

controlplane/src/core/bufservices/federated-graph/getCompositions.ts (1)

13-13: Consistent and effective limit handling.

The clamp implementation correctly prevents DoS by defaulting to 10 and bounding to [1, 50]. The logic is sound and consistent with the pagination pattern across the PR.

As with getAuditLogs.ts, consider using a local variable instead of mutating req.limit directly to avoid potential side effects if the request object is reused.

📝 Example refactor using a local variable
-    // default to 10 if no limit is provided
-    req.limit = clamp(req.limit || 10, 1, 50);
+    // default to 10 if no limit is provided
+    const limit = clamp(req.limit || 10, 1, 50);

     const compositions = await graphCompositionRepository.getGraphCompositions({
       fedGraphTargetId: federatedGraph.targetId,
       organizationId: authContext.organizationId,
-      limit: req.limit,
+      limit,
       offset: req.offset,

Also applies to: 74-75

controlplane/src/core/bufservices/check/getCheckOperations.ts (1)

13-13: Effective limit handling with appropriate bounds for operations.

The clamp implementation correctly prevents DoS by defaulting to 10 and bounding to [1, 200]. The higher maximum limit (200 vs. 50 in audit logs and compositions) is appropriate given that check operations typically involve larger datasets.

As with the other pagination handlers, consider using a local variable instead of mutating req.limit directly to maintain request object immutability.

📝 Example refactor using a local variable
-    // default to 10 if no limit is provided
-    req.limit = clamp(req.limit || 10, 1, 200);
+    // default to 10 if no limit is provided
+    const limit = clamp(req.limit || 10, 1, 200);

     const affectedOperations = await schemaCheckRepo.getAffectedOperationsByCheckId({
       checkId: req.checkId,
-      limit: req.limit,
+      limit,
       offset: req.offset,

Also applies to: 76-77

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 377f77c and 70444ba.

📒 Files selected for processing (7)
  • controlplane/src/core/bufservices/api-key/getAPIKeys.ts
  • controlplane/src/core/bufservices/check/getCheckOperations.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
  • controlplane/src/core/bufservices/federated-graph/getCompositions.ts
  • controlplane/src/core/bufservices/organization/getAuditLogs.ts
  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/api-key/getAPIKeys.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-19T11:26:26.657Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2331
File: studio/src/components/operations/client-usage-table.tsx:65-65
Timestamp: 2025-11-19T11:26:26.657Z
Learning: In the Cosmo studio codebase (studio/src/components/operations/client-usage-table.tsx), converting BigInt request counts from the API to Number is acceptable because request counts are not expected to exceed JavaScript's safe integer limit (2^53 - 1).

Applied to files:

  • controlplane/src/core/bufservices/check/getCheckOperations.ts
📚 Learning: 2025-08-29T10:28:04.846Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/SubgraphRepository.ts:1749-1751
Timestamp: 2025-08-29T10:28:04.846Z
Learning: In the controlplane codebase, authentication and authorization checks (including organization scoping) are handled at the service layer in files like unlinkSubgraph.ts before calling repository methods. Repository methods like unlinkSubgraph() in SubgraphRepository.ts can focus purely on data operations without redundant security checks.

Applied to files:

  • controlplane/src/core/bufservices/check/getCheckOperations.ts
🧬 Code graph analysis (1)
controlplane/src/core/bufservices/check/getCheckOperations.ts (1)
controlplane/src/core/util.ts (1)
  • clamp (543-545)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: build-router
  • GitHub Check: build_push_image
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: build_test
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: integration_test (./events)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
controlplane/test/fetch-checks-by-federated-graph.test.ts (1)

224-242: Consider publishing an initial schema before running checks.

The test creates 51 checks without first publishing a baseline schema to the subgraph. Other tests in this file follow the pattern of publishing a schema first (e.g., lines 73-80, 176-182, 365-379), then running additional checks against that baseline. While checkSubgraphSchema may work without a prior publish, adding an initial publish would:

  • Ensure consistency with the established test pattern
  • Provide a clear baseline for the checks to validate against
  • Reduce the risk of unexpected behavior in check recording
🔎 Suggested addition
 expect(createSubgraphResp.response?.code).toBe(EnumStatusCode.OK);

+// Publish an initial schema to establish a baseline
+const initialPublishResp = await client.publishFederatedSubgraph({
+  name: subgraphName,
+  namespace: DEFAULT_NAMESPACE,
+  schema: 'type Query { initial: String }',
+});
+
+expect(initialPublishResp.response?.code).toBe(EnumStatusCode.OK);
+
 // Create 51 checks
 for (let i = 0; i < 51; i++) {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70444ba and 75ae331.

📒 Files selected for processing (1)
  • controlplane/test/fetch-checks-by-federated-graph.test.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-08T20:57:07.946Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/SubgraphRepository.ts:1746-1763
Timestamp: 2025-09-08T20:57:07.946Z
Learning: The checkSubgraphSchema.ts file already correctly implements linked subgraph functionality, using byName(linkedSubgraph.name, linkedSubgraph.namespace) to fetch target subgraphs and properly handles parse(newSchemaSDL) for schema building. The implementation doesn't need fixes for byId usage or schema parsing as it's already correct.

Applied to files:

  • controlplane/test/fetch-checks-by-federated-graph.test.ts
📚 Learning: 2025-08-29T10:28:04.846Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/SubgraphRepository.ts:1749-1751
Timestamp: 2025-08-29T10:28:04.846Z
Learning: In the controlplane codebase, authentication and authorization checks (including organization scoping) are handled at the service layer in files like unlinkSubgraph.ts before calling repository methods. Repository methods like unlinkSubgraph() in SubgraphRepository.ts can focus purely on data operations without redundant security checks.

Applied to files:

  • controlplane/test/fetch-checks-by-federated-graph.test.ts
🧬 Code graph analysis (1)
controlplane/test/fetch-checks-by-federated-graph.test.ts (2)
controlplane/src/core/test-util.ts (1)
  • genID (53-55)
controlplane/test/test-util.ts (1)
  • DEFAULT_NAMESPACE (52-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build-router
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: integration_test (./events)
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
controlplane/test/fetch-checks-by-federated-graph.test.ts (2)

234-242: The identical schemas are acceptable for limit testing.

All 51 checks use the same schema (type Query { a: String }). While this is sufficient for testing the limit clamping behavior, varying the schemas slightly (e.g., adding an index to field names) could make the test more representative of real-world usage. However, for the specific purpose of validating pagination limits, the current approach is adequate.


247-278: LGTM! Limit clamping logic is correctly validated.

The test properly validates the new limit clamping behavior:

  • Limits exceeding 50 are accepted and return a successful response (line 260)
  • Results are correctly clamped to 50 items (line 262)
  • Valid limit values work as expected (line 278)

This aligns with the PR objective to add pagination and limit handling with clamping instead of hard rejections.

Copy link

@coderabbitai coderabbitai bot left a comment

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 (2)
controlplane/src/core/bufservices/api-key/getAPIKeys.ts (1)

27-35: LGTM! Pagination implementation follows standard patterns.

The paginated fetch and separate count retrieval are correctly implemented and scoped to the organization. This two-query approach is a common pagination pattern.

Optional consideration: If the count query becomes expensive at scale, consider caching the total count or using database-level optimizations (e.g., indexed count queries). Monitor query performance as the number of API keys grows.

controlplane/src/core/bufservices/federated-graph/getCompositions.ts (1)

74-76: Enhance the comment to document both pagination parameters and clamping bounds.

The comment on line 74 only mentions the default limit but doesn't describe the offset default or the clamping ranges for both parameters. Updating it would improve clarity:

-    // default to 10 if no limit is provided
+    // Clamp pagination: limit defaults to 10 [1-50], offset defaults to 0 [0-500000]
     req.limit = clamp(req.limit || 10, 1, 50);
     req.offset = clamp(req.offset || 0, 0, 500_000);

This pattern is consistent across other pagination handlers in bufservices (getAuditLogs, getProposalChecks, getChecksByFederatedGraphName, etc.), with the offset bound intentionally set to prevent database performance degradation from excessively large offsets.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75ae331 and 31657a5.

📒 Files selected for processing (7)
  • controlplane/src/core/bufservices/api-key/getAPIKeys.ts
  • controlplane/src/core/bufservices/check/getCheckOperations.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
  • controlplane/src/core/bufservices/federated-graph/getCompositions.ts
  • controlplane/src/core/bufservices/organization/getAuditLogs.ts
  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • controlplane/src/core/bufservices/proposal/getProposalsByFederatedGraph.ts
  • controlplane/src/core/bufservices/check/getChecksByFederatedGraphName.ts
  • controlplane/src/core/bufservices/proposal/getProposalChecks.ts
  • controlplane/src/core/bufservices/check/getCheckOperations.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: build-router
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: integration_test (./events)
  • GitHub Check: build_push_image
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (5)
controlplane/src/core/bufservices/organization/getAuditLogs.ts (1)

57-59: Good DoS prevention with pagination bounds.

The clamping logic correctly prevents DoS attacks by limiting both limit to [1, 50] and offset to [0, 500_000]. The addition of offset clamping (line 59) is a solid improvement.

I notice the mutation approach for req.limit and req.offset was retained despite the previous suggestion to use local variables. Given the earlier feedback that "either approach works", this is fine—just wanted to confirm this was the intended resolution.

controlplane/src/core/bufservices/api-key/getAPIKeys.ts (3)

7-7: LGTM! Clamp utility correctly imported.

The clamp utility is properly imported and used for enforcing pagination bounds.


22-23: LGTM! Limit validation is correct.

The default value of 10 and bounds [1, 50] are sensible for API key pagination.


37-43: LGTM! Response structure correctly includes pagination metadata.

The response properly includes both the paginated apiKeys and the count, enabling client-side pagination controls.

controlplane/src/core/bufservices/federated-graph/getCompositions.ts (1)

13-13: LGTM! Import addition supports the pagination clamping logic.

The clamp import is necessary for the new pagination bounds enforcement on lines 75-76.

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.

3 participants