Skip to content

feat: implement SetProjectMemberRole RPC#1481

Open
whoAbhishekSah wants to merge 10 commits intomainfrom
feat/set-project-member-role
Open

feat: implement SetProjectMemberRole RPC#1481
whoAbhishekSah wants to merge 10 commits intomainfrom
feat/set-project-member-role

Conversation

@whoAbhishekSah
Copy link
Copy Markdown
Member

Summary

  • Add SetProjectMemberRole RPC for atomic role assignment on project members
  • Enforces minimum-owner constraint (cannot remove last project owner)
  • Validates role is valid for project scope
  • Authorization checks update permission on the project

Closes #1461 (partially - RemoveProjectMember will be a separate PR)

Proton PR: raystack/proton#456

Test plan

  • Unit tests for service layer pass
  • E2E tests for role assignment, validation, and owner constraint
  • Verify authorization interceptor enforces update permission

🤖 Generated with Claude Code

whoAbhishekSah and others added 2 commits March 27, 2026 09:44
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add handler, service, and authorization for atomically changing
a user's role in a project. Enforces minimum-owner constraint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Mar 27, 2026 5:47am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added ability to change project member roles programmatically via a new SetMemberRole endpoint with proper authorization and validation.
  • Tests

    • Added comprehensive test coverage for role assignment functionality.
  • Chores

    • Updated Proton dependency version for protobuf generation.

Walkthrough

Adds a server-side RPC and service flow to set a project member's role: new ProjectService.SetMemberRole handler and API surface, Service.SetMemberRole implementation with role validation and policy CRUD, roleService dependency wiring, multiple mock additions/updates, new error values, an authorization check, and a Makefile PROTON_COMMIT update.

Changes

Cohort / File(s) Summary
Build config
Makefile
Updated PROTON_COMMIT hash used by make proto to fetch a different Proton archive.
Server wiring
cmd/serve.go
Passed roleService into project.NewService(...) when constructing API dependencies.
Domain errors
core/project/errors.go, internal/api/v1beta1connect/errors.go
Added ErrInvalidProjectRole, ErrNotOrgMember, and ErrInvalidPrincipalType error variables (API file also adds ErrInvalidProjectRole).
Project service
core/project/service.go
Added roleService dependency, new Service.SetMemberRole(...) implementation, plus internal helpers validatePrincipal and validateProjectRole.
Service tests
core/project/service_test.go
Updated mocks setup to include *mocks.RoleService, added TestService_SetMemberRole with table-driven cases and mock expectations.
Mocks — core project
core/project/mocks/...
core/project/mocks/policy_service.go, core/project/mocks/role_service.go, core/project/mocks/group_service.go, core/project/mocks/serviceuser_service.go
Added/extended autogenerated testify mocks: RoleService mock (new file + expecter), PolicyService.Delete, GroupService.Get, and ServiceuserService.Get with typed call helpers.
API surface & mocks
internal/api/v1beta1connect/interfaces.go, internal/api/v1beta1connect/mocks/project_service.go
Added ProjectService.SetMemberRole(...) to the Connect interface and corresponding mock expecter/call helpers.
API handler
internal/api/v1beta1connect/project.go
Added Connect RPC handler ConnectHandler.SetProjectMemberRole(...) with request validation, call into project service, structured logging, and explicit error→Connect code mapping.
Authorization interceptor
pkg/server/connect_interceptors/authorization.go
Added authorization validation entry for FrontierService/SetProjectMemberRole, checking update permission on the target project resource.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested reviewers

  • rsbh
  • AmanGIT07
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements SetProjectMemberRole RPC as required by #1461, with atomic operation, org membership validation, project role scope validation, and authorization checks.
Out of Scope Changes check ✅ Passed All changes are directly aligned with SetProjectMemberRole implementation; no out-of-scope modifications detected.

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


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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/project/service_test.go (1)

23-35: ⚠️ Potential issue | 🟠 Major

Add direct unit tests for SetMemberRole behavior (currently missing).

This update wires new dependencies, but the new project-member role mutation path is not covered here. Please add focused tests for role validation, non-member handling, and last-owner protection to reduce regression risk in the new RPC path.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 56252940-859b-4c10-83dd-9b50d88a457e

📥 Commits

Reviewing files that changed from the base of the PR and between d05d9e5 and b32bbf7.

