Skip to content

Conversation

gmazoyer
Copy link
Contributor

@gmazoyer gmazoyer commented Aug 14, 2025

This change adds a couple of permissions to the "Proposed Change Reviewer" role that we ship when Infrahub is started for the first time.

Summary by CodeRabbit

  • New Features

    • Expanded Proposed Change Reviewer role to also allow updating proposed changes.
    • Clearer, human‑readable descriptions for global permissions in role management.
  • Refactor

    • More reliable initialization of default global permissions to prevent duplicates and ensure consistent setups.
  • Tests

    • Stabilized Roles view end‑to‑end test by scoping assertions to the first matching element for improved reliability.

Copy link
Contributor

coderabbitai bot commented Aug 14, 2025

Walkthrough

Refactors permission initialization to use a new get_or_create_global_permission helper, adds human-readable permission descriptions, introduces an OBJECTPERMISSION for ProposedChange updates, updates role bindings accordingly, exports the new helper, and adjusts an e2e test to target the first matching UI elements.

Changes

Cohort / File(s) Summary of changes
Role/Permission initialization refactor
backend/infrahub/core/initialization.py
Replaced inline GlobalPermission creation with get_or_create_global_permission for several actions; added ProposedChange UPDATE object permission; updated Proposed Change Reviewer role to include edit_default_branch, review_proposed_change, and proposed_change_update permissions.
Permissions API updates
backend/infrahub/permissions/globals.py, backend/infrahub/permissions/__init__.py, backend/infrahub/permissions/constants.py
Added async get_or_create_global_permission to create/fetch CoreGlobalPermission using ALLOW_ALL and descriptions; exported the helper via init; introduced GLOBAL_PERMISSION_DESCRIPTION mapping GlobalPermissions to descriptions.
E2E test locator scoping
frontend/app/tests/e2e/role-management/read.spec.ts
Scoped two assertions with .first() on getByText locators to ensure checks target the first matching element.

Sequence Diagram(s)

sequenceDiagram
  actor Init as Initialization
  participant DB as Database
  participant Perm as permissions.globals

  Init->>Perm: get_or_create_global_permission(db, EDIT_DEFAULT_BRANCH)
  Perm->>DB: Query CoreGlobalPermission by action
  alt exists
    Perm-->>Init: return existing permission
  else
    Perm->>DB: Create CoreGlobalPermission(action, ALLOW_ALL, description)
    Perm-->>Init: return created permission
  end

  Init->>DB: Create OBJECTPERMISSION (ProposedChange, UPDATE, ALLOW_ALL)
  Init->>DB: Update Role: add [edit_default_branch, review_proposed_change, proposed_change_update]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ogenstad

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gma-20250814-ifc1750

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.
    • 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.
  • 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 the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or 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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

@gmazoyer gmazoyer changed the title Fix default PC Reviewer role permission set IFC-1750 Fix default PC Reviewer role permission set Aug 14, 2025
@github-actions github-actions bot added the group/backend Issue related to the backend (API Server, Git Agent) label Aug 14, 2025
Copy link

codspeed-hq bot commented Aug 14, 2025

CodSpeed Performance Report

Merging #7038 will not alter performance

Comparing gma-20250814-ifc1750 (fea2411) with develop (dddd72a)

Summary

✅ 10 untouched benchmarks

@github-actions github-actions bot added the group/frontend Issue related to the frontend (React) label Aug 14, 2025
@gmazoyer gmazoyer force-pushed the gma-20250814-ifc1750 branch from 6068602 to fea2411 Compare August 14, 2025 15:07
@gmazoyer gmazoyer marked this pull request as ready for review August 14, 2025 16:15
@gmazoyer gmazoyer requested review from a team as code owners August 14, 2025 16:15
Copy link
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.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
backend/infrahub/permissions/globals.py (1)

27-45: Add a docstring and make description lookup resilient.

  • Missing function docstring; our guidelines require docstrings for all Python functions.
  • Accessing GLOBAL_PERMISSION_DESCRIPTION[permission] will raise a KeyError for any enum not present in the map (e.g., OVERRIDE_CONTEXT). Add a safe fallback.

Apply this diff:

 async def get_or_create_global_permission(db: InfrahubDatabase, permission: GlobalPermissions) -> CoreGlobalPermission:
+    """Create or fetch a CoreGlobalPermission for the given GlobalPermissions.
+
+    Ensures idempotency by looking up an existing permission by action and, if absent,
+    creating it with an ALLOW_ALL decision and a human-readable description.
+
+    Args:
+        db: Database connection.
+        permission: Global permission to ensure exists.
+
+    Returns:
+        The existing or newly created CoreGlobalPermission node.
+    """
     permissions = await NodeManager.query(
         db=db, schema=CoreGlobalPermission, filters={"action__value": permission.value}, limit=1
     )
 
     if permissions:
         return permissions[0]
 
     p = await Node.init(db=db, schema=CoreGlobalPermission)
     await p.new(
         db=db,
         action=permission.value,
         decision=PermissionDecision.ALLOW_ALL.value,
-        description=GLOBAL_PERMISSION_DESCRIPTION[permission],
+        description=GLOBAL_PERMISSION_DESCRIPTION.get(
+            permission, f"Allow a user to {permission.value.replace('_', ' ')}"
+        ),
     )
     await p.save(db=db)
 
     return p
🧹 Nitpick comments (1)
frontend/app/tests/e2e/role-management/read.spec.ts (1)

28-29: Use exact text matching to avoid accidental partial matches.

To ensure we don’t match a superset text (e.g., embedded in a longer string), consider enabling exact matching.

