Skip to content

[architecture] required_permission() catch-all arm silently skips new EventKind variants #201

@intendednull

Description

@intendednull

Problem

The required_permission() function in crates/state/src/materialize.rs uses a catch-all _ => None arm that silently passes any unrecognised EventKind variant without a permission check. The spec (docs/specs/2026-04-12-state-authority-and-mutations.md) acknowledges this risk but mitigates it only through a code review convention:

Every variant that returns None is intentionally unrestricted or checked elsewhere. The catch-all arm MUST list these variants in a comment so reviewers notice when a new variant is missing.

There is no compiler-enforced mechanism to catch missing coverage when a new EventKind variant is added.

Impact

A developer adding a new EventKind variant who forgets to update required_permission() will have their new event type silently bypass all permission checks. This is a security regression risk on every new EventKind addition.

Fix

Add a test that exhaustively checks all EventKind variants are explicitly handled (not caught by the catch-all):

#[test]
fn required_permission_covers_all_event_kinds() {
    // For each EventKind variant, assert it is explicitly listed
    // in required_permission() — either with Some(perm) or None with a comment
    // This test should fail to compile if a new variant is added without updating the match.
}

Better: restructure required_permission() to use an exhaustive match with no catch-all arm, so the compiler enforces coverage:

pub fn required_permission(kind: &EventKind) -> Option<Permission> {
    match kind {
        EventKind::CreateChannel => Some(Permission::ManageChannels),
        // ... all variants explicitly listed
        // No _ arm — compiler error if a variant is missing
    }
}

Location

  • crates/state/src/materialize.rs (required_permission() function)

Found during

Codebase audit at commit 18119e343ec53a9393312006d9d3b205129f696d

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions