feat: SQL like queries for permissions#3617
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
📝 WalkthroughWalkthroughA new SQL-like query syntax for permissions was introduced for the Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API
participant RBAC
participant ErrorHandler
Client->>API: POST /v2/keys.verifyKey (permissions query string)
API->>RBAC: ParseQuery(permissions string)
alt Valid query
RBAC-->>API: PermissionQuery AST
API->>RBAC: EvaluatePermissions(PermissionQuery, user permissions)
RBAC-->>API: Evaluation result
API-->>Client: Success/Failure response
else Invalid query syntax
RBAC-->>API: Parse error
API->>ErrorHandler: Wrap error with codes.UserErrorsBadRequestPermissionsQuerySyntaxError
ErrorHandler-->>Client: 400 Bad Request with error details
end
Suggested labels
Suggested reviewers
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
Thank you for following the naming conventions for pull request titles! 🙏 |
There was a problem hiding this comment.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (19)
apps/docs/api-reference/errors-v2/user/bad_request/permissions_query_syntax_error.mdx(1 hunks)apps/docs/docs.json(1 hunks)go/apps/api/openapi/gen.go(1 hunks)go/apps/api/openapi/openapi.yaml(2 hunks)go/apps/api/routes/v2_keys_verify_key/200_test.go(3 hunks)go/apps/api/routes/v2_keys_verify_key/400_test.go(1 hunks)go/apps/api/routes/v2_keys_verify_key/handler.go(1 hunks)go/pkg/codes/constants_gen.go(2 hunks)go/pkg/codes/generate.go(1 hunks)go/pkg/codes/unkey_application.go(3 hunks)go/pkg/codes/user_request.go(1 hunks)go/pkg/rbac/doc.go(3 hunks)go/pkg/rbac/integration_test.go(1 hunks)go/pkg/rbac/lexer.go(1 hunks)go/pkg/rbac/lexer_test.go(1 hunks)go/pkg/rbac/parse_test.go(1 hunks)go/pkg/rbac/parser.go(1 hunks)go/pkg/rbac/rbac.go(3 hunks)go/pkg/zen/middleware_errors.go(1 hunks)
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: unkeyed/unkey#3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as `description`) alongside `$ref` in schema objects. Do not flag this as an error in future reviews.
go/pkg/zen/middleware_errors.go (3)
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: unkeyed/unkey#2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
go/apps/api/routes/v2_keys_verify_key/400_test.go (3)
Learnt from: MichaelUnkey
PR: unkeyed/unkey#2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the `v1/keys.updateKey` endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
go/pkg/rbac/rbac.go (1)
Learnt from: Flo4604
PR: unkeyed/unkey#3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.464Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.
go/pkg/rbac/doc.go (1)
Learnt from: chronark
PR: unkeyed/unkey#3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
go/apps/api/routes/v2_keys_verify_key/handler.go (2)
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
go/pkg/codes/constants_gen.go (1)
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
go/apps/api/routes/v2_keys_verify_key/200_test.go (4)
Learnt from: MichaelUnkey
PR: unkeyed/unkey#2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the `v1/keys.updateKey` endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: Flo4604
PR: unkeyed/unkey#2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
apps/docs/api-reference/errors-v2/user/bad_request/permissions_query_syntax_error.mdx (4)
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#3375
File: apps/dashboard/app/(app)/settings/root-keys/components/table/hooks/use-root-keys-list-query.ts:0-0
Timestamp: 2025-06-25T20:32:10.471Z
Learning: In the Unkey codebase, ogzhanolguncu prefers strict validation with fail-fast error handling. When validation errors occur that shouldn't happen in normal operation (like invalid operators), throwing errors to crash the page is preferred over graceful error handling or console logging.
Learnt from: Flo4604
PR: unkeyed/unkey#2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
go/apps/api/openapi/openapi.yaml (5)
undefined
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For destructive operations like deletion in the Unkey API, oneOf validation is preferred over anyOf to enforce explicit targeting and prevent ambiguity.
</retrieved_learning>
go/apps/api/openapi/gen.go (1)
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
</retrieved_learning>
🧬 Code Graph Analysis (7)
go/pkg/codes/generate.go (1)
go/pkg/codes/user_request.go (1)
User(19-23)
go/pkg/zen/middleware_errors.go (1)
go/pkg/codes/constants_gen.go (2)
UnkeyAuthErrorsAuthenticationMalformed(27-27)UserErrorsBadRequestPermissionsQuerySyntaxError(16-16)
go/pkg/rbac/integration_test.go (2)
go/pkg/rbac/query.go (1)
T(84-90)go/pkg/rbac/rbac.go (2)
New(23-25)ParseQuery(156-158)
go/pkg/rbac/rbac.go (2)
go/pkg/codes/unkey_application.go (1)
App(60-80)go/pkg/fault/wrap.go (2)
Internal(75-89)Public(97-111)
go/apps/api/routes/v2_keys_verify_key/handler.go (3)
go/pkg/rbac/rbac.go (1)
ParseQuery(156-158)go/pkg/codes/user_request.go (1)
User(19-23)go/pkg/fault/wrap.go (1)
Internal(75-89)
go/pkg/rbac/lexer.go (3)
go/pkg/codes/user_request.go (1)
User(19-23)go/pkg/codes/constants_gen.go (1)
URN(5-5)go/pkg/fault/wrap.go (1)
Public(97-111)
go/pkg/rbac/parser.go (3)
go/pkg/rbac/query.go (3)
Or(64-70)And(46-52)S(100-106)go/pkg/codes/user_request.go (1)
User(19-23)go/pkg/fault/wrap.go (1)
Public(97-111)
🪛 LanguageTool
apps/docs/api-reference/errors-v2/user/bad_request/permissions_query_syntax_error.mdx
[grammar] ~27-~27: Use correct spacing
Context: ...r end" } ] } } ``` ## What Happened? This error occurs when the permissions q...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~29-~29: There might be a mistake here.
Context: ...ntax or characters. This can happen due to: - Invalid characters in permission name...
(QB_NEW_EN_OTHER)
[grammar] ~33-~33: Use correct spacing
Context: ...ssions** that don't follow the expected grammar ## Permissions Query Requirements The `ver...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~35-~35: Use correct spacing
Context: ... expected grammar ## Permissions Query Requirements The verifyKey endpoint accepts a permi...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~37-~37: There might be a mistake here.
Context: ...ons query string that must follow these rules: ### Valid Characters The query parser acce...
(QB_NEW_EN_OTHER)
[grammar] ~39-~39: Use correct spacing
Context: ...hat must follow these rules: ### Valid Characters The query parser accepts these character...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~41-~41: There might be a mistake here.
Context: ...racters The query parser accepts these characters: - Permissions: Must follow the permissi...
(QB_NEW_EN_OTHER)
[grammar] ~43-~43: There might be a mistake here.
Context: ...ormat (alphanumeric, dots, underscores, hyphens) - Letters: a-z, A-Z - Numbers:...
(QB_NEW_EN_OTHER)
[grammar] ~44-~44: There might be a mistake here.
Context: ... underscores, hyphens) - Letters: a-z, A-Z - Numbers: 0-9 - **Dot...
(QB_NEW_EN_OTHER)
[grammar] ~51-~51: Add a comma
Context: ...r parentheses - Whitespace: Spaces, tabs and new lines for separation (ignored b...
(QB_NEW_EN_OTHER_ERROR_IDS_22)
[grammar] ~51-~51: There might be a problem here.
Context: ...nd new lines for separation (ignored by parser) Everyhing else is not allowed. ### Query Structu...
(QB_NEW_EN_MERGED_MATCH)
[grammar] ~53-~53: Use correct spacing
Context: ...nored by parser) Everyhing else is not allowed. ### Query Structure A permissions query can...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~55-~55: Use correct spacing
Context: ...eryhing else is not allowed. ### Query Structure A permissions query can be: 1. **A sing...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~57-~57: There might be a mistake here.
Context: ...uery Structure A permissions query can be: 1. A single permission: permission_1 2....
(QB_NEW_EN_OTHER)
[grammar] ~62-~62: Use correct spacing
Context: ...mission_1 OR permission_24. **Grouped expressions**:(permission_1 OR permission_2) AND permission_3` Key rules: - Permission names must be ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~65-~65: There might be a mistake here.
Context: ...s (letters, numbers, dots, underscores, hyphens) - Use AND when all permissions are requi...
(QB_NEW_EN_OTHER)
[grammar] ~66-~66: There might be a mistake here.
Context: ...s) - Use AND when all permissions are required - Use OR when any of the permissions is ...
(QB_NEW_EN_OTHER)
[grammar] ~67-~67: There might be a mistake here.
Context: ...Use OR when any of the permissions is sufficient - Use parentheses () to group expression...
(QB_NEW_EN_OTHER)
[grammar] ~68-~68: There might be a mistake here.
Context: ...s () to group expressions and control precedence - Operators are case insensitive: AND, `...
(QB_NEW_EN_OTHER)
[grammar] ~69-~69: Insert the missing word
Context: ... Operators are case insensitive: AND, AnD, and all work. ## Common Errors and S...
(QB_NEW_EN_OTHER_ERROR_IDS_32)
[grammar] ~69-~69: Use correct spacing
Context: ...se insensitive: AND, AnD, and all work. ## Common Errors and Solutions ### 1. Inva...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~71-~71: Use correct spacing
Context: ..., and all work. ## Common Errors and Solutions ### 1. Invalid Characters ```bash # ❌ Invali...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~73-~73: Use correct spacing
Context: ...on Errors and Solutions ### 1. Invalid Characters bash # ❌ Invalid - contains special characters curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission$1 OR permission@2" }' # ✅ Valid - use underscores or hyphens curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 OR permission_2" }' ### 2. Missing Operands ```bash # ❌ Invalid ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~94-~94: Use correct spacing
Context: ... permission_2" }' ### 2. Missing Operandsbash # ❌ Invalid - AND without right operand curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 AND" }' # ✅ Valid - complete AND expression curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 AND permission_2" }' ### 3. Unmatched Parenthesesbash # ❌ Inv...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~115-~115: Use correct spacing
Context: ...ermission_2" }' ### 3. Unmatched Parenthesesbash # ❌ Invalid - missing closing parenthesis curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "(permission_1 AND permission_2" }' # ✅ Valid - balanced parentheses curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "(permission_1 AND permission_2)" }' ### 4. Empty Parenthesesbash # ❌ Invalid...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~136-~136: Use correct spacing
Context: ...D permission_2)" }' ### 4. Empty Parenthesesbash # ❌ Invalid - empty parentheses curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 AND ()" }' # ✅ Valid - parentheses with content curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 AND (permission_2 OR permission_3)" }' ### 5. Incorrect Operator Placementbash ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~157-~157: Use correct spacing
Context: ...3)" }' ### 5. Incorrect Operator Placementbash # ❌ Invalid - operator at start curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "OR permission_1" }' # ✅ Valid - operators between permissions curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 OR permission_2" }' ``` ## Valid Query Examples ### Simple Permiss...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~178-~178: Use correct spacing
Context: ... permission_2" }' ## Valid Query Examples ### Simple Permissionbash curl -X POST h...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~180-~180: Use correct spacing
Context: ...`` ## Valid Query Examples ### Simple Permission bash curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1" }' ### AND Operation ```bash curl -X POST https...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~191-~191: Use correct spacing
Context: ...ions": "permission_1" }' ### AND Operationbash curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 AND permission_2" }' ### OR Operationbash curl -X POST https:...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~202-~202: Use correct spacing
Context: ...on_1 AND permission_2" }' ### OR Operationbash curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "permission_1 OR permission_2" }' ### Complex Expressionsbash curl -X POST...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~213-~213: Use correct spacing
Context: ... OR permission_2" }' ### Complex Expressionsbash curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "(permission_1 OR permission_2) AND permission_3" }' ### Nested Expressionsbash curl -X POST ...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~224-~224: Use correct spacing
Context: ... AND permission_3" }' ### Nested Expressionsbash curl -X POST https://api.unkey.com/v2/keys.verifyKey \ -H "Content-Type: application/json" \ -H "Authorization: Bearer unkey_XXXX" \ -d '{ "key": "sk_123", "permissions": "((permission_1 OR permission_2) AND permission_3) OR permission_4" }' ``` ## Valid Permission Formats ### Simple Nam...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~235-~235: Use correct spacing
Context: ...ission_4" }' ``` ## Valid Permission Formats ### Simple Names - permission_1 - `user_re...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~237-~237: Use correct spacing
Context: ...## Valid Permission Formats ### Simple Names - permission_1 - user_read - admin-access ### Namespaced Permissions - `api.users.read...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~242-~242: Use correct spacing
Context: ..._read-admin-access ### Namespaced Permissions -api.users.read-billing.invoices.create-workspace.settings.update ### Mixed Formats -user_management.create`...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
[grammar] ~247-~247: Use correct spacing
Context: ... workspace.settings.update ### Mixed Formats - user_management.create - billing-service.view - service123.feature_a.read ## Context This error is specific to the `...
(QB_NEW_EN_OTHER_ERROR_IDS_5)
🪛 YAMLlint (1.37.1)
go/apps/api/openapi/openapi.yaml
[warning] 3311-3311: too few spaces before comment: expected 2
(comments)
⏰ 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). (4)
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Test API / API Test Local
- GitHub Check: Build / Build
- GitHub Check: Test Packages / Test
🔇 Additional comments (32)
apps/docs/docs.json (1)
238-244: LGTM! Documentation structure follows existing patterns.The addition of the "User" error group and the permissions query syntax error documentation page correctly follows the established error documentation hierarchy and aligns with the new SQL-like permissions query feature.
go/pkg/codes/unkey_application.go (3)
33-35: LGTM! Preparatory structure for limits-related errors.The new
appLimitsstruct follows the established pattern for error categorization and sets up the foundation for future limits and quota-related error codes.
53-55: LGTM! Consistent field addition.The new
Limitsfield properly integrates the limits error category into the overall application error structure.
79-79: LGTM! Proper initialization.The
Limitsfield is correctly initialized with an emptyappLimitsstruct, maintaining consistency with the overall error code initialization pattern.go/pkg/codes/generate.go (1)
49-49: LGTM! Proper integration of user error domain.The new
processErrorDomaincall for the "User" system correctly integrates the newly introduced user error codes into the constant generation workflow. The placement before the Unkey domains is logical and maintains consistency.go/pkg/zen/middleware_errors.go (1)
62-63: LGTM! Proper error handling for permissions query syntax.The addition of
codes.UserErrorsBadRequestPermissionsQuerySyntaxErrorto the Bad Request error handling case correctly ensures that permissions query syntax errors return HTTP 400 responses, which is appropriate for user input validation errors.go/apps/api/routes/v2_keys_verify_key/400_test.go (1)
111-160: LGTM! Comprehensive test coverage for permissions query syntax validation.The new test subtest provides excellent coverage for invalid permissions query syntax scenarios. The test cases are well-structured and validate:
- Various syntax error types (missing operand, unmatched parenthesis, empty parentheses, operator at start)
- Correct HTTP 400 response status
- Proper error detail messages
- Correct error type URL pointing to the documentation
The test structure follows the existing pattern and properly validates the new SQL-like permissions query feature introduced in this PR.
go/pkg/codes/constants_gen.go (2)
9-17: LGTM! Well-structured error code addition.The new
UserErrorsBadRequestPermissionsQuerySyntaxErrorconstant follows the established naming conventions and URN format. The addition of the UserErrors section with BadRequest subsection provides a logical organization for user input validation errors.
127-128: Empty placeholder section added.The "Limits" section appears to be a placeholder with no constants defined yet. This is acceptable for future expansion.
go/pkg/rbac/integration_test.go (3)
9-21: Excellent test coverage for simple query parsing and evaluation.The integration test properly verifies that a simple permission query can be parsed and evaluated correctly. The test structure is clean and follows good testing practices.
23-34: Good coverage of complex query scenarios.The test validates complex queries with AND/OR operators and parentheses, ensuring the parser and evaluator work together correctly for realistic permission scenarios.
57-67: Excellent precedence testing.This test ensures that operator precedence is correctly handled (AND has higher precedence than OR), which is crucial for the SQL-like query syntax. The comment clearly explains the expected parsing behavior.
go/pkg/rbac/rbac.go (2)
122-127: Excellent improvement to error handling.The replacement of a generic error with a structured fault provides better error classification and user-friendly messaging. Using the fault package with proper error codes aligns with the codebase's error handling patterns.
139-158: Well-documented and designed public API.The
ParseQueryfunction is excellently documented with:
- Clear syntax rules and supported features
- Practical examples showing various query formats
- Explicit limits on query length and permission count
- Good delegation to internal implementation
This provides a clean public interface for the SQL-like permission query parsing functionality.
go/pkg/rbac/parse_test.go (2)
9-67: Comprehensive test coverage for successful parsing scenarios.The test cases cover all major parsing scenarios:
- Simple permissions
- Logical operators (AND, OR)
- Operator precedence
- Parentheses grouping
The use of helper functions like
S(),And(), andOr()makes the expected results very readable and maintainable.
69-105: Excellent error case coverage.The error tests validate specific failure scenarios with detailed error message checking:
- Empty queries
- Invalid characters
- Incomplete expressions
- Unmatched parentheses
This ensures robust error handling and helpful error messages for users.
go/apps/api/routes/v2_keys_verify_key/handler.go (1)
130-140: Excellent simplification of permissions handling.The replacement of complex custom conversion logic with a direct call to
rbac.ParseQuerysignificantly simplifies the code while providing better error handling. The structured fault wrapping with the appropriate error code ensures consistent error reporting for syntax errors.This change aligns perfectly with the PR objective of introducing SQL-like query syntax for permissions.
go/pkg/rbac/doc.go (3)
10-13: Well-structured documentation introduction.The introduction clearly differentiates between programmatic and SQL-like query construction methods, providing a good foundation for the detailed sections that follow.
22-62: Excellent programmatic usage example.The documentation provides a complete, practical example that demonstrates the full workflow from RBAC setup to permission evaluation. The inclusion of error handling and result checking shows good practices.
64-101: Comprehensive SQL-like query documentation.The documentation thoroughly covers the SQL-like query syntax with clear examples, precedence rules, and important limitations. The progression from simple to complex examples helps users understand the capabilities.
go/apps/api/routes/v2_keys_verify_key/200_test.go (3)
257-257: Excellent simplification of permission request construction.The change from complex permission objects to simple string queries significantly improves code readability and maintainability while preserving functionality.
Also applies to: 282-282, 301-301
310-340: Good test coverage for complex permission queries.The test correctly validates the AND operator functionality by creating a key with the required permissions and verifying the query evaluation works as expected.
342-394: Excellent scalability test for large permission queries.This test provides crucial validation for the parser's ability to handle complex, real-world scenarios with multiple permissions and logical operators. The 25-permission test case ensures the system can scale appropriately.
go/pkg/codes/user_request.go (3)
3-7: Well-structured error definition.The userBadRequest struct is cleanly defined with clear documentation explaining the purpose of the PermissionsQuerySyntaxError field.
9-14: Good hierarchical error organization.The UserErrors struct provides a logical grouping for user-related errors, making them easy to find and reference throughout the application.
16-23: Proper error code instantiation.The global User variable is correctly instantiated with the appropriate Code structure and follows consistent naming conventions. The documentation example helps developers understand how to reference these errors.
go/apps/api/openapi/openapi.yaml (1)
7260-7274: Example payload: confirmerror.statustype matches schemaIn previous Unkey specs
error.statuswas defined as a string ("400").
Here it’s provided as an integer (400). Make sure the example conforms to
#/components/schemas/ErrorObjectto prevent breaking generated clients.If the schema expects a string, the fix is:
- status: 400 + status: "400"Also double-check that
location: "body.permissions"follows the same path-format used elsewhere (some places use JSON-pointer/body/permissions).go/pkg/rbac/lexer_test.go (1)
1-420: Comprehensive test coverage!The lexer tests are well-structured with thorough coverage of tokenization scenarios, including edge cases, error handling, and various permission formats. The table-driven approach makes tests readable and maintainable.
apps/docs/api-reference/errors-v2/user/bad_request/permissions_query_syntax_error.mdx (1)
1-256: Well-structured and comprehensive error documentation!The documentation provides clear explanations, practical examples, and actionable solutions for permission query syntax errors. The format with invalid/valid comparison examples is particularly helpful for users.
go/pkg/rbac/parser.go (1)
1-309: Well-implemented recursive descent parser!The parser correctly implements operator precedence, provides detailed error messages with position information, and follows clean coding practices. The grammar documentation is clear and matches the implementation.
go/pkg/rbac/lexer.go (1)
1-296: Clean and efficient lexer implementation!The lexer correctly handles tokenization with proper position tracking, case-insensitive operators, and intelligent word boundary detection. The
isCompleteWordmethod elegantly solves the problem of distinguishing operators from permission identifiers containing operator substrings.go/apps/api/openapi/gen.go (1)
1637-1644: Breaking change implemented correctly in generated code.The simplification of the
Permissionsfield from a complex union type to a simple string is properly implemented. The documentation clearly explains the new SQL-like query syntax with good examples.Since this is auto-generated code from the OpenAPI specification, any issues should be addressed in the source specification rather than this file.
Note: This is a breaking API change that will require all clients to update their permission checking logic from the structured object approach to the new query string format.
apps/docs/api-reference/errors-v2/user/bad_request/permissions_query_syntax_error.mdx
Outdated
Show resolved
Hide resolved
…_query_syntax_error.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Graphite Automations"Notify author when CI fails" took an action on this PR • (07/17/25)1 teammate was notified to this PR based on Andreas Thomas's automation. "Post a GIF when PR approved" took an action on this PR • (07/17/25)1 gif was posted to this PR based on Andreas Thomas's automation. |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
go/apps/api/openapi/openapi.yaml (1)
3342-3342: YAML-lint spacing nit was already discussedThe single-space inline comment after
maxLength: 1000re-triggers YAML-lint’s “two-space” rule, but this exact nit was deemed non-blocking in earlier reviews.
Not flagging again.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
go/apps/api/openapi/gen.go(1 hunks)go/apps/api/openapi/openapi.yaml(2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.242Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
Learnt from: Flo4604
PR: unkeyed/unkey#2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
Learnt from: chronark
PR: unkeyed/unkey#3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.
Learnt from: Flo4604
PR: unkeyed/unkey#3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as `description`) alongside `$ref` in schema objects. Do not flag this as an error in future reviews.
go/apps/api/openapi/openapi.yaml (10)
undefined
<retrieved_learning>
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.242Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.
</retrieved_learning>
<retrieved_learning>
Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For destructive operations like deletion in the Unkey API, oneOf validation is preferred over anyOf to enforce explicit targeting and prevent ambiguity.
</retrieved_learning>
<retrieved_learning>
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-09T08:42:29.316Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,rb,java,c,cpp,h,cs,rs,php,html,css,scss,xml} : Make sure to add relevant anchor comments whenever a file or piece of code is too complex, very important, confusing, or could have a bug.
</retrieved_learning>
<retrieved_learning>
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-09T08:42:29.316Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,rb,java,c,cpp,h,cs,rs,php,html,css,scss,xml} : Use AIDEV-NOTE:, AIDEV-TODO:, AIDEV-BUSINESS_RULE:, or AIDEV-QUESTION: (all-caps prefix) as anchor comments aimed at AI and developers.
</retrieved_learning>
<retrieved_learning>
Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-09T08:42:29.316Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,rb,java,c,cpp,h,cs,rs,php,html,css,scss,xml} : Do not remove AIDEV-*s without explicit human instruction.
</retrieved_learning>
<retrieved_learning>
Learnt from: ogzhanolguncu
PR: #3321
File: apps/dashboard/lib/trpc/routers/authorization/roles/keys/schema-with-helpers.ts:5-8
Timestamp: 2025-06-18T12:28:10.449Z
Learning: In the unkey dashboard application, API validation for pagination limits is controlled at the UI level rather than requiring additional server-side validation, as the APIs are internal and protected by UI logic.
</retrieved_learning>
go/apps/api/openapi/gen.go (3)
<retrieved_learning>
Learnt from: chronark
PR: #3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.242Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via \s. Do not flag this as an error in future reviews.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.
</retrieved_learning>
<retrieved_learning>
Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.
</retrieved_learning>
🪛 YAMLlint (1.37.1)
go/apps/api/openapi/openapi.yaml
[warning] 3342-3342: too few spaces before comment: expected 2
(comments)
⏰ 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). (7)
- GitHub Check: Test Go API Local / Test
- GitHub Check: Test Agent Local / test_agent_local
- GitHub Check: Test API / API Test Local
- GitHub Check: Build / Build
- GitHub Check: Test Packages / Test
- GitHub Check: autofix
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
go/apps/api/openapi/gen.go (1)
1638-1645: LGTM! The simplified permissions field correctly implements the new SQL-like query syntax.The change from a complex union type to a simple string field with clear documentation examples aligns perfectly with the PR objectives. The comment provides excellent guidance on the supported query syntax including single permissions, logical operators (AND, OR), and parentheses for grouping.
go/apps/api/openapi/openapi.yaml (1)
3340-3351: Permissions field definition looks solid and aligns with the new parserThe switch to a plain
stringwith generousmaxLengthand an inclusive pattern is consistent with the lexer/parser that landed inpkg/rbac. The examples and description give SDK generators everything they need, and the regex correctly allows\sfor multi-line queries per the previous decision.
No issues from my side.


This POC replaces the complex oneOf union type in the verifyKey endpoint's
permissions field with a simple string-based query system. The previous union type was
a nightmare for SDK generation, creating confusing type definitions and poor
developer experience in generated client libraries. Now we have a clean string field
that generates beautiful, type-safe SDKs across all languages.
The new system supports SQL-like permission queries with AND/OR operators and
parentheses, while maintaining a simple API surface. This change dramatically
improves both our code generation quality and end-user experience - developers can now
write intuitive queries like "users.read AND (posts.write OR posts.delete)" instead
of constructing complex nested objects.
What does this PR do?
This PR enhances the permissions query system in the verifyKey endpoint by replacing the previous object-based permission structure with a more flexible SQL-like query string syntax. The new implementation includes:
Fixes #
Type of change
How should this be tested?
Checklist
Required
pnpm buildpnpm fmtconsole.logsgit pull origin mainAppreciated
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Refactor