⛔ Files ignored due to path filters (3)
  • proto/v1beta1/frontier.pb.go is excluded by !**/*.pb.go, !proto/**
  • proto/v1beta1/frontier.pb.validate.go is excluded by !proto/**
  • proto/v1beta1/frontierv1beta1connect/frontier.connect.go is excluded by !proto/**
📒 Files selected for processing (12)
  • Makefile
  • cmd/serve.go
  • core/project/errors.go
  • core/project/mocks/policy_service.go
  • core/project/mocks/role_service.go
  • core/project/service.go
  • core/project/service_test.go
  • internal/api/v1beta1connect/errors.go
  • internal/api/v1beta1connect/interfaces.go
  • internal/api/v1beta1connect/mocks/project_service.go
  • internal/api/v1beta1connect/project.go
  • pkg/server/connect_interceptors/authorization.go

…berRole

Project access can come from org-level permissions, so we don't enforce
minimum-owner constraint or require existing membership at project level.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coveralls
Copy link
Copy Markdown

coveralls commented Mar 27, 2026

Pull Request Test Coverage Report for Build 23633134429

Details

  • 64 of 111 (57.66%) changed or added relevant lines in 4 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.05%) to 41.284%

Changes Missing Coverage Covered Lines Changed/Added Lines %
cmd/serve.go 0 1 0.0%
pkg/server/connect_interceptors/authorization.go 0 4 0.0%
core/project/service.go 64 70 91.43%
internal/api/v1beta1connect/project.go 0 36 0.0%
Totals Coverage Status
Change from base Build 23540166648: 0.05%
Covered Lines: 14787
Relevant Lines: 35818

💛 - Coveralls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…emberRole

Each principal type has its own field in the request (user_id,
service_user_id, group_id). Validation checks that the principal
exists and belongs to the org that owns the project.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
core/project/service.go (1)

360-363: ⚠️ Potential issue | 🟠 Major

The last-owner invariant is gone.

Demoting the only direct owner now succeeds and leaves the project with zero project-scoped owners. That regresses the owner-constraint behavior this RPC is supposed to preserve; if org-level fallback is intentionally replacing that invariant, the contract/tests need to change too.

Also applies to: 377-390


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7a3f72ab-6cdf-4e25-beb2-3c66806bc560

📥 Commits

Reviewing files that changed from the base of the PR and between b32bbf7 and fc069d7.

📒 Files selected for processing (3)
  • core/project/errors.go
  • core/project/service.go
  • internal/api/v1beta1connect/project.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • core/project/errors.go
  • internal/api/v1beta1connect/project.go

…ate ID fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 test cases covering:
- validation errors (project/user/serviceuser/group not found)
- invalid principal type
- org membership check
- role validation (not found, wrong scope)
- success with no existing policies (add member)
- success replacing existing policies (role change)
- service user and group principal types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
core/project/service.go (1)

362-402: ⚠️ Potential issue | 🟠 Major

Use the resolved project ID (prj.ID) consistently.

Lines 380 and 396 use the raw projectID parameter instead of prj.ID. Since s.Get() at line 366 resolves both UUIDs and names, passing a project name will cause the policy filter and create operations to use the name string instead of the canonical UUID.

🐛 Proposed fix
 	existingPolicies, err := s.policyService.List(ctx, policy.Filter{
-		ProjectID:     projectID,
+		ProjectID:     prj.ID,
 		PrincipalID:   principalID,
 		PrincipalType: principalType,
 	})
@@
 	_, err = s.policyService.Create(ctx, policy.Policy{
 		RoleID:        newRoleID,
-		ResourceID:    projectID,
+		ResourceID:    prj.ID,
 		ResourceType:  schema.ProjectNamespace,
 		PrincipalID:   principalID,
 		PrincipalType: principalType,
 	})

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c2d62ec5-29b5-4805-9f36-2c26ab203e72

📥 Commits

Reviewing files that changed from the base of the PR and between fc069d7 and 1d15a38.

⛔ Files ignored due to path filters (2)
  • proto/v1beta1/frontier.pb.go is excluded by !**/*.pb.go, !proto/**
  • proto/v1beta1/frontier.pb.validate.go is excluded by !proto/**
📒 Files selected for processing (9)
  • Makefile
  • core/project/errors.go
  • core/project/mocks/group_service.go
  • core/project/mocks/serviceuser_service.go
  • core/project/service.go
  • core/project/service_test.go
  • internal/api/v1beta1connect/interfaces.go
  • internal/api/v1beta1connect/mocks/project_service.go
  • internal/api/v1beta1connect/project.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • Makefile
  • internal/api/v1beta1connect/project.go
  • core/project/errors.go

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.

Add high-level RPCs for project member management to remove client-side policy manipulation

2 participants