-
Couldn't load subscription status.
- Fork 11
feat: API key management #1407
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: API key management #1407
Conversation
|
Warning Rate limit exceeded@elibosley has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 31 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughThis update introduces a comprehensive API key management system, including backend GraphQL schema restructuring, new resolvers, and test coverage. It adds Vue components and pages for creating, listing, and deleting API keys with role and permission assignment. Supporting codegen rules, configuration tweaks, and UI utilities (accordion components and Tailwind animations) are also included. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ApiKeyManager (Vue)
participant ApiKeyCreate (Vue)
participant Backend GraphQL API
participant Database
User->>ApiKeyManager: Opens API Key page
ApiKeyManager->>Backend GraphQL API: Query apiKeys, apiKeyPossibleRoles, apiKeyPossiblePermissions
Backend GraphQL API->>Database: Fetch API keys, roles, permissions
Database-->>Backend GraphQL API: Return data
Backend GraphQL API-->>ApiKeyManager: Return keys, roles, permissions
User->>ApiKeyManager: Clicks "Create API Key"
ApiKeyManager->>ApiKeyCreate: Show creation form
User->>ApiKeyCreate: Fills form, submits
ApiKeyCreate->>Backend GraphQL API: Mutation apiKey.create(input)
Backend GraphQL API->>Database: Create API key, assign roles/permissions
Database-->>Backend GraphQL API: Return new API key
Backend GraphQL API-->>ApiKeyCreate: Return created API key
ApiKeyCreate->>ApiKeyManager: Emit 'created' event
ApiKeyManager->>Backend GraphQL API: Refetch apiKeys
Backend GraphQL API-->>ApiKeyManager: Return updated keys
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
🪧 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 (
|
3c11f7f to
54f30b4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
♻️ Duplicate comments (1)
api/dev/Unraid.net/myservers.cfg (1)
11-11: Avoid committing actual API keys to source control
Same concern as inapi/dev/states/myservers.cfg: this field contains a real API key. Use environment variables or a secrets manager to keep it out of version control.
🧹 Nitpick comments (9)
api/src/unraid-api/graph/resolvers/resolvers.module.ts (1)
5-5: Potentially unused importThe ApiKeyResolver import appears to be unused now that you're importing the entire ApiKeyModule. Consider removing this import to keep the code clean.
import { AuthModule } from '@app/unraid-api/auth/auth.module.js'; import { ApiKeyModule } from '@app/unraid-api/graph/resolvers/api-key/api-key.module.js'; -import { ApiKeyResolver } from '@app/unraid-api/graph/resolvers/api-key/api-key.resolver.js'; import { ArrayModule } from '@app/unraid-api/graph/resolvers/array/array.module.js';unraid-ui/src/components/common/accordion/AccordionTrigger.vue (1)
25-27: Consider adding accessibility attributes to the iconWhile the implementation works well, the chevron icon could benefit from additional accessibility attributes.
- <ChevronDown class="h-4 w-4 shrink-0 transition-transform duration-200" /> + <ChevronDown class="h-4 w-4 shrink-0 transition-transform duration-200" aria-hidden="true" />api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.ts (1)
69-79: Enhance delete method with more informative return valuesThe delete method returns a hardcoded
trueregardless of the actual deletion result. Consider returning more meaningful information about the operation's success.@ResolveField(() => Boolean, { description: 'Delete one or more API keys' }) async delete(@Args('input') input: DeleteApiKeyInput): Promise<boolean> { const validatedInput = await validateObject(DeleteApiKeyInput, input); - await this.apiKeyService.deleteApiKeys(validatedInput.ids); - return true; + const result = await this.apiKeyService.deleteApiKeys(validatedInput.ids); + return result.success; }This assumes the service method would be updated to return an object with operation status information.
web/components/ApiKey/ApiKeyManager.vue (2)
104-107: Improve accessibility for the show/hide key toggleThe eye icon button lacks appropriate accessibility attributes.
- <button type="button" class="focus:outline-none" @click="toggleShowKey"> - <component :is="showKey ? EyeSlashIcon : EyeIcon" class="w-5 h-5 text-gray-500" /> + <button + type="button" + class="focus:outline-none" + @click="toggleShowKey" + :aria-label="showKey ? 'Hide API key' : 'Show API key'" + > + <component :is="showKey ? EyeSlashIcon : EyeIcon" class="w-5 h-5 text-gray-500" aria-hidden="true" />
101-109: Add copy-to-clipboard functionality for the API keyUsers often need to copy API keys. Consider adding a copy button next to the key.
<div v-if="createdKey" class="mt-4"> <div class="flex items-center gap-2"> <span>API Key created:</span> <b>{{ showKey ? createdKey.key : '••••••••••••••••••••••••••••••••' }}</b> <button type="button" class="focus:outline-none" @click="toggleShowKey"> <component :is="showKey ? EyeSlashIcon : EyeIcon" class="w-5 h-5 text-gray-500" /> </button> + <button + v-if="showKey" + type="button" + class="focus:outline-none" + @click="navigator.clipboard.writeText(createdKey.key)" + aria-label="Copy API key to clipboard" + > + <ClipboardIcon class="w-5 h-5 text-gray-500" aria-hidden="true" /> + </button> </div> </div>Don't forget to import the ClipboardIcon:
import { EyeIcon, EyeSlashIcon } from '@heroicons/vue/24/solid'; +import { ClipboardIcon } from '@heroicons/vue/24/solid';web/components/ApiKey/ApiKeyCreate.vue (3)
110-129: Missing form field validation indicators.The form lacks visual cues for required fields and validation feedback.
Consider adding required indicators and validation feedback:
<div class="mb-2"> - <Label for="api-key-name">Name</Label> + <Label for="api-key-name">Name *</Label> <Input id="api-key-name" v-model="newKeyName" placeholder="Name" class="mt-1" /> + <span v-if="!newKeyName.trim() && formSubmitted" class="text-red-500 text-xs mt-1">Name is required</span> </div>
156-156: Potential event type safety issue.The event handling for the checkbox change doesn't use a more specific event type.
Consider using a more specific event type for better type safety:
- @change="(e: Event) => togglePermission(perm.resource, action, (e.target as HTMLInputElement)?.checked)" + @change="(e: Event & { target: HTMLInputElement }) => togglePermission(perm.resource, action, e.target.checked)"
168-169: Add disabled state to the Create button.The Create button should be disabled when the form is invalid or during submission.
Enhance the button with loading and validation states:
- <Button variant="primary" @click="createKey">Create</Button> + <Button + variant="primary" + @click="createKey" + :disabled="loading || !newKeyName.trim()" + > + {{ loading ? 'Creating...' : 'Create' }} + </Button> <Button variant="secondary" @click="$emit('cancel')">Cancel</Button>api/generated-schema.graphql (1)
901-911: Consider adding description validation to CreateApiKeyInput.While the input type is well-structured, consider adding validation constraints for the description field if there are specific requirements.
Consider using directives to document validation constraints if applicable:
input CreateApiKeyInput { name: String! - description: String + description: String @constraint(maxLength: 500) roles: [Role!] permissions: [AddPermissionInput!] """ This will replace the existing key if one already exists with the same name, otherwise returns the existing key """ overwrite: Boolean }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (26)
.cursor/rules/web-graphql.mdc(1 hunks)api/dev/Unraid.net/myservers.cfg(2 hunks)api/dev/states/myservers.cfg(2 hunks)api/generated-schema.graphql(3 hunks)api/src/unraid-api/auth/api-key.service.ts(1 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.model.ts(1 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.module.ts(1 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.ts(1 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts(2 hunks)api/src/unraid-api/graph/resolvers/mutation/mutation.model.ts(2 hunks)api/src/unraid-api/graph/resolvers/mutation/mutation.resolver.ts(2 hunks)api/src/unraid-api/graph/resolvers/resolvers.module.ts(3 hunks)unraid-ui/package.json(1 hunks)unraid-ui/src/components/common/accordion/Accordion.vue(1 hunks)unraid-ui/src/components/common/accordion/AccordionContent.vue(1 hunks)unraid-ui/src/components/common/accordion/AccordionItem.vue(1 hunks)unraid-ui/src/components/common/accordion/AccordionTrigger.vue(1 hunks)unraid-ui/src/components/common/accordion/index.ts(1 hunks)unraid-ui/src/index.ts(2 hunks)unraid-ui/tailwind.config.ts(2 hunks)web/components/ApiKey/ApiKeyCreate.vue(1 hunks)web/components/ApiKey/ApiKeyManager.vue(1 hunks)web/components/ApiKey/apikey.query.ts(1 hunks)web/composables/gql/gql.ts(3 hunks)web/composables/gql/graphql.ts(6 hunks)web/pages/apikey.vue(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
api/src/unraid-api/auth/api-key.service.ts (1)
Learnt from: mdatelle
PR: unraid/api#942
File: api/src/unraid-api/auth/auth.service.ts:0-0
Timestamp: 2024-11-04T20:44:46.432Z
Learning: When modifying `apiKey.roles` in `removeRoleFromApiKey` and `addRoleToApiKey` within `api/src/unraid-api/auth/auth.service.ts`, concurrency issues are not a concern because the keys are stored in the file system.
api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts (2)
Learnt from: mdatelle
PR: unraid/api#942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in `api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts`, methods like `removeRoleFromApiKey` rely on service-level error handling.
Learnt from: mdatelle
PR: unraid/api#942
File: api/src/unraid-api/auth/auth.service.ts:0-0
Timestamp: 2024-11-04T20:44:46.432Z
Learning: When modifying `apiKey.roles` in `removeRoleFromApiKey` and `addRoleToApiKey` within `api/src/unraid-api/auth/auth.service.ts`, concurrency issues are not a concern because the keys are stored in the file system.
api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.ts (1)
Learnt from: mdatelle
PR: unraid/api#942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in `api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts`, methods like `removeRoleFromApiKey` rely on service-level error handling.
🧬 Code Graph Analysis (4)
api/src/unraid-api/graph/resolvers/mutation/mutation.resolver.ts (1)
web/composables/gql/graphql.ts (2)
Mutation(892-921)ApiKeyMutations(135-145)
api/src/unraid-api/graph/resolvers/api-key/api-key.module.ts (1)
api/src/unraid-api/graph/resolvers/resolvers.module.ts (1)
Module(37-65)
web/components/ApiKey/apikey.query.ts (1)
web/composables/gql/gql.ts (1)
graphql(222-224)
web/composables/gql/gql.ts (1)
api/src/graphql/generated/client/gql.ts (1)
graphql(54-56)
🪛 GitHub Actions: CI - Main (API)
unraid-ui/tailwind.config.ts
[error] 1-1: Cannot find module '@/theme/preset'. This module is required by tailwind.config.ts but was not found, causing the build to fail.
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Cloudflare Pages
🔇 Additional comments (42)
api/dev/states/myservers.cfg (1)
2-2: Version bump to 4.8.0 is correctly applied
The API version under[api]has been updated from “4.7.0” to “4.8.0” to match the new schema changes. No further actions needed.unraid-ui/package.json (1)
56-56: Dependencyreka-uiupdated to ^2.1.1
The minor bump aligns with the new accordion components. Please ensure that version ^2.1.1 is available on the registry and that no breaking changes affect existing functionality.api/dev/Unraid.net/myservers.cfg (1)
2-2: Version bump to 4.8.0 is correctly applied
This matches the update inapi/dev/states/myservers.cfg.unraid-ui/src/index.ts (2)
12-17: Re-export new accordion components
Imports forAccordion,AccordionContent,AccordionItem, andAccordionTriggerlook correct and match the component paths.
89-93: Expose accordion components in public API
The export block correctly includes the newly added accordion components. Ensure the order is consistent with other components for readability.web/pages/apikey.vue (1)
1-6: Add new API Key management page
The template and script setup correctly import and renderApiKeyManager. Ensure this page is registered in the router configuration (e.g.,web/router/index.ts) so it’s accessible via its intended path.api/src/unraid-api/graph/resolvers/api-key/api-key.model.ts (1)
136-142: Well-structured input type for API key deletionThe new
DeleteApiKeyInputclass is properly designed with appropriate validation decorators to ensure the input contains an array of string IDs. This addition supports the bulk deletion operation within the new ApiKeyMutations group.unraid-ui/src/components/common/accordion/index.ts (1)
1-4: Clean barrel exports for accordion componentsThis is a good implementation of a barrel file that centralizes exports for the accordion component set. The approach simplifies imports in other parts of the codebase and follows common component library patterns.
api/src/unraid-api/graph/resolvers/mutation/mutation.resolver.ts (2)
4-4: Import matches implementationThe import of
ApiKeyMutationscorrectly aligns with its usage in the new mutation resolver method.
34-37: Consistent mutation resolver patternThe new
apiKey()resolver method follows the established pattern in the codebase - it's properly decorated with@Mutationand returns a new instance of the mutations class. This implementation aligns with the GraphQL schema restructuring that groups API key operations.api/src/unraid-api/auth/api-key.service.ts (2)
133-134: Improved validation for API key creationThe validation logic now correctly checks for either roles or permissions, which is more flexible and aligns with the expanded functionality of the API key system.
137-137: Added null safety with optional chainingGood addition of optional chaining to prevent potential TypeErrors when roles might be undefined. This defensive programming approach makes the code more robust.
api/src/unraid-api/graph/resolvers/api-key/api-key.module.ts (1)
4-4: Well-structured module with proper dependency integrationThe changes to ApiKeyModule correctly introduce the AuthModule import and integrate the new ApiKeyMutationsResolver. This modularization aligns with NestJS best practices by:
- Importing the required AuthModule
- Adding ApiKeyMutationsResolver to providers
- Exporting ApiKeyService alongside ApiKeyResolver
This structure supports the new API key management feature and follows good separation of concerns by grouping related functionality.
Also applies to: 6-6, 10-12
api/src/unraid-api/graph/resolvers/resolvers.module.ts (1)
4-4: Good modularization of ApiKey functionalityThe changes properly integrate ApiKeyModule into the ResolversModule by importing and exporting it. This is a good refactoring that improves code organization.
Also applies to: 38-38, 63-63
.cursor/rules/web-graphql.mdc (1)
1-9: Good GraphQL code organization rulesThese rules establish clear conventions for GraphQL code in the web directory, which will help maintain consistency as the codebase grows. The separation of queries and mutations into distinct file types is a good practice that makes the code more discoverable and maintainable.
unraid-ui/src/components/common/accordion/Accordion.vue (1)
1-19: Well-structured Vue component with proper prop forwardingThis Accordion component follows Vue 3 best practices:
- Uses the composition API with
<script setup>syntax- Properly types props and emits using TypeScript
- Efficiently forwards props and emits to the underlying component
- Provides a slot for flexible content injection
The component serves as a clean wrapper around the reka-ui AccordionRoot component, maintaining a consistent interface while leveraging the third-party functionality.
api/src/unraid-api/graph/resolvers/mutation/mutation.model.ts (2)
12-15: Clean implementation of API key mutations.The new
ApiKeyMutationsclass follows the existing pattern for organizing GraphQL mutations in the codebase, with proper use of decorators and descriptions.
33-34: Correctly integrates API key mutations into root schema.The addition of the
apiKeyfield toRootMutationsis properly implemented with appropriate typing and description, making API key operations accessible through the GraphQL API.unraid-ui/src/components/common/accordion/AccordionContent.vue (1)
1-22: Well-structured accordion content component.This component follows Vue best practices with:
- Proper TypeScript typing
- Clean prop forwarding using
reactiveOmit- Appropriate animation classes for accordion transitions
- Slot content handling with class merging via
cnutilityThe animation classes reference will work in conjunction with the keyframes defined in the Tailwind config.
unraid-ui/src/components/common/accordion/AccordionItem.vue (1)
1-19: Well-implemented accordion item component.This component:
- Correctly extends the base component from reka-ui
- Properly handles prop forwarding with
useForwardPropsandreactiveOmit- Applies consistent styling with border-bottom
- Maintains the slot pattern for content injection
The implementation follows the same pattern as the AccordionContent component, creating a cohesive accordion system.
unraid-ui/tailwind.config.ts (1)
91-112: Good addition of accordion animation keyframes.The keyframes and animation definitions are well-structured and provide smooth transitions for the accordion components. The values are appropriate for a good user experience:
- Using CSS variables for dynamic height calculation
- Reasonable animation duration (0.2s)
- Appropriate easing function (ease-out)
unraid-ui/src/components/common/accordion/AccordionTrigger.vue (2)
1-11: Good implementation of the AccordionTrigger componentThe component setup looks solid with proper use of TypeScript and Vue 3's script setup syntax. Using
reactiveOmitto handle prop forwarding is a good practice to avoid passing the class prop directly.
13-30: Well-structured template with proper stylingThe template implementation is clean and follows best practices:
- Wrapping with AccordionHeader
- Using slots for content customization
- Providing a default icon with animation
- Using the
cnutility for class mergingThe animation effect on the chevron icon (rotate 180 degrees when open) provides good visual feedback to users.
api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.ts (4)
21-26: Well-structured resolver with proper dependency injectionThe resolver class follows NestJS best practices with constructor-based dependency injection for services.
28-45: Create method properly validates input and handles permissionsThe create method:
- Uses appropriate permission decorators
- Validates input before processing
- Correctly converts optional values to undefined when needed
- Properly syncs roles after creation
This implementation aligns with best practices for GraphQL resolvers.
47-56: Good implementation of addRole methodThe method correctly:
- Applies permission checks
- Validates input
- Converts the role string to the appropriate enum value
- Returns the result from the service
This follows the established pattern in the project.
58-67: Consistent implementation of removeRole methodThis method follows the same pattern as addRole, ensuring consistency across the codebase.
web/components/ApiKey/apikey.query.ts (4)
1-18: Well-structured API keys queryThe GET_API_KEYS query is properly structured and fetches all necessary fields for displaying API keys, including nested permissions.
20-37: Comprehensive CREATE_API_KEY mutationThe mutation correctly uses the new hierarchical structure with
apiKey { create }and returns all relevant fields, including the secret key which is essential for first-time display to users.
39-45: Simple and effective DELETE_API_KEY mutationThe mutation is correctly structured to match the new schema pattern.
47-55: Useful metadata query for API key managementThe GET_API_KEY_META query retrieves essential information for the UI to display role and permission options.
web/components/ApiKey/ApiKeyManager.vue (2)
15-22: Well-defined interface for API keysThe interface includes all necessary properties for displaying and managing API keys.
24-37: Effective state management with Apollo composablesThe component properly handles state with Apollo composables and Vue reactivity. Using watchEffect is a good approach to keep the local state in sync with query results.
api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts (1)
57-66: Avoid rebuilding a static matrix on every request
resources.map(...)allocates a brand-new array each time the resolver is hit.
BecauseResourceandAuthActionVerbare compile-time enums, the result never changes, so we can compute it once:+// move to module scope (above the @Resolver class) +const ALL_PERMISSION_COMBOS: Permission[] = Object.values(Resource).map( + (resource) => ({ + resource, + actions: Object.values(AuthActionVerb).map(String), // ensure string[] + }), +); ... - const resources = Object.values(Resource); - const actions = Object.values(AuthActionVerb); - return resources.map((resource) => ({ - resource, - actions, - })); + return ALL_PERMISSION_COMBOS;This shaves off repeated allocations and keeps the resolver pure.
Also note the explicitmap(String)cast – without itactionsis typed asAuthActionVerb[], whereas the GraphQL schema expectsstring[].
[ suggest_optional_refactor ]web/composables/gql/gql.ts (1)
1-2045: Generated file – no manual changes requiredAll additions are code-gen output and look consistent with the updated schema.
No action needed.web/composables/gql/graphql.ts (1)
134-170: Schema types update acknowledgedThe new
ApiKeyMutations,DeleteApiKeyInput, and query fields are correctly reflected.
Nothing to flag here.web/components/ApiKey/ApiKeyCreate.vue (2)
1-24: Well-structured component setup with appropriate props and events.The component correctly uses Vue 3's Composition API with TypeScript and properly defines props and emits. The component accepts possible roles and permissions as props and emits events when a key is created or the operation is canceled.
35-51: Well-implemented permission toggle function.The
togglePermissionfunction correctly handles adding and removing permissions with proper checks for existing resources and actions.api/generated-schema.graphql (4)
886-899: Good design choice grouping API key mutations.Organizing related API key mutations under a dedicated
ApiKeyMutationstype improves API structure and maintainability. This approach follows GraphQL best practices for organizing related operations.
928-930: Good design for bulk delete operation.The
DeleteApiKeyInputtype efficiently supports bulk deletion by accepting an array of IDs, which is more efficient than making multiple single-delete requests.
1529-1536: Well-designed query endpoints for API key management.The addition of dedicated queries for API keys, including metadata queries for possible roles and permissions, provides a complete and cohesive API for managing API keys.
1574-1574: Consistent integration with root mutation type.The API key mutations are correctly integrated into the root
Mutationtype using a single field, maintaining a clean and organized schema structure.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (2)
api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.spec.ts (2)
59-60: Test the permissions functionalityThe test creates a mock with empty permissions array but doesn't test any permission-related functionality. If the resolver supports permission management, consider adding tests that verify this functionality works correctly.
76-86: Expand delete test casesThe current test only verifies the happy path for deleting API keys. Consider adding tests for:
- Deleting multiple API keys at once
- Error handling when deletion fails
- Edge cases like empty ID array or non-existent IDs
This will ensure robust error handling and functionality.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.cursor/rules/api-rules.mdc(1 hunks)api/dev/states/myservers.cfg(1 hunks)api/src/unraid-api/auth/api-key.service.spec.ts(1 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.spec.ts(1 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.spec.ts(0 hunks)api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts(3 hunks)
💤 Files with no reviewable changes (1)
- api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.spec.ts
✅ Files skipped from review due to trivial changes (1)
- .cursor/rules/api-rules.mdc
🚧 Files skipped from review as they are similar to previous changes (2)
- api/dev/states/myservers.cfg
- api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.spec.ts (1)
web/composables/gql/graphql.ts (2)
ApiKey(124-132)ApiKeyWithSecret(177-186)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: Test API
- GitHub Check: Build Web App
- GitHub Check: Build API
- GitHub Check: Cloudflare Pages
🔇 Additional comments (2)
api/src/unraid-api/auth/api-key.service.spec.ts (1)
188-188: Test updated to reflect new validation requirementsThe error message has been updated to reflect that API keys now require either roles OR permissions to be specified, rather than just roles. This aligns with the enhanced API key management system that now supports both role-based and permission-based access control.
api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.spec.ts (1)
64-73: Verify correct parameters in create testThe test verifies that
apiKeyService.createis called with the expected parameters, but there's a discrepancy:mockApiKeyWithSecretis returned by the service, butmockApiKey(without the secret) is used in the expectations forsyncApiKeyRoles. Ensure this is intentional and accurately reflects the resolver's behavior.
api/src/unraid-api/graph/resolvers/api-key/api-key.mutation.spec.ts
Outdated
Show resolved
Hide resolved
api/src/unraid-api/graph/resolvers/mutation/mutation.resolver.ts
Outdated
Show resolved
Hide resolved
|
Just a couple nits. |
|
This plugin has been deployed to Cloudflare R2 and is available for testing. |
🤖 I have created a release *beep* *boop* --- ## [4.9.0](v4.8.0...v4.9.0) (2025-07-08) ### Features * add graphql resource for API plugins ([#1420](#1420)) ([642a220](642a220)) * add management page for API keys ([#1408](#1408)) ([0788756](0788756)) * add rclone ([#1362](#1362)) ([5517e75](5517e75)) * API key management ([#1407](#1407)) ([d37dc3b](d37dc3b)) * api plugin management via CLI ([#1416](#1416)) ([3dcbfbe](3dcbfbe)) * build out docker components ([#1427](#1427)) ([711cc9a](711cc9a)) * docker and info resolver issues ([#1423](#1423)) ([9901039](9901039)) * fix shading in UPC to be less severe ([#1438](#1438)) ([b7c2407](b7c2407)) * info resolver cleanup ([#1425](#1425)) ([1b279bb](1b279bb)) * initial codeql setup ([#1390](#1390)) ([2ade7eb](2ade7eb)) * initialize claude code in codebse ([#1418](#1418)) ([b6c4ee6](b6c4ee6)) * move api key fetching to use api key service ([#1439](#1439)) ([86bea56](86bea56)) * move to cron v4 ([#1428](#1428)) ([b8035c2](b8035c2)) * move to iframe for changelog ([#1388](#1388)) ([fcd6fbc](fcd6fbc)) * native slackware package ([#1381](#1381)) ([4f63b4c](4f63b4c)) * send active unraid theme to docs ([#1400](#1400)) ([f71943b](f71943b)) * slightly better watch mode ([#1398](#1398)) ([881f1e0](881f1e0)) * upgrade nuxt-custom-elements ([#1461](#1461)) ([345e83b](345e83b)) * use bigint instead of long ([#1403](#1403)) ([574d572](574d572)) ### Bug Fixes * activation indicator removed ([5edfd82](5edfd82)) * alignment of settings on ManagementAccess settings page ([#1421](#1421)) ([70c790f](70c790f)) * allow rclone to fail to initialize ([#1453](#1453)) ([7c6f02a](7c6f02a)) * always download 7.1 versioned files for patching ([edc0d15](edc0d15)) * api `pnpm type-check` ([#1442](#1442)) ([3122bdb](3122bdb)) * **api:** connect config `email` validation ([#1454](#1454)) ([b9a1b9b](b9a1b9b)) * backport unraid/webgui[#2269](https://github.com/unraid/api/issues/2269) rc.nginx update ([#1436](#1436)) ([a7ef06e](a7ef06e)) * bigint ([e54d27a](e54d27a)) * config migration from `myservers.cfg` ([#1440](#1440)) ([c4c9984](c4c9984)) * **connect:** fatal race-condition in websocket disposal ([#1462](#1462)) ([0ec0de9](0ec0de9)) * **connect:** mothership connection ([#1464](#1464)) ([7be8bc8](7be8bc8)) * console hidden ([9b85e00](9b85e00)) * debounce is too long ([#1426](#1426)) ([f12d231](f12d231)) * delete legacy connect keys and ensure description ([22fe91c](22fe91c)) * **deps:** pin dependencies ([#1465](#1465)) ([ba75a40](ba75a40)) * **deps:** pin dependencies ([#1470](#1470)) ([412b329](412b329)) * **deps:** storybook v9 ([#1476](#1476)) ([45bb49b](45bb49b)) * **deps:** update all non-major dependencies ([#1366](#1366)) ([291ee47](291ee47)) * **deps:** update all non-major dependencies ([#1379](#1379)) ([8f70326](8f70326)) * **deps:** update all non-major dependencies ([#1389](#1389)) ([cb43f95](cb43f95)) * **deps:** update all non-major dependencies ([#1399](#1399)) ([68df344](68df344)) * **deps:** update dependency @types/diff to v8 ([#1393](#1393)) ([00da27d](00da27d)) * **deps:** update dependency cache-manager to v7 ([#1413](#1413)) ([9492c2a](9492c2a)) * **deps:** update dependency commander to v14 ([#1394](#1394)) ([106ea09](106ea09)) * **deps:** update dependency diff to v8 ([#1386](#1386)) ([e580f64](e580f64)) * **deps:** update dependency dotenv to v17 ([#1474](#1474)) ([d613bfa](d613bfa)) * **deps:** update dependency lucide-vue-next to ^0.509.0 ([#1383](#1383)) ([469333a](469333a)) * **deps:** update dependency marked to v16 ([#1444](#1444)) ([453a5b2](453a5b2)) * **deps:** update dependency shadcn-vue to v2 ([#1302](#1302)) ([26ecf77](26ecf77)) * **deps:** update dependency vue-sonner to v2 ([#1401](#1401)) ([53ca414](53ca414)) * disable file changes on Unraid 7.2 ([#1382](#1382)) ([02de89d](02de89d)) * do not start API with doinst.sh ([7d88b33](7d88b33)) * do not uninstall fully on 7.2 ([#1484](#1484)) ([2263881](2263881)) * drop console with terser ([a87d455](a87d455)) * error logs from `cloud` query when connect is not installed ([#1450](#1450)) ([719f460](719f460)) * flash backup integration with Unraid Connect config ([#1448](#1448)) ([038c582](038c582)) * header padding regression ([#1477](#1477)) ([e791cc6](e791cc6)) * incorrect state merging in redux store ([#1437](#1437)) ([17b7428](17b7428)) * lanip copy button not present ([#1459](#1459)) ([a280786](a280786)) * move to bigint scalar ([b625227](b625227)) * node_modules dir removed on plugin update ([#1406](#1406)) ([7b005cb](7b005cb)) * omit Connect actions in UPC when plugin is not installed ([#1417](#1417)) ([8c8a527](8c8a527)) * parsing of `ssoEnabled` in state.php ([#1455](#1455)) ([f542c8e](f542c8e)) * pin ranges ([#1460](#1460)) ([f88400e](f88400e)) * pr plugin promotion workflow ([#1456](#1456)) ([13bd9bb](13bd9bb)) * proper fallback if missing paths config modules ([7067e9e](7067e9e)) * rc.unraid-api now cleans up older dependencies ([#1404](#1404)) ([83076bb](83076bb)) * remote access lifecycle during boot & shutdown ([#1422](#1422)) ([7bc583b](7bc583b)) * sign out correctly on error ([#1452](#1452)) ([d08fc94](d08fc94)) * simplify usb listing ([#1402](#1402)) ([5355115](5355115)) * theme issues when sent from graph ([#1424](#1424)) ([75ad838](75ad838)) * **ui:** notifications positioning regression ([#1445](#1445)) ([f73e5e0](f73e5e0)) * use some instead of every for connect detection ([9ce2fee](9ce2fee)) ### Reverts * revert package.json dependency updates from commit 711cc9a for api and packages/* ([94420e4](94420e4)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Documentation
Tests