Skip to content

Conversation

@elibosley
Copy link
Member

@elibosley elibosley commented Jan 30, 2025

Summary by CodeRabbit

  • New Features

    • Added ability to overwrite existing API keys during creation
    • Introduced optional in-memory API key creation
    • Enhanced permission management for API keys
  • Bug Fixes

    • Improved handling of existing API keys to prevent unnecessary errors
  • Refactor

    • Reorganized API key resolver and related modules
    • Updated GraphQL schema types for more flexible permission handling
  • Chores

    • Updated session cookie handling in development environment

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 30, 2025

Walkthrough

The pull request introduces enhancements to API key management by adding an overwrite flag and expanding permission capabilities. The changes span multiple files, modifying GraphQL schema, service logic, and type definitions to provide more flexible API key creation and permission handling. The modifications allow for optional key overwriting, in-memory key storage, and more granular permission management.

Changes

File Change Summary
api/src/graphql/schema/types/api-key/api-key.graphql Added overwrite: Boolean to CreateApiKeyInput
api/src/unraid-api/auth/api-key.service.ts Updated create method to support overwrite and memory parameters
api/src/unraid-api/graph/resolvers/* Refactored resolvers from AuthResolver to ApiKeyResolver
web/composables/gql/graphql.ts Updated GraphQL type definitions for API keys and permissions

Sequence Diagram

sequenceDiagram
    participant Client
    participant Resolver
    participant ApiKeyService
    participant Storage

    Client->>Resolver: Create API Key
    Resolver->>ApiKeyService: create(input)
    alt Key exists and overwrite=false
        ApiKeyService-->>Resolver: Return existing key
    else Key doesn't exist or overwrite=true
        ApiKeyService->>Storage: Save API Key
        Storage-->>ApiKeyService: Confirm save
        ApiKeyService-->>Resolver: Return new key
    end
    Resolver-->>Client: API Key Response
Loading

Possibly related PRs

Suggested Reviewers

  • pujitm
  • mdatelle

Poem

Behold, the API key's might! 🔑
With overwrite power, shining bright
Permissions dancing, roles so clear
A resolver's dream, now drawing near!
Mwahahahaha! evil plankton laugh 🦠


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 6b3d5b4 and feb6f71.

📒 Files selected for processing (1)
  • api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.spec.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.spec.ts
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build and Test API
  • GitHub Check: Build Web App
  • GitHub Check: Cloudflare Pages

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

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

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link
Contributor

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

🧹 Nitpick comments (5)
web/composables/gql/graphql.ts (1)

354-360: Thar be new memories and overwrites on deck!
‘memory’ and ‘overwrite’ fields let ye craft ephemeral or replaceable API keys. Exercise caution when ephemeral keys vanish or get replaced, me matey—make sure the rest o’ the code handles it gracefully.

api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.spec.ts (1)

Line range hint 89-102: Yer tests could use a bit more muscle, cap'n!

While the test cases be solid, we could strengthen our assertions to ensure the API key creation behaves exactly as expected.

Add these additional assertions to yer test:

 expect(apiKeyService.create).toHaveBeenCalledWith({
     name: input.name,
     description: input.description,
     roles: input.roles,
     permissions: [],
+    memory: false,
+    overwrite: false
 });
+expect(result.id).toBeDefined();
+expect(result.key).toBeDefined();
+expect(result.createdAt).toBeDefined();
api/src/unraid-api/auth/api-key.service.ts (2)

106-113: Add more details to yer ship's log, sailor!

While ye've added the new memory parameter, we could use more documentation about its behavior and limitations.

Add JSDoc comments to explain:

+/**
+ * Creates a new API key with the specified parameters.
+ * @param {Object} params - The API key creation parameters
+ * @param {boolean} [params.memory=false] - If true, stores the key in memory only
+ * @param {boolean} [params.overwrite=false] - If true, overwrites existing key
+ * @throws {GraphQLError} When validation fails
+ * @returns {Promise<ApiKeyWithSecret>} The created or existing API key
+ */
 async create({

131-133: Add a log entry when returnin' an existin' key, ye scallywag!

When we find an existin' key and return it instead of throwin' an error, we should log this for the ship's records.

 if (!overwrite && existingKey) {
+    this.logger.debug(`Returning existing API key for name: ${sanitizedName}`);
     return existingKey;
 }
api/src/graphql/schema/types/api-key/api-key.graphql (1)

30-33: Yer schema documentation be ship-shape, but we could use some constraints!

The documentation for the new fields be clear as Caribbean waters! However, we might want to add some default values to help our crew.

Consider adding default values in the schema:

 """ This will replace the existing key if one already exists with the same name, otherwise returns the existing key """
-overwrite: Boolean
+overwrite: Boolean = false
 """ Whether to create the key in memory only (true), or on disk (false) - memory only keys will not persist through reboots of the API """
-memory: Boolean
+memory: Boolean = false
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 445af0c and 95c2e32.

⛔ Files ignored due to path filters (2)
  • api/src/graphql/generated/api/operations.ts is excluded by !**/generated/**
  • api/src/graphql/generated/api/types.ts is excluded by !**/generated/**
📒 Files selected for processing (11)
  • api/dev/states/myservers.cfg (1 hunks)
  • api/src/graphql/schema/types/api-key/api-key.graphql (1 hunks)
  • api/src/unraid-api/auth/api-key.service.ts (3 hunks)
  • api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.spec.ts (2 hunks)
  • api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts (2 hunks)
  • api/src/unraid-api/graph/resolvers/resolvers.module.ts (3 hunks)
  • web/components/UserProfile.ce.vue (1 hunks)
  • web/composables/gql/graphql.ts (10 hunks)
  • web/helpers/create-apollo-client.ts (3 hunks)
  • web/helpers/urls.ts (0 hunks)
  • web/pages/index.vue (3 hunks)
💤 Files with no reviewable changes (1)
  • web/helpers/urls.ts
✅ Files skipped from review due to trivial changes (2)
  • web/helpers/create-apollo-client.ts
  • web/components/UserProfile.ce.vue
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Build and Test API
  • GitHub Check: Build Web App
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (14)
web/pages/index.vue (2)

5-5: Arr, the import be ship-shape!

Ye've properly imported the SsoButtonCe from the components treasure chest.


163-163: Aye, the SSO button be properly mounted!

The SsoButtonCe component be correctly bound to the serverState's ssoEnabled flag. Smooth sailin' ahead!

web/composables/gql/graphql.ts (5)

47-47: Arr, multiple actions be a glorious bounty!
Switchin' from a single action to an array of actions grants more fine-grained permissions, me hearty. This be a worthy enhancement.


71-71: Aye, adding 'permissions' to the ApiKey type be smooth sailin'
This array structure neatly captures a treasure chest of permission details.


88-88: Shipshape expansion of 'ApiKeyWithSecret'
Ye new 'permissions' array ensures consistent scallywag-proofing across the code.


607-607: Yarr, typed arrays be better than uncharted JSON
Switchin’ to Array<Permission> gives clear structure over arbitrary JSON. This reduces confusion among the crew.


1036-1041: Hoist the sails, a new 'Permission' type be upon ye!
Definin’ actions as an array and specifying a resource be a grand approach for robust access control.

api/dev/states/myservers.cfg (1)

22-22: Ye changed the minigraph to 'ERROR_RETRYING'?
Beware the seas of infinite retries, me buccaneer. Ensure the code signals errors properly and does not swirl into a maelstrom.

api/src/unraid-api/graph/resolvers/resolvers.module.ts (4)

7-7: Avast, 'ApiKeyResolver' import be a new recruit!
This signals we be shippin’ out from the old 'AuthResolver' approach.


14-14: Thar be 'MeResolver' still on deck
But the changes speak of removing 'AuthResolver' in favor of 'ApiKeyResolver'. Verify if 'MeResolver' stays or if it was also meant to walk the plank.


28-28: Aye, providers now list 'ApiKeyResolver'
This lines up with the new key-based approach for authentication. Smooth sailing.


46-46: Exports array parted ways with old treasure
Replacing AuthResolver with ApiKeyResolver ensures the new system be fully operational.

api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts (2)

19-22: Aye, a fine renamin' of the resolver class, matey!

The change from AuthResolver to ApiKeyResolver be a proper move, followin' the single responsibility principle like a true pirate follows their treasure map!


Line range hint 1-100: Ye've kept a tidy ship here, cap'n!

The overall structure of this resolver be ship-shape, with proper decorators, clean method organization, and good use of types.

Comment on lines +18 to +20
onMounted(() => {
document.cookie = 'unraid_session_cookie=mockusersession';
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Blimey! This cookie be vulnerable to pirates!

Arr matey, setting cookies directly in the frontend code be askin' for trouble! Any scurvy dog with a browser console could manipulate this session.

Consider these security measures to protect yer treasure:

  • Move cookie settin' to the backend crow's nest
  • Add security flags like httpOnly, secure, and sameSite
  • Use proper session management instead of hardcoded values

Here's a safer way to handle sessions, ye landlubber:

-onMounted(() => {
-  document.cookie = 'unraid_session_cookie=mockusersession';
-});

Move this to your backend authentication route instead!

Comment on lines 63 to 64
memory: input.memory ?? false,
overwrite: input.overwrite ?? false
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Aye, ye concerns be valid as a compass pointin' north!

After diggin' through the ship's logs, there be no safety nets preventin' these dangerous waters:

  • A memory key could overwrite a disk key, leavin' us with ghost keys
  • A disk key could replace a memory key, causin' unwanted persistence

Here be the spots needin' attention:

  • api-key.service.ts: Add validation in the create() method before the memory/disk operations to prevent these conflictin' flags from causin' trouble

Example validation needed:

if (memory && overwrite && existingKey && !existingKey.memory) {
  throw new GraphQLError('Cannot overwrite a disk key with a memory key');
}
🔗 Analysis chain

Ahoy! We be needin' some guard rails on these new parameters!

While ye've added the new memory and overwrite flags, we should be checkin' that they don't conflict with each other in ways that could sink our ship!

Consider these edge cases:

  1. What happens if both memory and overwrite be true?
  2. Should we allow overwritin' a disk-stored key with a memory key?
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Let's search for any existing validation logic
ast-grep --pattern 'if ($memory && $overwrite) {
  $$$
}'

Length of output: 59


Script:

#!/bin/bash
# Let's find the complete createApiKey implementation
ast-grep --pattern 'createApiKey($$$) {
  $$$
}'

# Also search for the input type definition
ast-grep --pattern 'input CreateApiKeyInput {
  $$$
}'

# And check for any validation decorators or functions
rg -A 5 "memory.*overwrite|overwrite.*memory" --type typescript

Length of output: 208


Script:

#!/bin/bash
# Read the complete resolver file
cat api/src/unraid-api/graph/resolvers/api-key/api-key.resolver.ts

# Look for related test files
fd "api-key.*test" --type f

Length of output: 3030


Script:

#!/bin/bash
# Check the API key service implementation
cat api/src/unraid-api/auth/api-key.service.ts

Length of output: 11002

Comment on lines +13 to +14
describe('ApiKeyResolver', () => {
let resolver: ApiKeyResolver;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Arrr! We be missin' some important test cases here, matey!

The test suite be lackin' coverage for the new memory and overwrite parameters in the createApiKey mutation.

Add these test cases to yer test suite:

 describe('createApiKey', () => {
+    it('should create new API key in memory when memory flag is true', async () => {
+        const input = {
+            name: 'Memory API Key',
+            roles: [Role.GUEST],
+            memory: true
+        };
+        // Add test implementation
+    });
+
+    it('should overwrite existing API key when overwrite flag is true', async () => {
+        const input = {
+            name: 'Existing Key',
+            roles: [Role.GUEST],
+            overwrite: true
+        };
+        // Add test implementation
+    });
 });

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 147 to 151
if (memory) {
this.memoryApiKeys.push(apiKey as ApiKeyWithSecret)
} else {
await this.saveApiKey(apiKey as ApiKeyWithSecret);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ye need to swab the deck of old memory keys, cap'n!

The memory storage implementation be lackin' a way to clean up old keys. We should add methods to manage the memory-stored keys.

Consider adding these methods:

+private cleanupMemoryKeys(): void {
+    // Clean up memory keys older than X time
+    const now = new Date();
+    this.memoryApiKeys = this.memoryApiKeys.filter(key => {
+        const keyDate = new Date(key.createdAt);
+        const hoursDiff = (now.getTime() - keyDate.getTime()) / (1000 * 60 * 60);
+        return hoursDiff < 24; // Keep keys younger than 24 hours
+    });
+}

Committable suggestion skipped: line range outside the PR's diff.

mdatelle
mdatelle previously approved these changes Jan 30, 2025
@github-actions
Copy link
Contributor

This plugin has been deployed to Cloudflare R2 and is available for testing.
Download it at this URL: https://preview.dl.unraid.net/unraid-api/pr/1087/dynamix.unraid.net.staging.plg

@elibosley elibosley merged commit d0896f3 into main Jan 30, 2025
10 checks passed
@elibosley elibosley deleted the feat/session-fixes branch January 30, 2025 19:37
@coderabbitai coderabbitai bot mentioned this pull request Apr 10, 2025
@coderabbitai coderabbitai bot mentioned this pull request May 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants