Skip to content

Comments

[LFXV2-920] Committee member visibility - Conditional Relation#54

Open
mauriciozanettisalomao wants to merge 5 commits intolinuxfoundation:mainfrom
mauriciozanettisalomao:feat/lfxv2-920-committee-policies-member-visibility-conditional-relation
Open

[LFXV2-920] Committee member visibility - Conditional Relation#54
mauriciozanettisalomao wants to merge 5 commits intolinuxfoundation:mainfrom
mauriciozanettisalomao:feat/lfxv2-920-committee-policies-member-visibility-conditional-relation

Conversation

@mauriciozanettisalomao
Copy link
Contributor

Overview

Jira Ticket https://linuxfoundation.atlassian.net/browse/LFXV2-920

This pull request introduces support for a new "basic_profile" member visibility setting for committees, enabling fine-grained access control for member profile information. The changes update access control logic, constants, and configuration to reflect this new setting and its associated permissions.

Access Control & Configuration Updates:

  • Changed the authorization relation in ruleset.yaml from viewer to basic_profile_viewer to align with the new visibility setting.
  • Added a new constant RelationSelfForMemberBasicProfileAccess in access_control.go to represent self-access for committee members' basic profile information.

Committee Model Enhancements:

  • Added the memberVisibilityBasicProfileSetting constant and the IsMemberVisibilityBasicProfile method to the Committee model to check for the "basic_profile" visibility setting. [1] [2]
  • Updated the CommitteeAccessMessage struct to include a new Self field for storing self-relations related to basic profile access.
  • Modified the committee writer orchestrator to populate the Self field in access control messages when the "basic_profile" visibility is enabled.

Chart Version Update:

  • Bumped the Helm chart version for lfx-v2-committee-service from 0.2.19 to 0.2.20 to reflect these changes.

Test

Setup

Committee Created:

  • Name: Test committee - private 2026-01-08-084107
  • Committee UID: 0b93a757-2ebb-4195-95e2-24710bd2f399
  • Project UID: cbef1ed5-17dc-4a50-84e2-6cddd70f6878
  • Category: Technical Steering Committee
  • Public: false

Test Users:

  • Admin: project_super_admin_token (full access)
  • Member 1: andres (UID: f326933b-6a4a-4e35-97ff-b7cca085682f)
  • Member 2: mauriciozanetti (UID: aa2ffc1e-5f12-4db6-916c-58f51c90e92d)
  • Auditor: batman
  • Non-member: asitha

Test Scenario 1: Hidden Member Visibility (Default)

Creating Committee

Response:

{
  "member_visibility": "hidden",
  "name": "Test committee - private 2026-01-08-084107",
  "uid": "0b93a757-2ebb-4195-95e2-24710bd2f399",
  "writers": ["superman"],
  "auditors": ["batman"]
}

Result: Committee created with member_visibility: "hidden" as default

Adding Members

Member 1 (andres):

{
  "username": "andres",
  "first_name": "Andres",
  "last_name": "Tobon",
  "email": "[email protected]",
  "uid": "f326933b-6a4a-4e35-97ff-b7cca085682f",
  "role": {
    "name": "Chair",
    "start_date": "2025-01-01",
    "end_date": "2025-12-31"
  }
}

Member 2 (mauriciozanetti):

{
  "username": "mauriciozanetti",
  "first_name": "Mauricio",
  "last_name": "Salomao",
  "email": "[email protected]",
  "uid": "aa2ffc1e-5f12-4db6-916c-58f51c90e92d",
  "role": {
    "name": "Chair"
  }
}

Access Control Tests - Hidden Mode

Admin User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $project_super_admin_token

Result: Returns both members (andres and mauriciozanetti)

Member User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $mauriciozanetti_token

Result: {"resources": []} - No access to member list

Member User (Get Specific Member)

GET /committees/0b93a757-2ebb-4195-95e2-24710bd2f399/members/f326933b-6a4a-4e35-97ff-b7cca085682f?v=1
Authorization: Bearer $mauriciozanetti_token

Result: HTTP/1.1 403 Forbidden - Access denied

Member User (Query Committee)

GET /query/resources?v=1&type=committee&tags=committee_uid:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $mauriciozanetti_token

Result: Returns committee info (member can see the committee they belong to)


Test Scenario 2: Basic Profile Visibility

Updating Settings to Basic Profile

PUT /committees/0b93a757-2ebb-4195-95e2-24710bd2f399/settings

Response:

{
  "business_email_required": false,
  "member_visibility": "basic_profile",
  "uid": "0b93a757-2ebb-4195-95e2-24710bd2f399",
  "updated_at": "2026-01-08T12:06:20Z"
}

Result: Settings updated successfully

Access Control Tests - Basic Profile Mode

Member User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $mauriciozanetti_token

Result: Returns both members with full profile data

{
  "resources": [
    {
      "data": {
        "username": "andres",
        "first_name": "Andres",
        "last_name": "Tobon",
        "email": "[email protected]",
        "uid": "f326933b-6a4a-4e35-97ff-b7cca085682f"
      }
    },
    {
      "data": {
        "username": "mauriciozanetti",
        "first_name": "Mauricio",
        "last_name": "Salomao",
        "email": "[email protected]",
        "uid": "aa2ffc1e-5f12-4db6-916c-58f51c90e92d"
      }
    }
  ]
}

Member User (Get Specific Member)

GET /committees/0b93a757-2ebb-4195-95e2-24710bd2f399/members/f326933b-6a4a-4e35-97ff-b7cca085682f?v=1
Authorization: Bearer $mauriciozanetti_token

Result: HTTP/1.1 200 OK - Member data returned successfully

Auditor User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $batman_token

Result: Returns both members (auditors have access)

Non-Member User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $asitha_token

Result: {"resources": []} - No access

Non-Member User (Get Specific Member)

GET /committees/0b93a757-2ebb-4195-95e2-24710bd2f399/members/f326933b-6a4a-4e35-97ff-b7cca085682f?v=1
Authorization: Bearer $asitha_token

Result: HTTP/1.1 403 Forbidden - Access denied


Test Scenario 3: Switching Back to Hidden

Updating Settings Back to Hidden

PUT /committees/0b93a757-2ebb-4195-95e2-24710bd2f399/settings

Response:

{
  "business_email_required": false,
  "member_visibility": "hidden",
  "uid": "0b93a757-2ebb-4195-95e2-24710bd2f399",
  "updated_at": "2026-01-08T12:15:26Z"
}

Result: Settings updated successfully

Access Control Tests - Back to Hidden Mode

Member User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $mauriciozanetti_token

Result: {"resources": []} - No access to member list (as expected)

Member User (Query Committee)

GET /query/resources?v=1&type=committee&tags=committee_uid:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $mauriciozanetti_token

Result: Returns committee info (member can still see the committee)

Auditor User (Query Members)

GET /query/resources?v=1&parent=committee:0b93a757-2ebb-4195-95e2-24710bd2f399
Authorization: Bearer $batman_token

Result: Returns both members (auditors always have access)


Summary of Test Results

User Type Hidden Mode Basic Profile Mode
Admin ✅ Full access ✅ Full access
Auditor ✅ Full access ✅ Full access
Member ❌ No member access
✅ Committee access
✅ Full member access
✅ Committee access
Non-member ❌ No access ❌ No access

Key Findings

  1. Default behavior: New committees default to member_visibility: "hidden"
  2. Hidden mode: Members cannot see other members' information
  3. Basic profile mode: Members can view all committee members' profiles
  4. Auditor access: Auditors maintain full access regardless of visibility setting
  5. Committee visibility: Members can always see the committee itself, just not other members in hidden mode
  6. Dynamic updates: Settings can be changed dynamically and take effect immediately

Copilot AI review requested due to automatic review settings January 8, 2026 12:22
@mauriciozanettisalomao mauriciozanettisalomao requested a review from a team as a code owner January 8, 2026 12:22
@coderabbitai
Copy link

coderabbitai bot commented Jan 8, 2026

Walkthrough