-      await expect(page.getByText("Infrahub Users").first()).toBeVisible();
-      await expect(page.getByText("global:edit_default_branch:").first()).toBeVisible();
+      await expect(page.getByText("Infrahub Users", { exact: true }).first()).toBeVisible();
+      await expect(page.getByText("global:edit_default_branch:", { exact: true }).first()).toBeVisible();
📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between dddd72a and fea2411.

📒 Files selected for processing (5)
  • backend/infrahub/core/initialization.py (3 hunks)
  • backend/infrahub/permissions/__init__.py (2 hunks)
  • backend/infrahub/permissions/constants.py (1 hunks)
  • backend/infrahub/permissions/globals.py (2 hunks)
  • frontend/app/tests/e2e/role-management/read.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
backend/**/*

📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)

Run backend tests with pytest or via invoke tasks

Files:

  • backend/infrahub/permissions/constants.py
  • backend/infrahub/permissions/__init__.py
  • backend/infrahub/permissions/globals.py
  • backend/infrahub/core/initialization.py
**/*.py

📄 CodeRabbit Inference Engine (CLAUDE.md)

**/*.py: Use type hints for all function parameters and return values in Python files
Use async/await whenever possible in Python code
Use async def for asynchronous functions in Python
Use await for asynchronous calls in Python
Use Pydantic models for dataclasses in Python
All Python functions must have docstrings
Always use triple quotes (""") for docstrings in Python
Follow Google-style docstring format in Python files
Include sections in Python docstrings when applicable: Brief one-line description, Detailed description, Args/Parameters (without typing), Returns, Raises, Examples
Use ruff and mypy for type checking and validations in Python files
Format all Python files using poetry run invoke format
Validate Python formatting and linting using poetry run invoke lint

Files:

  • backend/infrahub/permissions/constants.py
  • backend/infrahub/permissions/__init__.py
  • backend/infrahub/permissions/globals.py
  • backend/infrahub/core/initialization.py
🧬 Code Graph Analysis (3)
backend/infrahub/permissions/constants.py (1)
backend/infrahub/core/constants/__init__.py (1)
  • GlobalPermissions (91-101)
backend/infrahub/permissions/__init__.py (1)
backend/infrahub/permissions/globals.py (2)
  • define_global_permission_from_branch (18-24)
  • get_or_create_global_permission (27-44)
backend/infrahub/core/initialization.py (4)
backend/infrahub/permissions/globals.py (1)
  • get_or_create_global_permission (27-44)
backend/infrahub/core/constants/__init__.py (3)
  • GlobalPermissions (91-101)
  • PermissionAction (104-109)
  • PermissionDecision (112-116)
backend/infrahub/core/node/standard.py (1)
  • save (88-94)
backend/infrahub/core/protocols.py (1)
  • CoreAccountRole (255-258)
🔇 Additional comments (5)
frontend/app/tests/e2e/role-management/read.spec.ts (1)

28-29: Targeting the first match reduces test flakiness.

Chaining .first() is a pragmatic way to disambiguate multiple matches and should make these assertions more stable.

backend/infrahub/permissions/__init__.py (1)

2-2: Re-export of get_or_create_global_permission looks correct.

Import path and all exposure align with current module layout.

Also applies to: 15-15

backend/infrahub/permissions/globals.py (1)

27-45: Ensure uniqueness to prevent duplicate permission creation under concurrency.

If two coroutines race, both could create the permission before either sees the other’s write. Please confirm there’s a uniqueness constraint or index on CoreGlobalPermission.action to enforce singletons. If not, consider adding one or handling unique-violation errors during save.

backend/infrahub/core/initialization.py (2)

40-40: Importing get_or_create_global_permission aligns with new helper API.

Good step towards idempotent permission initialization.


444-448: Confirmed — GraphQL permission pipeline requires BOTH EDIT_DEFAULT_BRANCH (global) AND the object-level UPDATE for ProposedChange.

Short summary: Default-branch and object-permission checks run in the GraphQL permission checker chain, so granting EDIT_DEFAULT_BRANCH alone does not bypass object-level UPDATE checks for ProposedChange.

Key locations (evidence):

  • backend/infrahub/core/initialization.py — create_proposed_change_reviewer_role (role created with edit_default_branch_permission + reviewer_permission + proposed_change_update_permission). (lines ~423–448)
  • backend/infrahub/graphql/auth/query_permission_checker/default_branch_checker.py — enforces GlobalPermissions.EDIT_DEFAULT_BRANCH on default-branch mutations via active_permissions.raise_for_permission().
  • backend/infrahub/graphql/auth/query_permission_checker/object_permission_checker.py — builds required ObjectPermission(s) (including UPDATE for kinds) and calls active_permissions.raise_for_permissions(...).
  • backend/infrahub/graphql/auth/query_permission_checker/checker.py — executes the checker chain (sub_checkers) so both default-branch and object checks are applied.
  • backend/infrahub/permissions/manager.py — report_object_permission / resolve_object_permission implement object-level decision logic used by raise_for_permissions/has_permission.

Note / caveat:

  • Some mutations also perform explicit global-permission checks inside resolvers (e.g., MERGE/REVIEW checks in backend/infrahub/graphql/mutations/proposed_change.py) — these are additional safeguards and do not replace object-level checks.
  • If there are non‑GraphQL code paths or external APIs that perform only a global EDIT_DEFAULT_BRANCH check, review those paths separately. I can scan for such code paths on request.

@gmazoyer gmazoyer merged commit 975687f into develop Aug 14, 2025
40 checks passed
@gmazoyer gmazoyer deleted the gma-20250814-ifc1750 branch August 14, 2025 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
group/backend Issue related to the backend (API Server, Git Agent) group/frontend Issue related to the frontend (React)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants