Skip to content

add managing org to org perms#3586

Open
Jacobjeevan wants to merge 3 commits intoohcnetwork:developfrom
Jacobjeevan:org-perms
Open

add managing org to org perms#3586
Jacobjeevan wants to merge 3 commits intoohcnetwork:developfrom
Jacobjeevan:org-perms

Conversation

@Jacobjeevan
Copy link
Copy Markdown
Contributor

@Jacobjeevan Jacobjeevan commented Mar 24, 2026

Proposed Changes

  • add managing org for fetching perms in org scope

Merge Checklist

  • Tests added/fixed
  • Update docs in /docs
  • Linting Complete
  • Any other necessary step

Only PR's with test cases included and passing lint and test pipelines will be reviewed

@ohcnetwork/care-backend-maintainers @ohcnetwork/care-backend-admins

Summary by CodeRabbit

  • Bug Fixes
    • More accurate permission inheritance for role-type organizations: users now correctly receive permissions from managing organizations and their own organization, reducing unexpected permission gaps and improving access control consistency.

@Jacobjeevan Jacobjeevan requested a review from a team as a code owner March 24, 2026 14:05
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9cd5d887-f329-4a7c-bf71-7712c4b9a8f4

📥 Commits

Reviewing files that changed from the base of the PR and between c5c0bdf and dc4995c.

📒 Files selected for processing (1)
  • care/security/authorization/organization.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • care/security/authorization/organization.py

📝 Walkthrough

Walkthrough

get_permission_on_organization() now conditionally builds organization_parents: for organizations with org_type == OrganizationTypeChoices.role.value it uses [organization.id] + list(organization.managing_organizations); otherwise it uses [*organization.parent_cache, organization.id]. Role lookup and permission merging are unchanged.

Changes

Cohort / File(s) Summary
Authorization Permission Logic
care/security/authorization/organization.py
Changed get_permission_on_organization() to build organization_parents from managing_organizations plus the org ID for role-type organizations; preserved previous parent_cache behavior for other types. No public signatures changed. (+8/-1)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is missing critical sections: no Associated Issue link provided, no Architecture changes explanation despite modifying authorization logic, and merge checklist items are unchecked. Add the Associated Issue section with a link, explain architectural implications of the managing_organizations inclusion, and indicate which checklist items have been completed (tests added, linting done, etc.).
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'add managing org to org perms' directly reflects the main change: including managing organizations in permission computations for organization 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

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 24, 2026

Greptile Summary

This PR extends get_permission_on_organization in OrganizationAccess so that, when the organization is of role type, its managing organizations are also included when computing the user's merged permissions. This permission set is surfaced in the organization retrieve API endpoint via OrganizationRetrieveSpec.

Key observations:

  • The logic for including managing organizations in the parent scope is correct in intent, but the implementation retains parent_cache for role-type orgs while every other role-type branch in the same file (can_manage_organization_users_obj, can_list_organization_users_obj) explicitly excludes it. This inconsistency may surface broader permissions than are actually exercisable through the other authorization checks.
  • The loop building managing_organization_ids is unnecessary given that managing_organizations is already a plain Python list (ArrayField), and it is inconsistent with the direct unpack style used throughout the rest of the file.
  • No test coverage was added (the merge checklist confirms this), which makes it harder to validate the intended behaviour for role-type orgs.

Confidence Score: 2/5

  • PR has a likely logic inconsistency that may over-report permissions for role-type organizations, and no tests cover the new behaviour.
  • The core intent (include managing orgs in permission lookup) is sound, but retaining parent_cache for role-type orgs contradicts every other role-type permission check in the file, where parent_cache is deliberately excluded. This could expose inflated permission sets through the retrieve API. Combined with zero test coverage for the change, confidence is low.
  • care/security/authorization/organization.py — specifically the parent_cache inclusion for role-type organizations in get_permission_on_organization.

Important Files Changed

Filename Overview
care/security/authorization/organization.py Extends get_permission_on_organization to include managing organizations for role-type orgs; however, it also retains parent_cache in the lookup scope unlike every other role-type branch in the same file, and uses an unnecessary manual loop instead of the consistent direct unpack pattern used elsewhere.

Reviews (1): Last reviewed commit: "add managing org to org perms" | Re-trigger Greptile

Comment on lines +141 to +145
if organization.org_type == OrganizationTypeChoices.role.value:
managing_organization_ids = []
for managing_organization in organization.managing_organizations:
managing_organization_ids.append(managing_organization)
organization_parents = [*organization_parents, *managing_organization_ids]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Unnecessary loop inconsistent with existing patterns

