51 issue h missing mip 02 validation for welcome events#96
Conversation
WalkthroughAdded a private validate_welcome_event(...) implementing MIP‑02 checks for MLS Welcome events (Kind::MlsWelcome / 444): requires at least tags Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
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. Comment |
❌ Coverage: 86.3% → 86.27% (-0.03%) |
❌ Coverage: 86.3% → 86.27% (-0.03%) |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
crates/mdk-core/src/welcomes.rs (3)
87-90: Unnecessary heap allocation.The
Veccollection is used only for indexed access. Consider using the iterator'snth()method or checking ifnostr::Tagssupports direct indexing to avoid the allocation.🔎 Proposed refactor
- let tags: Vec<&Tag> = event.tags.iter().collect(); - if tags.len() < 3 { + if event.tags.len() < 3 { return Err(Error::InvalidWelcomeMessage); } + + let tags: Vec<&Tag> = event.tags.iter().collect();Alternatively, if you keep the Vec, move it after the length check so the allocation only happens for valid events.
570-570: Moveusestatement to top of file.As per coding guidelines, place all
usestatements at the top of the file, never inside functions or other blocks.🔎 Proposed refactor
Move the import to the test module's imports section:
#[cfg(test)] mod tests { use super::*; use crate::test_util::*; use crate::tests::create_test_mdk; use nostr::{Keys, Kind, TagKind}; + use nostr::RelayUrl;Then remove line 570 from inside the test function.
567-650: Consider adding test cases for encoding tag validation.The validation function checks encoding tag values (lines 117-130), but the test doesn't cover:
- Invalid encoding value (e.g., "utf8" instead of "hex"/"base64")
- Encoding tag with missing content
Adding these would improve test coverage for the encoding validation path.
🔎 Example test case for invalid encoding
// Test 5: Invalid encoding value let mut tags5 = nostr::Tags::new(); tags5.push(nostr::Tag::relays(vec![ RelayUrl::parse("wss://relay.example.com").unwrap(), ])); tags5.push(nostr::Tag::event(EventId::all_zeros())); tags5.push(nostr::Tag::client("mdk".to_string())); tags5.push(nostr::Tag::custom( nostr::TagKind::Custom("encoding".into()), vec!["utf8"], // Invalid encoding )); let invalid_encoding_event = UnsignedEvent { id: None, pubkey: Keys::generate().public_key(), created_at: Timestamp::now(), kind: Kind::MlsWelcome, tags: tags5, content: "test".to_string(), }; let result = mdk.process_welcome(&wrapper_event_id, &invalid_encoding_event); assert!(result.is_err(), "Should reject invalid encoding value");
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/mdk-core/src/welcomes.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)
**/*.rs: All trait bounds should be written inwhereclauses rather than inline with type parameters in Rust
UseSelfinstead of the explicit type name when referring to the type in impl blocks
DeriveDebug,Clone,Copy,PartialEq,Eq, andHashfor public types when possible, in that order
DeriveDefaultfor public types when there is a reasonable default value
Always use full paths for logging withtracing::<op>!(...)instead of importing and using<op>!(...)
Prefer.to_string()or.to_owned()for&strtoStringconversion instead of.into()orString::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import thefmtmodule rather than using full paths when implementing traits fromcore::fmtorstd::fmt
Use relativeself::imports for sub-modules rather than bare module names
Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoidif let ... { } else { }constructs; usematchinstead when both branches are non-empty
Useif let ... { }without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g.,x.rs) withmod x;declaration rather than inlinemod x { .. }blocks, except fortestsandbenchesmodules
Use inlinemod tests { #[cfg(test)] ... }for test modules rather than creating separatetests.rsfiles
Use inlinemod benches { #[cfg(bench)] ... }for benchmark modules rather than creating separatebenches.rsfiles
Files:
crates/mdk-core/src/welcomes.rs
🔇 Additional comments (3)
crates/mdk-core/src/welcomes.rs (3)
6-6: LGTM!Import additions are appropriate for the new validation logic.
117-130: Silent acceptance of unknown 4th tags.If a 4th tag exists but is not of kind
Custom("encoding"), the validation passes without checking it. Clarify if this is intentional for forward compatibility with future extensions, or if unknown tags should trigger an error.
141-142: LGTM!Validation is correctly placed at the start of
process_welcome, ensuring invalid events are rejected before any processing or storage operations occur.
✅ Coverage: 86.3% → 86.34% (+0.04%) |
dannym-arx
left a comment
There was a problem hiding this comment.
Good work, only one small change is needed in my opinion
✅ Coverage: 86.3% → 86.35% (+0.05%) |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
crates/mdk-core/src/welcomes.rs (2)
119-126: Refactorif let...elsetomatchper coding guidelines.The guideline states: "Avoid
if let ... { } else { }constructs; usematchinstead when both branches are non-empty."🔎 Proposed refactor using match
- // Validate encoding value if present - if let Some(encoding_value) = tag.content() { - // Validate encoding value is either "hex" or "base64" - if encoding_value != "hex" && encoding_value != "base64" { - return Err(Error::InvalidWelcomeMessage); - } - } else { - return Err(Error::InvalidWelcomeMessage); - } + // Validate encoding value if present + match tag.content() { + Some(encoding_value) if encoding_value == "hex" || encoding_value == "base64" => { + // Valid encoding + } + _ => return Err(Error::InvalidWelcomeMessage), + }As per coding guidelines, ...
107-108: Consider cachingtag.content()result to avoid duplicate calls.Both validations call
tag.content()twice in the same condition, which is slightly inefficient.🔎 Optional optimization
For the e tag validation:
kind if kind == TagKind::e() => { // Check that e tag has non-empty content - if tag.content().is_some() && tag.content() != Some("") { + if let Some(content) = tag.content() { + if !content.is_empty() { + has_event_ref = true; + } + } - has_event_ref = true; - } }Similar pattern for the client tag at lines 111-116.
Also applies to: 113-114
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/mdk-core/src/welcomes.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)
**/*.rs: All trait bounds should be written inwhereclauses rather than inline with type parameters in Rust
UseSelfinstead of the explicit type name when referring to the type in impl blocks
DeriveDebug,Clone,Copy,PartialEq,Eq, andHashfor public types when possible, in that order
DeriveDefaultfor public types when there is a reasonable default value
Always use full paths for logging withtracing::<op>!(...)instead of importing and using<op>!(...)
Prefer.to_string()or.to_owned()for&strtoStringconversion instead of.into()orString::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import thefmtmodule rather than using full paths when implementing traits fromcore::fmtorstd::fmt
Use relativeself::imports for sub-modules rather than bare module names
Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoidif let ... { } else { }constructs; usematchinstead when both branches are non-empty
Useif let ... { }without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g.,x.rs) withmod x;declaration rather than inlinemod x { .. }blocks, except fortestsandbenchesmodules
Use inlinemod tests { #[cfg(test)] ... }for test modules rather than creating separatetests.rsfiles
Use inlinemod benches { #[cfg(bench)] ... }for benchmark modules rather than creating separatebenches.rsfiles
Files:
crates/mdk-core/src/welcomes.rs
🧠 Learnings (1)
📚 Learning: 2025-12-03T10:17:44.932Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/marmot.mdc:0-0
Timestamp: 2025-12-03T10:17:44.932Z
Learning: Ensure all code implementation is on spec with the Marmot Protocol specification
Applied to files:
crates/mdk-core/src/welcomes.rs
⏰ 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 Coverage
🔇 Additional comments (4)
crates/mdk-core/src/welcomes.rs (4)
6-6: LGTM! Imports properly added for validation.The additions of
Kind,Tag, andTagKindare necessary for the new MIP-02 validation logic and follow the coding guidelines for import ordering.
79-144: Strong validation logic that properly implements MIP-02 requirements.The validation correctly enforces:
- Kind 444 (MlsWelcome)
- Required tags (relays, e, client) with non-empty content
- Optional encoding tag validation (hex/base64)
- Tag order independence for interoperability
This addresses the past review feedback about tag order flexibility and empty content validation.
152-153: LGTM! Early validation prevents processing invalid events.Calling
Self::validate_welcome_eventat the start ofprocess_welcomeis good practice—it rejects malformed events before any expensive MLS operations. The use ofSelffollows the coding guidelines.
578-702: Excellent test coverage for validation edge cases.The test comprehensively validates rejection of:
- Wrong event kind
- Insufficient tag count
- Empty relays array
- Empty e tag content
- Empty client tag content
- Invalid encoding values
All assertions correctly expect
Error::InvalidWelcomeMessagefor each invalid case.
✅ Coverage: 86.3% → 86.37% (+0.07%) |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
crates/mdk-core/src/welcomes.rs (1)
86-86: Encoding tag handling is intentionally deferred and appropriately documented.The code correctly validates the encoding tag when present and defaults to hex for legacy events. While MIP-02 specifies the encoding tag should be required, deferring this to issue #61 is reasonable given the backward compatibility concerns. The tests already generate welcome events with 4 tags (including encoding), demonstrating forward-compatibility. The current approach with clear documentation in comments and docstrings is acceptable.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/mdk-core/src/welcomes.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)
**/*.rs: All trait bounds should be written inwhereclauses rather than inline with type parameters in Rust
UseSelfinstead of the explicit type name when referring to the type in impl blocks
DeriveDebug,Clone,Copy,PartialEq,Eq, andHashfor public types when possible, in that order
DeriveDefaultfor public types when there is a reasonable default value
Always use full paths for logging withtracing::<op>!(...)instead of importing and using<op>!(...)
Prefer.to_string()or.to_owned()for&strtoStringconversion instead of.into()orString::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import thefmtmodule rather than using full paths when implementing traits fromcore::fmtorstd::fmt
Use relativeself::imports for sub-modules rather than bare module names
Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoidif let ... { } else { }constructs; usematchinstead when both branches are non-empty
Useif let ... { }without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g.,x.rs) withmod x;declaration rather than inlinemod x { .. }blocks, except fortestsandbenchesmodules
Use inlinemod tests { #[cfg(test)] ... }for test modules rather than creating separatetests.rsfiles
Use inlinemod benches { #[cfg(bench)] ... }for benchmark modules rather than creating separatebenches.rsfiles
**/*.rs: All trait bounds must be placed inwhereclauses, not inline with generic parameters in Rust code
UseSelfinstead of the type name when possible in Rust code
Derive macros must be ordered as:Debug,Clone,Copy,PartialEq,Eq,Hashin Rust code
Always usetracing::warn!(...)with explicit module path, never im...
Files:
crates/mdk-core/src/welcomes.rs
🧠 Learnings (2)
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to **/*.rs : When adding or modifying code related to encrypted media, ensure tests are run with the `mip04` feature using `cargo test --features mip04`
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2025-12-03T10:17:44.932Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/marmot.mdc:0-0
Timestamp: 2025-12-03T10:17:44.932Z
Learning: Ensure all code implementation is on spec with the Marmot Protocol specification
Applied to files:
crates/mdk-core/src/welcomes.rs
🧬 Code graph analysis (1)
crates/mdk-core/src/welcomes.rs (3)
crates/mdk-core/src/lib.rs (4)
create_test_mdk(308-310)new(53-55)new(97-102)new(258-260)crates/mdk-core/src/encrypted_media/manager.rs (2)
create_test_mdk(351-353)new(35-37)crates/mdk-core/src/encrypted_media/crypto.rs (1)
create_test_mdk(204-206)
⏰ 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 Coverage
🔇 Additional comments (2)
crates/mdk-core/src/welcomes.rs (2)
6-6: LGTM!Import additions are appropriate for the new validation logic and follow the coding guidelines for import ordering.
159-160: LGTM!Early validation call enables fail-fast behavior and follows Rust best practices. The integration is clean and allows invalid welcomes to be rejected before any storage or processing occurs.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
crates/mdk-core/CHANGELOG.mdcrates/mdk-core/src/welcomes.rs
🧰 Additional context used
📓 Path-based instructions (3)
crates/*/CHANGELOG.md
📄 CodeRabbit inference engine (AGENTS.md)
crates/*/CHANGELOG.md: Every change that modifies functionality must update the appropriate crate CHANGELOG.md file (mdk-core, mdk-storage-traits, mdk-memory-storage, or mdk-sqlite-storage)
Follow Keep a Changelog format with sections for Unreleased, Breaking changes, Changed, Added, Fixed, Removed, and Deprecated in CHANGELOG files
Always include a PR reference link in changelog entries using the format([#123](https://github.com/marmot-protocol/mdk/pull/123))
Files:
crates/mdk-core/CHANGELOG.md
**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Never use bare URLs in markdown files. All URLs must be properly formatted: use
[link text](url)for inline links,<url>for standalone URLs,([#123](https://github.com/marmot-protocol/mdk/pull/123))for PR/issue references, and([abc1234](https://github.com/.../commit/abc1234...))for commit references
Files:
crates/mdk-core/CHANGELOG.md
**/*.rs
📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)
**/*.rs: All trait bounds should be written inwhereclauses rather than inline with type parameters in Rust
UseSelfinstead of the explicit type name when referring to the type in impl blocks
DeriveDebug,Clone,Copy,PartialEq,Eq, andHashfor public types when possible, in that order
DeriveDefaultfor public types when there is a reasonable default value
Always use full paths for logging withtracing::<op>!(...)instead of importing and using<op>!(...)
Prefer.to_string()or.to_owned()for&strtoStringconversion instead of.into()orString::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import thefmtmodule rather than using full paths when implementing traits fromcore::fmtorstd::fmt
Use relativeself::imports for sub-modules rather than bare module names
Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoidif let ... { } else { }constructs; usematchinstead when both branches are non-empty
Useif let ... { }without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g.,x.rs) withmod x;declaration rather than inlinemod x { .. }blocks, except fortestsandbenchesmodules
Use inlinemod tests { #[cfg(test)] ... }for test modules rather than creating separatetests.rsfiles
Use inlinemod benches { #[cfg(bench)] ... }for benchmark modules rather than creating separatebenches.rsfiles
**/*.rs: All trait bounds must be placed inwhereclauses, not inline with generic parameters in Rust code
UseSelfinstead of the type name when possible in Rust code
Derive macros must be ordered as:Debug,Clone,Copy,PartialEq,Eq,Hashin Rust code
Always usetracing::warn!(...)with explicit module path, never im...
Files:
crates/mdk-core/src/welcomes.rs
🧠 Learnings (7)
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to crates/*/CHANGELOG.md : Every change that modifies functionality must update the appropriate crate CHANGELOG.md file (mdk-core, mdk-storage-traits, mdk-memory-storage, or mdk-sqlite-storage)
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to crates/*/CHANGELOG.md : Follow Keep a Changelog format with sections for Unreleased, Breaking changes, Changed, Added, Fixed, Removed, and Deprecated in CHANGELOG files
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to crates/*/CHANGELOG.md : Always include a PR reference link in changelog entries using the format `([#123](https://github.com/marmot-protocol/mdk/pull/123))`
Applied to files:
crates/mdk-core/CHANGELOG.mdcrates/mdk-core/src/welcomes.rs
📚 Learning: 2025-12-03T10:17:44.932Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/marmot.mdc:0-0
Timestamp: 2025-12-03T10:17:44.932Z
Learning: Ensure all code implementation is on spec with the Marmot Protocol specification
Applied to files:
crates/mdk-core/CHANGELOG.mdcrates/mdk-core/src/welcomes.rs
📚 Learning: 2025-12-12T14:58:57.710Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/mls.mdc:0-0
Timestamp: 2025-12-12T14:58:57.710Z
Learning: This repository implements the Marmot protocol, which integrates MLS with the Nostr protocol. Reference https://github.com/marmot-protocol/marmot for protocol specifications and design decisions.
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T15:51:58.505Z
Learnt from: dannym-arx
Repo: marmot-protocol/mdk PR: 98
File: crates/mdk-core/CHANGELOG.md:46-46
Timestamp: 2026-01-01T15:51:58.505Z
Learning: In CHANGELOG.md files, keep the GitHub issue references (e.g., #61) as-is; do not convert '#61' (with no space) into an MD heading '# 61'. The hash without a space is intentional for GitHub auto-linking. This guideline applies to all CHANGELOG.md files in the repo.
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to **/*.rs : When adding or modifying code related to encrypted media, ensure tests are run with the `mip04` feature using `cargo test --features mip04`
Applied to files:
crates/mdk-core/src/welcomes.rs
🔇 Additional comments (4)
crates/mdk-core/src/welcomes.rs (4)
6-6: LGTM - Required imports for validation.The added imports (
Kind,Tag,TagKind) are properly used in the new validation function and tests.
56-151: LGTM - Comprehensive MIP-02 validation implementation.The validation function correctly implements all required checks and addresses all past review feedback:
- Enforces kind 444 (MlsWelcome)
- Validates presence of all 4 required tags without enforcing order (good for interoperability)
- Validates relay URLs with proper length checks to prevent incomplete URLs like
"wss://"- Validates non-empty content for e and client tags (checks both
is_some()and not empty string)- Validates encoding tag is present with value "hex" or "base64"
The implementation is thorough and follows the documented MIP-02 requirements.
159-160: LGTM - Validation called at the right point.The validation is invoked early in
process_welcome, before any storage operations or processing. This fail-fast approach prevents malformed events from causing storage pollution or resource exhaustion, addressing the security audit concern (Issue H).
585-773: LGTM - Comprehensive test coverage for validation.The test suite thoroughly exercises all validation paths:
- Invalid kind (Test 1)
- Missing required tags (Tests 2, 3)
- Empty/invalid relay URLs (Tests 4, 5, 6) - including incomplete URLs as suggested in past review
- Empty tag content (Tests 7, 8)
- Invalid encoding value (Test 9)
All validation branches are covered, and the tests correctly verify rejection with
InvalidWelcomeMessageerror.
ebc6a87 to
553b8dd
Compare
✅ Coverage: 86.3% → 86.4% (+0.10%) |
553b8dd to
09df7b8
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
crates/mdk-core/CHANGELOG.mdcrates/mdk-core/src/welcomes.rs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs
📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)
**/*.rs: All trait bounds should be written inwhereclauses rather than inline with type parameters in Rust
UseSelfinstead of the explicit type name when referring to the type in impl blocks
DeriveDebug,Clone,Copy,PartialEq,Eq, andHashfor public types when possible, in that order
DeriveDefaultfor public types when there is a reasonable default value
Always use full paths for logging withtracing::<op>!(...)instead of importing and using<op>!(...)
Prefer.to_string()or.to_owned()for&strtoStringconversion instead of.into()orString::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import thefmtmodule rather than using full paths when implementing traits fromcore::fmtorstd::fmt
Use relativeself::imports for sub-modules rather than bare module names
Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoidif let ... { } else { }constructs; usematchinstead when both branches are non-empty
Useif let ... { }without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g.,x.rs) withmod x;declaration rather than inlinemod x { .. }blocks, except fortestsandbenchesmodules
Use inlinemod tests { #[cfg(test)] ... }for test modules rather than creating separatetests.rsfiles
Use inlinemod benches { #[cfg(bench)] ... }for benchmark modules rather than creating separatebenches.rsfiles
**/*.rs: All trait bounds must be placed inwhereclauses, not inline with generic parameters in Rust code
UseSelfinstead of the type name when possible in Rust code
Derive macros must be ordered as:Debug,Clone,Copy,PartialEq,Eq,Hashin Rust code
Always usetracing::warn!(...)with explicit module path, never im...
Files:
crates/mdk-core/src/welcomes.rs
crates/*/CHANGELOG.md
📄 CodeRabbit inference engine (AGENTS.md)
crates/*/CHANGELOG.md: Every change that modifies functionality must update the appropriate crate CHANGELOG.md file (mdk-core, mdk-storage-traits, mdk-memory-storage, or mdk-sqlite-storage)
Follow Keep a Changelog format with sections for Unreleased, Breaking changes, Changed, Added, Fixed, Removed, and Deprecated in CHANGELOG files
Always include a PR reference link in changelog entries using the format([#123](https://github.com/marmot-protocol/mdk/pull/123))
Files:
crates/mdk-core/CHANGELOG.md
**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Never use bare URLs in markdown files. All URLs must be properly formatted: use
[link text](url)for inline links,<url>for standalone URLs,([#123](https://github.com/marmot-protocol/mdk/pull/123))for PR/issue references, and([abc1234](https://github.com/.../commit/abc1234...))for commit references
Files:
crates/mdk-core/CHANGELOG.md
🧠 Learnings (9)
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to **/*.rs : When adding or modifying code related to encrypted media, ensure tests are run with the `mip04` feature using `cargo test --features mip04`
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2025-12-03T10:17:44.932Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/marmot.mdc:0-0
Timestamp: 2025-12-03T10:17:44.932Z
Learning: Ensure all code implementation is on spec with the Marmot Protocol specification
Applied to files:
crates/mdk-core/src/welcomes.rscrates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to crates/*/CHANGELOG.md : Always include a PR reference link in changelog entries using the format `([#123](https://github.com/marmot-protocol/mdk/pull/123))`
Applied to files:
crates/mdk-core/src/welcomes.rscrates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to crates/*/CHANGELOG.md : Every change that modifies functionality must update the appropriate crate CHANGELOG.md file (mdk-core, mdk-storage-traits, mdk-memory-storage, or mdk-sqlite-storage)
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to crates/*/CHANGELOG.md : Follow Keep a Changelog format with sections for Unreleased, Breaking changes, Changed, Added, Fixed, Removed, and Deprecated in CHANGELOG files
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T15:51:58.505Z
Learnt from: dannym-arx
Repo: marmot-protocol/mdk PR: 98
File: crates/mdk-core/CHANGELOG.md:46-46
Timestamp: 2026-01-01T15:51:58.505Z
Learning: In CHANGELOG.md files, keep the GitHub issue references (e.g., #61) as-is; do not convert '#61' (with no space) into an MD heading '# 61'. The hash without a space is intentional for GitHub auto-linking. This guideline applies to all CHANGELOG.md files in the repo.
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T16:28:05.744Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-01T16:28:05.744Z
Learning: Applies to **/*.md : Never use bare URLs in markdown files. All URLs must be properly formatted: use `[link text](url)` for inline links, `<url>` for standalone URLs, `([#123](https://github.com/marmot-protocol/mdk/pull/123))` for PR/issue references, and `([abc1234](https://github.com/.../commit/abc1234...))` for commit references
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2025-12-12T14:58:57.710Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/mls.mdc:0-0
Timestamp: 2025-12-12T14:58:57.710Z
Learning: This repository implements the Marmot protocol, which integrates MLS with the Nostr protocol. Reference https://github.com/marmot-protocol/marmot for protocol specifications and design decisions.
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2025-12-12T14:58:57.710Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/mls.mdc:0-0
Timestamp: 2025-12-12T14:58:57.710Z
Learning: Reference RFC 9420 (The Messaging Layer Security (MLS) Protocol) when implementing MLS-related code. Available at https://www.rfc-editor.org/rfc/rfc9420.html or locally at docs/mls/rfc9420.txt
Applied to files:
crates/mdk-core/CHANGELOG.md
⏰ 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 Coverage
🔇 Additional comments (4)
crates/mdk-core/src/welcomes.rs (3)
56-151: LGTM! Comprehensive MIP-02 validation implementation.The validation function correctly enforces all MIP-02 requirements:
- Kind 444 enforcement
- All required tags validated (relays, e, client, encoding)
- Relay URLs validated for both protocol (
wss://orws://) and minimum content after the protocol- Empty string content properly rejected for e and client tags
- Encoding restricted to "hex" or "base64"
- Tag order independence maintained for interoperability
This addresses all concerns raised in past reviews regarding empty content, relay URL completeness, and encoding requirements.
159-160: LGTM! Proper early validation.The validation is correctly integrated at the beginning of
process_welcome, ensuring malformed events are rejected before any expensive processing or storage operations. The use ofSelf::follows the coding guidelines.
585-773: LGTM! Comprehensive test coverage for validation.The test thoroughly validates rejection of all invalid welcome event scenarios, including:
- Structural issues (wrong kind, missing tags)
- Relay validation (empty, invalid protocol, incomplete URLs)
- Content validation (empty e/client tag content)
- Encoding validation (missing tag, invalid value)
This addresses all the test coverage gaps identified in past reviews, particularly for incomplete relay URLs and empty string content.
crates/mdk-core/CHANGELOG.md (1)
30-54: LGTM! Changelog properly documents breaking changes and fixes.The changelog entries correctly:
- Use PR reference format
([#96](https://github.com/marmot-protocol/mdk/pull/96))as required by coding guidelines- Follow Keep a Changelog structure with appropriate sections
- Document breaking changes clearly (encoding tag now required, 4 tags required, relay URL validation)
- Properly reference security fix for Audit Issue H
- Accurately describe the validation logic added in the code
As per coding guidelines: "Always include a PR reference link in changelog entries using the format
([#123](https://github.com/marmot-protocol/mdk/pull/123))"
✅ Coverage: 86.3% → 86.4% (+0.10%) |
✅ Coverage: 86.3% → 86.4% (+0.10%) |
✅ Coverage: 86.6% → 86.69% (+0.09%) |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
crates/mdk-core/src/welcomes.rs (2)
57-150: Excellent MIP-02 validation implementation with comprehensive checks.The validation function correctly enforces all MIP-02 requirements:
- Kind 444 validation
- Required tag presence (order-independent for interoperability)
- Relay URL validation using
RelayUrl::parse(thorough approach)- Non-empty content checks for e and client tags
- Encoding value validation (hex/base64)
The logic is sound and addresses all past review feedback.
Optional: More idiomatic pattern for content validation
Lines 109-111 and 115-117 call
tag.content()twice. Consider a more idiomatic pattern:- kind if kind == TagKind::e() => { - // Check that e tag has non-empty content - if tag.content().is_some() && tag.content() != Some("") { - has_event_ref = true; - } - } + kind if kind == TagKind::e() => { + // Check that e tag has non-empty content + if matches!(tag.content(), Some(c) if !c.is_empty()) { + has_event_ref = true; + } + }Apply the same pattern to the client tag validation. This avoids calling
tag.content()twice and is more readable.
589-589: Move import to test module level per coding guidelines.The
use nostr::RelayUrl;statement inside the test function violates the coding guideline: "Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks."🔎 Proposed fix
Move the import to the top of the test module (around line 470):
mod tests { use super::*; use crate::test_util::*; use crate::tests::create_test_mdk; - use nostr::{Keys, Kind, TagKind}; + use nostr::{Keys, Kind, RelayUrl, TagKind};Then remove the import from line 589.
As per coding guidelines: "Place all
usestatements at file top, never inside functions"
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
crates/mdk-core/CHANGELOG.mdcrates/mdk-core/src/welcomes.rs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs
📄 CodeRabbit inference engine (.cursor/rules/rust.mdc)
**/*.rs: All trait bounds should be written inwhereclauses rather than inline with type parameters in Rust
UseSelfinstead of the explicit type name when referring to the type in impl blocks
DeriveDebug,Clone,Copy,PartialEq,Eq, andHashfor public types when possible, in that order
DeriveDefaultfor public types when there is a reasonable default value
Always use full paths for logging withtracing::<op>!(...)instead of importing and using<op>!(...)
Prefer.to_string()or.to_owned()for&strtoStringconversion instead of.into()orString::from()
Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Import thefmtmodule rather than using full paths when implementing traits fromcore::fmtorstd::fmt
Use relativeself::imports for sub-modules rather than bare module names
Place allusestatements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoidif let ... { } else { }constructs; usematchinstead when both branches are non-empty
Useif let ... { }without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g.,x.rs) withmod x;declaration rather than inlinemod x { .. }blocks, except fortestsandbenchesmodules
Use inlinemod tests { #[cfg(test)] ... }for test modules rather than creating separatetests.rsfiles
Use inlinemod benches { #[cfg(bench)] ... }for benchmark modules rather than creating separatebenches.rsfiles
**/*.rs: All trait bounds in generics must be placed inwhereclauses, not inline
UseSelfinstead of the type name when possible
Derive order must be:Debug,Clone,Copy,PartialEq,Eq,Hash(in this order)
Always usetracing::warn!(...), never import and usewarn!(...)
Use.to_string()or.to_owned()for string ...
Files:
crates/mdk-core/src/welcomes.rs
**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Never use bare URLs in markdown files; all URLs must be properly formatted using
[link text](url),<url>, or([#123](url))for PR/issue references
Files:
crates/mdk-core/CHANGELOG.md
crates/*/CHANGELOG.md
📄 CodeRabbit inference engine (AGENTS.md)
Every crate CHANGELOG entry must include a PR reference using the format
([#123](https://github.com/marmot-protocol/mdk/pull/123))
Files:
crates/mdk-core/CHANGELOG.md
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T08:39:39.799Z
Learning: All code must follow the MLS Protocol (RFC 9420) specification exactly
📚 Learning: 2026-01-03T08:39:39.799Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T08:39:39.799Z
Learning: All code must follow the Marmot Protocol specification exactly; ask clarifying questions if any part of the spec is unclear
Applied to files:
crates/mdk-core/src/welcomes.rscrates/mdk-core/CHANGELOG.md
📚 Learning: 2025-12-03T10:17:44.932Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/marmot.mdc:0-0
Timestamp: 2025-12-03T10:17:44.932Z
Learning: Ensure all code implementation is on spec with the Marmot Protocol specification
Applied to files:
crates/mdk-core/src/welcomes.rscrates/mdk-core/CHANGELOG.md
📚 Learning: 2025-12-03T10:18:10.432Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/rust.mdc:0-0
Timestamp: 2025-12-03T10:18:10.432Z
Learning: Applies to **/*.rs : Order imports in the following sequence: (1) core/alloc/std, (2) external crates, (3) current sub-modules with mod declarations, (4) internal crate modules
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2025-12-03T10:18:10.432Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/rust.mdc:0-0
Timestamp: 2025-12-03T10:18:10.432Z
Learning: Applies to **/*.rs : Place all `use` statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2026-01-03T08:39:39.799Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T08:39:39.799Z
Learning: Applies to **/*.rs : Import order must follow: core/alloc/std, then external crates, then sub-module declarations, then internal crate imports
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2026-01-03T08:39:39.799Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T08:39:39.799Z
Learning: Applies to **/*.rs : Place all `use` statements at file top, never inside functions
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2025-12-03T10:18:10.432Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/rust.mdc:0-0
Timestamp: 2025-12-03T10:18:10.432Z
Learning: Applies to **/*.rs : Import the `fmt` module rather than using full paths when implementing traits from `core::fmt` or `std::fmt`
Applied to files:
crates/mdk-core/src/welcomes.rs
📚 Learning: 2026-01-03T08:39:39.799Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T08:39:39.799Z
Learning: Applies to crates/*/CHANGELOG.md : Every crate CHANGELOG entry must include a PR reference using the format `([#123](https://github.com/marmot-protocol/mdk/pull/123))`
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-03T08:39:39.799Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-03T08:39:39.799Z
Learning: Every change that modifies functionality must update the CHANGELOG in the affected crate
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2026-01-01T15:51:58.505Z
Learnt from: dannym-arx
Repo: marmot-protocol/mdk PR: 98
File: crates/mdk-core/CHANGELOG.md:46-46
Timestamp: 2026-01-01T15:51:58.505Z
Learning: In CHANGELOG.md files, keep the GitHub issue references (e.g., #61) as-is; do not convert '#61' (with no space) into an MD heading '# 61'. The hash without a space is intentional for GitHub auto-linking. This guideline applies to all CHANGELOG.md files in the repo.
Applied to files:
crates/mdk-core/CHANGELOG.md
📚 Learning: 2025-12-12T14:58:57.710Z
Learnt from: CR
Repo: marmot-protocol/mdk PR: 0
File: .cursor/rules/mls.mdc:0-0
Timestamp: 2025-12-12T14:58:57.710Z
Learning: This repository implements the Marmot protocol, which integrates MLS with the Nostr protocol. Reference https://github.com/marmot-protocol/marmot for protocol specifications and design decisions.
Applied to files:
crates/mdk-core/CHANGELOG.md
🧬 Code graph analysis (1)
crates/mdk-core/src/welcomes.rs (4)
crates/mdk-core/src/lib.rs (4)
create_test_mdk(308-310)new(53-55)new(97-102)new(258-260)crates/mdk-core/src/encrypted_media/manager.rs (2)
create_test_mdk(351-353)new(35-37)crates/mdk-core/src/encrypted_media/crypto.rs (1)
create_test_mdk(204-206)crates/mdk-core/src/test_util.rs (2)
new(167-179)new(221-225)
⏰ 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 Coverage
🔇 Additional comments (4)
crates/mdk-core/CHANGELOG.md (1)
30-57: LGTM! Comprehensive and accurate changelog documentation.The changelog entries accurately document the MIP-02 validation implementation with proper PR references, clear breaking change descriptions, and appropriate security context. The structure follows the required format and provides sufficient detail for users to understand the impact.
crates/mdk-core/src/welcomes.rs (3)
3-5: LGTM! Imports follow correct order.External crate imports are correctly placed before internal crate imports (lines 7-9), following the coding guideline.
158-159: LGTM! Validation correctly integrated into welcome processing.The validation is called at the start of
process_welcome, ensuring malformed events are rejected early per MIP-02 requirements.
586-774: LGTM! Comprehensive test coverage for validation scenarios.The test function thoroughly validates rejection of:
- Wrong event kind
- Missing required tags
- Missing encoding tag
- Empty relays
- Invalid/incomplete relay URLs
- Empty e/client tag content
- Invalid encoding values
Excellent coverage of all MIP-02 validation requirements.
Summary by CodeRabbit
Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.