WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Conversation

@Flo4604
Copy link
Member

@Flo4604 Flo4604 commented Dec 5, 2025

What does this PR do?

When someone forgets to set any verify key permissions we now throw a 403 error.

Fixes #4482

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?

Tests

Create root key without permissions, verify a key -> no matter if the key exists or doesn't we should respond with a 403 error.

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
  • Ran make fmt on /go directory
  • 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

@vercel
Copy link

vercel bot commented Dec 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
dashboard Ignored Ignored Preview Dec 5, 2025 11:09am
engineering Ignored Ignored Preview Dec 5, 2025 11:09am

@changeset-bot
Copy link

changeset-bot bot commented Dec 5, 2025

⚠️ No Changeset found

Latest commit: 18d5ec2

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

@Flo4604 Flo4604 marked this pull request as ready for review December 5, 2025 11:05
Copy link
Member Author

Flo4604 commented Dec 5, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

📝 Walkthrough

Walkthrough

Adds an early root-key permission check to the keys.verify endpoint, updates OpenAPI descriptions to clarify 403/NOT_FOUND behaviors, introduces KeyVerifier.HasAnyPermission, and adds/adjusts tests covering root-key permission permutations.

Changes

Cohort / File(s) Summary
OpenAPI Documentation
go/apps/api/openapi/openapi-generated.yaml, go/apps/api/openapi/spec/paths/v2/keys/verifyKey/index.yaml
Rewrote verifyKey response descriptions: clarified when 403 Forbidden is returned for root keys without verify permissions and when a NOT_FOUND (code NOT_FOUND) may be returned to avoid leaking key existence.
Handler & Validation Logic
go/apps/api/routes/v2_keys_verify_key/handler.go, go/internal/services/keys/validation.go
Added an early RBAC check in the verify handler that returns a permission-based error if the root key lacks any verify permission. Added HasAnyPermission(resourceType, action) on KeyVerifier and added tracing around permission resolution.
Tests
go/apps/api/routes/v2_keys_verify_key/200_test.go, go/apps/api/routes/v2_keys_verify_key/403_test.go
Removed a previous insufficient-permissions subtest from 200 tests; added 403_test.go with multiple subtests exercising: root key lacking verify permissions (403), root key with verify for other API (200 with NOT_FOUND payload), wildcard and specific-API verify success cases.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant HTTP_Handler as Handler
    participant KeyVerifier
    participant KeyStore as DataStore

    Client->>Handler: POST /v2/keys/verify (Authorization: root key)
    Handler->>KeyVerifier: HasAnyPermission(resource: "api", action: "verify")
    alt Root key has no verify permission
        KeyVerifier-->>Handler: false
        Handler-->>Client: 403 Forbidden (auth.VerifyRootKey)
    else Root key has verify permission (wildcard or for API)
        KeyVerifier-->>Handler: true
        Handler->>KeyStore: Lookup target key
        alt Key not found or permissions mismatch by API
            KeyStore-->>Handler: not found
            Handler-->>Client: 200 with code NOT_FOUND (avoid leakage)
        else Key found and valid
            KeyStore-->>Handler: key data
            Handler-->>Client: 200 VALID
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify the RBAC OR logic in handler.go correctly differentiates "no verify permission" vs "verify for other API".
  • Review HasAnyPermission string-prefix/suffix matching in validation.go for edge cases (permission formatting, escaping).
  • Inspect new subtests in 403_test.go to ensure they accurately assert response codes and payloads and that removed test coverage from 200_test.go is adequately replaced.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description provides context (fixing #4482) and testing instructions, with most required checklist items marked complete. However, no type-of-change option is selected despite the template requiring one. Select the appropriate type-of-change checkbox (Enhancement is most likely) to indicate the nature of this modification for proper tracking.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a 403 error response when a root key has zero verification permissions, which aligns with the primary modifications across handler, tests, and documentation.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/403-error-when-no-verifiy-perms

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.

❤️ Share

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

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

Caution

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

⚠️ Outside diff range comments (2)
go/apps/api/openapi/openapi-generated.yaml (1)

5436-5449: Fix inconsistency: endpoint no longer “always returns 200”.

The description still claims “Always returns HTTP 200” (Line 5436), but you’ve added a documented 403 case (Line 5449). Please update the text to reflect the exception.

Suggested wording (update the source OpenAPI, not the generated file):

-**Important**: Always returns HTTP 200. Check the `valid` field in response data to determine if the key is authorized.
+**Important**: Returns HTTP 200 for verification outcomes (success or failure). Exception: if the calling root key has no verify permissions at all, this endpoint returns HTTP 403. Otherwise, check the `valid` field in response data to determine if the key is authorized.

This keeps the no‑leak posture while accurately documenting the new 403 behavior. Based on learnings, authentication/authorization errors typically map to NOT_FOUND to avoid leakage; this narrow 403 exception should be clearly called out wherever “always 200” is mentioned.

go/apps/api/openapi/spec/paths/v2/keys/verifyKey/index.yaml (1)

10-10: Clarify 200 vs 4xx behavior in the description

The new note and the 403 description look consistent with the handler/tests and nicely call out the 200 + code: NOT_FOUND behavior to avoid leaking key existence (which matches the broader pattern in this codebase of hiding existence via NOT_FOUND). Based on learnings, this is the right direction for avoiding information disclosure.

However, the description still says this endpoint “Always returns HTTP 200” in two places (Line 10 and in the 200 response description at Line 37), which is now clearly inaccurate given the explicit 403 case for “no verify permissions at all” (and the existing 401/404/500 responses).

Consider rewording those statements along the lines of:

  • “For authorized root keys, verification results are always encoded in a 200 response; use valid and code to distinguish outcomes. Authentication/authorization failures still use standard 4xx/5xx responses.”

That keeps the main contract while making the 403/401/etc. behavior explicit and non‑contradictory.

Also applies to: 23-23, 36-37, 76-77

🧹 Nitpick comments (3)
go/apps/api/openapi/openapi-generated.yaml (1)

5499-5505: 403 semantics LGTM; add an example for parity and verify handler/tests.

The 403 description precisely scopes the case (zero verify perms across all APIs). Consider adding a small example error body here, like other endpoints do for 400/403, to aid SDKs and docs consistency. Also ensure the handler returns 403 only for this case and that tests cover:

  • zero verify perms → 403
  • verify perms for other API → 200 with code NOT_FOUND

I can help draft the example snippet if useful.

go/internal/services/keys/validation.go (1)

80-95: HasAnyPermission implementation looks correct; minor doc‑comment nit

The helper cleanly captures the “any <resource>.*.<action> / <resource>.<id>.<action>” pattern and should behave as intended for api.*.verify_key and api.<apiId>.verify_key given the current naming scheme.

Very small nit: the first comment line says “checks if the key has any permission matching the given action”, but the method actually matches both the resourceType and action. Consider tweaking the docstring to mention both so the exported API is fully self‑describing.

No functional issues from this change.

go/apps/api/routes/v2_keys_verify_key/403_test.go (1)

15-160: Good coverage of 403 vs 200/NOT_FOUND/VALID semantics

The test matrix here does a nice job pinning down the intended behavior:

  • 403 when the root key has no verify permissions at all (including the “no permissions” root‑key case).
  • 200 + code: NOT_FOUND, valid=false when the root key has verify permission, but only for a different API (preventing key‑existence leaks across APIs).
  • 200 + code: VALID, valid=true for both wildcard and API‑specific verify permissions.

This aligns with the new OpenAPI note and the helper semantics in KeyVerifier.HasAnyPermission, and with the broader pattern of masking existence via NOT_FOUND where appropriate. Based on learnings, this keeps the security story consistent.

Minor nit (optional): res.Body.Error in openapi.ForbiddenErrorResponse is a value field, so require.NotNil(t, res.Body.Error) will always pass; you could drop that assertion and rely on checking Error.Detail / Error.Status instead.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0740117 and adbe292.

📒 Files selected for processing (6)
  • go/apps/api/openapi/openapi-generated.yaml (2 hunks)
  • go/apps/api/openapi/spec/paths/v2/keys/verifyKey/index.yaml (2 hunks)
  • go/apps/api/routes/v2_keys_verify_key/200_test.go (0 hunks)
  • go/apps/api/routes/v2_keys_verify_key/403_test.go (1 hunks)
  • go/apps/api/routes/v2_keys_verify_key/handler.go (1 hunks)
  • go/internal/services/keys/validation.go (2 hunks)
💤 Files with no reviewable changes (1)
  • go/apps/api/routes/v2_keys_verify_key/200_test.go
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/workflows/runbook-freshness-check.yaml:157-173
Timestamp: 2025-08-08T14:59:52.283Z
Learning: Repo unkeyed/unkey: When a CI/workflow fix is deferred, imeyer prefers a thorough GitHub issue be opened with sections (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References) and assigned to imeyer, including backlinks to the originating PR and comment.
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 4190
File: go/internal/services/keys/verifier.go:51-53
Timestamp: 2025-10-30T15:10:52.743Z
Learning: PR #4190 for unkeyed/unkey is focused solely on database schema and query changes for identity-based credits. It adds IdentityCredits and KeyCredits fields to structs and queries, but does not implement the priority enforcement logic in the usagelimiter. The logic implementation is intentionally deferred to a later PR in the stack.
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/workflows/job_detect_changes.yaml:111-114
Timestamp: 2025-08-08T16:10:00.224Z
Learning: Repo: unkeyed/unkey — When imeyer writes “make me an issue” on a PR thread, automatically open a thorough GitHub issue (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References), include backlinks to the PR and comment, and assign to imeyer.
📚 Learning: 2025-08-29T12:08:57.482Z
Learnt from: perkinsjr
Repo: unkeyed/unkey PR: 3880
File: apps/dashboard/app/(app)/settings/root-keys/components/root-key/root-key-dialog.tsx:137-141
Timestamp: 2025-08-29T12:08:57.482Z
Learning: Root keys in the Unkey system require at least one permission at minimum, so there is no valid case where a root key would have zero permissions. This means checking for permission existence when determining UI labels is unnecessary.

Applied to files:

  • go/apps/api/routes/v2_keys_verify_key/handler.go
📚 Learning: 2025-07-15T14:25:05.608Z
Learnt from: chronark
Repo: unkeyed/unkey 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.

Applied to files:

  • go/apps/api/routes/v2_keys_verify_key/handler.go
📚 Learning: 2025-07-16T17:51:57.297Z
Learnt from: chronark
Repo: unkeyed/unkey PR: 3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
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.

Applied to files:

  • go/apps/api/openapi/spec/paths/v2/keys/verifyKey/index.yaml
  • go/apps/api/openapi/openapi-generated.yaml
📚 Learning: 2025-07-03T05:58:10.699Z
Learnt from: Flo4604
Repo: unkeyed/unkey 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.

Applied to files:

  • go/apps/api/openapi/spec/paths/v2/keys/verifyKey/index.yaml
  • go/apps/api/openapi/openapi-generated.yaml
📚 Learning: 2025-09-15T19:53:28.487Z
Learnt from: mcstepp
Repo: unkeyed/unkey PR: 3952
File: go/proto/ctrl/v1/routing.proto:0-0
Timestamp: 2025-09-15T19:53:28.487Z
Learning: In the Unkey codebase, authentication/authorization errors intentionally return NOT_FOUND error codes instead of distinct auth error codes (like FORBIDDEN or UNAUTHORIZED) for security reasons. This prevents attackers from distinguishing between "resource doesn't exist" and "you don't have permission to access this resource", avoiding information disclosure about workspace existence and access boundaries.

Applied to files:

  • go/apps/api/openapi/spec/paths/v2/keys/verifyKey/index.yaml
  • go/apps/api/openapi/openapi-generated.yaml
📚 Learning: 2025-08-14T16:25:48.167Z
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 3785
File: go/apps/api/routes/v2_keys_reroll_key/401_test.go:52-61
Timestamp: 2025-08-14T16:25:48.167Z
Learning: User Flo4604 requested creation of a GitHub issue to track converting all test files to use table-driven test patterns as a broader codebase improvement, following the suggestion made during review of go/apps/api/routes/v2_keys_reroll_key/401_test.go.

Applied to files:

  • go/apps/api/routes/v2_keys_verify_key/403_test.go
🧬 Code graph analysis (3)
go/apps/api/routes/v2_keys_verify_key/handler.go (3)
go/pkg/db/models_generated.go (1)
  • Api (648-659)
go/pkg/rbac/permissions.go (3)
  • VerifyKey (67-67)
  • Tuple (178-187)
  • ResourceType (11-11)
go/internal/services/keys/options.go (1)
  • WithPermissions (47-52)
go/internal/services/keys/validation.go (2)
go/internal/services/keys/verifier.go (1)
  • KeyVerifier (32-61)
go/pkg/rbac/permissions.go (2)
  • ResourceType (11-11)
  • ActionType (15-15)
go/apps/api/routes/v2_keys_verify_key/403_test.go (5)
go/pkg/testutil/http.go (2)
  • NewHarness (59-209)
  • CallRoute (405-439)
go/apps/api/routes/v2_keys_verify_key/handler.go (3)
  • Handler (32-38)
  • Request (25-25)
  • Response (26-26)
go/pkg/testutil/seed/seed.go (1)
  • CreateApiRequest (84-92)
go/pkg/rbac/permissions.go (1)
  • CreateKey (49-49)
go/apps/api/openapi/gen.go (4)
  • ForbiddenErrorResponse (138-144)
  • Meta (279-282)
  • NOTFOUND (40-40)
  • VALID (43-43)
⏰ 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 API / API Test Local
  • GitHub Check: Lint Go Code / Lint
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Build / Build
🔇 Additional comments (1)
go/apps/api/routes/v2_keys_verify_key/handler.go (1)

124-149: LGTM! The later permission check correctly uses the actual API ID.

This check correctly uses key.Key.ApiID from the looked-up key, properly validating permissions for the specific API. The 200 status with NOT_FOUND code (lines 137-148) is the correct approach to prevent leaking key existence when the root key lacks permissions for this specific API, even if it has permissions for other APIs.

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: 0

🧹 Nitpick comments (1)
go/apps/api/routes/v2_keys_verify_key/403_test.go (1)

15-15: Consider a more descriptive test function name.

The test function name TestForbidden_NoVerifyPermissions describes only the first subtest's scenario, but the function contains 4 subtests covering broader permission validation (forbidden, NOT_FOUND for wrong API, and successful cases). A name like TestVerifyKey_RootKeyPermissions would better reflect the comprehensive permission scenarios being tested.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between adbe292 and 18d5ec2.

📒 Files selected for processing (1)
  • go/apps/api/routes/v2_keys_verify_key/403_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/workflows/runbook-freshness-check.yaml:157-173
Timestamp: 2025-08-08T14:59:52.283Z
Learning: Repo unkeyed/unkey: When a CI/workflow fix is deferred, imeyer prefers a thorough GitHub issue be opened with sections (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References) and assigned to imeyer, including backlinks to the originating PR and comment.
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/actions/setup-node/action.yaml:0-0
Timestamp: 2025-08-08T15:10:46.436Z
Learning: Repo: unkeyed/unkey — Preference: If imeyer comments “issue” on a PR thread, automatically open a thorough GitHub issue (Summary, Impact, Where, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References), include backlinks to the PR and comment, and assign to imeyer.
Learnt from: imeyer
Repo: unkeyed/unkey PR: 3755
File: .github/workflows/job_detect_changes.yaml:111-114
Timestamp: 2025-08-08T16:10:00.224Z
Learning: Repo: unkeyed/unkey — When imeyer writes “make me an issue” on a PR thread, automatically open a thorough GitHub issue (Summary, Impact, Where, Repro, Observed vs Expected, Acceptance Criteria, Validation Plan, Out of Scope, References), include backlinks to the PR and comment, and assign to imeyer.
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 4190
File: go/internal/services/keys/verifier.go:51-53
Timestamp: 2025-10-30T15:10:52.743Z
Learning: PR #4190 for unkeyed/unkey is focused solely on database schema and query changes for identity-based credits. It adds IdentityCredits and KeyCredits fields to structs and queries, but does not implement the priority enforcement logic in the usagelimiter. The logic implementation is intentionally deferred to a later PR in the stack.
Learnt from: perkinsjr
Repo: unkeyed/unkey PR: 3880
File: apps/dashboard/app/(app)/settings/root-keys/components/root-key/root-key-dialog.tsx:137-141
Timestamp: 2025-08-29T12:08:57.482Z
Learning: Root keys in the Unkey system require at least one permission at minimum, so there is no valid case where a root key would have zero permissions. This means checking for permission existence when determining UI labels is unnecessary.
Learnt from: chronark
Repo: unkeyed/unkey PR: 3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
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.
📚 Learning: 2025-08-14T16:25:48.167Z
Learnt from: Flo4604
Repo: unkeyed/unkey PR: 3785
File: go/apps/api/routes/v2_keys_reroll_key/401_test.go:52-61
Timestamp: 2025-08-14T16:25:48.167Z
Learning: User Flo4604 requested creation of a GitHub issue to track converting all test files to use table-driven test patterns as a broader codebase improvement, following the suggestion made during review of go/apps/api/routes/v2_keys_reroll_key/401_test.go.

Applied to files:

  • go/apps/api/routes/v2_keys_verify_key/403_test.go
📚 Learning: 2025-09-15T19:53:28.487Z
Learnt from: mcstepp
Repo: unkeyed/unkey PR: 3952
File: go/proto/ctrl/v1/routing.proto:0-0
Timestamp: 2025-09-15T19:53:28.487Z
Learning: In the Unkey codebase, authentication/authorization errors intentionally return NOT_FOUND error codes instead of distinct auth error codes (like FORBIDDEN or UNAUTHORIZED) for security reasons. This prevents attackers from distinguishing between "resource doesn't exist" and "you don't have permission to access this resource", avoiding information disclosure about workspace existence and access boundaries.

Applied to files:

  • go/apps/api/routes/v2_keys_verify_key/403_test.go
⏰ 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). (1)
  • GitHub Check: Test API / API Test Local
