Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add permissions for ratelimit overrides #2126

Open
wants to merge 56 commits into
base: main
Choose a base branch
from

Conversation

MichaelUnkey
Copy link
Collaborator

@MichaelUnkey MichaelUnkey commented Sep 23, 2024

What does this PR do?

Fixes # (issue)
eng-1336

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

Check if I understood the assignment properly.

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced API routes for managing rate limit overrides:
      • Delete Override: /v1/ratelimit.deleteOverride
      • List Overrides: /v1/ratelimit.listOverrides
      • Set Override: /v1/ratelimit.setOverride
      • Get Override: /v1/ratelimit.getOverride
    • Added permissions for managing rate limit overrides in the dashboard.
  • Bug Fixes

    • Enhanced error handling for missing parameters in API requests.
  • Tests

    • Added comprehensive test coverage for the new rate limit override functionalities, including success and error scenarios.

Copy link

linear bot commented Sep 23, 2024

Copy link

changeset-bot bot commented Sep 23, 2024

⚠️ No Changeset found

Latest commit: 754b87b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

vercel bot commented Sep 23, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
dashboard ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 15, 2024 1:45pm
engineering ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 15, 2024 1:45pm
planetfall ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 15, 2024 1:45pm
play ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 15, 2024 1:45pm
unkey-engineering ❌ Failed (Inspect) Nov 15, 2024 1:45pm
www ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 15, 2024 1:45pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
workflows ⬜️ Ignored (Inspect) Visit Preview Nov 15, 2024 1:45pm

Copy link
Contributor

coderabbitai bot commented Sep 23, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

This pull request introduces several new API routes and corresponding functionalities for managing rate limit overrides in the application. The new routes include the ability to delete, list, set, and get rate limit overrides, all requiring bearer authentication. Additionally, several permissions related to these operations are added to the workspace permissions structure. The changes also include updates to audit logging and various test cases to ensure the proper functioning and security of the new features.

Changes

File Path Change Summary
apps/api/src/routes/v1_ratelimit_deleteOverride.ts Introduced a POST endpoint for deleting rate limit overrides at /v1/ratelimit.deleteOverride, requiring specific request body properties.
apps/api/src/routes/v1_ratelimit_listOverrides.ts Implemented a GET endpoint for listing rate limit overrides at /v1/ratelimit.listOverrides, accepting query parameters and returning a paginated response.
apps/api/src/routes/v1_ratelimit_setOverride.ts Created a POST endpoint for setting rate limit overrides at /v1/ratelimit.setOverride, including validation and transaction management.
apps/api/src/routes/v1_ratelimit_getOverride.ts Added a GET endpoint for retrieving specific rate limit overrides at /v1/ratelimit.getOverride, requiring query parameters for identification.
apps/api/src/worker.ts Registered new route functions for the rate limiting features.
apps/dashboard/app/(app)/settings/root-keys/[keyId]/permissions/permissions.ts Added new permissions (set_override, read_override, delete_override) under the Ratelimit category.
internal/schema/src/auditlog.ts Updated unkeyAuditLogEvents enum to remove old event types and add new ones for rate limit actions.
packages/api/src/client.ts Introduced a commented-out method setOverride for handling POST requests to the new endpoint.
apps/api/src/routes/v1_ratelimit_deleteOverride.happy.test.ts Added unit tests for the deletion of rate limit overrides.
apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts Implemented unit tests for retrieving rate limit overrides.
apps/api/src/routes/v1_ratelimit_listOverrides.happy.test.ts Created unit tests for listing rate limit overrides with various scenarios.
apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts Added tests for setting and updating rate limit overrides.
apps/api/src/routes/v1_ratelimit_deleteOverride.error.test.ts Introduced error handling tests for the deletion endpoint.
apps/api/src/routes/v1_ratelimit_deleteOverride.security.test.ts Added security tests for role-based access control on the deletion endpoint.
apps/api/src/routes/v1_ratelimit_getOverride.error.test.ts Created error handling tests for the retrieval endpoint.
apps/api/src/routes/v1_ratelimit_getOverride.security.test.ts Introduced security tests for the retrieval endpoint.
apps/api/src/routes/v1_ratelimit_listOverrides.error.test.ts Added error handling tests for the listing endpoint.
apps/api/src/routes/v1_ratelimit_listOverrides.security.test.ts Implemented security tests for the listing endpoint.
apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts Created error handling tests for setting overrides.
apps/api/src/routes/v1_ratelimit_setOverride.security.test.ts Added security tests for the set override endpoint.

Possibly related PRs

Suggested labels

Feature, Dashboard, 🕹️ oss.gg, :joystick: 300 points

Suggested reviewers

  • chronark
  • mcstepp
  • perkinsjr

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

github-actions bot commented Sep 23, 2024

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

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

🧹 Outside diff range and nitpick comments (15)
apps/api/src/pkg/analytics.ts (1)

Line range hint 13-23: Consider extracting the schema for reusability and adding constraints.

The implementation looks good and follows best practices with proper schema validation. However, there are some potential improvements:

  1. Consider extracting the schema into a separate constant for reuse across the codebase
  2. Add constraints for field validation (e.g., max length for strings, time range validation)
  3. Consider making the schema extensible with optional fields for future telemetry data

