Return masked to-dos behind expired group SAML sessions
What does this MR do and why?
On the dashboard To-Do list, a to-do whose target sits behind an expired group SAML session was dropped from the list entirely, while the to-do counter still counted it. This produced a mismatch: the badge showed more items than the list displayed (for example counter says 6, list shows 4). The frontend already has UI to render such a to-do "masked" (contents hidden, prompting the user to reauthenticate with group SAML), introduced in #500715 (closed), but the backend never returned these to-dos, so the masked UI never appeared.
Root cause: TodoPolicy#read_todo requires the user can read the to-do's target. An expired group SAML session makes the target unreadable, so GraphQL connection authorization filtered the to-do out of the list.
Fix: an EE extension of TodoPolicy keeps read_todo enabled when the target is inaccessible only because of an expired-but-restorable group SAML session, detected via Gitlab::Auth::GroupSaml::SsoEnforcer.access_restricted?. The target_entity GraphQL field still resolves to null via the target's own authorization, so the existing frontend renders the to-do masked. To-dos the user genuinely cannot access (lost membership, confidential notes) stay hidden. Scope is EE and SAML-only, no feature flag, and only the GraphQL to-dos connection is affected.
This addresses point 1 of #565992 (closed) (the banner in point 2 was handled separately in !253026 (merged)), and the count-vs-list discrepancy is tracked in #473762.
Screenshots or screen recordings
To-Do List with a to-do whose target is behind an expired group SAML session. Before, the counter reads 2 but only one item shows (the group SAML to-do is hidden). After, both items show and the group SAML to-do is masked with a "Hidden" badge and a prompt to reauthenticate.
Light mode
| Before | After |
|---|---|
![]() |
![]() |
Dark mode
| Before | After |
|---|---|
![]() |
![]() |
How to set up and validate locally
- On a SAML-enforced group, create a private project and an issue, and ensure the current user has a to-do targeting it (for example, get assigned or mentioned).
- Let the group SAML session expire (or avoid establishing one).
- Visit the dashboard To-Do list at /dashboard/todos.
- Confirm the to-do now appears in the list in a masked state (contents hidden, with a prompt to reauthenticate) rather than being missing, and that the visible list count matches the counter badge.
Also note the automated coverage: ee/spec/policies/ee/todo_policy_spec.rb and the group SAML context added to ee/spec/requests/api/graphql/current_user/todos_query_spec.rb.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist at https://docs.gitlab.com/development/code_review/#acceptance-checklist.