🔇 Additional comments (5)
go/apps/api/routes/v2_keys_verify_key/403_test.go (5)

15-33: LGTM! Well-structured test setup.

The test harness is properly initialized with all required handler dependencies, and the base fixtures (workspace, API, key) are correctly created for use across subtests.


35-57: Excellent permission validation and error detail checking.

The test correctly validates the 403 response when the root key lacks verify permissions, and the assertions on lines 55-56 ensure the error message helpfully mentions both permission options (api.*.verify_key and api.<API_ID>.verify_key). The RequestId assertion on line 52 is good practice for validating error response metadata.


59-82: Excellent security-conscious test design.

This test correctly validates that when a root key has verify permission for a different API, the endpoint returns 200 with NOT_FOUND (not 403) to avoid leaking key existence—a critical security pattern. The comment on line 76 clearly documents this behavior. Based on learnings, this aligns with the intentional design to prevent information disclosure about workspace boundaries.


84-102: LGTM! Wildcard permission validation is correct.

The test properly validates that a root key with wildcard api.*.verify_key permission successfully verifies keys across all APIs, returning 200 with VALID code.


104-122: LGTM! Specific API permission validation is correct.

The test properly validates that a root key with a specific API verify permission (api.<API_ID>.verify_key) successfully verifies keys for that API, returning 200 with VALID code.

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.

403 error when verifying keys but no verify key permissions

3 participants