Fixed case search fan-out by scoping role check to the current tenant. - #153
Merged
richard-churchman merged 1 commit intoAug 31, 2026
Merged
Conversation
CompileAsync built the case-search WHERE clause with a derived "RoleRegistry" table that resolved the caller's role by UserRegistry.Name alone, with no tenant predicate. UserRegistry rows are not unique per username across tenants (the same login can belong to multiple tenants via UserInTenant), so a user in more than one tenant could get back more than one RoleRegistry.Guid here. That fed the CaseWorkflowRole/CaseWorkflowStatusRole join predicates, which are junction tables (one row per workflow/status x granted role). Each extra role match multiplied the Case row in the joined result, producing duplicate cases in the search results, sourced from role grants in other tenants. SessionCaseSearchCompiledSqlController's limit-100 query has no DISTINCT, so the duplicates could also crowd out genuinely distinct cases within a page. Moved the CaseWorkflowRole/CaseWorkflowStatusRole/RoleRegistry checks out of the joined FROM list and into EXISTS subqueries correlated to the current CaseWorkflow/CaseWorkflowStatus/TenantRegistry, matching the EXISTS-based permission-check pattern already used elsewhere (GetCaseByIdQuery, GetCaseByCaseKeyValueQuery, etc.). Role matches can no longer multiply the outer Case row regardless of how many tenants or roles the user holds. Not reproduced locally; but matched a known fan-out/duplicate-case pattern seen before. Have verified this fix against a live case search.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixed case search fan-out by scoping role check to the current tenant. CompileAsync built the case-search WHERE clause with a derived "RoleRegistry" table that resolved the caller's role by UserRegistry.Name alone, with no tenant predicate. UserRegistry rows are not unique per username across tenants (the same login can belong to multiple tenants via UserInTenant), so a user in more than one tenant could get back more than one RoleRegistry.Guid here. That fed the CaseWorkflowRole/CaseWorkflowStatusRole join predicates, which are junction tables (one row per workflow/status x granted role). Each extra role match multiplied the Case row in the joined result, producing duplicate cases in the search results, sourced from role grants in other tenants.
SessionCaseSearchCompiledSqlController's limit-100 query has no DISTINCT, so the duplicates could also crowd out genuinely distinct cases within a page.
Moved the CaseWorkflowRole/CaseWorkflowStatusRole/RoleRegistry checks out of the joined FROM list and into EXISTS subqueries correlated to the current CaseWorkflow/CaseWorkflowStatus/TenantRegistry, matching the EXISTS-based permission-check pattern already used elsewhere (GetCaseByIdQuery, GetCaseByCaseKeyValueQuery, etc.). Role matches can no longer multiply the outer Case row regardless of how many tenants or roles the user holds.
Not reproduced locally; but matched a known fan-out/duplicate-case pattern seen before. Have verified this fix against a live case search.