Skip to content

Conversation

@mchenani
Copy link
Contributor

@mchenani mchenani commented Dec 15, 2025

Persist pending MLS proposals during group sync in xmtp_mls::groups::mls_sync::Group::sync for the POC of sending and receiving proposals

Store incoming ProposalMessage items as pending via mls_group.store_pending_proposal in mls_sync.rs and add a POC integration test asserting one pending proposal in test_mls_proposal_poc.rs.

📍Where to Start

Start with the Group::sync match arm handling ProposalMessage in mls_sync.rs.


Macroscope summarized b4d5b96.

@claude
Copy link

claude bot commented Dec 15, 2025

Claude finished @mchenani's task —— View job


Code Review - December 15, 2025, 19:52 UTC

Review Checklist:

  • Read changed files
  • Analyze code quality and implementation
  • Check for bugs and edge cases
  • Review test coverage
  • Post feedback

Summary

This POC successfully implements basic proposal handling by storing incoming ProposalMessage items as pending proposals. The changes are minimal and focused, which is appropriate for a proof of concept.

Key Changes

  1. xmtp_mls/src/groups/mls_sync.rs:1134 - Changed from ignoring proposals to persisting them:

    ProcessedMessageContent::ProposalMessage(proposal) => {
        mls_group.store_pending_proposal(storage, *proposal)?;
        Ok(())
    }
  2. New test file - Adds integration test demonstrating proposal send/receive flow

Observations

✅ What Works Well

  1. Minimal, focused changes - Only touches the necessary code path
  2. Follows existing patterns - Uses the same error handling and transaction patterns as other message types
  3. Good test coverage - The integration test covers the full round-trip (create, send, receive, verify)
  4. Proper logging - Test includes helpful tracing statements
  5. Correct test macro - Uses #[xmtp_common::test] as required by CLAUDE.md

⚠️ Considerations for Production

As a POC, this is fine, but for production the following should be addressed:

  1. No sender validation for proposals - Unlike commits, there's no validation that the proposal sender is authorized. The code at mls_sync.rs:2745 indicates extract_message_sender doesn't validate installation_id membership. For proposals, you may want to add validation to ensure:

    • The sender is a current group member
    • The sender has appropriate permissions for the proposal type
  2. No cleanup mechanism - There's no code to handle stale proposals. Consider:

    • What happens to pending proposals when they're committed by someone else?
    • What happens to proposals from members who leave the group?
    • Should there be a TTL or maximum number of pending proposals?
  3. No duplicate prevention - Multiple identical proposals could be stored. OpenMLS may handle this, but worth verifying.

  4. Missing logging/metrics - Unlike ApplicationMessage and StagedCommitMessage which have log_event! calls, ProposalMessage handling has no structured logging. Consider adding:

    log_event!(
        Event::MLSReceivedProposal,
        group_id = msg_group_id,
        sender_inbox_id = sender_inbox_id,
    );
  5. Test only covers happy path - Consider edge cases:

    • Proposal from a non-member
    • Proposal for an already-pending action
    • Receiving multiple proposals before committing
  6. No WASM test - Test is marked #[cfg(not(target_arch = "wasm32"))] but no WASM equivalent provided

🔍 Security Note

The comment at mls_sync.rs:2745 states: "Extracts the message sender, but does not do any validation to ensure that the installation_id is actually part of the inbox." While OpenMLS's cryptographic validation should prevent unauthorized proposals, explicit authorization checks would add defense in depth.

Recommendation

Approve for POC purposes - The implementation is sound for demonstrating the basic flow. Before promoting to production, address the validation, cleanup, and edge case handling mentioned above.


@codecov
Copy link

codecov bot commented Dec 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.60%. Comparing base (7f5684f) to head (b4d5b96).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2954   +/-   ##
=======================================
  Coverage   73.59%   73.60%           
=======================================
  Files         405      405           
  Lines       51710    51711    +1     
=======================================
+ Hits        38057    38061    +4     
+ Misses      13653    13650    -3     

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants