-
Notifications
You must be signed in to change notification settings - Fork 85
fix: Add proper HTTP error handling to BaseAssignmentViewSet.perform_create #888
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
base: devel
Are you sure you want to change the base?
Conversation
9671117 to
3ba9334
Compare
…form_create - Add try-catch block around remote_sync_assignment call - Convert HTTP 400 errors to ValidationError - Convert HTTP 401/403 errors to PermissionDenied - Re-raise other HTTP errors unchanged - Add comprehensive pytest tests for all error scenarios - Tests cover both user and team assignment error handling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
5c3bc60 to
2494815
Compare
|
@AlanCoding Please review |
john-westcott-iv
left a comment
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.
📋 Code Review Summary
This PR adds important error handling for HTTP failures during remote role assignment synchronization. The core approach of wrapping the operation in a transaction is sound and addresses the race condition issue. However, there are several areas that need attention before approval.
Files Reviewed: 2 files
Comments Posted: 6 review comments
🔍 Issues Found
- 1 correctness/logic issue (missing return value)
- 2 code quality suggestions (error message preservation, test coverage)
- 2 minor improvements (error handling consistency, exception type choice)
Overall Assessment
Needs work - The transaction handling is correct, but there are important improvements needed around error message preservation and test coverage.
General Feedback
- ✅ Good use of transaction.atomic() to ensure rollback on sync failures
- ✅ Comprehensive test coverage for various HTTP error codes
- ✅ Proper conversion of HTTP errors to DRF exceptions
⚠️ Consider preserving structured error messages from the gateway response⚠️ Add test coverage for team assignments (not just users)- ℹ️ Document the intentional lack of ConnectionError handling
john-westcott-iv
left a comment
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.
File: ansible_base/rbac/api/views.py, Line 195-202
The original code returned the result from super().perform_create(serializer). While perform_create typically doesn't use return values in DRF, removing the return is a behavioral change. Consider:
with transaction.atomic():
ret = super().perform_create(serializer)
self.remote_sync_assignment(serializer.instance)
return retThis preserves the original behavior while still providing transaction safety.
john-westcott-iv
left a comment
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.
File: ansible_base/rbac/api/views.py, Line 207
The error data loses the structured error information from the gateway response. The HTTPError already includes response content (line 129 in rest_client.py), but it's being converted to a simple string.
Consider parsing the response JSON to preserve the structured error:
error_data = {"detail": str(exc)}
try:
if hasattr(exc.response, 'json'):
error_data = exc.response.json()
except Exception:
pass # Fall back to string representationThis would preserve error messages like {"role_definition": ["Object with name=... does not exist."]} which are more useful for API consumers.
john-westcott-iv
left a comment
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.
File: ansible_base/rbac/api/views.py, Line 214-216
For 500 errors or HTTPError with no response, raising APIException results in another 500. This seems redundant. Consider:
- Re-raising the original
HTTPErrorto preserve the full stack trace for debugging - Using a more specific exception type if there's a meaningful distinction
- Adding logging before raising to capture the error for diagnostics
Example:
else:
logger.error(f"Unexpected HTTP error during remote sync: {exc}")
raise # Re-raise original exception
john-westcott-iv
left a comment
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.
File: test_app/tests/rbac/api/test_rbac_views.py, Missing Coverage
The tests only cover RoleUserAssignment (via roleuserassignment-list), but the fix is in BaseAssignmentViewSet which is also used by RoleTeamAssignmentViewSet.
Recommendation: Add parallel tests for team assignments to ensure the error handling works correctly for both assignment types:
@pytest.mark.parametrize("sync_error_status, expected_status", [...])
@pytest.mark.django_db
def test_team_assignment_remote_sync_error_handling(admin_api_client, inv_rd, team, inventory, sync_error_status, expected_status):
"""Test that remote sync HTTP errors are handled correctly for team assignments"""
url = get_relative_url('roleteamassignment-list')
data = dict(role_definition=inv_rd.id, team=team.id, object_id=inventory.id)
# ... rest similar to user test
john-westcott-iv
left a comment
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.
File: ansible_base/rbac/api/views.py, Line 205-206
The comment mentions "eliminating the race condition where assignments briefly exist before manual deletion." This is excellent context!
However, the comment could be even clearer about why transaction.atomic() solves this:
# Wrap the entire operation in a single atomic transaction
# This ensures that if remote sync fails, the local assignment creation is rolled back
# automatically. Without this, there was a race condition where:
# 1. Local assignment is committed to the database
# 2. Remote sync fails
# 3. Assignment must be manually deleted, but may be visible to users briefly
# The transaction.atomic() ensures step 1 only commits if step 2 succeeds.|
DVCS PR Check Results: PR appears valid (JIRA key(s) found) |
Fixed |
|
|
@john-westcott-iv thanks for the review, I addressed all the comments. |



https://issues.redhat.com/browse/AAP-58366
Description
🤖 Generated with Claude Code
Type of Change
Self-Review Checklist
Screenshots/Logs