Proposal: Multiselect Attribute Operators for ABAC Simple Mode

Proposal: Multiselect Attribute Operators for ABAC Simple Mode

PR: mattermost/mattermost#35896


BLUF

Replace the overloaded in operator for multiselect attributes with two new operators: has any of (OR) and has all of (AND, default). This eliminates a semantic mismatch where in means OR for select attributes but AND for multiselect — a silent misconfiguration risk in classified environments. If OR CEL generation proves infeasible with the locked backend, ship has all of only in v1 and add has any of in a fast-follow.


The Problem

PR #35896 reuses the in operator for multiselect attributes, but the underlying logic is inverted:

Attribute Type

Expression

Operator Label

Actual Logic

Attribute Type

Expression

Operator Label

Actual Logic

Select (single-value)

user.dept in ["Eng", "Ops"]

in

OR — user's dept is Eng or Ops

Multiselect (multi-value)

"Dragon" in user.programs && "Phoenix" in user.programs

in

AND — user has Dragon and Phoenix

Same label. Opposite behavior. An admin configuring both attribute types in one policy has no way to tell them apart. In IL4/IL5 environments, this creates a data spillage or denial-of-access risk.


Proposed Solution

Operator Mapping (Simple Mode)

Attribute Type

Operator

Meaning

CEL Output

Help Text

Attribute Type

Operator

Meaning

CEL Output

Help Text

Select / Text

is

Exact single match

user.attr == "value"

Select / Text

in

Any of the values (OR)

user.attr in ["v1", "v2"]

"Matches any of the selected values"

Multiselect

has any of

User has at least one of the values (OR)

"v1" in user.attr \|\| "v2" in user.attr

"User has at least one of these values"

Multiselect

has all of

User has every one of the values (AND)

"v1" in user.attr && "v2" in user.attr

"User has all of these values"

Key Design Decisions

  1. Operator naming: "has" verb family

  • "Has all of" / "has any of" are concise (10 chars each), plain-English, and self-explanatory

  • Creates a clean two-family system: is/in for scalar attributes, has for set attributes

  • Research showed "includes" is the industry standard (Klaviyo, Amplitude) but adds a third verb family that breaks Mattermost's short-label pattern. The clarity difference is negligible.

  • Avoids the Jira anti-pattern of mapping "equals" to IN semantics

  1. Operator dropdown behavior

  • When a multiselect attribute is selected, the operator dropdown shows only has any of and has all of (not is or in)

  • When switching from a select to multiselect attribute, operator auto-resets to has any of

  • When switching from multiselect to select, operator auto-resets to is

  1. Advanced mode (CEL editor) implications

  • The CEL output is standard in membership tests — no new CEL syntax needed

  • An admin who switches to advanced mode sees "Dragon" in user.programs || "Phoenix" in user.programs — the in keyword here is CEL's native membership test, not the simple-mode in operator label

  • Switching back to simple mode: the backend visual AST parser sees ||-joined in expressions → maps to has any of; &&-joined → maps to has all of

  1. Inline plain-language summary (recommended, not required for v1)

  • Below each rule row, show a plain-English summary: "User must have any of: Dragon Spacecraft, Black Phoenix"

  • Differentiation opportunity: no competitor does this. High value for DoD admins auditing policies.


Implementation Scope

Frontend Changes (PR #35896 update)

  1. Add has any of and has all of to operator constants — new entries in the operator descriptor map

  2. Filter operators by attribute type — multiselect shows only has any of / has all of; select/text shows only is / in

  3. Update CEL generation in table_editor.tsx:

    • has all of → values joined with && (already implemented as current in behavior)

    • has any of → values joined with || (new: same pattern, different joiner)

  4. Update default operator logic — multiselect rows default to has all of

  5. Update attribute-switch handler — reset operator when crossing type boundaries

  6. Add help text — tooltip on each multiselect operator explaining the logic

Backend Changes

  • None required if the visual AST → CEL conversion already handles ||-joined in expressions

  • [VERIFY WITH ENGINEERING] Confirm that the visual AST parser can round-trip "v1" in attr || "v2" in attr back to simple mode as has any of

Fallback: Ship has all of only

If engineering confirms that OR CEL generation or round-tripping is not feasible without AST changes:

  • Ship only has all of (AND) in v1

  • Hide the operator dropdown for multiselect (only one option)

  • Add has any of in a fast-follow once backend supports it

  • This is acceptable but not preferred — it forces OR use cases to the CEL editor


What This Looks Like

┌─────────────────────────────────────────────────────────┐ │ Access Rules [All attributes required ▼] │ │ │ │ ┌──────────────┐ ┌────────────┐ ┌─────────────────────┐ │ │ │ Program ▼ │ │ has any of▼│ │ Dragon ✕ Phoenix ✕│ │ │ └──────────────┘ └────────────┘ └─────────────────────┘ │ │ ℹ️ User must have any of: Dragon Spacecraft, Black Phoenix │ │ │ │ ┌──────────────┐ ┌────────────┐ ┌─────────────────────┐ │ │ │ Clearance ▼ │ │ is ▼ │ │ Top Secret │ │ │ └──────────────┘ └────────────┘ └─────────────────────┘ │ │ │ │ + Select user attribute │ └────────────────────────────────────────────────────────────────┘

Operator Dropdown (when multiselect attribute selected)

┌─────────────┐ │ has any of │ ← "User has at least one of these values" │ has all of │ ← "User has all of these values" └─────────────┘

Cheatsheet Update

Add to the Expression Syntax Cheatsheet modal:

Operator

Meaning

Attribute Type

Example

Operator

Meaning

Attribute Type

Example

is

Exact match

Select / Text

user.clearance == "Top Secret"

in

Any of the values

Select / Text

user.dept in ["Eng", "Ops"]

has any of

Has at least one value

Multiselect

"Dragon" in user.programs \|\| "Phoenix" in user.programs

has all of

Has all values

Multiselect

"Dragon" in user.programs && "Phoenix" in user.programs


Risk Register

Risk

Likelihood

Impact

Mitigation

Risk

Likelihood

Impact

Mitigation

Admins confuse has any of with in (both are OR)

Low

Low

Different verb family signals different attribute type. Tooltip clarifies.

OR CEL round-trip fails with locked backend

Medium

High

Verify with engineering before implementation. Fallback: ship AND-only.

Operator dropdown truncates on narrow viewports

Low

Low

"Has all of" / "has any of" are 10 chars — shorter than "includes" variants.


Open Items

  1. [VERIFY WITH ENGINEERING] Can the visual AST parser round-trip "v1" in attr || "v2" in attr to has any of in simple mode?


Appendix: Alternative — Single "has" Operator with One Value Per Row

Description

An alternative was evaluated: use a single has operator for multiselect attributes, restricted to one value per row. Admins would express AND logic by adding multiple rows with the same attribute (joined by the global "All attributes required" toggle), and OR logic by switching the global toggle to "Any 1 attribute required."

Example — "User must have Dragon AND Phoenix" (global = All attributes required):

[Program] [has] [Dragon] [Program] [has] [Phoenix]

Pros

  • Simpler operator vocabulary: One operator (has) instead of two. Nothing to learn.

  • Simpler value picker: Single-value select instead of multi-value chip picker.

  • Trivial CEL round-trip: Each row maps to exactly one "value" in attr expression. No compound pattern recognition needed in the parser.

  • Simpler mental model (narrow case): "Each row is one check. The global operator combines them."

  • No backend changes: Works with existing CEL generation and AST parsing.

Cons (including fatal flaw)

  • Fatal composability flaw — cannot express mixed-logic policies:
    The global logical operator (AND/OR) applies to ALL rows. When an admin needs AND between multiselect rows but OR within another attribute (or vice versa), this approach breaks:

Policy Intent

Approach A (recommended)

Single "has"

Policy Intent

Approach A (recommended)

Single "has"

"Has ANY of [Dragon, Phoenix] AND Clearance is Top Secret"

[Program] [has any of] [Dragon, Phoenix] + [Clearance] [is] [Top Secret], global AND. Works.

[Program] [has] [Dragon] + [Program] [has] [Phoenix] + [Clearance] [is] [Top Secret], global AND = Dragon AND Phoenix AND Top Secret. Wrong — requires both programs instead of either. Global OR = Dragon OR Phoenix OR Top Secret. Also wrong. No valid configuration exists.

"Has ALL of [Dragon, Phoenix] OR Dept is Engineering"

[Program] [has all of] [Dragon, Phoenix] + [Dept] [is] [Engineering], global OR. Works.

[Program] [has] [Dragon] + [Program] [has] [Phoenix] + [Dept] [is] [Engineering], global OR = Dragon OR Phoenix OR Engineering. Wrong — loses the AND between Dragon and Phoenix.

These are common policy patterns in defense environments (e.g., "must be read into any of these compartments AND hold TS/SCI"). Forcing admins to the CEL editor for routine policies defeats the purpose of simple mode.

  • Row proliferation: An "all of 5 values" policy requires 5 rows instead of 1, making the rule table harder to scan and audit. At scale (10+ multiselect values across multiple attributes), the table becomes unwieldy.

  • Breaks existing multi-value pattern: Select attributes already support in with multiple values in a single row. Restricting multiselect to single-value rows is an inconsistency that will confuse admins.

  • AND/OR logic is spatially separated from data: The admin must look at the global toggle (top of the table) to understand the relationship between rows. With has all of / has any of, the intent is self-documenting within the row itself.

Decision

Rejected. The composability flaw is disqualifying. A simple mode that cannot express "has any of X values AND some other condition" — one of the most common real-world policy patterns — forces admins into the CEL editor for routine work. The implementation simplicity gains do not justify the expressiveness loss for DoD system admins managing classified channel access.