The manual loop to build managing_organization_ids is redundant since managing_organizations is already a list of integer IDs (ArrayField(models.IntegerField())). Every other usage of this field in the same file unpacks it directly (lines 65, 81, 97). This adds unnecessary indirection without benefit.

Suggested change
if organization.org_type == OrganizationTypeChoices.role.value:
managing_organization_ids = []
for managing_organization in organization.managing_organizations:
managing_organization_ids.append(managing_organization)
organization_parents = [*organization_parents, *managing_organization_ids]
if organization.org_type == OrganizationTypeChoices.role.value:
organization_parents = [*organization_parents, *organization.managing_organizations]

Comment on lines +139 to +145
def get_permission_on_organization(self, organization, user):
organization_parents = [*organization.parent_cache, organization.id]
if organization.org_type == OrganizationTypeChoices.role.value:
managing_organization_ids = []
for managing_organization in organization.managing_organizations:
managing_organization_ids.append(managing_organization)
organization_parents = [*organization_parents, *managing_organization_ids]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 parent_cache included for role-type orgs — inconsistent with sibling methods

The initial assignment unconditionally sets organization_parents = [*organization.parent_cache, organization.id], so for role-type orgs the final lookup becomes [parent_cache..., organization.id, ...managing_organizations].

By contrast, both can_manage_organization_users_obj (line 63) and can_list_organization_users_obj (line 96) explicitly exclude parent_cache for role-type organizations and only use [organization.id, *managing_organizations]. This suggests that the parent hierarchy is intentionally not checked for role-type orgs in permission decisions.

Keeping parent_cache here means a user who holds a role in an ancestor of the role-type org (but has no connection through managing_organizations) would have those ancestor permissions surfaced via the permissions field in the retrieve API — potentially widening the apparent permission set beyond what can actually be exercised through the other authorization checks.

If the intent is to mirror the behaviour of the other methods, parent_cache should be excluded for role types:

def get_permission_on_organization(self, organization, user):
    if organization.org_type == OrganizationTypeChoices.role.value:
        organization_parents = [organization.id, *organization.managing_organizations]
    else:
        organization_parents = [*organization.parent_cache, organization.id]

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
care/security/authorization/organization.py (1)

141-145: The intermediate loop is unnecessary and inconsistent with existing patterns.

The loop at lines 142-144 simply copies organization.managing_organizations into a new list before spreading it. Other methods in this same file (lines 65, 81, 97) spread organization.managing_organizations directly. It would be lovely if this followed the same pattern.

♻️ Suggested simplification
         organization_parents = [*organization.parent_cache, organization.id]
         if organization.org_type == OrganizationTypeChoices.role.value:
-            managing_organization_ids = []
-            for managing_organization in organization.managing_organizations:
-                managing_organization_ids.append(managing_organization)
-            organization_parents = [*organization_parents, *managing_organization_ids]
+            organization_parents = [*organization_parents, *organization.managing_organizations]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@care/security/authorization/organization.py` around lines 141 - 145, Replace
the unnecessary intermediate loop that copies
organization.managing_organizations into managing_organization_ids with the same
direct spreading used elsewhere: when organization.org_type ==
OrganizationTypeChoices.role.value, append organization.managing_organizations
directly into organization_parents (remove managing_organization_ids and the for
loop that populates it), keeping the conditional and resulting assignment to
organization_parents unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@care/security/authorization/organization.py`:
- Around line 141-145: Replace the unnecessary intermediate loop that copies
organization.managing_organizations into managing_organization_ids with the same
direct spreading used elsewhere: when organization.org_type ==
OrganizationTypeChoices.role.value, append organization.managing_organizations
directly into organization_parents (remove managing_organization_ids and the for
loop that populates it), keeping the conditional and resulting assignment to
organization_parents unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6e056053-f44d-4eb7-a4bf-c38d89822151

📥 Commits

Reviewing files that changed from the base of the PR and between 0a72994 and a36cc98.

📒 Files selected for processing (1)
  • care/security/authorization/organization.py

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.20%. Comparing base (0a72994) to head (dc4995c).
⚠️ Report is 6 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3586      +/-   ##
===========================================
+ Coverage    77.07%   77.20%   +0.13%     
===========================================
  Files          474      474              
  Lines        22408    22424      +16     
  Branches      2346     2349       +3     
===========================================
+ Hits         17270    17313      +43     
+ Misses        4579     4531      -48     
- Partials       559      580      +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread care/security/authorization/organization.py Outdated
@Jacobjeevan Jacobjeevan requested a review from vigneshhari April 6, 2026 11:44
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