-
Notifications
You must be signed in to change notification settings - Fork 578
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
Add secret-key guard for team endpoints #1251
Conversation
WalkthroughThe changes to the Changes
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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 (
|
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
🧹 Outside diff range and nitpick comments (2)
backend/routers/plugins.py (2)
175-175
: Fix parameter formattingAdd a space after the comma in the parameter list for better readability.
-def reject_plugin(plugin_id: str,secret_key: str = Header(...)): +def reject_plugin(plugin_id: str, secret_key: str = Header(...)):
Line range hint
167-195
: Consider additional security measures for admin endpointsThe current implementation could benefit from these architectural improvements:
Environment variable validation:
- Validate ADMIN_KEY presence at application startup
- Ensure minimum length/complexity requirements
Audit logging:
- Log all admin actions (approvals/rejections)
- Include timestamps and admin identifiers
- Consider using structured logging
Authentication strategy:
- Consider implementing token-based auth instead of a single shared key
- Add key rotation capability
- Consider implementing role-based access control (RBAC)
Would you like help implementing any of these suggestions?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
backend/routers/plugins.py
(3 hunks)
🔇 Additional comments (1)
backend/routers/plugins.py (1)
9-9
: LGTM: Header import added correctly
The import is properly placed with other FastAPI imports and is necessary for the new secret key validation.
def reject_plugin(plugin_id: str,secret_key: str = Header(...)): | ||
if secret_key != os.getenv('ADMIN_KEY'): | ||
raise HTTPException(status_code=403, detail='You are not authorized to perform this action') |
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.
🛠️ Refactor suggestion
Apply consistent security improvements
Apply the same security enhancements as suggested for the approve_plugin endpoint:
- Use constant-time comparison
- Add rate limiting
- Add return type hint
@router.post('/v1/plugins/{plugin_id}/reject', tags=['v1'])
-def reject_plugin(plugin_id: str, secret_key: str = Header(...)):
+def reject_plugin(plugin_id: str, secret_key: str = Header(...)) -> dict[str, str]:
+ from hmac import compare_digest
- if secret_key != os.getenv('ADMIN_KEY'):
+ if not compare_digest(secret_key, os.getenv('ADMIN_KEY', '')):
raise HTTPException(status_code=403, detail='You are not authorized to perform this action')
change_plugin_approval_status(plugin_id, False)
return {'status': 'ok'}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
def reject_plugin(plugin_id: str,secret_key: str = Header(...)): | |
if secret_key != os.getenv('ADMIN_KEY'): | |
raise HTTPException(status_code=403, detail='You are not authorized to perform this action') | |
def reject_plugin(plugin_id: str, secret_key: str = Header(...)) -> dict[str, str]: | |
from hmac import compare_digest | |
if not compare_digest(secret_key, os.getenv('ADMIN_KEY', '')): | |
raise HTTPException(status_code=403, detail='You are not authorized to perform this action') | |
change_plugin_approval_status(plugin_id, False) | |
return {'status': 'ok'} |
def get_unapproved_public_plugins(secret_key: str = Header(...)): | ||
if secret_key != os.getenv('ADMIN_KEY'): | ||
raise HTTPException(status_code=403, detail='You are not authorized to perform this action') |
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.
💡 Codebase verification
🛠️ Refactor suggestion
Security and performance improvements needed
The verification confirms that:
- The database layer fetches all unapproved plugins at once without pagination (
get_unapproved_public_plugins_db()
returns full list) - No existing pagination patterns were found in the codebase
The original review comment is valid as:
- Fetching all unapproved plugins at once could lead to performance issues and potential DoS
- The security concerns about constant-time comparison are legitimate for admin key validation
- Return type hints would improve code maintainability
The suggested changes in the review should be implemented:
- Add pagination parameters and slice the results
- Use
compare_digest
for secure key comparison - Add return type hints for better type safety
🔗 Analysis chain
Enhance security and add pagination
While the basic security is implemented, consider these improvements:
- Security enhancements:
- Use constant-time comparison
- Add rate limiting
- Add return type hint
- Add pagination to prevent potential DoS from large datasets
@router.get('/v1/plugins/public/unapproved', tags=['v1'])
-def get_unapproved_public_plugins(secret_key: str = Header(...)):
+def get_unapproved_public_plugins(
+ secret_key: str = Header(...),
+ skip: int = 0,
+ limit: int = 50
+) -> list[Plugin]:
+ from hmac import compare_digest
- if secret_key != os.getenv('ADMIN_KEY'):
+ if not compare_digest(secret_key, os.getenv('ADMIN_KEY', '')):
raise HTTPException(status_code=403, detail='You are not authorized to perform this action')
plugins = get_unapproved_public_plugins_db()
- return plugins
+ return plugins[skip:skip + limit]
Let's verify the potential impact of large datasets:
The results show that the database layer fetches all unapproved plugins at once without pagination, which confirms the review's concern. Let me verify if there are any existing pagination patterns in the codebase that we should follow.
Let me check for any pagination-related query parameters in the FastAPI routes to understand the existing patterns.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if there's any pagination implementation in the database layer
rg -A 5 "get_unapproved_public_plugins_db"
Length of output: 1356
Script:
#!/bin/bash
# Check for existing pagination patterns in the codebase
rg -B 2 -A 2 "skip.*limit" backend/
Length of output: 37
Script:
#!/bin/bash
# Look for FastAPI route definitions with query parameters
ast-grep --pattern 'def $_($$$, skip: int = $_,$$$):'
Length of output: 55
def approve_plugin(plugin_id: str, secret_key: str = Header(...)): | ||
if secret_key != os.getenv('ADMIN_KEY'): | ||
raise HTTPException(status_code=403, detail='You are not authorized to perform this action') |
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.
💡 Codebase verification
🛠️ Refactor suggestion
Based on the search results, I can now generate the final response since I have enough context about the security implementation in the codebase. There's no existing rate limiting mechanism, and the security suggestions in the review are valid.
Security improvements needed for admin endpoint
The suggested security enhancements are valid and necessary:
- Using
compare_digest
is essential to prevent timing attacks on the admin key comparison - Rate limiting is missing and should be implemented to prevent brute-force attempts
- Return type hint addition improves type safety
The suggested code changes are appropriate:
from hmac import compare_digest
def approve_plugin(plugin_id: str, secret_key: str = Header(...)) -> dict[str, str]:
if not compare_digest(secret_key, os.getenv('ADMIN_KEY', '')):
raise HTTPException(status_code=403, detail='You are not authorized to perform this action')
🔗 Analysis chain
Enhance security implementation
While the basic secret key validation is implemented correctly, consider these security improvements:
- Use a secure constant-time comparison to prevent timing attacks
- Add rate limiting to prevent brute-force attempts
- Add return type hint for better type safety
Apply this enhancement:
@router.post('/v1/plugins/{plugin_id}/approve', tags=['v1'])
-def approve_plugin(plugin_id: str, secret_key: str = Header(...)):
+def approve_plugin(plugin_id: str, secret_key: str = Header(...)) -> dict[str, str]:
+ from hmac import compare_digest
if secret_key != os.getenv('ADMIN_KEY'):
- raise HTTPException(status_code=403, detail='You are not authorized to perform this action')
+ if not compare_digest(secret_key, os.getenv('ADMIN_KEY', '')):
+ raise HTTPException(status_code=403, detail='You are not authorized to perform this action')
change_plugin_approval_status(plugin_id, True)
return {'status': 'ok'}
Let's verify if rate limiting is implemented elsewhere:
Let me search for any existing security-related code or middleware that might handle rate limiting.
Let me check for any existing security utilities or authentication middleware that might be relevant.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for rate limiting middleware or decorators
rg -l "RateLimiter|rate_limit" --type py
Length of output: 1356
Script:
#!/bin/bash
# Check for security middleware and rate limiting
rg -l "middleware|limiter|security" --type py
# Check FastAPI dependencies and security utilities
rg -A 5 "from fastapi import.*security" --type py
rg -A 5 "from fastapi import.*Depends" --type py
Length of output: 4882
Script:
#!/bin/bash
# Check for auth utilities and security implementations
rg -A 5 "utils.other import endpoints as auth" --type py
# Check the auth endpoints implementation
rg -A 10 "class endpoints" backend/utils/other.py
Length of output: 4227
lgtm @mdmohsin7 🥳 |
/v1/plugins/{plugin_id}/approve
,/v1/plugins/{plugin_id}/reject
,/v1/plugins/public/unapproved
will require admin key to be passed as a header with keysecret-key
Summary by CodeRabbit
secret_key
for authorization on specific endpoints.