Skip to content

fix: scope case lookups to the current organization - #7319

Merged
compwron merged 2 commits into
rubyforgood:mainfrom
A-RYAN-1:fix/7106-org-scoped-case-lookups
Nov 2, 2026
Merged

compwron merged 2 commits into
rubyforgood:mainfrom
A-RYAN-1:fix/7106-org-scoped-case-lookups

Conversation

@A-RYAN-1

@A-RYAN-1 A-RYAN-1 commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

What github issue is this PR for, if any?

Resolves #7106 (step 1, the case lookups only)

What changed, and why?

Case slugs and case numbers are only unique within an org, so an unscoped CasaCase lookup can resolve another org's case when two orgs share a number. This resolves the case through current_organization.casa_cases in the five places the issue lists:

  • casa_cases#copy_court_orders: find_by! on the case number, so a number from another org is a 404 instead of copying that org's court orders
  • fund_requests: scoped lookup, keeps the existing redirect to root for a case the user cannot reach
  • emancipations#show and #save
  • case_assignments#case_assignment_parent
  • volunteers#activate: the case is resolved before the volunteer is activated, so a case that is not in the org is a 404 with no activation and no email
  • CaseCourtReportContext: CasaCase.find by id (both callers pass the id of an already scoped case), so no unscoped friendly.find is left in the app

The org-in-URL routes, slug backfill, FriendlyId history and org slug hardening are left for follow-up PRs, as discussed on the issue.

How is this tested? (please write rspec and jest tests!)

New spec/requests/case_lookup_org_scoping_spec.rb: the same case number exists in two orgs (the other org's case is created first) and the caller resolves to their own org's case, and a case that exists only in another org is not reachable through each endpoint. Six of the nine examples fail on main and pass with this change; the other three are controls. The existing request specs for these controllers and the court report specs pass.

Behaviour change: a case from another org used to end in a Pundit denial (emancipations), a cross-org write (case assignments) or a 500 (copy_court_orders with an unknown number); these now return 404.

Screenshots please :)

No UI change.

Several controllers resolved a case with an unscoped lookup. The slug
and case number are only unique within an org, so a case with the same
number in another org could be found first: copy_court_orders read
another org's court orders, and fund requests, emancipations, case
assignments and volunteer activation could resolve the wrong case.

Resolve the case through current_organization.casa_cases in all five
places and add request specs with the same case number in two orgs.

Refs rubyforgood#7106
@github-actions github-actions Bot added 🧪 Tests Tests ruby Touches Ruby code labels Nov 1, 2026
@compwron

compwron commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Thanks @A-RYAN-1, this is a really clean change, and the request spec with two orgs sharing a case number is exactly the right test. CI is red on 3 older examples in spec/controllers/emancipations_controller_spec.rb (lines 42, 72, 223) that still expect the old "not authorized" redirect / 401 for another org's case. With the scoped lookup that's now a 404, which I think is the better behavior (it doesn't reveal the case exists). Could you update those to expect :not_found, and remove #not_authorized if nothing else uses it? Then this is good to merge.

@compwron

compwron commented Nov 1, 2026

Copy link
Copy Markdown
Collaborator

Specs need fixing, but the approach looks good :)

The case lookup is now scoped to the current organization, so a user
from another org gets not found instead of the old not-authorized
redirect or 401. Update the three examples that still expected the old
behaviour (show, save, and the #not_authorized handler).

The #not_authorized example now uses an unassigned volunteer in the
same org. That path still reaches the JSON 401 handler, so the handler
stays.

Refs rubyforgood#7106
@A-RYAN-1

A-RYAN-1 commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 59afcb1: the three examples now expect 404, and the full spec/controllers and spec/requests run passes locally (1052 examples, 0 failures). I kept #not_authorized because an unassigned volunteer in the same org still reaches it, so the last example now covers that case.

@compwron
compwron merged commit b12f820 into rubyforgood:main Nov 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ruby Touches Ruby code 🧪 Tests Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Include the org in CASA case URLs and finish the switch away from database ids

2 participants