Adds basic-profile member visibility: chart version bumped, OpenFGA rules updated to require basic_profile_viewer, a new self relation constant and Self field added to access messages, and writer logic appends the self relation when applicable.

Changes

Cohort / File(s) Summary
Helm Chart & Ruleset
charts/lfx-v2-committee-service/Chart.yaml, charts/lfx-v2-committee-service/templates/ruleset.yaml
Chart version 0.2.19 → 0.2.20; two OpenFGA rules updated to require basic_profile_viewer instead of viewer.
Domain Model: committee base & tests
internal/domain/model/committee_base.go, internal/domain/model/committee_base_test.go
Added memberVisibilityBasicProfileSetting constant and IsMemberVisibilityBasicProfile() on Committee; new unit test TestCommitteeIsMemberVisibilityBasicProfile.
Domain Model: access message
internal/domain/model/committee_message.go
Added public field Self []string (json:"self") to CommitteeAccessMessage (affects serialized contract).
Service writer & tests
internal/service/committee_writer.go, internal/service/committee_writer_test.go
buildAccessControlMessage initializes Self and appends RelationSelfForMemberBasicProfileAccess when member visibility is basic_profile; tests updated to expect Self contents.
Constants
pkg/constants/access_control.go
Added exported constant RelationSelfForMemberBasicProfileAccess = "self_for_member_basic_profile_access" with comment.

Sequence Diagram(s)

sequenceDiagram
  participant Writer as CommitteeWriter
  participant Model as CommitteeAccessMessage
  participant OpenFGA as OpenFGA API

  Writer->>Model: build access message (include base relations)
  alt committee settings.member_visibility == "basic_profile"
    Model->>Model: append "self_for_member_basic_profile_access" to Self
  end
  Writer->>OpenFGA: send access control message (includes Self)
  OpenFGA-->>Writer: acknowledge / enforce rules (uses basic_profile_viewer)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly references the Jira ticket and describes the main change: implementing conditional relations for committee member visibility.
Description check ✅ Passed The PR description comprehensively documents the changes, linking to the Jira ticket, explaining access control updates, model enhancements, and includes detailed test scenarios with expected results.
Linked Issues check ✅ Passed The PR successfully addresses the core coding requirements from LFXV2-920: implements configurable member_visibility with HIDDEN and BASIC_PROFILE levels, updates access control rules via ruleset changes and Self field additions, adds necessary constants and model methods, and updates the committee writer to populate access control messages appropriately.
Out of Scope Changes check ✅ Passed All changes are directly aligned with LFXV2-920 objectives: ruleset authorization updates, new access control constant, Committee model enhancements, CommitteeAccessMessage extensions, writer orchestrator updates for Self field population, comprehensive test coverage, and chart version bump for release.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c650253 and 893404c.

📒 Files selected for processing (1)
  • internal/domain/model/committee_base_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/domain/model/committee_base_test.go
⏰ 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: MegaLinter

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

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a new "basic_profile" member visibility setting for committees, enabling members to view each other's basic profile information while maintaining access control for non-members. The implementation updates the authorization layer, access control messaging, and domain models to support this fine-grained visibility control.

Key Changes:

  • Added support for basic_profile member visibility setting with corresponding OpenFGA relation
  • Updated access control message structure to support self-access relations for committee members
  • Modified authorization rules to check for basic_profile_viewer relation on member GET endpoints

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/constants/access_control.go Added new constant RelationSelfForMemberBasicProfileAccess for self-access relation
internal/service/committee_writer.go Updated buildAccessControlMessage to populate Self field when basic_profile visibility is enabled
internal/domain/model/committee_message.go Added Self field to CommitteeAccessMessage struct for storing self-relations
internal/domain/model/committee_base.go Added constant and IsMemberVisibilityBasicProfile method to check visibility setting
charts/lfx-v2-committee-service/templates/ruleset.yaml Changed authorization relation from "viewer" to "basic_profile_viewer" for member GET endpoint
charts/lfx-v2-committee-service/Chart.yaml Bumped chart version from 0.2.19 to 0.2.20

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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: 1

🤖 Fix all issues with AI agents
In @internal/domain/model/committee_message.go:
- Around line 112-113: The comment on the Self field is misleading; update the
comment for the Self []string field in committee_message.go to explain that Self
stores OpenFGA self-relation tuples enabling conditional member-to-member
visibility and that when populated members can view other members' basic
profiles according to committee visibility settings (this aligns with how the
field is populated in internal/service/committee_writer.go when
IsMemberVisibilityBasicProfile() is true).
🧹 Nitpick comments (1)
internal/domain/model/committee_base.go (1)

22-22: Consider defining constants for all member visibility levels.

The codebase defines exactly two member visibility levels ("hidden" and "basic_profile"), as documented in the API design. Currently only basic_profile has a constant, while hidden (the default) is hardcoded as string literals throughout the codebase. Define a constant for consistency and to avoid repeating magic strings.

📝 Suggested additional constants
 const (
 	categoryGovernmentAdvisoryCouncil = "Government Advisory Council"
 
+	memberVisibilityHidden             = "hidden"
 	memberVisibilityBasicProfileSetting = "basic_profile"
 )

Consider also adding IsMemberVisibilityHidden() to match the existing IsMemberVisibilityBasicProfile() method for symmetrical access.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bfb883e and 1fbc743.

📒 Files selected for processing (6)
  • charts/lfx-v2-committee-service/Chart.yaml
  • charts/lfx-v2-committee-service/templates/ruleset.yaml
  • internal/domain/model/committee_base.go
  • internal/domain/model/committee_message.go
  • internal/service/committee_writer.go
  • pkg/constants/access_control.go
🧰 Additional context used
🧬 Code graph analysis (1)
internal/domain/model/committee_base.go (2)
cmd/committee-api/design/type.go (1)
  • CommitteeSettings (35-39)
internal/domain/model/committee_settings.go (1)
  • CommitteeSettings (11-22)
⏰ 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). (3)
  • GitHub Check: Agent
  • GitHub Check: CodeQL analysis (go)
  • GitHub Check: MegaLinter
🔇 Additional comments (6)
charts/lfx-v2-committee-service/Chart.yaml (1)

8-8: LGTM!

Appropriate chart version bump for the new basic profile visibility feature.

pkg/constants/access_control.go (1)

15-16: LGTM!

The new constant is well-named, follows existing conventions, and has a clear explanatory comment.

internal/domain/model/committee_base.go (1)

161-168: LGTM!

The method correctly implements a nil-safe check for the basic profile visibility setting. The defensive nil check on CommitteeSettings prevents potential panics.

charts/lfx-v2-committee-service/templates/ruleset.yaml (2)

231-256: All member-related endpoints follow a consistent authorization pattern: read operations use basic_profile_viewer, while write operations (POST, PUT, DELETE) use writer. No list endpoint (GET /committees/:uid/members) exists in this ruleset that would require similar authorization updates.


248-249: Ensure deployment coordination with fga-sync service for the basic_profile_viewer relation.

The ruleset checks for the basic_profile_viewer relation, which is managed by the fga-sync service, not defined in this repository. When a committee's member_visibility is set to basic_profile, this service publishes a CommitteeAccessMessage with self_for_member_basic_profile_access to the fga-sync service. Verify that:

  1. The fga-sync service has been updated to handle the self_for_member_basic_profile_access relation and map it to the basic_profile_viewer OpenFGA relation
  2. fga-sync is deployed and operational before this ruleset change is deployed
  3. The relation mapping between the service's constant (self_for_member_basic_profile_access) and the ruleset check (basic_profile_viewer) is correctly configured in fga-sync
internal/service/committee_writer.go (1)

241-243: All related changes verified and in place.

The implementation correctly adds the self-relation for basic profile member visibility. All dependencies verified:

  • IsMemberVisibilityBasicProfile() method exists and properly validates member visibility setting
  • RelationSelfForMemberBasicProfileAccess constant defined with correct value
  • Self field added to CommitteeAccessMessage struct with appropriate documentation
  • Logic follows established patterns and is consistent with Writers/Auditors handling

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