Skip to content

Fix audit endpoints dropping rows whose related active_* row is soft-deleted#449

Merged
somethingnew2-0 merged 2 commits into
mainfrom
pcollins/laughing-montalcini-f69bbf
May 18, 2026
Merged

Fix audit endpoints dropping rows whose related active_* row is soft-deleted#449
somethingnew2-0 merged 2 commits into
mainfrom
pcollins/laughing-montalcini-f69bbf

Conversation

@somethingnew2-0
Copy link
Copy Markdown
Collaborator

@somethingnew2-0 somethingnew2-0 commented May 16, 2026

Summary

  • Removes the joinedload(active_user) / joinedload(active_role_group) introduced by the FastAPI migration in Migrate from Flask + Marshmallow to FastAPI + Pydantic #425 that caused audit pages to silently drop rows whose user or role group had been soft-deleted (reducing one production page from 398 entries to 19).
  • Drops the matching unused active_* fields from the audit response schemas — the user / group / role_group fields (with their existing deleted_at columns) are all the frontend reads off audit rows; no consumer touches the active_* keys.
  • Adds regression tests for the soft-deleted user and soft-deleted role-group cases.

Why

OktaUserGroupMember.active_user and RoleGroupMap.active_role_group are defined with innerjoin=True plus a primaryjoin filter on deleted_at IS NULL. When the migration eager-loaded them via joinedload(...), SQLAlchemy emitted INNER JOINs that excluded any row whose target had since been soft-deleted, even though the audit row itself is valid history. selectinload(active_group) / selectinload(active_role_group_mapping) don't cause the same regression but were unused additions on the response and have been dropped for consistency with the pre-migration Flask wire shape. The base joinedload(user) / joinedload(group) / joinedload(role_group) (all unfiltered) plus the existing deleted_at on the row helpers give the frontend everything it needs to render soft-deleted entities.

The shared helper api/routers/_eager.py:40 has the same joinedload(active_user) pattern but is used by groups/apps/users/role_requests routes whose consumers do read active_user, so the fix there is joinedload(..., innerjoin=False) or selectinload(...) rather than deletion — left for a separate follow-up.

Test plan

  • pytest tests/ — 424 passed
  • New test_users_audit_returns_rows_when_user_is_soft_deleted and test_groups_audit_returns_rows_when_role_group_is_soft_deleted cover the regression
  • ruff check clean on the touched files
  • UI smoke: /groups/Role-All-Employees/audit?active=false shows soft-deleted users with the strikethrough style (handled by the existing displayUserName helper off user.deleted_at)

🤖 Generated with Claude Code

somethingnew2-0 and others added 2 commits May 15, 2026 23:17
…deleted

The FastAPI migration in #425 added joinedload(active_user) on
/api/audit/users and joinedload(active_role_group) on /api/audit/groups.
Both relationships carry innerjoin=True + a primaryjoin filter on
deleted_at IS NULL, so SQLAlchemy emitted INNER JOINs that silently
dropped audit rows whose user or role group had since been soft-deleted
(reducing one production audit page from 398 entries to 19).

Removed every active_* load and matching response field the migration
added to either audit endpoint — the unfiltered user/group/role_group
fields plus the existing deleted_at columns are all the frontend reads
off audit rows, and no consumer touches the active_* keys. This restores
the pre-migration wire shape and closes both INNER-JOIN regressions.

Added regression tests covering the soft-deleted user and soft-deleted
role-group cases.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI ruff format check wanted the new test function signatures on a
single line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@somethingnew2-0 somethingnew2-0 marked this pull request as ready for review May 16, 2026 06:26
@somethingnew2-0 somethingnew2-0 enabled auto-merge (squash) May 16, 2026 07:22
@somethingnew2-0 somethingnew2-0 merged commit 97c0597 into main May 18, 2026
6 checks passed
@somethingnew2-0 somethingnew2-0 deleted the pcollins/laughing-montalcini-f69bbf branch May 18, 2026 15:48
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