Skip to content

refactor: access and roles management #483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 17, 2025

Conversation

thicham43
Copy link
Collaborator

@thicham43 thicham43 commented Jun 30, 2025

Summary by CodeRabbit

  • New Features

    • Expanded and clarified documentation for user roles and rights, including detailed diagrams, explicit role definitions, management rules, and practical examples.
    • Introduced new roles and consolidated export rights for improved clarity and control.
  • Bug Fixes

    • Corrected and simplified permission checks, ensuring consistent enforcement of manage rights and export permissions.
  • Refactor

    • Streamlined and unified export rights, replacing multiple CSV export permissions with a single XLSX export right.
    • Removed obsolete read rights and related logic, focusing access control on management capabilities.
    • Simplified and clarified role and rights models for easier management and assignment.
  • Tests

    • Updated and expanded test cases to reflect new role definitions, rights structure, and export permissions.
  • Chores

    • Updated project version to 3.28.0-rc.

@thicham43 thicham43 force-pushed the 3031_refactor_access_management branch 2 times, most recently from 06f3f08 to e6155ef Compare July 1, 2025 09:28
@thicham43 thicham43 force-pushed the 3031_refactor_access_management branch from e6155ef to 7c39899 Compare July 8, 2025 08:42
Copy link

coderabbitai bot commented Jul 8, 2025

Walkthrough

This update overhauls the rights and roles management system, consolidating and renaming roles and rights for clarity, removing obsolete reading and export rights, and introducing a more structured schema. The codebase, migrations, and documentation are updated to reflect these changes, with tests and permissions logic adapted accordingly. The project version advances to "3.28.0-rc".

Changes

File(s) / Area Change Summary
.docs/rights_schema.md Expanded and clarified roles/rights schema, added management/use case sections, renamed/consolidated roles and rights, removed/added roles, and documented assignment constraints.
accesses/migrations/0011_add_new_rights_and_rename_others.py, accesses/migrations/0019_remove_multiple_rights.py, accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py, accesses/migrations/data/new_rights.py Migrations to remove, rename, and consolidate rights/roles fields; load new rights schema; update data accordingly.
accesses/models/right.py, accesses/models/role.py Removed obsolete read/export rights fields; consolidated export rights; updated/added methods for role management dependencies.
accesses/permissions.py, admin_cohort/permissions.py, exports/permissions.py Removed read rights checks; consolidated export permissions; updated permission logic for new rights structure.
accesses/q_expressions.py, cohort/services/cohort_rights.py Renamed/removed query constants for export rights; removed read-related queries.
accesses/serializers.py Updated serializers to remove obsolete fields and consolidate export rights.
accesses/services/accesses.py, accesses/services/rights.py, accesses/services/roles.py, accesses/services/shared.py Removed read/export rights logic; refactored rights checks; updated role management logic; consolidated export rights.
accesses/services/perimeters.py Changed perimeter user count update logic to iterate over all perimeters.
accesses/views/profile.py, accesses/views/right.py, accesses/views/role.py, accesses/views/perimeter.py Updated views to remove dynamic serializer selection, obsolete filters, and adapt to new rights structure.
admin_cohort/tests/tests_auth.py, content_management/tests/tests_view_content.py, exporters/tests/base_test.py, exports/tests/base_test.py, exports/tests/test_view_export_request.py Updated/removed test data and imports to align with new roles/rights structure.
accesses/tests/base.py, accesses/tests/test_view_access.py, accesses/tests/test_view_perimeters.py, accesses/tests/test_view_role.py Refactored, expanded, and updated test roles, rights, and expected results; split/renamed roles for finer granularity; new/updated test cases.
pyproject.toml Version bumped from "3.28.0-dev" to "3.28.0-rc".

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AccessesService
    participant Role
    participant RightsService

    User->>AccessesService: Request to manage role/access
    AccessesService->>Role: Check required rights for target role
    Role->>AccessesService: Return required management rights
    AccessesService->>RightsService: Verify user has required rights
    RightsService-->>AccessesService: Rights check result
    AccessesService-->>User: Allow or deny management action
Loading

Poem

🐇
A hop, a skip, a schema bright,
Old rights retired, new names in sight.
Exports merged, permissions clear,
Roles redefined—let’s give a cheer!
Tests now dance in structured rows,
Version hops up—how progress grows!
🥕✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6cb4c2 and ce02a8d.

📒 Files selected for processing (33)
  • .docs/rights_schema.md (1 hunks)
  • accesses/migrations/0011_add_new_rights_and_rename_others.py (1 hunks)
  • accesses/migrations/0019_remove_multiple_rights.py (1 hunks)
  • accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py (1 hunks)
  • accesses/migrations/data/new_rights.py (1 hunks)
  • accesses/models/right.py (0 hunks)
  • accesses/models/role.py (3 hunks)
  • accesses/permissions.py (2 hunks)
  • accesses/q_expressions.py (1 hunks)
  • accesses/serializers.py (2 hunks)
  • accesses/services/accesses.py (9 hunks)
  • accesses/services/perimeters.py (1 hunks)
  • accesses/services/rights.py (1 hunks)
  • accesses/services/roles.py (3 hunks)
  • accesses/services/shared.py (2 hunks)
  • accesses/tests/base.py (2 hunks)
  • accesses/tests/test_view_access.py (7 hunks)
  • accesses/tests/test_view_perimeters.py (10 hunks)
  • accesses/tests/test_view_role.py (6 hunks)
  • accesses/views/perimeter.py (1 hunks)
  • accesses/views/profile.py (1 hunks)
  • accesses/views/right.py (0 hunks)
  • accesses/views/role.py (3 hunks)
  • admin_cohort/permissions.py (3 hunks)
  • admin_cohort/tests/tests_auth.py (1 hunks)
  • cohort/services/cohort_rights.py (2 hunks)
  • content_management/tests/tests_view_content.py (2 hunks)
  • exporters/tests/base_test.py (1 hunks)
  • exports/permissions.py (1 hunks)
  • exports/services/rights_checker.py (2 hunks)
  • exports/tests/base_test.py (1 hunks)
  • exports/tests/test_view_export_request.py (3 hunks)
  • pyproject.toml (1 hunks)
💤 Files with no reviewable changes (2)
  • accesses/views/right.py
  • accesses/models/right.py
✅ Files skipped from review due to trivial changes (3)
  • pyproject.toml
  • accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py
  • accesses/migrations/data/new_rights.py
🚧 Files skipped from review as they are similar to previous changes (25)
  • accesses/views/perimeter.py
  • exporters/tests/base_test.py
  • accesses/migrations/0011_add_new_rights_and_rename_others.py
  • accesses/views/profile.py
  • content_management/tests/tests_view_content.py
  • accesses/views/role.py
  • exports/tests/base_test.py
  • accesses/serializers.py
  • exports/tests/test_view_export_request.py
  • accesses/services/rights.py
  • exports/services/rights_checker.py
  • admin_cohort/permissions.py
  • accesses/services/perimeters.py
  • accesses/services/shared.py
  • admin_cohort/tests/tests_auth.py
  • accesses/tests/base.py
  • exports/permissions.py
  • accesses/tests/test_view_access.py
  • accesses/tests/test_view_perimeters.py
  • cohort/services/cohort_rights.py
  • accesses/models/role.py
  • accesses/migrations/0019_remove_multiple_rights.py
  • accesses/permissions.py
  • accesses/q_expressions.py
  • accesses/services/accesses.py
🧰 Additional context used
🧬 Code Graph Analysis (2)
accesses/tests/test_view_role.py (2)
accesses/models/role.py (1)
  • Role (11-89)
admin_cohort/tests/tests_tools.py (3)
  • ListCase (165-188)
  • new_user_and_profile (81-95)
  • check_list_case (458-479)
accesses/services/roles.py (3)
accesses/services/rights.py (1)
  • all_rights (7-8)
admin_cohort/models/user.py (1)
  • User (7-27)
accesses/models/perimeter.py (1)
  • Perimeter (14-66)
🪛 LanguageTool
.docs/rights_schema.md

[style] ~177-~177: ‘With respect to’ might be wordy. Consider a shorter alternative.
Context: ...ter of P1 ### Listing user accesses With respect to the hierarchy tree above, if user Y has...

(EN_WORDINESS_PREMIUM_WITH_RESPECT_TO)


[style] ~189-~189: Unless you want to emphasize “not”, use “Cannot” which is more common.
Context: ...| | Data reader nominative on APHP | Can not read any of user Y's accesses ...

