Nick MisasiandCursor Agent c7eff70026 ABAC: plugin-keyed resource types, trusted plugin PAP/CEL APIs, and AuthZEN-style decision API (#37509)
* MM: add v0.5 plugin access control policy model, registry, and decision outcomes

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: add plugin access control PDP/PAP app-layer methods with fail-closed semantics

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: expose plugin access control API surface (EvaluateAccessControl + PAP/CEL methods)

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: add store-layer round-trip tests for v0.5 plugin access control policies

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: extract plugin access control app code into plugin_access_control.go

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: add atomic type-guarded AccessControlPolicyStore.DeleteIfType

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: plugin PAP hardening — atomic typed delete, indistinguishable 404s, audit every attempt

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: close plugin Get-by-ID TOCTOU via GetPolicyOfType; stamp save audit operation at entry

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Fix gob RPC poisoning from native attribute select options

NativeUserAttributeFields stored bool-select options as
[]map[string]string inside PropertyField.Attrs (map[string]any). gob
requires concrete types inside interface values to be registered, and
[]map[string]string is not registered in client_rpc.go, so encoding the
GetAccessControlFieldsAutocomplete reply failed and net/rpc shut down
the shared plugin API connection, breaking every subsequent plugin API
call.

Build the options from gob-registered containers ([]any/map[string]any)
instead; JSON output is byte-identical. Add gob round-trip regression
tests covering every plugin access control API reply payload: the
autocomplete response including native attribute fields (fails against
the old code), policies with JSON-decoded Props, visual AST condition
values of every runtime shape, expression check errors, query users
responses, and evaluation decisions.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Move plugin access control gob-safety tests into their own file

Pure move: plugin_access_control_test.go crossed 1000 lines; the gob-safety
helper and TestPluginAccessControlGobSafety now live in
plugin_access_control_gob_test.go, unchanged.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* MM: resolve plugin policy existence when ABAC is unavailable (Option B)

Every evaluation-impossible branch of EvaluatePluginAccessRequest
(service nil / unlicensed / flag off / user load or subject build
failure / evaluator infra error / unknown outcome) now performs a raw
open-core store read on the already-validated resource ID: no stored
row returns no_policy so the caller can safely apply legacy behavior;
any stored row (with a Warn on a foreign-type anomaly) or a failed
read returns unavailable so the caller must fail closed. This lets the
plugin drop its local policy index entirely.

Strengthens the EvaluateAccessControl doc contract accordingly and
reworks the fail-closed test matrix with with/without-row splits per
branch, a foreign-type-row case, a store-read-error case on the store
mock, and passthrough rows pinning that the fallback read never runs
when the evaluator answers.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Clarify EvaluateAccessControl failure-mapping doc

A failure with a definitive store miss maps to no_policy under the
Option B semantics, so 'failures never map to allow or no_policy' was
inaccurate. State precisely: never allow; no_policy only on positively
determined non-existence; deny for defensive failures on a resolved
policy; unavailable otherwise.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Tighten ABAC comments

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Document AccessDecision.Outcome as plugin-API-only

The evaluator populates Outcome on every lane, but the only production
reader is the app layer's EvaluatePluginAccessRequest, which maps it
into PluginAccessControlDecision; core channel/team enforcement reads
the collapsed Decision bool alone. State that on the field.

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Retrigger CI to rebuild enterprise image with updated enterprise branch

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* Document that only the evaluator's plugin lane sets AccessDecision.Outcome

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: key plugin resource types as plugin_id:type and drop the static registry

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: replace AccessDecision.Outcome with the AuthZEN decision context reason

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: drop type-scoped policy get/delete and check the type in the app layer

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: compare plugin policy type ownership exactly instead of case-insensitively

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: bound the whole policy type to the Type column width

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: require an allow before treating a decision as the no-policy fallback

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: treat a colliding foreign-type policy row as no_policy, not a deny

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: gate plugin policy reads on a raw store read before normalization

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: pin policy type immutability on save in the store tests

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: reuse a single unavailable-error constructor in the existence fallback

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: re-check plugin policy ownership on the normalized get read

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

* ABAC: confirm plugin policy ownership before surfacing a normalization error

Co-authored-by: nick.misasi <nick.misasi@mattermost.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-04 09:59:48 -04:00
2026-07-21 13:10:25 -04:00
2018-05-30 10:23:25 -04:00
2026-04-01 13:03:36 +00:00

Mattermost logo

Mattermost is an open core, self-hosted collaboration platform that offers chat, workflow automation, voice calling, screen sharing, and AI integration. This repo is the primary source for core development on the Mattermost platform; it's written in Go and React, runs as a single Linux binary, and relies on PostgreSQL. A new compiled version is released under an MIT license every month on the 16th.

Deploy Mattermost on-premises, or try it for free in the cloud.

mattermost user interface

Learn more about the following use cases with Mattermost:

Other useful resources:

Table of contents

Install Mattermost

Other install guides:

Native mobile and desktop apps

In addition to the web interface, you can also download Mattermost clients for Android, iOS, Windows PC, macOS, and Linux.

Get Mattermost on Google Play Get Mattermost on the App Store Get Mattermost on Windows PC Get Mattermost on Mac OSX Get Mattermost on Linux

Get security bulletins

Receive notifications of critical security updates. The sophistication of online attackers is perpetually increasing. If you're deploying Mattermost it's highly recommended you subscribe to the Mattermost Security Bulletin mailing list for updates on critical security releases.

Subscribe here

Get involved

Learn more

License

See the LICENSE file for license rights and limitations.

Get the latest news

Contributing

Small Image

Please see CONTRIBUTING.md. Join the Mattermost Contributors server to join community discussions about contributions, development, and more.

S
Description
Mattermost is an open source platform for secure collaboration across the entire software development lifecycle..
Readme
3.8 GiB
Languages
TypeScript 48.7%
Go 40.1%
JavaScript 6.4%
SCSS 2.5%
HTML 1.9%
Other 0.2%