Example refactor:

+const sdkTelemetrySchema = z.object({
+  request_id: z.string().max(100),
+  time: z.number().int().min(0),
+  runtime: z.string().max(50),
+  platform: z.string().max(50),
+  versions: z.array(z.string().max(20)).max(10),
+  // Optional fields for future use
+  metadata: z.record(z.string(), z.unknown()).optional(),
+});

 public get insertSdkTelemetry() {
   return this.clickhouse.client.insert({
     table: "telemetry.raw_sdks_v1",
-    schema: z.object({
-      request_id: z.string(),
-      time: z.number().int(),
-      runtime: z.string(),
-      platform: z.string(),
-      versions: z.array(z.string()),
-    }),
+    schema: sdkTelemetrySchema,
   });
 }
🧰 Tools
🪛 Biome

[error] 41-41: expected } but instead the file ends

the file ends here

(parse)

apps/api/src/routes/v1_ratelimit_listOverrides.happy.test.ts (5)

8-8: Test description could be more specific.

Consider renaming the test to better describe the scenario being tested, e.g., "should return all overrides for given namespace and identifier".


16-33: Consider extracting test data setup.

The namespace and override creation logic could be moved to a helper function for better reusability across tests.

async function createTestNamespaceWithOverride(h: IntegrationHarness) {
  const namespaceId = newId("test");
  const namespaceName = "test.Name";
  const overrideId = newId("test");
  const identifier = randomUUID();

  await h.db.primary.insert(schema.ratelimitNamespaces).values({
    id: namespaceId,
    name: namespaceName,
    workspaceId: h.resources.userWorkspace.id,
    createdAt: new Date(),
  });

  await h.db.primary.insert(schema.ratelimitOverrides).values({
    id: overrideId,
    workspaceId: h.resources.userWorkspace.id,
    namespaceId: namespaceId,
    identifier: identifier,
    limit: 1,
    duration: 60_000,
    async: false,
  });

  return { namespaceId, namespaceName, overrideId, identifier };
}

31-31: Consider using a named constant for duration.

The magic number 60_000 would be clearer as a named constant, e.g., const ONE_MINUTE_MS = 60_000.


42-42: Improve error message specificity.

The error message could be more specific about what failed in the request.

-expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200);
+expect(res.status, `List overrides request failed with status ${res.status}. Response: ${JSON.stringify(res, null, 2)}`).toBe(200);

43-45: Enhance assertion coverage.

The test only validates the ID and identifier of the override. Consider adding assertions for other important properties like limit, duration, and async.

 expect(res.body.total).toBe(1);
 expect(res.body.overrides[0].id).toEqual(overrideId);
 expect(res.body.overrides[0].identifier).toEqual(identifier);
+expect(res.body.overrides[0].limit).toEqual(1);
+expect(res.body.overrides[0].duration).toEqual(60_000);
+expect(res.body.overrides[0].async).toEqual(false);
apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (3)

25-25: Remove debug console.log statement

Debug logging statements should be removed from test files to maintain clean test output.

- console.log(namespaceRes);

27-35: Consider extracting test constants

The hardcoded values for limit, duration, and async flag could be extracted into named constants at the top of the file. This would make the test more maintainable and the values' purposes more explicit.

+const TEST_RATE_LIMIT = 1;
+const TEST_DURATION_MS = 60_000;
+const TEST_ASYNC = false;

 await h.db.primary.insert(schema.ratelimitOverrides).values({
   id: overrideId,
   workspaceId: h.resources.userWorkspace.id,
   namespaceId: namespaceId,
   identifier: identifier,
-  limit: 1,
-  duration: 60_000,
-  async: false,
+  limit: TEST_RATE_LIMIT,
+  duration: TEST_DURATION_MS,
+  async: TEST_ASYNC,
 });

43-43: Remove debug console.log statement

Debug logging statements should be removed from test files to maintain clean test output.

- console.log(res);
apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts (2)

33-37: Enhance namespace verification coverage.

The test only verifies the namespace ID. Consider verifying other fields like workspaceId, name, and createdAt for more comprehensive testing.

  expect(namespaceRes?.id).toBe(namespaceId);
+ expect(namespaceRes?.workspaceId).toBe(h.resources.userWorkspace.id);
+ expect(namespaceRes?.name).toBe(namespace.name);
+ expect(namespaceRes?.createdAt).toEqual(namespace.createdAt);

39-45: Use named constants for duration values.

The test uses magic numbers (6500, 50000) for duration values. Consider using named constants to make the test more maintainable and self-documenting.

+ const INITIAL_DURATION_MS = 6500;
+ const UPDATED_DURATION_MS = 50000;

  const override = {
    namespaceId: namespaceId,
    identifier: identifier,
    limit: 10,
-   duration: 6500,
+   duration: INITIAL_DURATION_MS,
    async: true,
  };

  // ... later in the code ...

  body: {
    namespaceId: namespaceId,
    identifier: identifier,
    limit: 10,
-   duration: 50000,
+   duration: UPDATED_DURATION_MS,
    async: true,
  },

Also applies to: 74-80

apps/api/src/routes/v1_ratelimit_getOverride.ts (4)

25-29: Add validation for wildcard patterns in identifier.

The description mentions support for wildcards (*) but there's no validation to ensure proper wildcard pattern format.

Consider adding a regex pattern validation:

       identifier: z.string().openapi({
+        pattern: "^[a-zA-Z0-9_*]+$",
         description:
           "Identifier of your user, this can be their userId, an email, an ip or anything else. Wildcards ( * ) can be used to match multiple identifiers, More info can be found at https://www.unkey.com/docs/ratelimiting/overrides#wildcard-rules",
         example: "user_123",
       }),

42-42: Document the purpose of the async field.

The response schema includes an optional async field but its purpose and usage aren't documented.

Add a description in the OpenAPI schema:

-            async: z.boolean().nullable().optional(),
+            async: z.boolean().nullable().optional().openapi({
+              description: "When true, indicates that rate limit checks are performed asynchronously",
+            }),

91-93: Improve error message clarity.

The error message construction could be clearer about which identifier was not found.

-      throw new Error(`Namespace ${namespaceId ? namespaceId : namespaceName} not found`);
+      throw new UnkeyApiError({
+        code: "NOT_FOUND",
+        message: `Namespace not found: ${namespaceId ? `id=${namespaceId}` : `name=${namespaceName}`}`,
+      });

109-115: Consider adding telemetry for rate limit override access.

For better observability, consider tracking access to rate limit overrides.

Add telemetry tracking before returning the response:

