Skip to content

fix(api): move recent-actions LogEntry query out of api/ (S-15 guard)#523

Merged
MartinCastroAlvarez merged 1 commit into
mainfrom
fix/recent-actions-s15-012505
May 27, 2026
Merged

fix(api): move recent-actions LogEntry query out of api/ (S-15 guard)#523
MartinCastroAlvarez merged 1 commit into
mainfrom
fix/recent-actions-s15-012505

Conversation

@MartinCastroAlvarez
Copy link
Copy Markdown
Owner

Summary

The recent-actions view (#502, merged in #505) queried LogEntry.objects.filter(user=…) inline, which trips the S-15 security guard (tests/test_security.py::test_s15_no_objects_all_or_filter_in_api — no Model.objects.all|filter in api/). It landed on main because the test suite doesn't gate CI yet (#452); a full local run flagged it.

Fix: move the user-scoped query into django_admin_react/audit.py as recent_actions_for_user(), next to the existing object_log_entries(). That module is the documented home for framework audit-table (LogEntry) access outside api/LogEntry is not a consumer model, so the get_queryset rule is categorically inapplicable (the history view already follows this pattern). The view delegates to it. No behaviour change.

Role

Author. Eligible for same-session review/merge once CI is green — this restores a green security guard on main.

Test plan

  • test_s15_no_objects_all_or_filter_in_api passes (was failing on main).
  • tests/test_security.py + tests/test_history.py green (34 passed); tests/test_recent_actions.py green (12).
  • ruff + mypy clean on audit.py + recent_actions.py.

🤖 Generated with Claude Code

The recent-actions view (#502) queried LogEntry.objects.filter(user=…)
inline, tripping the S-15 security guard (no Model.objects.all/filter in
api/). CI didn't catch it — the test suite doesn't gate CI yet (#452),
only CodeQL does — so it landed on main and the full local run flagged it.

Move the user-scoped LogEntry query into django_admin_react/audit.py as
recent_actions_for_user(), alongside object_log_entries(). That module is
the designated, documented home for framework audit-table access outside
api/ (LogEntry is not a consumer model, so the get_queryset rule is
categorically inapplicable). The view now delegates to it — no behaviour
change, S-15 satisfied honestly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Owner Author

@MartinCastroAlvarez MartinCastroAlvarez left a comment

Choose a reason for hiding this comment

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

Security + architecture review (same-session reviewer lane).

Confirmed correct and security-positive:

  • Behaviour identical: recent_actions_for_user runs the same LogEntry.objects.filter(user__pk=user_pk).order_by("-action_time")[:limit] — pure relocation, no semantic change.
  • User-scoping intact: still keyed on request.user.pk, so each admin sees only their own actions — no IDOR / cross-user leak.
  • Architecture correct: lands in audit.py beside object_log_entries(), the documented home for framework LogEntry access. Rule 2 (get_queryset) is categorically inapplicable — LogEntry is Django's audit table, not a consumer model — and the query now physically lives outside api/, restoring the S-15 guard (test_s15_no_objects_all_or_filter_in_api) to green.
  • LogEntry import in the view is still used by _serialize_action's annotations — no orphaned import.
  • no-store header + _target_for deep-link has_view_permission gating untouched.

This is exactly the fix flagged when the suite is run locally (the gap that #452/#506 closes in CI). Merging on green CodeQL.

@MartinCastroAlvarez MartinCastroAlvarez merged commit 9bed8e3 into main May 27, 2026
3 checks passed
@MartinCastroAlvarez MartinCastroAlvarez deleted the fix/recent-actions-s15-012505 branch May 28, 2026 13:10
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