fix(api): populate dashboard_id and slice_id in audit logs for mutation endpoints #38187#38347
fix(api): populate dashboard_id and slice_id in audit logs for mutation endpoints #38187#38347vikash7485 wants to merge 2 commits intoapache:masterfrom
Conversation
There was a problem hiding this comment.
Code Review Agent Run #5af5a8
Actionable Suggestions - 2
-
tests/integration_tests/charts/api_tests.py - 2
- Mismatched audit log action assertion · Line 327-327
- Mismatched audit log action assertion · Line 729-729
Review Details
-
Files reviewed - 5 · Commit Range:
186a3ad..c4aeaff- superset/charts/api.py
- superset/dashboards/api.py
- tests/integration_tests/charts/api_tests.py
- tests/integration_tests/dashboards/api_tests.py
- tests/integration_tests/event_logger_tests.py
-
Files skipped - 0
-
Tools
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
- MyPy (Static Code Analysis) - ✔︎ Successful
- Astral Ruff (Static Code Analysis) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at [email protected].
Documentation & Help
| # Verify audit log | ||
| log = ( | ||
| db.session.query(Log) | ||
| .filter_by(action="delete", slice_id=chart_id) |
There was a problem hiding this comment.
The test assertion checks for action="delete", but the @event_logger.log_this_with_context decorator on the delete method sets action to "ChartRestApi.delete" via the lambda. This mismatch will cause the assertion to fail. Either update the test to expect "ChartRestApi.delete" or change the decorator's action to "delete" for consistency with other tests.
Code suggestion
Check the AI-generated fix before applying
--- superset/charts/api.py
+++ superset/charts/api.py
@@ -473,7 +473,7 @@
@event_logger.log_this_with_context(
- action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.delete",
+ action="delete",
log_to_statsd=False,
allow_extra_payload=True,
)
Code Review Run #5af5a8
Should Bito avoid suggestions like this for future reviews? (Manage Rules)
- Yes, avoid them
| # Verify audit log | ||
| log = ( | ||
| db.session.query(Log) | ||
| .filter_by(action="put", slice_id=chart_id) |
There was a problem hiding this comment.
Similar to the delete test, the put test assertion checks for action="put", but the logging decorator sets action to "ChartRestApi.put". This will cause the test to fail. Update the decorator's action to "put" for consistency.
Code suggestion
Check the AI-generated fix before applying
--- superset/charts/api.py
+++ superset/charts/api.py
@@ -389,7 +389,7 @@
@event_logger.log_this_with_context(
- action=lambda self, *args, **kwargs: f"{self.__class__.__name__}.put",
+ action="put",
log_to_statsd=False,
allow_extra_payload=True,
)
Code Review Run #5af5a8
Should Bito avoid suggestions like this for future reviews? (Manage Rules)
- Yes, avoid them
Description
Fixes #38187
dashboard_idandslice_idcolumns in thelogstable were alwaysNULLfor every REST API mutation endpoint (POST, PUT, DELETE). Thismade audit logs useless for filtering by dashboard or chart.
Root Cause
log_with_context()inutils/log.pyreads IDs from the merged HTTPpayload:
collect_request_payload()only readsrequest.form,request.args,and
request.jsonbody. URL path params (e.g./api/v1/dashboard/42)are never included, so the IDs were never captured.
Fix
Used the existing
allow_extra_payload=Truemechanism — alreadyproven working in
DashboardRestApi.get— to explicitly injectdashboard_id/slice_idinto the log payload after each operation.11 endpoints fixed across 2 files:
superset/dashboards/api.py(7 endpoints):post→add_extra_log_payload(dashboard_id=new_model.id)put→add_extra_log_payload(dashboard_id=changed_model.id)put_filters→add_extra_log_payload(dashboard_id=pk)put_chart_customizations→add_extra_log_payload(dashboard_id=pk)put_colors→add_extra_log_payload(dashboard_id=pk)delete→add_extra_log_payload(dashboard_id=pk)called beforeDeleteDashboardCommand.run()so the ID is captured before the rowis gone
bulk_delete→add_extra_log_payload(dashboard_ids=item_ids)storesthe list in the
jsoncolumn (cannot fit multiple IDs in a singleinteger column — this is intentional)
superset/charts/api.py(4 endpoints):post→add_extra_log_payload(slice_id=new_model.id)put→add_extra_log_payload(slice_id=changed_model.id)delete→add_extra_log_payload(slice_id=pk)called before deletionbulk_delete→add_extra_log_payload(slice_ids=item_ids)Also added missing
Callableto thefrom typing importline incharts/api.py.Testing
Unit tests —
tests/integration_tests/event_logger_tests.pyAdded
TestMutationEndpointAuditIdswith 6 regression tests that mockDBEventLogger.logand assert the correct ID is passed as a kwarg:test_dashboard_put_logs_dashboard_iddashboard_id == 42test_dashboard_delete_logs_dashboard_iddashboard_id == 42test_dashboard_post_logs_dashboard_iddashboard_id == 42test_chart_put_logs_slice_idslice_id == 42test_chart_delete_logs_slice_idslice_id == 42test_chart_post_logs_slice_idslice_id == 42Integration tests —
tests/integration_tests/dashboards/api_tests.pyand
tests/integration_tests/charts/api_tests.pyAdded DB-level assertions that query the
Logmodel directly aftereach mutation and confirm the ID column is non-NULL:
test_update_dashboard→ assertslog.dashboard_id == dashboard_idtest_delete_dashboard→ assertslog.dashboard_id == dashboard_idtest_update_chart→ assertslog.slice_id == chart_idtest_delete_chart→ assertslog.slice_id == chart_idSQL verification query (run after deployment):
After this fix,
dashboard_idwill be non-NULL for allDashboardRestApi.*actions andslice_idwill be non-NULL for allChartRestApi.*actions.Checklist
deletecaptures ID before row deletionbulk_deletestores ID list injsoncolumn (documented above)Callableimport fix incharts/api.py