Skip to content

Prevent cross jurisdiction permission patching#1642

Open
landonshumway-ia wants to merge 2 commits into
csg-org:mainfrom
InspiringApps:fix/check-cross-jurisdiction
Open

Prevent cross jurisdiction permission patching#1642
landonshumway-ia wants to merge 2 commits into
csg-org:mainfrom
InspiringApps:fix/check-cross-jurisdiction

Conversation

@landonshumway-ia

@landonshumway-ia landonshumway-ia commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

The patch_user endpoint is the only staff-user mutation handler that does NOT verify the target user is within the calling jurisdiction admin's purview. All other staff endpoints that modify staff user permissions fetch the target and require the caller to have admin permissions for the target user's jurisdiction. patch_user relies only on collect_and_authorize_changes, which validates the requested changes against the caller's scopes but never loads the target to confirm the caller may administer that specific user.

This adds that check so that if the caller does not have the needed jurisdiction admin scopes for the target user, the endpoint returns a 404 not found response.

Testing List

  • yarn test:unit:all should run without errors or warnings
  • yarn serve should run without errors or warnings
  • yarn build should run without errors or warnings
  • For API configuration changes: CDK tests added/updated in backend/compact-connect/tests/unit/test_api.py
  • For API endpoint changes: OpenAPI spec updated to show latest endpoint configuration run compact-connect/bin/download_oas30.py
  • Code review

Closes #1640

Summary by CodeRabbit

  • Bug Fixes

    • Tightened jurisdiction-based access for admin user edits: admins can only modify users who share at least one allowed jurisdiction; attempts outside permitted jurisdictions now return 404. Caller activity is verified earlier in the request flow.
  • Tests

    • Added functional tests to cover jurisdiction-scoped access control and the 404 behavior when editing users outside an admin’s allowed jurisdictions.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fea5a415-af59-4976-9a06-f534cf68f1ca

📥 Commits

Reviewing files that changed from the base of the PR and between 5e9c9d2 and 87129d8.

📒 Files selected for processing (3)
  • backend/social-work-app/lambdas/python/staff-users/handlers/users.py
  • backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_delete_user.py
  • backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py
✅ Files skipped from review due to trivial changes (1)
  • backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_delete_user.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/social-work-app/lambdas/python/staff-users/handlers/users.py
  • backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py

📝 Walkthrough

Walkthrough

Three staff-users handlers (compact-connect, cosmetology-app, social-work-app) compute caller allowed jurisdictions, verify the caller is active, load the target user in-compact, and return HTTP 404 when the target has no permissions intersecting the caller's allowed jurisdictions; tests exercise the 404 path.

Changes

Jurisdiction authorization checks in patch_user

Layer / File(s) Summary
Compact-connect patch_user authorization and test
backend/compact-connect/lambdas/python/staff-users/handlers/users.py, backend/compact-connect/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py
Compact-connect patch_user computes allowed_jurisdictions, verifies caller is active, fetches target user, and returns CCNotFoundException (404) when target user has no permissions in any allowed jurisdiction. Test validates 404 when ne/aslp.admin attempts to patch an aslp user outside jurisdiction.
Cosmetology-app patch_user authorization and test
backend/cosmetology-app/lambdas/python/staff-users/handlers/users.py, backend/cosmetology-app/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py
Cosmetology-app patch_user computes allowed_jurisdictions early, verifies caller is active, loads target user, and enforces permission intersection before updates; returns 404 on no intersection. Test asserts 404 when NE admin scope targets a user with only OH permissions.
Social-work-app patch_user authorization, docs and tests
backend/social-work-app/lambdas/python/staff-users/handlers/users.py, backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py, backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_delete_user.py
Social-work-app patch_user derives allowed_jurisdictions, verifies caller active before loading the target, enforces jurisdiction-intersection check returning 404 on no overlap, updates a docstring example, and adds/edits tests and comments to cover the 404 path.

Sequence Diagram

sequenceDiagram
  participant Client
  participant patch_user
  participant get_allowed_jurisdictions
  participant get_user_in_compact
  participant update_user_permissions
  Client->>patch_user: PATCH /v1/compacts/{compact}/users/{userId}
  patch_user->>get_allowed_jurisdictions: compute from request scopes
  get_allowed_jurisdictions-->>patch_user: allowed_jurisdictions or None
  patch_user->>patch_user: _verify_caller_is_active
  patch_user->>get_user_in_compact: fetch target user record
  get_user_in_compact-->>patch_user: target user with permissions
  alt allowed_jurisdictions intersects target permissions
    patch_user->>update_user_permissions: apply permission changes
    update_user_permissions-->>patch_user: success
    patch_user-->>Client: 200 OK
  else no intersection
    patch_user-->>Client: 404 User not found
  end
Loading

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested Labels

bug

Suggested Reviewers

  • jlkravitz
  • isabeleliassen

Poem

🐰
I hopped through code and found the gate,
Where admins once could roam and skate.
Now fences check each target's land—
No patch slips through an outsider's hand.
Hooray, the boundaries are just and tight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change—adding jurisdiction validation to the patch_user endpoint to prevent cross-jurisdiction permission patching.
Description check ✅ Passed The description explains the security gap, the intended fix, and provides a complete testing checklist matching the template's required sections.
Linked Issues check ✅ Passed Code changes implement the suggested fix from #1640: fetch target user, compute allowed_jurisdictions, and verify intersection with target's jurisdictions before patching; return 404 if no overlap. Changes applied across all three app copies with corresponding unit tests.
Out of Scope Changes check ✅ Passed All changes directly support the core objective of adding cross-jurisdiction verification to patch_user. A minor comment update in test_delete_user.py is aligned with the overall fix scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
backend/social-work-app/lambdas/python/staff-users/handlers/users.py (1)

75-77: 💤 Low value

Docstring example references wrong compact name.

The docstring mentions oh/cosm admin and oh/cosm write but this is the social-work-app where the compact should be socw.

📝 Suggested fix
     Example: This body would be requesting to:
       - add socw/admin permission
-      - add oh/cosm admin permission
-      - remove oh/cosm write permission
+      - add oh/socw admin permission
+      - remove oh/socw write permission
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/social-work-app/lambdas/python/staff-users/handlers/users.py` around
lines 75 - 77, Update the incorrect compact name in the users.py docstring:
replace any occurrences of "oh/cosm admin" and "oh/cosm write" with the correct
social-work-app compact names (e.g., "socw admin" or "socw/admin" and "socw
write" or "socw/write") in the module/function docstring where the permission
list is documented so the docstring matches the actual permissions used by this
service.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@backend/social-work-app/lambdas/python/staff-users/handlers/users.py`:
- Around line 75-77: Update the incorrect compact name in the users.py
docstring: replace any occurrences of "oh/cosm admin" and "oh/cosm write" with
the correct social-work-app compact names (e.g., "socw admin" or "socw/admin"
and "socw write" or "socw/write") in the module/function docstring where the
permission list is documented so the docstring matches the actual permissions
used by this service.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 075e386b-b3b8-44f4-8d64-5c8e80f4d9bb

📥 Commits

Reviewing files that changed from the base of the PR and between 7f00884 and 5e9c9d2.

📒 Files selected for processing (6)
  • backend/compact-connect/lambdas/python/staff-users/handlers/users.py
  • backend/compact-connect/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py
  • backend/cosmetology-app/lambdas/python/staff-users/handlers/users.py
  • backend/cosmetology-app/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py
  • backend/social-work-app/lambdas/python/staff-users/handlers/users.py
  • backend/social-work-app/lambdas/python/staff-users/tests/function/test_handlers/test_patch_user.py

@landonshumway-ia

Copy link
Copy Markdown
Collaborator Author

@jlkravitz This is ready for your review. Thanks

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.

[Security/Medium] patch_user missing cross-jurisdiction target check in staff-users handler

1 participant