(CAN_NOT_PREMIUM)

🪛 markdownlint-cli2 (0.17.2)
.docs/rights_schema.md

53-53: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)


53-53: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


60-60: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


73-73: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


78-78: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


79-79: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


79-79: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


86-86: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


87-87: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


87-87: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


94-94: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


100-100: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


108-108: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


155-155: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


157-157: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


158-158: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


164-164: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


165-165: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


171-171: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


172-172: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


179-179: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


179-179: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


180-180: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


180-180: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


181-181: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


181-181: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: test
🔇 Additional comments (16)
accesses/tests/test_view_role.py (5)

51-51: LGTM! Consolidated export right is correctly used.

The test correctly uses the consolidated right_export_csv_xlsx_nominative field, which aligns with the refactoring described in the AI summary.


118-118: LGTM! Consistent usage of consolidated export right.

The test data correctly uses the consolidated export right field in the test case for inconsistent rights validation.


165-165: LGTM! Patch test correctly uses consolidated export right.

The patch test data correctly uses the consolidated right_export_csv_xlsx_nominative field, maintaining consistency with the refactoring.


206-286: LGTM! New test methods properly validate assignable roles functionality.

The new test methods for assignable roles comprehensively cover different scenarios:

  • Same level admin access managers
  • Inferior level admin access managers
  • Different perimeter contexts

The test cases correctly validate the expected role assignment behavior according to the hierarchy and permissions model.


236-244: Role definitions verified in test base class
All roles referenced in the to_find list are defined in accesses/tests/base.py and match your test fixtures—no changes needed.

.docs/rights_schema.md (4)

3-49: LGTM! Clear and comprehensive role hierarchy diagram.

The Mermaid class diagram effectively visualizes the role structure and dependencies. The consolidated export rights (right_export_csv_xlsx_nominative) are properly reflected in the CSV_Excel_Exports class.


51-112: LGTM! Comprehensive role descriptions with important warnings.

The role descriptions are clear and include important warnings about constraints and dependencies. The consolidation of export rights is properly documented.


115-124: LGTM! Well-structured role management rules.

The table clearly defines which rights are required to manage roles with specific capabilities. This provides excellent clarity for understanding the permission hierarchy.


127-189: LGTM! Practical use cases enhance understanding.

The use cases with concrete examples and perimeter hierarchy help users understand how the role management works in practice. The tabular summary effectively illustrates the management capabilities.

accesses/services/roles.py (7)

21-21: LGTM! Updated help text reflects consolidated export right.

The help text correctly describes the consolidated CSV/Excel export functionality in French, aligning with the refactoring to merge separate CSV and Excel export rights.


50-52: LGTM! Improved filtering logic for hierarchy-agnostic rights.

The filtering logic correctly identifies rights that are not hierarchy-dependent by checking the suffix patterns. This is a clean approach to separate different types of rights.


56-57: LGTM! Simplified hierarchy-dependent text generation.

The code correctly generates help text for the two types of hierarchy-dependent access management rights (admin and data), which aligns with the current role model.


67-67: LGTM! Consistent role management permission check.

The method correctly checks all the management rights to determine if a role allows managing accesses. The logic is comprehensive and covers all relevant management permissions.


70-70: LGTM! Simplified read access check aligns with refactoring.

The simplified logic that equates read access with manage access aligns with the removal of separate read rights mentioned in the AI summary.


75-108: LGTM! Comprehensive role validation logic.

The validation functions correctly check for:

  • Full admin roles with falsy rights
  • Inconsistent combinations of pseudonymized read with nominative export
  • IPP search without nominative read rights
  • Access management without user management rights

The logic is sound and prevents invalid role configurations.


111-116: LGTM! Clear method signature and implementation.

The method signature is descriptive and the implementation correctly filters assignable roles based on the user's management permissions for the target perimeter.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@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.

Actionable comments posted: 4

🧹 Nitpick comments (5)
accesses/migrations/0019_remove_multiple_rights.py (1)

15-21: Note: This update appears to be temporary.

The SQL sets right_read_accesses_above_levels = True, but according to the next migration (0020_remove_role_right_read_accesses_above_levels), this field is removed immediately after. Consider if this intermediate step is necessary or if the migrations could be consolidated.

Also applies to: 92-92

accesses/models/role.py (1)

66-89: Well-structured role management categorization methods.

The three new methods provide clear categorization of roles based on their management requirements. The inline comments effectively document the required rights.

Consider adding the @lru_cache(maxsize=None) decorator to these methods for consistency with other methods in the class, as role rights are immutable after creation:

+    @lru_cache(maxsize=None)
     def requires_full_admin_right_to_be_managed(self):
accesses/services/roles.py (1)

75-108: Good refactoring with clear validation logic.

The helper functions improve readability and the new validation preventing IPP search without nominative rights is a valuable security check.

For consistency, rename the helper function to match the pattern:

-        def allow_manage_accesses(d: dict) -> bool:
+        def allows_manage_accesses(d: dict) -> bool:
.docs/rights_schema.md (1)

1-189: Excellent documentation restructuring with comprehensive coverage.

The new documentation provides clear role definitions, management rules, and practical examples. The class diagram effectively visualizes the role hierarchy.

Consider addressing the markdown formatting issues flagged by the linters:

  1. Use consistent heading levels (line 53 should be h3 not h4)
  2. Remove trailing colons from headings
  3. Use consistent list markers (dashes instead of asterisks)
  4. Fix the grammatical issue on line 117: "The rules of managing roles"
accesses/services/accesses.py (1)

311-317: Consider removing redundant adapter methods.

These static methods now simply delegate to the role's methods. Consider calling the role methods directly to reduce indirection.

Instead of:

if self.role_requires_full_admin_right_to_be_read(role):
    # ...

Use:

if role.requires_full_admin_right_to_be_managed():
    # ...

This would make the code more direct and remove unnecessary abstraction layers.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 547978e and 7c39899.

📒 Files selected for processing (33)
  • .docs/rights_schema.md (1 hunks)
  • accesses/migrations/0011_add_new_rights_and_rename_others.py (1 hunks)
  • accesses/migrations/0019_remove_multiple_rights.py (1 hunks)
  • accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py (1 hunks)
  • accesses/migrations/data/new_rights.py (1 hunks)
  • accesses/models/right.py (0 hunks)
  • accesses/models/role.py (3 hunks)
  • accesses/permissions.py (2 hunks)
  • accesses/q_expressions.py (1 hunks)
  • accesses/serializers.py (2 hunks)
  • accesses/services/accesses.py (9 hunks)
  • accesses/services/perimeters.py (1 hunks)
  • accesses/services/rights.py (1 hunks)
  • accesses/services/roles.py (3 hunks)
  • accesses/services/shared.py (2 hunks)
  • accesses/tests/base.py (2 hunks)
  • accesses/tests/test_view_access.py (7 hunks)
  • accesses/tests/test_view_perimeters.py (10 hunks)
  • accesses/tests/test_view_role.py (6 hunks)
  • accesses/views/perimeter.py (1 hunks)
  • accesses/views/profile.py (1 hunks)
  • accesses/views/right.py (0 hunks)
  • accesses/views/role.py (3 hunks)
  • admin_cohort/permissions.py (3 hunks)
  • admin_cohort/tests/tests_auth.py (1 hunks)
  • cohort/services/cohort_rights.py (2 hunks)
  • content_management/tests/tests_view_content.py (2 hunks)
  • exporters/tests/base_test.py (1 hunks)
  • exports/permissions.py (1 hunks)
  • exports/services/rights_checker.py (2 hunks)
  • exports/tests/base_test.py (1 hunks)
  • exports/tests/test_view_export_request.py (3 hunks)
  • pyproject.toml (1 hunks)
💤 Files with no reviewable changes (2)
  • accesses/views/right.py
  • accesses/models/right.py
🧰 Additional context used
🧬 Code Graph Analysis (9)
accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py (2)
accesses/migrations/0011_add_new_rights_and_rename_others.py (1)
  • Migration (20-94)
accesses/migrations/0019_remove_multiple_rights.py (1)
  • Migration (34-93)
accesses/services/rights.py (1)
accesses/models/right.py (1)
  • Right (6-15)
exports/permissions.py (3)
accesses/permissions.py (4)
  • can_user_read_datalabs (55-56)
  • can_user_manage_datalabs (59-60)
  • can_user_make_export_csv_xlsx_nomi (51-52)
  • can_user_make_export_jupyter_nomi (43-44)
exports/apps.py (1)
  • ExportsConfig (6-20)
exporters/enums.py (1)
  • ExportTypes (7-24)
admin_cohort/permissions.py (3)
accesses/permissions.py (8)
  • can_user_manage_users (35-36)
  • has_object_permission (19-20)
  • has_object_permission (76-77)
  • has_object_permission (86-87)
  • has_permission (15-17)
  • has_permission (64-67)
  • has_permission (71-74)
  • has_permission (81-84)
accesses/services/accesses.py (1)
  • user_is_full_admin (32-34)
cohort_job_server/permissions.py (3)
  • has_object_permission (18-19)
  • has_permission (8-10)
  • has_permission (14-16)
exports/tests/test_view_export_request.py (2)
accesses/models/role.py (1)
  • Role (11-89)
accesses/models/access.py (1)
  • Access (17-53)
cohort/services/cohort_rights.py (2)
admin_cohort/models/user.py (1)
  • User (7-27)
cohort/models/cohort_result.py (1)
  • CohortResult (9-21)
accesses/tests/test_view_role.py (2)
accesses/models/role.py (1)
  • Role (11-89)
admin_cohort/tests/tests_tools.py (3)
  • ListCase (165-188)
  • new_user_and_profile (81-95)
  • check_list_case (458-479)
accesses/migrations/0019_remove_multiple_rights.py (3)
accesses/serializers.py (1)
  • RightSerializer (13-30)
accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py (1)
  • Migration (6-19)
accesses/migrations/0011_add_new_rights_and_rename_others.py (1)
  • Migration (20-94)
accesses/services/accesses.py (5)
accesses/q_expressions.py (3)
  • q_allow_manage_accesses_on_same_level (21-23)
  • q_allow_manage_accesses_on_inf_levels (27-29)
  • q_impact_inferior_levels (33-35)
accesses/models/perimeter.py (4)
  • above_levels (41-48)
  • q_all_parents (65-66)
  • Perimeter (14-66)
  • is_child_of (61-62)
accesses/models/access.py (1)
  • Access (17-53)
admin_cohort/models/user.py (1)
  • User (7-27)
accesses/models/role.py (4)
  • requires_full_admin_right_to_be_managed (66-71)
  • requires_admin_accesses_managing_right_to_be_managed (73-79)
  • requires_data_accesses_managing_right_to_be_managed (81-89)
  • Role (11-89)
🪛 LanguageTool
.docs/rights_schema.md

[grammar] ~51-~51: Use proper spacing conventions.
Context: ...ders --> Users ``` --- ## Possible roles #### Full_Admin role: This is a *Super User...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~54-~54: Use singular and plural nouns appropriately.
Context: ...ding everything, including managing all kind of accesses. This role has the follow...

(QB_NEW_EN_OTHER_ERROR_IDS_000012)


[grammar] ~54-~54: Use proper spacing conventions.
Context: ...including managing all kind of accesses. This role has the following right enable...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~56-~56: Use proper spacing conventions.
Context: ...ing right enabled: - right_full_admin > ⚠️ Only one Full Admin role is expe...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~58-~58: Use proper spacing conventions.
Context: ... enabled: - right_full_admin > ⚠️ Only one Full Admin role is expecte...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~58-~58: Use proper spacing conventions.
Context: ...Admin role is expected to be configured. #### Patient_Data_Reader role: It allows read...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~61-~61: Use proper spacing conventions.
Context: ... in nominative or in pseudonymized mode. It must have at least one of the followi...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~64-~64: Use proper spacing conventions.
Context: ...ive* - right_read_patient_pseudonymized Furthermore, this role could be enhanced...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~71-~71: Use proper spacing conventions.
Context: ...e* - right_export_jupyter_pseudonymized #### Unlimited_Data_Reader role: A role havin...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~74-~74: Use proper spacing conventions.
Context: ... in all perimeters without restrictions. Only the Full_Admin role is allowed to a...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~75-~75: There might be a mistake here.
Context: ...allowed to assign such a role to a user: - right_search_patients_unlimited ####...

(QB_NEW_EN_OTHER)


[grammar] ~76-~76: Place a period at the end of declarative sentences.
Context: ...er: - right_search_patients_unlimited #### Administrator_Of_Patient_Data_Readers ro...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~79-~79: There might be a mistake here.
Context: ...Of_Patient_Data_Readers role: It allows to manage accesses associated with Patient_Data...

(QB_NEW_EN_OTHER)


[grammar] ~82-~82: Use proper spacing conventions.
Context: ...s_inferior_levels* - right_manage_users > ⚠️ The rights granted by this role are ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~84-~84: Use proper spacing conventions.
Context: ...ior_levels* - right_manage_users > ⚠️ The rights granted by this role are dep...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~84-~84: Use correct prepositions.
Context: ...ghts granted by this role are dependent to the perimeters' hierarchy #### Manager...

(QB_NEW_EN_OTHER_ERROR_IDS_000010)


[grammar] ~84-~84: Place a period at the end of declarative sentences.
Context: ...e dependent to the perimeters' hierarchy #### Manager_Of_Administrators role: It allow...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~87-~87: There might be a mistake here.
Context: ...nager_Of_Administrators role: It allows to manage accesses associated with _Administrator...

(QB_NEW_EN_OTHER)


[grammar] ~87-~87: Use proper spacing conventions.
Context: ...istrator_Of_Patient_Data_Readers_ roles. - right_manage_admin_accesses_same_level ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~90-~90: Use proper spacing conventions.
Context: ...s_inferior_levels* - right_manage_users > ⚠️ The rights granted by this role are ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~92-~92: Use proper spacing conventions.
Context: ...ior_levels* - right_manage_users > ⚠️ The rights granted by this role are dep...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~92-~92: Use correct prepositions.
Context: ...ghts granted by this role are dependent to the perimeters' hierarchy #### CSV_Exc...

(QB_NEW_EN_OTHER_ERROR_IDS_000010)


[grammar] ~92-~92: Place a period at the end of declarative sentences.
Context: ...e dependent to the perimeters' hierarchy #### CSV_Excel_Exports role: It allows to exp...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~95-~95: There might be a mistake here.
Context: ... #### CSV_Excel_Exports role: It allows to export data in CSV and XLSX formats. - *righ...

(QB_NEW_EN_OTHER)


[grammar] ~95-~95: Use proper spacing conventions.
Context: ... to export data in CSV and XLSX formats. - right_export_csv_xlsx_nominative > ⚠️ ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~96-~96: Use proper spacing conventions.
Context: ...s. - right_export_csv_xlsx_nominative > ⚠️ Exporting patient data in CSV or Exc...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~98-~98: Use proper spacing conventions.
Context: ...right_export_csv_xlsx_nominative > ⚠️ Exporting patient data in CSV or Excel ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~98-~98: Use commas after Latin abbreviations.
Context: ...rmat is only allowed in nominative mode (i.e. must have the **right_read_patient_nomi...

(QB_NEW_EN_OTHER_ERROR_IDS_000037)


[grammar] ~98-~98: Place a period at the end of declarative sentences.
Context: ...right_read_patient_nominative** enabled) #### Jupyter_Exports role: It allows to expor...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~101-~101: There might be a mistake here.
Context: ...) #### Jupyter_Exports role: It allows to export data in Hive format to a Jupyter datala...

(QB_NEW_EN_OTHER)


[grammar] ~101-~101: Use proper spacing conventions.
Context: ...ormat to a Jupyter datalab or workspace. - right_export_jupyter_nominative - *righ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~103-~103: Use proper spacing conventions.
Context: ...e* - right_export_jupyter_pseudonymized > ⚠️ Having **right_export_jupyter_nomina...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~105-~105: Use proper spacing conventions.
Context: ...ight_export_jupyter_pseudonymized* > ⚠️ Having **right_export_jupyter_nominativ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~105-~105: Place a period at the end of declarative sentences.
Context: ..._patient_nominative** is enabled as well #### Datalabs role: It allows you to manage/r...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~109-~109: Use proper spacing conventions.
Context: ...you to manage/read the list of Datalabs. - right_manage_datalabs - *right_read_dat...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~111-~111: Use proper spacing conventions.
Context: ..._manage_datalabs* - right_read_datalabs --- ## Roles management The rules of managing ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~115-~115: Use proper spacing conventions.
Context: ...read_datalabs* --- ## Roles management The rules of managing role are defined a...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~117-~117: Use singular and plural nouns appropriately.
Context: ...Roles management The rules of managing role are defined according to the following ...

(QB_NEW_EN_OTHER_ERROR_IDS_000012)


[grammar] ~117-~117: Use proper spacing conventions.
Context: ...according to the following dependencies: | If a Role has one of these rights ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~127-~127: Use proper spacing conventions.
Context: ...ses_inferior_levels | --- ## Use cases Given this perimeters hierarchy tree: ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~129-~129: Use proper spacing conventions.
Context: ...s Given this perimeters hierarchy tree: mermaid graph TD APHP --> P0 APHP --> P1 APHP --> P2 P0 --> P3 P0 --> P4 P0 --> P5 P1 --> P6 P1 --> P7 P2 --> P8 P2 --> P9 P2 --> P10 P4 --> P11 P4 --> P12 P10 --> P13 P10 --> P14 ### Basic examples: 1. On perimeter P1: ...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~157-~157: There might be a mistake here.
Context: ...Access Manager on inferior perimeters only" * User Y has a role of "Data Acces...

(QB_NEW_EN_OTHER)


[grammar] ~158-~158: There might be a problem here.
Context: ...Access Manager on inferior perimeters only" > User X can manage accesses of user Y onl...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~160-~160: Use articles correctly.
Context: ...meters only**" > User X can manage accesses of user Y only if they are defined with...

(QB_NEW_EN_OTHER_ERROR_IDS_000004)


[grammar] ~160-~160: Use proper spacing conventions.
Context: ...y are defined within inferior levels of P1 2. On perimeter P1: * User X has "A...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~164-~164: There might be a mistake here.
Context: ...dmin Access Manager on same perimeter only" * User Y has "Data Access Manager ...

(QB_NEW_EN_OTHER)


[grammar] ~165-~165: There might be a problem here.
Context: ...Data Access Manager on same perimeter only" > User X can manage accesses of user Y as ...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~167-~167: Place a period at the end of declarative sentences.
Context: ...ey are defined within the same perimeter P1 3. mix: * User X has "Admin Access Mana...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~171-~171: There might be a mistake here.
Context: ...inferior perimeters only**" on perimeter P1 * User Y has "Data Access Manag...

(QB_NEW_EN_OTHER)


[grammar] ~172-~172: Place a period at the end of declarative sentences.
Context: ...on same perimeter only" on perimeter P7 > User X can manage accesses of user Y as ...

(QB_NEW_EN_OTHER_ERROR_IDS_000178)


[grammar] ~174-~174: Use articles correctly.
Context: ...perimeter P7 > User X can manage accesses of user Y as they are defined within an...

(QB_NEW_EN_OTHER_ERROR_IDS_000004)


[grammar] ~174-~174: Use proper spacing conventions.
Context: ...defined within an inferior perimeter of P1 ### Listing user accesses With respect to t...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~176-~176: Use proper spacing conventions.
Context: ...meter of P1 ### Listing user accesses With respect to the hierarchy tree above...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[style] ~177-~177: ‘With respect to’ might be wordy. Consider a shorter alternative.
Context: ...ter of P1 ### Listing user accesses With respect to the hierarchy tree above, if user Y has...

(EN_WORDINESS_PREMIUM_WITH_RESPECT_TO)


[grammar] ~180-~180: Use proper spacing conventions.
Context: ...1: Data reader nominative * On P4`: Admin accesses manager (on same level +...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~181-~181: Use proper spacing conventions.
Context: ...ses manager (on same level + inf levels) | X roles | Res...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[grammar] ~187-~187: There might be a mistake here.
Context: ...efined on P4 is listed as readonly | | Data Access Manager on APHP | Can...

(QB_NEW_EN_OTHER)


[grammar] ~188-~188: Use proper spacing conventions.
Context: ...** | | Data Access Manager on APHP | Can manage access defined within `...

(QB_NEW_EN_OTHER_ERROR_IDS_000007)


[style] ~189-~189: Unless you want to emphasize “not”, use “Cannot” which is more common.
Context: ...| | Data reader nominative on APHP | Can not read any of user Y's accesses ...

(CAN_NOT_PREMIUM)


[grammar] ~189-~189: Use proper spacing conventions.
Context: ... | Can not read any of user Y's accesses |

(QB_NEW_EN_OTHER_ERROR_IDS_000007)

🪛 markdownlint-cli2 (0.17.2)
.docs/rights_schema.md

53-53: Heading levels should only increment by one level at a time
Expected: h3; Actual: h4

(MD001, heading-increment)


53-53: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


60-60: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


73-73: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


78-78: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


79-79: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


79-79: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


86-86: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


87-87: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


87-87: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


94-94: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


100-100: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


108-108: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


155-155: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


157-157: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


158-158: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


164-164: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


165-165: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


171-171: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


172-172: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


179-179: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


179-179: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


180-180: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


180-180: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)


181-181: Unordered list style
Expected: dash; Actual: asterisk

(MD004, ul-style)


181-181: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (63)
pyproject.toml (1)

3-3: Ensure version bump is reflected everywhere & CI accepts the -rc suffix

The switch from a -dev to an -rc suffix looks fine here, but please double-check that:

  1. Any hard-coded __version__ attributes (e.g., in package/__init__.py) are bumped in sync.
  2. Release workflows (Docker tags, PyPI publish jobs, Helm charts, etc.) don’t filter out pre-releases and will correctly pick up 3.28.0-rc.
  3. CHANGELOG / docs mention the release-candidate status so downstream teams know it’s not GA yet.
content_management/tests/tests_view_content.py (1)

9-9: LGTM: Consistent renaming of role definition.

The import and usage have been consistently updated to use the new full_admin_role_definition naming convention, maintaining test functionality while aligning with the refactored role definitions.

Also applies to: 27-27

exporters/tests/base_test.py (1)

20-20: LGTM: Updated to use consolidated export right.

The change correctly updates the test to use the new right_export_csv_xlsx_nominative flag, which consolidates the previous separate CSV and XLSX export rights into a single permission. This aligns with the broader rights consolidation effort.

exports/tests/base_test.py (1)

34-34: LGTM: Consistent update to consolidated export right.

The test correctly uses the new right_export_csv_xlsx_nominative permission, maintaining consistency with the consolidated export rights schema across the test suite.

accesses/migrations/0020_remove_role_right_read_accesses_above_levels.py (1)

1-20: LGTM: Clean removal of deprecated right field.

The migration correctly removes the right_read_accesses_above_levels field from the Role model and cleans up corresponding database entries. The dependency on the previous migration (0019) is appropriate.

Note: The migration is irreversible due to the noop reverse operations, which is acceptable for this rights simplification effort.

accesses/migrations/0011_add_new_rights_and_rename_others.py (1)

16-16: LGTM! Correct fix for rights attribute setting.

This change correctly adapts to the updated all_rights method that now returns a list of right names (strings) instead of Right objects. Using right directly instead of right.name is the proper fix.

admin_cohort/tests/tests_auth.py (1)

12-12: LGTM! Appropriate cleanup of unused imports.

The removal of Role and Access imports aligns with the elimination of role and access creation in the test setup, reflecting the broader refactoring of access rights management.

accesses/services/rights.py (2)

7-8: LGTM! Correct refactoring of all_rights method.

Returning a flat list of right names instead of Right objects is consistent with the migration usage and simplifies the interface for callers that only need the names.


10-13: LGTM! Proper conversion to static method.

Converting to static method and using Right.objects.all() directly is correct since:

  1. The method no longer needs instance state
  2. It requires full Right objects to access category, label, and depends_on fields
  3. This maintains functionality while adapting to the all_rights method changes
exports/tests/test_view_export_request.py (2)

85-93: LGTM! Correct consolidation of export roles.

The replacement of separate "EXP_CSV_PSEUDO" and "EXP_CSV_NOMI" roles with a single "EXP_CSV_XLSX_NOMI" role properly reflects the consolidation of export rights mentioned in the PR objectives.


103-109: LGTM! Consistent access object updates.

The access objects are correctly updated to use the new consolidated export role, maintaining test coverage while adapting to the new rights schema.

Also applies to: 153-159

accesses/services/perimeters.py (1)

202-206: LGTM! Improved logic ensures data consistency.

Iterating over all perimeters instead of only those in the updates dictionary ensures that perimeters with zero users also get their count_allowed_users field properly updated to 0. This maintains better data consistency across all perimeter records.

accesses/views/role.py (3)

12-12: LGTM: Good consolidation of rights management.

The import of all_rights centralizes rights definitions, which improves maintainability and consistency across the codebase.


131-131: Parameter renaming improves code clarity.

The parameter name change from queryset to all_roles better reflects the actual data being passed and improves code readability.


61-67: Ensure all_rights values align with Role BooleanField names

The view builds data by iterating over each name in all_rights and falling back to getattr(role, right, False). This works correctly only if every Right.name exactly matches a Role attribute; otherwise you’ll silently get False for unrecognized rights.

• accesses/services/rights.py: all_rights = rights_service.all_rights() should return strings like
"right_full_admin", "right_manage_users", etc.
• accesses/models/role.py: verify that each of these names corresponds to a declared BooleanField.

If your Right.name values differ (for example, missing the "right_" prefix), either
– adjust how you store/derive those names in the Right model/service, or
– normalize them in the view before merging into data, and/or raise an explicit error on missing attributes to catch mismatches early.

accesses/views/profile.py (3)

6-6: LGTM: Simplified imports align with permission model changes.

The removal of can_user_read_users import is consistent with the broader refactor that eliminates read-only rights.


17-17: Simplified serializer usage is consistent with permission refactor.

The fixed serializer_class = ProfileSerializer simplifies the code by removing conditional logic, which aligns with the broader removal of read permission checks.


11-11: Verify sensitive data exposure in ProfileSerializer
Please review the fields definitions in accesses/serializers.py to ensure that switching from ReducedProfileSerializer to ProfileSerializer doesn’t now leak any private or sensitive attributes (e.g., email addresses, phone numbers, internal identifiers) to clients that previously received only the reduced view.

• File: accesses/serializers.py
class ReducedProfileSerializer (Meta.fields around line 55)
class ProfileSerializer (Meta.fields around line 73)

If any sensitive fields appear in ProfileSerializer that weren’t in ReducedProfileSerializer, either re-introduce conditional serializer logic or add appropriate permission checks.

accesses/serializers.py (2)

27-30: LGTM: Cleaned up serializer fields align with model changes.

The removal of read access fields from the extra_kwargs is consistent with the broader refactor that eliminates read-only rights from the role management system.


204-204: Export rights consolidation simplifies permission model.

The replacement of separate right_export_csv_nominative and right_export_csv_pseudonymized with a single right_export_csv_xlsx_nominative field effectively consolidates export permissions and aligns with the broader refactor.

exports/permissions.py (3)

6-7: LGTM: Import consolidation aligns with unified export permissions.

The updated import statement correctly uses the consolidated can_user_make_export_csv_xlsx_nomi function, which unifies CSV and XLSX export permission checks.


15-16: Verify the consolidation correctly handles both CSV and XLSX formats.

The logic now uses a single permission function for both CSV and XLSX formats, which is consistent with the broader refactor. The condition output_format in (ExportTypes.CSV, ExportTypes.XLSX) correctly covers both formats.


23-24: Confirm Intentional Removal of Pseudonymized CSV/XLSX Exports

File: exports/permissions.py (lines 23–24)

    if output_format in (ExportTypes.CSV, ExportTypes.XLSX):
        raise PermissionDenied("Vous n'avez pas le droit d'export CSV/Excel pseudonymisé")

Please verify that:

  • Disabling pseudonymized CSV/XLSX exports aligns with current business requirements.
  • No existing workflows or automated tests depend on this functionality.
  • User-facing messages and documentation clearly communicate this change.

If this behavior is unintentional, consider restoring the original permission check or introducing a new permission that allows pseudonymized exports for authorized users.

accesses/services/shared.py (2)

17-17: LGTM: DataRight field consolidation aligns with export rights refactor.

The consolidation of CSV export rights into a single right_export_csv_xlsx_nominative field simplifies the data structure and is consistent with the broader refactor.


28-28: Method correctly updated to use consolidated export right.

The acquire_extra_global_rights method properly uses the new consolidated field name while maintaining the same logical behavior (OR operation).

cohort/services/cohort_rights.py (4)

9-10: Import consolidation looks good.

The consolidation of CSV export rights into a unified CSV/XLSX export right is well-implemented. The removal of q_allow_export_csv_pseudo aligns with the refactoring to eliminate pseudonymized CSV exports.


18-18: Constant renaming is consistent.

The constant EXPORT_CSV_XLSX_NOMI properly reflects the unified CSV/XLSX export right, maintaining consistency with the new naming convention.


26-26: Rights dictionary update is correct.

The all_true_rights function correctly uses the new unified export right constant, maintaining consistency with the refactored permissions structure.


77-77: Query expression update is properly implemented.

The method now correctly uses the unified q_allow_export_csv_xlsx_nominative query expression, removing the need for separate CSV and XLSX logic.

exports/services/rights_checker.py (2)

15-15: Right constant renaming is consistent.

The constant right_csv_xlsx_nomi properly reflects the unified CSV/XLSX export right, maintaining consistency with the broader refactoring.


28-28: Verify unified CSV/XLSX permission covers both nominative and pseudonymized exports

Please confirm that granting right_export_csv_xlsx_nominative for all CSV and XLSX exports (regardless of nominative vs. pseudonymized) is acceptable under our security requirements. If pseudonymized exports should remain less-privileged, you’ll need to restore conditional logic.

Consider also renaming the field to remove the “_nominative” suffix for clarity (e.g. right_export_csv_xlsx), since it now governs both export modes.

Affected locations to review:

  • exports/services/rights_checker.py:28
  • accesses/models/role.py (field definition at line 20)
  • accesses/q_expressions.py:14
  • accesses/permissions.py:52
accesses/q_expressions.py (1)

14-14: Query expression renaming is consistent.

The renaming from q_allow_export_csv_nominative to q_allow_export_csv_xlsx_nominative properly reflects the unified CSV/XLSX export permission, maintaining consistency with the broader refactoring.

admin_cohort/permissions.py (3)

5-5: Import simplification is consistent with refactoring.

The removal of read-only permission functions aligns with the broader refactoring to eliminate read-only rights and simplify the permission model.


28-28: Permission logic update is more restrictive.

The change from can_user_read_logs to accesses_service.user_is_full_admin makes the logs permission more restrictive, requiring full admin rights instead of specific read permissions. This aligns with the removal of read-only rights.


42-42: Object permission simplification is consistent.

The delegation to has_permission removes the previous object-level ownership check, simplifying the permission model in line with the broader refactoring.

accesses/migrations/data/new_rights.py (3)

1-106: Rights definition is well-structured and comprehensive.

The rights list provides a clear hierarchy with proper categorization and scope flags. The separation of data access management from admin access management is well-designed, and the impact flags properly indicate inheritance behavior.


108-116: Dependent rights structure is properly implemented.

The dependent rights mechanism provides a clean way to handle rights that automatically inherit from other rights. The right_read_datalabs depending on right_manage_datalabs follows the principle of read access being implied by manage access.


88-93: Consolidation of CSV/XLSX export rights is consistent
Confirmed that legacy CSV-only rights only appear in migrations (for data cleanup) and that all application logic, serializers, permissions checks and tests now reference the unified right_export_csv_xlsx_nominative. No unintended permission broadening detected.

accesses/tests/test_view_access.py (6)

48-48: LGTM!

The role name change is consistent with the PR's consolidation of export rights.


326-334: Role-based access control logic is correctly implemented.

The updated perimeter filtering and editability checks properly reflect the hierarchical management rules where admin access managers can manage data accesses but not admin accesses at the same level.


337-344: Access control hierarchy is properly enforced.

The logic correctly restricts data access managers from editing admin-level accesses while allowing them to manage data accesses.


391-391: Role updates are consistent with the refactoring objectives.

All role references have been properly updated to use the consolidated XLSX export role and the new admin accesses manager role.

Also applies to: 405-405, 440-443


454-457: Rights structure correctly reflects the new schema.

The updated rights dictionary properly sets permissions for the data reader role with the consolidated XLSX export right.


462-483: Comprehensive test coverage for perimeter-based rights.

The new test cases effectively validate rights aggregation across different perimeter levels.

accesses/permissions.py (3)

51-52: Export permission function correctly updated.

The function name and permission check have been properly updated to use the consolidated CSV/XLSX export right.


77-77: Object permission check is appropriate.

The permission check correctly validates management rights for specific access objects.


84-84: Verify the removal of read permission checks is intentional.

The has_permission method now allows all authenticated users to perform GET requests on profiles. Please confirm this aligns with the intended access control model after removing read-only rights.

Also applies to: 87-87

accesses/tests/base.py (2)

61-137: Well-structured role definitions with clear separation of concerns.

The new role definitions provide excellent clarity with:

  • Explicit naming conventions
  • Granular separation between same-level and inferior-level management rights
  • Proper consolidation of export rights

This structure will make test maintenance easier and more intuitive.


199-200: Good refactoring to static method.

Since create_new_access_for_user doesn't use instance state, converting it to a static method is the correct approach.

accesses/migrations/0019_remove_multiple_rights.py (1)

41-89: Migration operations are comprehensive and well-structured.

The field renaming and removals properly implement the rights schema refactoring while preserving critical data through the rename operation.

accesses/tests/test_view_role.py (3)

51-51: Export right references consistently updated.

All occurrences of the CSV export right have been properly updated to use the consolidated CSV/XLSX export right.

Also applies to: 56-56, 61-61, 68-68, 118-118, 165-165


250-287: Excellent test coverage for granular role management.

The new test cases effectively validate the hierarchical role assignment rules:

  • Same-level managers cannot assign roles to child perimeters
  • Inferior-level managers can assign appropriate roles to child perimeters

This ensures the access control hierarchy is properly enforced.


236-244: Comprehensive role lists for assignability tests.

The expected assignable roles correctly include all data-level roles and the new granular management role variants, ensuring complete test coverage.

Also applies to: 274-282, 297-305

accesses/tests/test_view_perimeters.py (4)

133-138: Role naming updates look good.

The updated role names align with the new explicit naming convention documented in the rights schema.


151-156: Correct addition of P1 read rights.

The new PerimeterReadRight for P1 with all rights enabled correctly reflects the role_data_reader_full_access assignment.

Also applies to: 172-172


445-446: Appropriate use of level-specific manager roles.

The updated roles correctly test the scenario where a user has management rights but no data reading rights.


324-324: No changes needed for opposed patient lookup flag

The allow_lookup_opposed_patients value is driven by the user’s right_search_opposed_patients setting (default False in accesses/models/role.py and exposed via accesses_service.can_user_read_opposed_patient_data). The updated tests now correctly expect False for roles without that right and still cover the True case where a role grants it.

accesses/models/role.py (1)

19-20: Good consolidation of CSV/Excel export rights.

Merging the export rights into a single right_export_csv_xlsx_nominative field simplifies permission management while maintaining clarity.

accesses/services/roles.py (1)

69-70: Logical simplification of read access permissions.

Making read access implicit in manage access aligns with the principle that managers need to see what they manage.

accesses/services/accesses.py (4)

59-66: Appropriate simplification of access filtering logic.

Removing the separate read access check and treating all non-manageable accesses as readonly aligns with the simplified permission model.


78-85: Correct updates to perimeter access logic.

The changes appropriately reflect the shift from read-based to manage-based permissions for accessing child perimeters.


290-308: Excellent refactoring of access management logic.

The new implementation effectively uses the role's categorization methods and provides clearer logic for determining management permissions. The OR operation correctly allows admin access managers to manage data accesses.


145-145: Consistent application of consolidated export rights.

All export right references have been properly updated to use the single right_export_csv_xlsx_nominative field.

Also applies to: 159-159, 173-173, 221-221, 230-230

@@ -125,7 +125,7 @@ def check_read_patient_data_rights(self, request, *args, **kwargs):
serializer = RightReadPatientDataSerializer(data={"allow_read_patient_data_nomi": True,
"allow_lookup_opposed_patients": True,
"allow_read_patient_without_perimeter_limit": True,
"allow_read_administrative_data": True,
"allow_read_administrative_data": True, # todo: remove this ? used in FHIR ?
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Resolve the TODO comment about administrative data rights.

The TODO comment indicates uncertainty about whether allow_read_administrative_data should be removed, particularly in relation to FHIR usage. This technical debt should be addressed to avoid confusion and maintain clean code.

Would you like me to help investigate the FHIR usage of this flag or create an issue to track this cleanup task?

Let me search for FHIR-related usage of this administrative data flag:


🏁 Script executed:

#!/bin/bash
# Search for usage of allow_read_administrative_data in FHIR-related code
rg -A 3 -B 3 "allow_read_administrative_data" --type py

# Search for FHIR-related code that might use administrative data
rg -A 5 -B 5 "fhir|FHIR" --type py | rg -A 5 -B 5 "administrative"

Length of output: 13629


Remove or clarify the outdated TODO on allow_read_administrative_data
The TODO mentioning FHIR is outdated—there are no FHIR references in the codebase. You should either remove this comment (and the field if unused) or update it to reflect the real intent of the flag.

  • accesses/views/perimeter.py (line 128): Remove the # todo: remove this ? used in FHIR ? comment.
  • accesses/serializers.py: Review whether allow_read_administrative_data is still required; if not, remove it from the serializer.
  • accesses/tests/test_view_perimeters.py: Update or remove all test assertions related to this flag.

Let me know if you’d like assistance creating an issue or a migration to clean this up.

🤖 Prompt for AI Agents
In accesses/views/perimeter.py at line 128, remove the outdated TODO comment
about FHIR from the "allow_read_administrative_data" field. Then, check
accesses/serializers.py to determine if this field is still needed; if it is
unused, remove it from the serializer. Finally, update or remove any related
test assertions in accesses/tests/test_view_perimeters.py to reflect these
changes.

Comment on lines +38 to 39
(request.method == "GET" or
(request.method in ("POST", "PATCH") and can_user_manage_users(request.user)))
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify the security implications of allowing unrestricted GET requests.

The logic now allows any authenticated user to make GET requests without checking read permissions. This is a significant change that could potentially expose sensitive user data.


🏁 Script executed:

#!/bin/bash
# Description: Check what data is exposed through GET requests in the users endpoint
# Expected: Understand the security implications of allowing unrestricted GET access

echo "Searching for user-related view classes and their GET methods..."
rg -n "class.*User.*View" --type py -A 10

echo "Searching for serializers that handle user data..."
rg -n "class.*User.*Serializer" --type py -A 10

Length of output: 13761


🏁 Script executed:

#!/bin/bash
echo "Extracting UsersPermission class implementation..."
rg -n "class UsersPermission" -A 40 admin_cohort/permissions.py

echo
echo "Locating can_user_manage_users function..."
rg -n "def can_user_manage_users" -A 20 admin_cohort/permissions.py

Length of output: 1366


🏁 Script executed:

#!/bin/bash
echo "Searching for the definition of can_user_manage_users across the repository..."
rg -n "def can_user_manage_users" -A 20 .

echo
echo "Searching for its import statements to locate the module..."
rg -n "can_user_manage_users" -n -C 2 .

Length of output: 2801


Restrict unrestricted GET on User endpoints
The current UsersPermission implementation in admin_cohort/permissions.py (lines 37–39) allows any authenticated user to perform GET on the UserViewSet, and admin_cohort/views/users.py uses queryset = User.objects.all() with a serializer that exposes username, firstname, lastname, and email. This effectively lets any logged-in user list or retrieve all user records.

• Files to review:
– admin_cohort/permissions.py (UsersPermission.has_permission)
– admin_cohort/views/users.py (UserViewSet; default get_queryset and serializer fields)

Suggestions:

  1. Confirm whether all authenticated users should see other users’ details.
  2. If not, restrict GET to users with can_user_manage_users(request.user).
  3. Alternatively, introduce a read-only serializer that omits sensitive fields or implement object-level permissions for GET.
🤖 Prompt for AI Agents
In admin_cohort/permissions.py around lines 38 to 39, the current permission
allows any authenticated user to perform GET requests on UserViewSet, exposing
all user details. To fix this, restrict GET access by requiring
can_user_manage_users(request.user) to be true for GET requests as well, or
alternatively implement a read-only serializer with limited fields or
object-level permissions to prevent unrestricted access to user data.

Comment on lines +13 to +14
delete_old_rights = "DELETE FROM accesses_right WHERE True;"

Copy link

@coderabbitai coderabbitai bot Jul 8, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider the risks of deleting all rights data.

The migration deletes all existing rights before loading new ones. This approach has risks:

  1. If the migration fails after deletion but before loading, you'll lose all rights data
  2. The error handling in load_new_rights only logs errors without failing the migration

Consider:

  • Adding a database transaction wrapper to ensure atomicity
  • Making the migration fail if rights loading encounters errors
  • Creating a backup of the rights table before deletion

Also applies to: 24-31, 90-91

🤖 Prompt for AI Agents
In accesses/migrations/0019_remove_multiple_rights.py around lines 13-14, 24-31,
and 90-91, the migration deletes all rights data without transactional safety or
proper error handling, risking data loss if the process fails mid-way. Wrap the
deletion and rights loading steps inside a single database transaction to ensure
atomicity, modify the error handling in load_new_rights to raise exceptions and
fail the migration on errors, and implement a backup mechanism for the
accesses_right table before deletion to allow recovery if needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it's safe!

Copy link

Choose a reason for hiding this comment

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

@thicham43 Understood! I appreciate you confirming that the migration approach is safe in your context. You likely have additional safeguards or considerations in place that ensure the data integrity during the migration process.

Comment on lines 59 to 62
roles = [self.role_data_accesses_manager,
self.role_admin_accesses_reader,
self.role_admin_accesses_manager,
self.role_export_accesses_manager,
self.role_admin_accesses_manager,
self.role_data_accesses_manager]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix duplicate role assignment.

The roles list contains self.role_admin_accesses_manager twice, which doesn't align with the comment indicating different access levels (S+I) for different perimeters.

Based on the pattern in other test methods and the hierarchy diagram, this should likely use different role variants:

            roles = [self.role_data_accesses_manager,
                     self.role_admin_accesses_manager,
-                     self.role_admin_accesses_manager,
+                     self.role_admin_accesses_manager_same_level,  # or _inf_levels based on the test scenario
                     self.role_data_accesses_manager]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
roles = [self.role_data_accesses_manager,
self.role_admin_accesses_reader,
self.role_admin_accesses_manager,
self.role_export_accesses_manager,
self.role_admin_accesses_manager,
self.role_data_accesses_manager]
roles = [self.role_data_accesses_manager,
self.role_admin_accesses_manager,
self.role_admin_accesses_manager_same_level, # or _inf_levels based on the test scenario
self.role_data_accesses_manager]
🤖 Prompt for AI Agents
In accesses/tests/test_view_perimeters.py around lines 59 to 62, the roles list
has a duplicate entry of self.role_admin_accesses_manager, which conflicts with
the intended different access levels for perimeters. Replace the second
occurrence of self.role_admin_accesses_manager with the appropriate distinct
role variant, such as self.role_admin_accesses_manager_inherited or another
relevant role, to reflect the correct access hierarchy and match the pattern
used in other test methods.

Copy link

@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.

Actionable comments posted: 4

🧹 Nitpick comments (3)
admin_cohort/apps.py (1)

4-4: Consider removing the intermediate variable.

The env variable is only used twice and doesn't provide significant value. You could use os.environ.get() directly.

-env = os.environ

Then update the usage:

-    auth_hooks = env.get("USER_AUTHENTICATION_HOOKS")
-    user_identity_hooks = env.get("USER_IDENTITY_HOOKS")
+    auth_hooks = os.environ.get("USER_AUTHENTICATION_HOOKS")
+    user_identity_hooks = os.environ.get("USER_IDENTITY_HOOKS")
cohort_job_server/cohort_creator.py (1)

43-45: Improve job status handling with consistent logging.

The explicit handling of failed and other terminal job statuses provides clearer logging and better observability. The use of _logger_err.error for failures and _logger.info for other statuses is appropriate.

However, consider using the is_end_state property from the JobStatus enum to make the logic more maintainable:

            if job_status in (JobStatus.finished, JobStatus.failed):
                data["request_job_duration"] = str(timezone.now() - cohort.created_at)
                if job_status == JobStatus.failed:
                    data["request_job_fail_msg"] = data.pop(ERR_MESSAGE, None)
                    _logger_err.error(f"CohortResult[{cohort.uuid}] - Failed")
-            else:
+            elif job_status.is_end_state:
                _logger.info(f"CohortResult[{cohort.uuid}] - Ended with status: {job_status}")
cohort_job_server/cohort_counter.py (1)

73-77: Improve job status handling with explicit failure logging.

The explicit handling of failed job statuses with error logging provides better observability and debugging capabilities. The else branch for other job statuses ensures all terminal states are properly logged.

Similar to the cohort_creator.py suggestion, consider using the is_end_state property from the JobStatus enum for consistency:

        if job_status == JobStatus.finished:
            # ... existing logic ...
            _logger.info(f"DatedMeasure[{dm.uuid}] successfully updated from Query Executor")
        elif job_status == JobStatus.failed:
            data["request_job_fail_msg"] = data.pop(ERR_MESSAGE, None)
            _logger_err.error(f"DatedMeasure[{dm.uuid}] - Failed")
-        else:
+        elif job_status.is_end_state:
            _logger.info(f"DatedMeasure[{dm.uuid}] - Ended with status: {job_status}")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7c39899 and d6cb4c2.

📒 Files selected for processing (9)
  • admin_cohort/apps.py (1 hunks)
  • admin_cohort/management/commands/load_initial_data.py (3 hunks)
  • cohort/serializers.py (1 hunks)
  • cohort/services/dated_measure.py (1 hunks)
  • cohort_job_server/cohort_counter.py (2 hunks)
  • cohort_job_server/cohort_creator.py (3 hunks)
  • cohort_job_server/query_executor_api/cohort_requests/base_cohort_request.py (1 hunks)
  • cohort_job_server/query_executor_api/query_executor_client.py (1 hunks)
  • cohort_job_server/query_executor_api/query_executor_requester.py (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • cohort_job_server/query_executor_api/cohort_requests/base_cohort_request.py
  • cohort_job_server/query_executor_api/query_executor_client.py
  • cohort_job_server/query_executor_api/query_executor_requester.py
🧰 Additional context used
🧬 Code Graph Analysis (2)
cohort/serializers.py (1)
cohort/models/request.py (1)
  • dated_measures (20-21)
cohort_job_server/cohort_counter.py (1)
admin_cohort/types.py (1)
  • JobStatus (35-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: test
  • GitHub Check: test
🔇 Additional comments (11)
cohort/services/dated_measure.py (1)

65-65: Approve with caution: validate snapshot_id handling and access implications

The addition of snapshot_id to the WebSocket payload gives clients valuable context, but please double-check:

  • That dm.request_query_snapshot_id can’t be None (or is safely serialized as null) so front-end handlers won’t break.
  • That exposing this internal ID aligns with your access/roles refactor and doesn’t leak unauthorized snapshot information.

Location to review:

  • cohort/services/dated_measure.py, in ws_send_to_client at the line
"snapshot_id": dm.request_query_snapshot_id,
admin_cohort/apps.py (2)

1-1: LGTM: Proper import for environment variable access.

The os import is necessary and correctly placed for accessing environment variables.


10-14: Consider adding hook validation for security.

The current implementation trusts environment variables without validation, which could lead to runtime errors or security issues if invalid hook paths are provided.

Consider adding validation to ensure hook paths are valid and secure:

def validate_hook_path(hook_path):
    """Validate that hook path is a valid Python import path."""
    if not hook_path or not isinstance(hook_path, str):
        return False
    # Add validation logic for your specific hook format
    return True

# Then use in the HOOKS configuration:
auth_hooks_list = [hook.strip() for hook in auth_hooks.split(",") if validate_hook_path(hook.strip())] if auth_hooks else []

You should verify what format these hooks should have and implement appropriate validation.

cohort/serializers.py (1)

276-276: Good addition of clarifying comment.

The comment helps explain the purpose of the filter condition, improving code readability.

cohort_job_server/cohort_creator.py (2)

10-10: LGTM: Proper error logger import.

Adding _logger_err import is appropriate for the new error logging functionality introduced in the failure handling logic below.


61-61: LGTM: Consistent log message formatting.

The change from "QUERY_EXECUTOR" to "Query Executor" aligns with the standardization effort mentioned in the AI summary and improves readability.

admin_cohort/management/commands/load_initial_data.py (2)

19-19: LGTM: Environment variable for query executor username.

Adding the environment variable allows for configuration flexibility while maintaining a sensible default.


31-31: LGTM: Method call integration.

The call to setup_query_executor_user_account() is properly placed after the admin user setup.

cohort_job_server/cohort_counter.py (3)

72-72: LGTM: Consistent log message formatting.

The change from "QUERY_EXECUTOR" to "Query Executor" maintains consistency with the logging standardization across the codebase.


95-99: LGTM: Consistent failure handling pattern.

The explicit handling of failed job statuses in the feasibility study method follows the same pattern established in the dated measure handler, ensuring consistency across the codebase.


101-101: LGTM: Appropriate logging level change.

Changing from _logger_err.exception to _logger_err.error is appropriate here since the exception is being re-raised and will be handled upstream. This avoids duplicate stack traces in logs while maintaining error visibility.

Comment on lines 13 to 14
HOOKS = {"USER_AUTHENTICATION": auth_hooks and auth_hooks.split(",") or [],
"USER_IDENTITY": user_identity_hooks and user_identity_hooks.split(",") or [],
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Handle whitespace and improve readability.

The current implementation doesn't handle whitespace around commas in environment variables, which could lead to malformed hook names.

-    HOOKS = {"USER_AUTHENTICATION": auth_hooks and  auth_hooks.split(",") or [],
-             "USER_IDENTITY":  user_identity_hooks and  user_identity_hooks.split(",") or [],
+    HOOKS = {
+        "USER_AUTHENTICATION": [hook.strip() for hook in auth_hooks.split(",")] if auth_hooks else [],
+        "USER_IDENTITY": [hook.strip() for hook in identity_hooks.split(",")] if identity_hooks else [],
+    }

This change:

  • Strips whitespace from individual hook names
  • Uses more readable conditional logic
  • Improves formatting consistency
  • Handles empty strings properly

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In admin_cohort/apps.py around lines 13 to 14, the code splits environment
variable strings by commas but does not strip whitespace from each hook name,
which can cause malformed entries. Update the code to split the strings by
commas, then strip whitespace from each resulting hook name. Also, refactor the
conditional logic to be clearer and handle empty strings properly, ensuring the
HOOKS dictionary values are lists of clean, trimmed hook names or empty lists if
the variables are not set.

Comment on lines 10 to 11
auth_hooks = env.get("USER_AUTHENTICATION_HOOKS")
user_identity_hooks = env.get("USER_IDENTITY_HOOKS")
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve consistency and add input validation.

The variable naming is inconsistent (auth_hooks vs user_identity_hooks), and there's no validation of the environment variable values.

-    auth_hooks = env.get("USER_AUTHENTICATION_HOOKS")
-    user_identity_hooks = env.get("USER_IDENTITY_HOOKS")
+    auth_hooks = os.environ.get("USER_AUTHENTICATION_HOOKS", "")
+    identity_hooks = os.environ.get("USER_IDENTITY_HOOKS", "")

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In admin_cohort/apps.py around lines 10 to 11, the variable names auth_hooks and
user_identity_hooks are inconsistent in style and there is no validation for the
environment variable values. Rename the variables to use a consistent naming
pattern, such as both using snake_case with similar prefixes or suffixes, and
add checks to validate that the retrieved environment variables are not None or
empty before using them, raising an appropriate error or handling the case if
validation fails.

Comment on lines 57 to 64
def setup_query_executor_user_account(self) -> None:
_ = self.create_profile(username=QUERY_EXECUTOR_USERNAME,
firstname='Query',
lastname='EXECUTOR',
email='[email protected]',
password='1234'
)
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Address security concerns with hardcoded credentials.

The method creates a system user for query executor operations but has several security concerns:

  1. Hardcoded password: The password '1234' is hardcoded and weak
  2. Hardcoded email: Using '[email protected]' may not be appropriate for production
  3. No role assignment: Unlike the admin user, no role or permissions are assigned to this user

Apply this diff to improve security:

 def setup_query_executor_user_account(self) -> None:
+    query_executor_password = env.get('QUERY_EXECUTOR_PASSWORD', '1234')
+    query_executor_email = env.get('QUERY_EXECUTOR_EMAIL', '[email protected]')
+    
     _ = self.create_profile(username=QUERY_EXECUTOR_USERNAME,
                             firstname='Query',
                             lastname='EXECUTOR',
-                            email='[email protected]',
-                            password='1234'
+                            email=query_executor_email,
+                            password=query_executor_password
                             )

Additionally, consider whether this user needs specific roles or permissions for its intended purpose.


I need to verify how create_profile is implemented and whether an env utility is available before suggesting the diff. Let me gather that:


🏁 Script executed:

#!/bin/bash
# Locate and preview the management command file
fd load_initial_data.py
sed -n '1,50p' admin_cohort/management/commands/load_initial_data.py

# Find where create_profile is defined and check its parameters
rg -n "def create_profile" .

# Check for any existing env utility or import
rg -n "import .*env" .
rg -n "env\." .

Length of output: 7894


I’d like to see how the admin account setup handles role assignment to mirror that for the query executor. Gathering that now:


🏁 Script executed:

#!/bin/bash
# Show the setup_admin_user_account implementation to check role assignment
rg -n "def setup_admin_user_account" -A 30 admin_cohort/management/commands/load_initial_data.py

Length of output: 1306


Externalize Query Executor credentials and assign permissions

To secure the query executor account, replace the hardcoded email and password with environment-backed defaults and mirror the admin’s role‐and‐access setup:

• File to update: admin_cohort/management/commands/load_initial_data.py
• Location: inside setup_query_executor_user_account (around lines 57–63)

Suggested diff:

     def setup_query_executor_user_account(self) -> None:
-        _ = self.create_profile(username=QUERY_EXECUTOR_USERNAME,
-                                firstname='Query',
-                                lastname='EXECUTOR',
-                                email='[email protected]',
-                                password='1234'
-                                )
+        # Read credentials from environment (fallback to defaults)
+        query_executor_email = env.get('QUERY_EXECUTOR_EMAIL', '[email protected]')
+        query_executor_password = env.get('QUERY_EXECUTOR_PASSWORD', '1234')
+
+        profile = self.create_profile(
+            username=QUERY_EXECUTOR_USERNAME,
+            firstname='Query',
+            lastname='EXECUTOR',
+            email=query_executor_email,
+            password=query_executor_password
+        )
+
+        # TODO: assign minimal role and perimeter access as needed
+        # e.g., create a “Query Executor” Role and link it to the appropriate perimeter:
+        # rights = {f.name: False for f in Role._meta.fields if f.name.startswith("right_")}
+        # query_role = Role.objects.create(name="Query Executor", **rights)
+        # Access.objects.create(
+        #     profile=profile,
+        #     role=query_role,
+        #     perimeter=<desired_perimeter>,
+        #     start_datetime=timezone.now(),
+        #     end_datetime=timezone.now() + timedelta(days=365)
+        # )

• Environment utility (env = os.environ) is already imported.
• Ensure you define and scope the “Query Executor” role and perimeter to enforce least privilege.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def setup_query_executor_user_account(self) -> None:
_ = self.create_profile(username=QUERY_EXECUTOR_USERNAME,
firstname='Query',
lastname='EXECUTOR',
email='[email protected]',
password='1234'
)
def setup_query_executor_user_account(self) -> None:
# Read credentials from environment (fallback to defaults)
query_executor_email = env.get('QUERY_EXECUTOR_EMAIL', '[email protected]')
query_executor_password = env.get('QUERY_EXECUTOR_PASSWORD', '1234')
profile = self.create_profile(
username=QUERY_EXECUTOR_USERNAME,
firstname='Query',
lastname='EXECUTOR',
email=query_executor_email,
password=query_executor_password
)
# TODO: assign minimal role and perimeter access as needed
# e.g., create a “Query Executor” Role and link it to the appropriate perimeter:
# rights = {f.name: False for f in Role._meta.fields if f.name.startswith("right_")}
# query_role = Role.objects.create(name="Query Executor", **rights)
# Access.objects.create(
# profile=profile,
# role=query_role,
# perimeter=<desired_perimeter>,
# start_datetime=timezone.now(),
# end_datetime=timezone.now() + timedelta(days=365)
# )
🤖 Prompt for AI Agents
In admin_cohort/management/commands/load_initial_data.py around lines 57 to 63,
replace the hardcoded email and password in setup_query_executor_user_account
with values read from environment variables using the existing env utility.
Additionally, assign the query executor user the appropriate role and
permissions that mirror the admin's access but scoped to enforce least
privilege, defining and applying a specific "Query Executor" role and perimeter
as needed.

@thicham43 thicham43 force-pushed the 3031_refactor_access_management branch from d6cb4c2 to ce02a8d Compare July 15, 2025 13:34
Copy link

@thicham43 thicham43 merged commit c57ba1f into main Jul 17, 2025
17 checks passed
@thicham43 thicham43 deleted the 3031_refactor_access_management branch July 17, 2025 11:29
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.

1 participant