+    await c.get("services").analytics.track({
+      event: "ratelimit.override.accessed",
+      workspaceId: authorizedWorkspaceId,
+      properties: {
+        overrideId: override.id,
+        namespaceId: override.namespaceId,
+      },
+    });
+
     return c.json({
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6d390a4 and 45f2732.

📒 Files selected for processing (8)
  • apps/api/src/pkg/analytics.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts (1 hunks)
  • apps/api/src/worker.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.happy.test.ts
  • apps/api/src/routes/v1_ratelimit_listOverrides.ts
  • apps/api/src/worker.ts
🧰 Additional context used
🪛 Biome
apps/api/src/pkg/analytics.ts

[error] 41-41: expected } but instead the file ends

the file ends here

(parse)

🔇 Additional comments (7)
apps/api/src/routes/v1_ratelimit_listOverrides.happy.test.ts (2)

1-7: LGTM! Well-structured imports.

The imports are well-organized, using native Node.js modules and proper type imports.


10-10: Review permission scope.

The permission "ratelimit.*.read_override" uses a wildcard which might be too permissive. Consider if a more specific scope would be more appropriate for the test.

✅ Verification successful

Permission scope is appropriate.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of this permission to understand the intended scope
rg -A 2 "ratelimit\.\*\.read_override"

Length of output: 2265


Script:

#!/bin/bash
# Search for the definition or creation of the "ratelimit.*.read_override" permission
rg '"ratelimit\.\*\.read_override"'

Length of output: 757

apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (1)

1-7: LGTM: Imports are well-organized and complete

All necessary dependencies and types are properly imported.

apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts (2)

1-11: LGTM! Well-structured imports and type declarations.

The imports are properly organized and include all necessary dependencies for testing.


57-57: Rename unclear variable.

The variable name resInit is unclear. Consider a more descriptive name like initialOverride or createdOverride.

apps/api/src/routes/v1_ratelimit_getOverride.ts (2)

1-7: LGTM! All necessary imports are present and well-organized.

The imports cover all required functionality including authentication, error handling, OpenAPI/Zod integration, and database operations.


51-55: LGTM! Type exports are well-defined.

The types are properly inferred from Zod schemas and follow TypeScript best practices.

apps/api/src/pkg/analytics.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_getOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_getOverride.ts Outdated Show resolved Hide resolved
Copy link
Contributor

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

🧹 Outside diff range and nitpick comments (18)
apps/api/src/routes/v1_ratelimit_getOverride.error.test.ts (2)

8-33: Consider improving test maintainability with constants and helpers.

While the test setup is thorough, consider these improvements:

  1. Extract the permission string into a constant
  2. Make the rate limit values more explicit
  3. Consider moving the test data setup into a reusable helper
+const RATELIMIT_READ_PERMISSION = "ratelimit.*.read_override";
+const DEFAULT_RATE_LIMIT = 1;
+const ONE_MINUTE_MS = 60_000;
+
 test("Missing Namespace", async (t) => {
   const h = await IntegrationHarness.init(t);
-  const root = await h.createRootKey(["ratelimit.*.read_override"]);
+  const root = await h.createRootKey([RATELIMIT_READ_PERMISSION]);
   // ... other setup code ...
   await h.db.primary.insert(schema.ratelimitOverrides).values({
     id: overrideId,
     workspaceId: h.resources.userWorkspace.id,
     namespaceId: namespaceId,
     identifier: identifier,
-    limit: 1,
-    duration: 60_000,
+    limit: DEFAULT_RATE_LIMIT,
+    duration: ONE_MINUTE_MS,
     async: false,
   });

34-48: Consider adding test coverage for namespaceName parameter.

Since the error message mentions "You must provide a namespaceId or a namespaceName", consider adding test cases for:

  1. Empty namespaceName
  2. Both namespaceId and namespaceName empty
  3. Both parameters present but invalid

Would you like me to help generate these additional test cases?

apps/api/src/routes/v1_ratelimit_listOverrides.error.test.ts (2)

8-8: Consider a more descriptive test name

The test name could be more specific about what's being tested, e.g., "should return 400 when both namespaceId and namespaceName are missing".


42-49: Consider using a constant for the docs URL

The hardcoded docs URL "https://unkey.dev/docs/api-reference/errors/code/BAD_REQUEST" could be problematic if the documentation structure changes. Consider extracting this to a shared constant.

+ // In a shared constants file
+ export const ERROR_DOCS_BASE_URL = "https://unkey.dev/docs/api-reference/errors/code";
+ 
  expect(res.body).toMatchObject({
    error: {
      code: "BAD_REQUEST",
-     docs: "https://unkey.dev/docs/api-reference/errors/code/BAD_REQUEST",
+     docs: `${ERROR_DOCS_BASE_URL}/BAD_REQUEST`,
      message: "You must provide a namespaceId or a namespaceName",
    },
  });
apps/api/src/routes/v1_ratelimit_deleteOverride.error.test.ts (1)

13-36: Consider improving test data setup for better maintainability

While the setup is functional, consider these improvements:

  1. Extract magic numbers into named constants (e.g., DEFAULT_RATE_LIMIT = 1, ONE_MINUTE_MS = 60_000)
  2. Consider moving the test data setup into a helper function for reuse
  3. Add a comment explaining the significance of the async flag

Example refactor:

+const DEFAULT_RATE_LIMIT = 1;
+const ONE_MINUTE_MS = 60_000;
+
+async function setupTestOverride(h: IntegrationHarness) {
+  const overrideId = newId("test");
+  const identifier = randomUUID();
+  const namespaceId = newId("test");
+  
+  // Setup namespace
+  const namespace = {
+    id: namespaceId,
+    workspaceId: h.resources.userWorkspace.id,
+    createdAt: new Date(),
+    name: "namespace",
+  };
+  await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
+
+  // Setup override with default rate limiting
+  await h.db.primary.insert(schema.ratelimitOverrides).values({
+    id: overrideId,
+    workspaceId: h.resources.userWorkspace.id,
+    namespaceId,
+    identifier,
+    limit: DEFAULT_RATE_LIMIT,
+    duration: ONE_MINUTE_MS,
+    async: false, // Synchronous rate limiting for predictable test behavior
+  });
+
+  return { overrideId, identifier, namespaceId };
+}
apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts (2)

13-47: Improve test robustness and permission naming consistency.

  1. The permission string has inconsistent casing. It should be ratelimit.*.set_override to match the conventional snake_case format.
  2. Consider adding a database check to verify the namespace doesn't exist before making the request.
 const root = await h.createRootKey([
   "*",
-  "ratelimit.*.set_Override",
+  "ratelimit.*.set_override",
   "ratelimit.*.create_namespace",
   "ratelimit.*.read_override",
 ]);
+
+// Verify namespace doesn't exist
+const namespace = await h.db.primary.query.ratelimitNamespaces.findFirst({
+  where: (table, { eq }) => eq(table.id, namespaceId),
+});
+expect(namespace).toBeNull();

1-97: Consider adding more error test cases.

The current test file only covers two error scenarios. Consider adding tests for:

  1. Invalid duration (negative or zero)
  2. Invalid limit (negative or zero)
  3. Missing or insufficient permissions
  4. Invalid async flag value

Would you like me to help generate these additional test cases?

apps/api/src/routes/v1_ratelimit_getOverride.ts (1)

8-49: Consider adding additional validation rules to the schema.

While the schema is well-documented, consider adding these validations for better input handling:

  • namespaceId: Add pattern validation for the rlns_ prefix
  • limit and duration: Add minimum value constraints (e.g., > 0)
  • identifier: Add maximum length constraint
 request: {
   query: z.object({
     namespaceId: z.string()
+      .regex(/^rlns_[a-zA-Z0-9]+$/, 'Must start with rlns_')
       .optional()
       .openapi({
         description: "The id of the namespace.",
         example: "rlns_1234",
       }),
     // ... other fields ...
     identifier: z.string()
+      .max(255, 'Identifier too long')
       .openapi({
         description: // ...
       }),
   }),
 },
 responses: {
     // ... 
     schema: z.object({
       // ...
-      limit: z.number().int(),
-      duration: z.number().int(),
+      limit: z.number().int().positive(),
+      duration: z.number().int().positive(),
       // ...
     }),
   },
 },
apps/api/src/routes/v1_ratelimit_listOverrides.security.test.ts (2)

12-42: Consider extracting test data setup to reduce duplication.

The test data setup logic is duplicated across different test suites. Consider extracting it into a helper function.

Example refactor:

async function setupTestData(rh: IntegrationHarness) {
  const overrideId = newId("test");
  const identifier = randomUUID();
  const namespaceId = newId("test");
  const namespace = {
    id: namespaceId,
    workspaceId: rh.resources.userWorkspace.id,
    createdAt: new Date(),
    name: "namespace",
  };
  
  await rh.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
  await rh.db.primary.insert(schema.ratelimitOverrides).values({
    id: overrideId,
    workspaceId: rh.resources.userWorkspace.id,
    namespaceId,
    identifier,
    limit: 1,
    duration: 60_000,
    async: false,
  });
  
  return { namespaceId, overrideId, identifier };
}

29-31: Consider using constants for rate limit values.

Magic numbers are used for rate limit values. Consider extracting these into named constants for better maintainability.

Example:

const TEST_RATE_LIMIT = {
  LIMIT: 1,
  DURATION_MS: 60_000,
};
apps/api/src/routes/v1_ratelimit_getOverride.security.test.ts (3)

12-42: Consider extracting test data setup to reduce duplication.

The test data setup logic is duplicated across different test sections. Consider extracting it into a helper function to improve maintainability.

async function setupTestData(h: IntegrationHarness) {
  const overrideId = newId("test");
  const identifier = randomUUID();
  const namespaceId = newId("test");
  const namespace = {
    id: namespaceId,
    workspaceId: h.resources.userWorkspace.id,
    createdAt: new Date(),
    name: "namespace",
  };
  
  await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
  await h.db.primary.insert(schema.ratelimitOverrides).values({
    id: overrideId,
    workspaceId: h.resources.userWorkspace.id,
    namespaceId,
    identifier,
    limit: 1,
    duration: 60_000,
    async: false,
  });
  
  return { namespaceId, identifier };
}

30-30: Consider using a named constant for the duration value.

The magic number 60_000 would be more maintainable as a named constant that clearly indicates it represents one minute in milliseconds.

const ONE_MINUTE_MS = 60_000;

1-11: Consider adding tests for invalid input scenarios.

The test file would benefit from additional test cases covering:

  • Invalid namespace IDs
  • Malformed identifiers
  • Missing query parameters
  • Invalid content types

Also, consider adding JSDoc comments to describe the test suite's purpose and requirements.

/**
 * Security tests for the rate limit override endpoint.
 * 
 * These tests verify:
 * - Role-based access control
 * - Input validation
 * - Error handling
 * 
 * Required permissions:
 * - ratelimit.*.read_override
 */
apps/api/src/routes/v1_ratelimit_setOverride.security.test.ts (2)

12-46: Consider enhancing test coverage for edge cases.

While the basic setup is good, consider adding tests for:

  1. Different duration values (especially edge cases)
  2. The implications of the async flag
  3. Validation that the namespace was created correctly before proceeding
 const override = {
   namespaceId: namespaceId,
   identifier: identifier,
-  limit: 10,
-  duration: 6500,
+  limit: 10,
+  duration: 60_000, // Use a more standard duration value
   async: true,
 };
+
+// Add validation
+const createdNamespace = await rh.db.primary.query.ratelimitNamespaces.findFirst({
+  where: (table, { eq }) => eq(table.id, namespaceId),
+});
+if (!createdNamespace) {
+  throw new Error("Failed to create test namespace");
+}

47-111: Enhance test assertions and use constants for better maintainability.

The test coverage for successful operations is good, but consider these improvements:

  1. Use constants for magic numbers (limit: 1, limit: 7, duration: 60_000)
  2. Add assertions for all override properties, not just the limit
  3. Add test cases for concurrent updates to verify race conditions
+const TEST_CONSTANTS = {
+  INITIAL_LIMIT: 1,
+  UPDATED_LIMIT: 7,
+  DURATION: 60_000,
+} as const;

 test("returns 200", async (t) => {
   // ... existing setup ...
   body: {
     namespaceId,
     identifier,
-    limit: 1,
-    duration: 60_000,
+    limit: TEST_CONSTANTS.INITIAL_LIMIT,
+    duration: TEST_CONSTANTS.DURATION,
     async: false,
   },
 });

 // Add more comprehensive assertions
 expect(found?.limit).toEqual(7);
+expect(found?.duration).toEqual(TEST_CONSTANTS.DURATION);
+expect(found?.async).toEqual(false);
+expect(found?.namespaceId).toEqual(namespaceId);
+expect(found?.identifier).toEqual(identifier);
apps/api/src/routes/v1_ratelimit_deleteOverride.security.test.ts (3)

12-46: Consider enhancing test data setup.

While the setup is functional, consider these improvements:

  1. Extract magic numbers into named constants (e.g., DEFAULT_DURATION_MS = 60_000)
  2. Consider parameterizing the test data values (limit, duration, async) for better test coverage
  3. Ensure proper cleanup of test data after tests
+const DEFAULT_DURATION_MS = 60_000;
+const DEFAULT_LIMIT = 1;
+
 runCommonRouteTests<V1RatelimitDeleteOverrideRequest>({
   prepareRequest: async (rh) => {
     const overrideId = newId("test");
     const identifier = randomUUID();
     const namespaceId = newId("test");
     const namespace = {
       id: namespaceId,
       workspaceId: rh.resources.userWorkspace.id,
       createdAt: new Date(),
       name: "namespace",
     };
     await rh.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
     await rh.db.primary.insert(schema.ratelimitOverrides).values({
       id: overrideId,
       workspaceId: rh.resources.userWorkspace.id,
       namespaceId,
       identifier,
-      limit: 1,
-      duration: 60_000,
+      limit: DEFAULT_LIMIT,
+      duration: DEFAULT_DURATION_MS,
       async: false,
     });

47-101: Consider extracting duplicated setup code.

The test setup code is duplicated from the common tests. Consider extracting the setup into a shared helper function.

async function setupTestData(h: IntegrationHarness) {
  const overrideId = newId("test");
  const identifier = randomUUID();
  const namespaceId = newId("test");
  // ... rest of the setup
  return { overrideId, identifier, namespaceId };
}

The role-based permission check and database verification are well implemented.


102-157: LGTM! Comprehensive negative test case.

The test properly verifies:

  1. 403 status code for unauthorized access
  2. Data persistence (override remains in database)
  3. Correct error handling for incorrect roles

Consider adding more test cases with different incorrect roles to ensure robust permission checking.

 describe("incorrect roles", () => {
   describe.each([
-    { name: "delete override", roles: ["ratelimit.*.create_override"] }
+    { name: "create override role", roles: ["ratelimit.*.create_override"] },
+    { name: "read override role", roles: ["ratelimit.*.read_override"] },
+    { name: "no roles", roles: [] }
   ])(
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 45f2732 and f18588d.

📒 Files selected for processing (13)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.error.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.error.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.error.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.ts
  • apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts
  • apps/api/src/routes/v1_ratelimit_listOverrides.ts
  • apps/api/src/routes/v1_ratelimit_setOverride.ts
🔇 Additional comments (17)
apps/api/src/routes/v1_ratelimit_getOverride.error.test.ts (3)

1-7: LGTM! Well-organized imports with clear dependencies.

The imports are properly structured, including all necessary dependencies for testing, database operations, and type safety.


34-48: LGTM! Clear and thorough error case testing.

The test properly verifies the error response structure and includes helpful error messages in the assertions.


1-48: Verify consistency with other error test patterns.

Let's ensure this error test follows the same patterns as other error tests in the codebase.

✅ Verification successful

Error test follows consistent patterns across the codebase

The test follows the established error testing patterns in the codebase:

  • Uses consistent status code assertion format: expect(res.status, 'expected 400...').toBe(400)
  • Follows similar error response structure with toMatchObject
  • Belongs to the same family of rate limit error tests (found in deleteOverride.error.test.ts, listOverrides.error.test.ts, etc.)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for similar error test patterns in other test files
rg -t ts "Missing.*test.*async.*expect.*BAD_REQUEST" apps/api/src/routes/

Length of output: 75


Script:

#!/bin/bash
# Let's search for error test patterns more broadly
rg -t ts "test.*BAD_REQUEST.*error" apps/api/src/routes/ -B 1 -A 1

# Also search for similar test structure
rg -t ts "\.error\.test\.ts" apps/api/src/routes/ --files-with-matches

# Look for test files with expect status checks
rg -t ts "expect\(.*status.*\).*toBe\(400\)" apps/api/src/routes/ -B 1 -A 1

Length of output: 1747

apps/api/src/routes/v1_ratelimit_listOverrides.error.test.ts (3)

1-7: LGTM! Clean and well-organized imports

The imports follow good practices with a clear separation between built-in Node.js modules, external dependencies, and internal imports.


35-40: LGTM! Well-structured API request setup

The request is properly configured to test the error case, with good type safety through the response type assertion.


10-10: Verify permission scope alignment

The test uses the "ratelimit.*.read_override" permission. Let's verify this matches the API implementation.

✅ Verification successful

The permission "ratelimit.*.read_override" is consistently used across the codebase:

  1. In the route handler v1_ratelimit_listOverrides.ts which is being tested
  2. In a related route handler v1_ratelimit_getOverride.ts
  3. In the dashboard permissions configuration

The test's permission scope perfectly aligns with the API implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for permission validation in the route handler
ast-grep --pattern 'verifyPermission($_, "ratelimit.*.read_override")'

# Search for permission documentation
rg -g '!*.test.ts' "ratelimit\.\*\.read_override"

Length of output: 742

apps/api/src/routes/v1_ratelimit_deleteOverride.error.test.ts (2)

1-11: LGTM: Imports and type declarations are well-organized

The imports are properly structured, with clear separation between node built-ins, internal packages, and external dependencies.


50-57: Verify the error documentation URL

The test includes a hardcoded documentation URL. Let's ensure this URL is valid and matches our documentation structure.

✅ Verification successful

Documentation URL pattern is correctly implemented and consistent

The error documentation URL in the test is valid and matches the centralized error handling implementation in apps/api/src/pkg/errors/http.ts. The URL is consistently constructed using template literals across the codebase:

  • The base URL pattern https://unkey.dev/docs/api-reference/errors/code/ is used in the error schema factory
  • Error responses are generated through centralized functions that maintain this URL pattern
  • The error code is appended to create the complete documentation URL
  • This pattern is used consistently across 35+ files in the codebase
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the error documentation URL pattern across the codebase

# Check if this URL pattern is consistently used
rg -l "unkey\.dev/docs/api-reference/errors/code/" --type ts

# Check if there's a central constant or configuration for the docs URL
rg "const\s+.*DOC.*URL|const\s+.*ERROR.*URL" --type ts

Length of output: 2073


Script:

#!/bin/bash
# Let's check the error handling implementation to see if there's a centralized error creation
ast-grep --pattern 'class $_ extends Error {
  $$$
  docs: string;
  $$$
}'

# Also check the specific file where errors are defined
cat apps/api/src/pkg/errors/http.ts

Length of output: 6463

apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts (1)

1-11: LGTM! Imports are well-organized and necessary.

All required dependencies and types are properly imported.

apps/api/src/routes/v1_ratelimit_getOverride.ts (2)

1-7: LGTM! Dependencies are well organized.

The imports are clean, relevant, and properly typed.


51-55: LGTM! Type exports are well-defined.

The types are properly derived from the Zod schema and exported correctly.

apps/api/src/routes/v1_ratelimit_listOverrides.security.test.ts (2)

1-11: LGTM! Imports and type declarations are well-organized.

All necessary dependencies are properly imported, and the types are correctly referenced from the implementation file.


1-123: Verify complete security coverage.

While the basic RBAC testing is in place, let's verify coverage of additional security aspects:

  1. SQL injection via namespaceId parameter
  2. Rate limiting on the endpoint itself
  3. Workspace isolation (ensuring users can't access other workspaces' data)
apps/api/src/routes/v1_ratelimit_getOverride.security.test.ts (1)

43-85: Enhance test coverage for role combinations.

The test only verifies a single role combination. Consider adding more test cases with different role combinations to ensure comprehensive coverage.

describe.each([
  { name: "get override with specific permission", roles: ["ratelimit.*.read_override"] },
  { name: "get override with wildcard permission", roles: ["ratelimit.*"] },
  { name: "get override with admin role", roles: ["admin"] }
])

Additionally, consider verifying the response body structure to ensure the API returns the expected data format.

apps/api/src/routes/v1_ratelimit_setOverride.security.test.ts (2)

1-11: LGTM! Imports are well-organized and appropriate for security testing.

The imports include all necessary testing utilities, database schema, and type definitions.


1-155: Add boundary tests for limit and duration values.

Consider adding test cases to verify the behavior with boundary values:

  • Maximum allowed limit
  • Maximum allowed duration
  • Zero or negative values
  • Very large numbers
✅ Verification successful

The implementation shows that there are input validations for both limit and duration:

  • limit: Must be a positive integer (z.number().int().positive())
  • duration: Must be an integer with minimum value of 1000ms (z.number().int().min(1000))

Since the validation rules are clearly defined in the implementation, I can generate the final response:

Add test cases for limit and duration validation boundaries

Add test cases to verify the input validation rules:

  • limit: Test with 0 and negative values (should fail)
  • duration: Test with values < 1000ms (should fail)

Example test cases to add:

test("fails with invalid limit", async (t) => {
  // Test with limit: 0
  // Test with limit: -1
});

test("fails with invalid duration", async (t) => {
  // Test with duration: 999
  // Test with duration: 0
  // Test with duration: -1
});
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any validation of limit and duration values in the implementation
rg -A 5 "limit|duration" apps/api/src/routes/v1_ratelimit_setOverride.ts

Length of output: 4620

apps/api/src/routes/v1_ratelimit_deleteOverride.security.test.ts (1)

1-11: LGTM! Imports are well-organized and complete.

All necessary testing utilities and types are properly imported.

apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_getOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_getOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_getOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_deleteOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_deleteOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_deleteOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_deleteOverride.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_listOverrides.ts Outdated Show resolved Hide resolved
apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts Outdated Show resolved Hide resolved

expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200);

const resInit = await h.db.primary.query.ratelimitOverrides.findFirst({
Copy link
Collaborator

Choose a reason for hiding this comment

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

where: (table, { eq, and }) =>
and(eq(table.namespaceId, namespaceId), eq(table.identifier, identifier)),
});
expect(resNew?.identifier).toEqual(identifier);
Copy link
Collaborator

Choose a reason for hiding this comment

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

do a check that it's not undefined, and then assert it with !

apps/api/src/routes/v1_ratelimit_setOverride.ts Outdated Show resolved Hide resolved
@chronark chronark dismissed their stale review November 13, 2024 19:12

by accident

Copy link
Collaborator

@chronark chronark left a comment

Choose a reason for hiding this comment

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

reviewed all

Copy link
Contributor

@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

🧹 Outside diff range and nitpick comments (2)
apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (2)

31-31: Consider extracting magic numbers into named constants

The duration value 60_000 would be more maintainable and readable if extracted into a named constant.

+const ONE_MINUTE_MS = 60_000;
+
 test("return a single override using namespaceId", async (t) => {
   // ...
-    duration: 60_000,
+    duration: ONE_MINUTE_MS,

8-48: Consider reducing code duplication

Both test cases share similar setup code. Consider extracting the common setup logic into a helper function to improve maintainability and reduce duplication.

async function setupTestOverride(h: IntegrationHarness) {
  const namespaceId = newId("test");
  const namespaceName = randomUUID();
  const overrideId = newId("test");
  const identifier = randomUUID();

  const namespace = {
    id: namespaceId,
    name: namespaceName,
    workspaceId: h.resources.userWorkspace.id,
    createdAt: new Date(),
  };
  
  await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
  await h.db.primary.insert(schema.ratelimitOverrides).values({
    id: overrideId,
    workspaceId: h.resources.userWorkspace.id,
    namespaceId: namespaceId,
    identifier: identifier,
    limit: 1,
    duration: ONE_MINUTE_MS,
    async: false,
  });

  return { namespaceId, namespaceName, overrideId, identifier };
}

Also applies to: 50-89

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7fd98d1 and cb2ca1e.

📒 Files selected for processing (14)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.error.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_getOverride.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_listOverrides.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.security.test.ts (1 hunks)
  • apps/api/src/routes/v1_ratelimit_setOverride.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (13)
  • apps/api/src/routes/v1_ratelimit_deleteOverride.error.test.ts
  • apps/api/src/routes/v1_ratelimit_deleteOverride.happy.test.ts
  • apps/api/src/routes/v1_ratelimit_deleteOverride.security.test.ts
  • apps/api/src/routes/v1_ratelimit_deleteOverride.ts
  • apps/api/src/routes/v1_ratelimit_getOverride.security.test.ts
  • apps/api/src/routes/v1_ratelimit_getOverride.ts
  • apps/api/src/routes/v1_ratelimit_listOverrides.happy.test.ts
  • apps/api/src/routes/v1_ratelimit_listOverrides.security.test.ts
  • apps/api/src/routes/v1_ratelimit_listOverrides.ts
  • apps/api/src/routes/v1_ratelimit_setOverride.error.test.ts
  • apps/api/src/routes/v1_ratelimit_setOverride.happy.test.ts
  • apps/api/src/routes/v1_ratelimit_setOverride.security.test.ts
  • apps/api/src/routes/v1_ratelimit_setOverride.ts
🧰 Additional context used
📓 Learnings (1)
apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts (1)
Learnt from: chronark
PR: unkeyed/unkey#2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., `apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts`), URL parameters like `namespaceId` and `identifier` do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Comment on lines +8 to +89
test("return a single override using namespaceId", async (t) => {
const h = await IntegrationHarness.init(t);
const root = await h.createRootKey(["ratelimit.*.read_override"]);
const namespaceId = newId("test");
const namespaceName = randomUUID();
const overrideId = newId("test");
const identifier = randomUUID();

// Namespace
const namespace = {
id: namespaceId,
name: namespaceName,
workspaceId: h.resources.userWorkspace.id,
createdAt: new Date(),
};
await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
// Initial Override
await h.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: h.resources.userWorkspace.id,
namespaceId: namespaceId,
identifier: identifier,
limit: 1,
duration: 60_000,
async: false,
});

const res = await h.get<V1RatelimitGetOverrideResponse>({
url: `/v1/ratelimit.getOverride?namespaceId=${namespaceId}&identifier=${identifier}`,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
});
expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200);
expect(res.body.id).toBe(overrideId);
expect(res.body.identifier).toEqual(identifier);
expect(res.body.limit).toEqual(1);
expect(res.body.duration).toEqual(60_000);
expect(res.body.async).toEqual(false);
});

test("return a single override using namespaceName", async (t) => {
const h = await IntegrationHarness.init(t);
const root = await h.createRootKey(["ratelimit.*.read_override"]);
const namespaceId = newId("test");
const namespaceName = randomUUID();
const overrideId = newId("test");
const identifier = randomUUID();

// Namespace
const namespace = {
id: namespaceId,
name: namespaceName,
workspaceId: h.resources.userWorkspace.id,
createdAt: new Date(),
};
await h.db.primary.insert(schema.ratelimitNamespaces).values(namespace);
await h.db.primary.insert(schema.ratelimitOverrides).values({
id: overrideId,
workspaceId: h.resources.userWorkspace.id,
namespaceId: namespaceId,
identifier: identifier,
limit: 1,
duration: 60_000,
async: false,
});

const res = await h.get<V1RatelimitGetOverrideResponse>({
url: `/v1/ratelimit.getOverride?namespaceName=${namespaceName}&identifier=${identifier}`,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
});
expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200);
expect(res.body.id).toBe(overrideId);
expect(res.body.identifier).toEqual(identifier);
expect(res.body.limit).toEqual(1);
expect(res.body.duration).toEqual(60_000);
expect(res.body.async).toEqual(false);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

🛠️ Refactor suggestion

Review comment needs to be updated but is partially correct

The review comment is partially correct as it suggests adding error case tests, but there's already a dedicated error test file (v1_ratelimit_getOverride.error.test.ts) that covers the "Missing Namespace" scenario. However, other suggested error cases are still missing:

  • Invalid permissions
  • Non-existent overrides
  • Missing identifier
  • Invalid namespace ID/name format
🔗 Analysis chain

Add error case tests

The current tests only cover successful scenarios. Consider adding tests for error cases such as:

  • Invalid namespace ID/name
  • Missing identifier
  • Invalid permissions
  • Non-existent overrides
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for error case test coverage

# Look for error test files
fd "v1_ratelimit_getOverride.*error.*test.ts$" apps/api/src/routes/

# Search for error case tests in other test files
rg "test\(.*(error|fail|invalid|exception)" "apps/api/src/routes/v1_ratelimit_getOverride.*test.ts"

Length of output: 324


Script:

#!/bin/bash
# Let's check the content of the error test file to see what cases are already covered
cat apps/api/src/routes/v1_ratelimit_getOverride.error.test.ts

Length of output: 1683

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants