Skip to content

51 issue h missing mip 02 validation for welcome events#96

Merged
mubarakcoded merged 10 commits intomasterfrom
51-issue-h-missing-mip-02-validation-for-welcome-events
Jan 5, 2026
Merged

51 issue h missing mip 02 validation for welcome events#96
mubarakcoded merged 10 commits intomasterfrom
51-issue-h-missing-mip-02-validation-for-welcome-events

Conversation

@mubarakcoded
Copy link
Contributor

@mubarakcoded mubarakcoded commented Jan 1, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Stricter MIP-02 welcome validation: must be the welcome kind, include the four required tags (relays, event ref, client, encoding), have non-empty values, require encoding "hex" or "base64", and enforce relay URLs start with ws:// or wss://. Invalid welcomes are rejected earlier to prevent malformed messages, storage pollution, and resource exhaustion.
  • Tests

    • Expanded tests covering many invalid welcome scenarios to ensure robust rejection and safer processing.

✏️ Tip: You can customize this high-level summary in your review settings.

@mubarakcoded mubarakcoded linked an issue Jan 1, 2026 that may be closed by this pull request
@coderabbitai
Copy link

coderabbitai bot commented Jan 1, 2026

Walkthrough

Added a private validate_welcome_event(...) implementing MIP‑02 checks for MLS Welcome events (Kind::MlsWelcome / 444): requires at least tags relays, e, client, encoding; validates non‑empty e/client, encoding ∈ {"hex","base64"}, and well‑formed relay URLs. process_welcome now calls the validator; tests added for invalid welcomes.

Changes

Cohort / File(s) Summary
Welcome validation & processing
crates/mdk-core/src/welcomes.rs
Added validate_welcome_event(&UnsignedEvent) -> Result<(), Error> performing MIP‑02 checks (event kind == Kind::MlsWelcome (444); presence of relays, e, client, encoding tags; non‑empty e and client; encoding is "hex" or "base64"; relay URLs parsed/validated). Integrated validator call into process_welcome.
Imports & tests
crates/mdk-core/src/welcomes.rs
Expanded imports (e.g., TagKind, EventId, Kind, Timestamp, UnsignedEvent); added unit tests asserting rejection of malformed welcome events (wrong kind, missing tags, missing/empty encoding, empty relays/e/client, malformed/incomplete relay URLs, invalid encoding value).
Changelog
crates/mdk-core/CHANGELOG.md
Documented MIP‑02 Welcome Event Validation changes (encoding tag required, encoding value restrictions, relay URL format checks, validation added to prevent malformed welcome events).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing missing MIP-02 validation for welcome events, which is the core purpose of the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@github-actions
Copy link

github-actions bot commented Jan 1, 2026

❌ Coverage: 86.3% → 86.27% (-0.03%)

@mubarakcoded mubarakcoded marked this pull request as ready for review January 1, 2026 12:35
@github-actions
Copy link

github-actions bot commented Jan 1, 2026

❌ Coverage: 86.3% → 86.27% (-0.03%)

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

🧹 Nitpick comments (3)
crates/mdk-core/src/welcomes.rs (3)

87-90: Unnecessary heap allocation.

The Vec collection is used only for indexed access. Consider using the iterator's nth() method or checking if nostr::Tags supports 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: Move use statement to top of file.

As per coding guidelines, place all use statements 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6744f18 and c54fa2d.

📒 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 in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::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 the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

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.

@github-actions
Copy link

github-actions bot commented Jan 1, 2026

✅ Coverage: 86.3% → 86.34% (+0.04%)

Copy link
Contributor

@dannym-arx dannym-arx left a comment

Choose a reason for hiding this comment

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

Good work, only one small change is needed in my opinion

@github-actions
Copy link

github-actions bot commented Jan 1, 2026

✅ Coverage: 86.3% → 86.35% (+0.05%)

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

🧹 Nitpick comments (2)
crates/mdk-core/src/welcomes.rs (2)

119-126: Refactor if let...else to match per coding guidelines.

The guideline states: "Avoid if let ... { } else { } constructs; use match instead 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 caching tag.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

📥 Commits

Reviewing files that changed from the base of the PR and between 8815d93 and 8542278.

📒 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 in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::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 the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

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, and TagKind are 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_event at the start of process_welcome is good practice—it rejects malformed events before any expensive MLS operations. The use of Self follows 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::InvalidWelcomeMessage for each invalid case.

Copy link
Contributor

@jgmontoya jgmontoya left a comment

Choose a reason for hiding this comment

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

Looks good, just a couple of questions

@github-actions
Copy link

github-actions bot commented Jan 2, 2026

✅ Coverage: 86.3% → 86.37% (+0.07%)

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8542278 and 3c1c6db.

📒 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 in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::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 the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

**/*.rs: All trait bounds must be placed in where clauses, not inline with generic parameters in Rust code
Use Self instead of the type name when possible in Rust code
Derive macros must be ordered as: Debug, Clone, Copy, PartialEq, Eq, Hash in Rust code
Always use tracing::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.

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

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c1c6db and de407e3.

📒 Files selected for processing (2)
  • crates/mdk-core/CHANGELOG.md
  • crates/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 in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::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 the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

**/*.rs: All trait bounds must be placed in where clauses, not inline with generic parameters in Rust code
Use Self instead of the type name when possible in Rust code
Derive macros must be ordered as: Debug, Clone, Copy, PartialEq, Eq, Hash in Rust code
Always use tracing::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.md
  • 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/CHANGELOG.md
  • crates/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 InvalidWelcomeMessage error.

@mubarakcoded mubarakcoded force-pushed the 51-issue-h-missing-mip-02-validation-for-welcome-events branch from ebc6a87 to 553b8dd Compare January 2, 2026 09:37
@github-actions
Copy link

github-actions bot commented Jan 2, 2026

✅ Coverage: 86.3% → 86.4% (+0.10%)

@mubarakcoded mubarakcoded force-pushed the 51-issue-h-missing-mip-02-validation-for-welcome-events branch from 553b8dd to 09df7b8 Compare January 2, 2026 09:40
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

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebc6a87 and 553b8dd.

📒 Files selected for processing (2)
  • crates/mdk-core/CHANGELOG.md
  • crates/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 in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::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 the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

**/*.rs: All trait bounds must be placed in where clauses, not inline with generic parameters in Rust code
Use Self instead of the type name when possible in Rust code
Derive macros must be ordered as: Debug, Clone, Copy, PartialEq, Eq, Hash in Rust code
Always use tracing::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.rs
  • 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/src/welcomes.rs
  • 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 : 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:// or ws://) 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 of Self:: 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))"

@github-actions
Copy link

github-actions bot commented Jan 2, 2026

✅ Coverage: 86.3% → 86.4% (+0.10%)

@github-actions
Copy link

github-actions bot commented Jan 2, 2026

✅ Coverage: 86.3% → 86.4% (+0.10%)

@github-actions
Copy link

github-actions bot commented Jan 5, 2026

✅ Coverage: 86.6% → 86.69% (+0.09%)

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: 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 all use statements 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 use statements at file top, never inside functions"

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e884fe8 and d7ec97e.

📒 Files selected for processing (2)
  • crates/mdk-core/CHANGELOG.md
  • crates/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 in where clauses rather than inline with type parameters in Rust
Use Self instead of the explicit type name when referring to the type in impl blocks
Derive Debug, Clone, Copy, PartialEq, Eq, and Hash for public types when possible, in that order
Derive Default for public types when there is a reasonable default value
Always use full paths for logging with tracing::<op>!(...) instead of importing and using <op>!(...)
Prefer .to_string() or .to_owned() for &str to String conversion instead of .into() or String::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 the fmt module rather than using full paths when implementing traits from core::fmt or std::fmt
Use relative self:: imports for sub-modules rather than bare module names
Place all use statements at the top of the file following the specified import order, never inside functions, methods, or other blocks
Avoid if let ... { } else { } constructs; use match instead when both branches are non-empty
Use if let ... { } without an else clause when a match arm would be intentionally empty
Define sub-modules using separate files (e.g., x.rs) with mod x; declaration rather than inline mod x { .. } blocks, except for tests and benches modules
Use inline mod tests { #[cfg(test)] ... } for test modules rather than creating separate tests.rs files
Use inline mod benches { #[cfg(bench)] ... } for benchmark modules rather than creating separate benches.rs files

**/*.rs: All trait bounds in generics must be placed in where clauses, not inline
Use Self instead of the type name when possible
Derive order must be: Debug, Clone, Copy, PartialEq, Eq, Hash (in this order)
Always use tracing::warn!(...), never import and use warn!(...)
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.rs
  • crates/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.rs
  • crates/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.

@mubarakcoded mubarakcoded merged commit e5cb194 into master Jan 5, 2026
12 checks passed
@mubarakcoded mubarakcoded deleted the 51-issue-h-missing-mip-02-validation-for-welcome-events branch January 5, 2026 13:59
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.

Issue H: Missing MIP-02 Validation for Welcome Events

4 participants