* Update docs-impact-review workflow with improved configuration
- Include PR head SHA in concurrency group to avoid cancelling concurrent runs on different commits
- Move permissions to workflow level
- Remove Docs/Not Needed label skip condition from job if clause
- Upgrade model to claude-sonnet-4-20250514 with increased max-turns (30→50)
- Add Bash(ls*) to allowedTools
- Add bug-fix pattern to no-docs-needed list
- Refine security fix rule to skip docs unless externally observable contract change
- Guard label addition behind !analysisFailed check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Revert structural changes from #37084, keep prompt improvements
Reverts the concurrency group SHA addition, permissions restructure,
model/max-turns/tool changes, and label guard from #37084 as they are
not needed.
Keeps only the meaningful prompt changes:
- Remove Docs/Not Needed label skip from job if condition
- Add bug-fix pattern to no-docs-needed list
- Refine security fix rule to skip docs unless externally observable contract change
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Restore Docs/Not Needed label skip condition
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Update docs-impact-review workflow
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* [MM-69506] Preserve permission rule fields on validation error
The channel permission rule editor wiped all field values (conditions,
permissions, role) whenever a validation error was surfaced on save for
a new rule. The editor re-seeded its draft from an `initial` prop via an
effect keyed on that prop's identity; for a new rule the parent built a
fresh `initial` object on every render, so the `setFormError` re-render
triggered the effect and reset the draft.
Give the editor a stable React key so it remounts only when switching
rules, and seed the draft once via the state initializer instead of a
re-seed effect.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* [MM-69506] Add regression test for permission rule field preservation
Covers the channel permission rule editor: a failed save (empty name)
surfaces the validation error while preserving the role, conditions
expression, and selected permissions, and a valid save commits the rule
to the list. The first test fails against the pre-fix behavior.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* [MM-69506] Expand permission rule editor test coverage
Add guard tests for editor remount-on-reopen reseeding defaults and for
preserving in-progress edits to an existing rule on validation failure
(covering the non-404 policy load branch), and tighten assertions per
test-quality review.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* [MM-69506] Tighten seed-once comment in permission rule editor
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add direct message support to mmctl post create
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Regenerate mmctl docs for post create direct messages
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Strengthen mmctl post create direct message test coverage
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Document why local mmctl client cannot send direct messages
Add a test comment explaining that local mode lacks the post-create,
direct-channel, and current-user API endpoints required by post create.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add local mode API support for mmctl post create
Implement local mode handlers for POST /posts and POST /channels/direct,
and add --user flag to mmctl post create for specifying the acting user
in local mode instead of relying on GET /users/me.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Address CodeRabbit feedback and regenerate mmctl docs
- Defer WriteHeader in localCreatePost until after burn-on-read handling
- Preserve prior viper local state in post create tests
- Regenerate mmctl docs for --user flag
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Address PR feedback: 2 answered, 3 resolved, 0 declined
* Reset mmctl unit test config state
* Address PR feedback: 3 answered, 1 resolved, 0 declined
* Address PR feedback: 1 answered, 1 resolved, 0 declined
* Retrigger CI after transient Enterprise FIPS proxy.golang.org failure
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Merge local-mode API tests into their parent test functions
Fold TestLocalCreateDirectChannel into TestCreateDirectChannel and
TestLocalCreatePost into TestCreatePost as local-mode subtests, per
reviewer feedback to consolidate the local-mode coverage with the
existing create tests.
* Revert local mode support for mmctl post create
Reverts 20a2b1c per reviewer feedback: remove the local-mode POST /posts
and POST /channels/direct API handlers, the --user flag, and the associated
audit events. mmctl post create now errors out when run with --local instead
of attempting to create posts in local mode.
* Retrigger CI after transient Enterprise FIPS npm cache failure
The Enterprise CI/tests failure on 8d04b5c was caused by an npm
EEXIST cache error during webapp node_modules install — unrelated to
this PR's mmctl changes.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* [MM-69528] Enable feature flags for ranked attributes, permission policies and masking
Change the default value to true for AttributeValueMasking,
PermissionPolicies, ChannelPermissionPolicies, PolicySimulation and
PropertyFieldRank, and update the unit tests and a stale comment that
pinned the old defaults.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Fix access control tests for feature flags enabled by default
Tests that assumed AttributeValueMasking, PermissionPolicies, and
PolicySimulation were off by default now explicitly disable those flags
in setup or use SetReadOnlyFF(false) before runtime UpdateConfig calls.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add regression test for PropertyFieldRank default
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Disable masking in store-mock tests that assume flag off
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Fix store-mock masking helper without UpdateConfig
UpdateConfig triggers config persistence listeners that call
Store.Post() on the mock store. Mutate feature flags in place instead.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Fix masking-off deactivation test for new flag default
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Fix Setup/InitBasic compile errors in access control tests
Pass testing.TB to Setup and InitBasic after removing redundant
feature-flag SetupConfig wrappers.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Restore ABAC feature-flag defaults in test cleanup
Defer blocks in access_control_test.go were resetting PermissionPolicies,
ChannelPermissionPolicies, and PolicySimulation to false after subtests,
leaving the shared TestHelper in a partially-disabled state. With these
flags now defaulting to true, cleanup should restore the default-enabled
baseline instead.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
The Recaps sparkle icon had an extra opacity: 0.64 on top of its
color-based alpha (rgba(..., 0.64)), making it ~0.41 effective opacity
and noticeably dimmer than the Threads/Drafts icons. Remove the redundant
opacity so the icon matches the other sidebar items, and drop the now
dead opacity: 1 override on the unread-title state.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* MM-67755: WYSIWYG editor for message composition
- Add TipTap-based WYSIWYG editor as an opt-in setting
- Implement formatting bar with text styles dropdown, link popover
- Add custom list extension for Mattermost markdown compatibility
- Add suggestion list integration for mentions and emoji
- Add feature flag and user preference toggle
- Update e2e tests for WYSIWYG editor compatibility
Made-with: Cursor
* Fix package versions to match current master (11.7.0)
Made-with: Cursor
* Add missing PermissionPolicies feature flag from master
Made-with: Cursor
* Fix remaining WYSIWYG UX issues: toolbar overlap, autocomplete, emoji, tables
Made-with: Cursor
* Address CodeRabbit review: null guards, XSS fix, e2e tests, constants alignment
Made-with: Cursor
* UX fixes required by Matt
* linter
* fix e2e
* Fix CI failures: resolve merge conflicts with master
- Fix TS errors from useRewrite hook refactor (additionalControl → rewriteMenuProps)
- Fix onComposition → onCompositionUpdate prop rename on Textbox
- Remove accidentally re-added enzyme-to-json/serializer from jest config
- Extract new i18n strings for WYSIWYG editor components
Made-with: Cursor
* Fix lint: remove unused aiRewriteEnabled and rewriteMenuProps vars
Made-with: Cursor
* Fix jest and E2E test failures
- Add lowlight and ESM deps to jest transformIgnorePatterns
- Replace have.value with have.text for contenteditable elements
- Remove selectionStart/selectionEnd assertions for WYSIWYG editor
Made-with: Cursor
* e2e test
* Expose focus()/blur() on WysiwygEditor handle so focus hooks work
useTextboxFocus drives focus into the composer for many flows (channel
switch, RHS open, post-submit refocus, Reply shortcut, "type to focus
main input"). It calls textboxRef.current?.focus(), but textboxRef is
the legacy <Textbox> ref and is null when the WYSIWYG editor is the
mounted composer, so every focus call becomes a silent no-op.
Add focus() and blur() to WysiwygEditorHandle, backed by editor.commands
.focus()/blur(), and pass wysiwygRef into useTextboxFocus so it picks
whichever ref is mounted. The hook keeps its existing signature for
legacy callers; wysiwygRef is optional.
Verified locally on the WYSIWYG branch:
- messaging/focus_move_spec (3/6 failing -> 6/6 passing)
- messaging/message_edit_post_clear_text_spec (0/1 -> 1/1)
- messaging/message_edit_post_history_spec (0/3 -> 1/3)
- keyboard_shortcuts/dot_menu_spec gets past the Reply-focus assertion
Co-authored-by: Cursor <cursoragent@cursor.com>
* e2e: coerce postMessage args to string in WYSIWYG branch
The legacy textarea path used cy.invoke('val', message) which silently
coerced numbers/undefined to strings. The WYSIWYG branch added in the
previous refactor calls message.replace() and crashes with
"TypeError: message.replace is not a function" whenever a spec passes a
non-string value, e.g. cy.uiPostMessageQuickly(0) or before-each hooks
that pass undefined.
Funnel everything through asPostMessage() so the WYSIWYG branch is just
as forgiving as the textarea branch. Loosen postMessage /
postMessageReplyInRHS / uiPostMessageQuickly typings to `unknown` to
match what callers actually pass.
Fixes failures in: copy_post_text_spec, save_post_spec,
search_filter/{after,before,future_date}_spec, and
scroll/default_images_collapsed_spec.
Co-authored-by: Cursor <cursoragent@cursor.com>
* filtetr by feature flag for now
* coderabbit ai feedback
* coderabbitai comments
* align with code conventions
* fix e2e test
* PR comments
* fix i18n
* anchor link popover to editor selectio
* UX issues
* regression
* Final UX feedback
* linter
* e2e test rename
* Final UX
* Fix playwright lint
* Align e2e mocks with master
* Disable feature flag
* Sanitize urls before handling actions with link popove
---------
Co-authored-by: Nevyana Angelova <nevyangelova@192.168.100.47>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* [MM-26508] Fix SetJobWarning not decrementing active job metric
SetJobWarning was the only terminal-state job setter that did not call
DecrementJobActive, causing a permanent metrics leak in the
mattermost_jobs_active gauge for any job completing with warnings
(message_export, and soon LDAP sync).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add missing metrics mock expectations to TestSetJobWarning
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Enforce single DecrementJobActive call in TestSetJobWarning
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* Fix missing return after c.Err in api4 handlers
Two handlers set c.Err but omitted a return, allowing subsequent code
to execute with an error already signalled:
- getJobs: invalid status passed to GetJobsByTypesAndStatuses DB query
- validateOutgoingOAuthConnectionCredentials: auditRec.Success() and
ReturnStatusOK called even when token retrieval failed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Drop redundant w.WriteHeader in error branch
c.Err being set is sufficient; the framework writes the error response
after the handler returns. Calling w.WriteHeader explicitly would cause
a double-write.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Remove unused resultStatusCode variable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add integration test for getJobs with invalid status param
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix inconsistent error assertion in validate test
The invalid-credentials test was the only error-path check in the file
using httpRecorder.Code. All other error cases check c.Err.StatusCode,
which is consistent with the framework pattern (c.Err drives the HTTP
response; handlers do not write it directly).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Add API-layer assertion to invalid validate test
The test previously only checked c.Err.StatusCode (internal handler
state). A regression that sets c.Err but fails to write the HTTP error
response would go undetected. Now the test also calls the endpoint
through the full API layer and asserts the HTTP response is not 200.
Mock matchers changed to mock.Anything so the expectation matches both
the direct handler call and the API-layer call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix non-clickable links on SAML system console page
Render the W3C specification URLs in the Signature Algorithm and
Canonicalization Algorithm dropdown help text as clickable markdown
links by enabling help_text_markdown on those options.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add test for dropdown option markdown help text rendering as links
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Improve dropdown help text tests with negative case and shared helpers
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Guard SAML help link fix with definition test and exercise descriptor path
Add admin_definition_saml_help_links test asserting the SAML signature
and canonicalization dropdown options carry help_text_markdown plus
markdown link syntax, so a revert of the fix fails. Render the dropdown
help-text tests through MessageDescriptor help text to match the
production FormattedMarkdownMessage path.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Derive dropdown setting type locally to satisfy type check
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Fix Quarantine for Review modal overflow with many attachments
Constrain the GenericModal wrapper to a flex column capped at 90vh so the
header and footer stay pinned inside the modal while the body (post preview
with its attachments) scrolls, instead of overflowing the modal boundary.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Satisfy stylelint property order in flag post modal styles
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
The `prettier@2.3.2` devDependency in webapp/channels has been unused for
the entire visible history of this repo. The channels webapp formats code
via ESLint (the `fix` script runs `eslint --fix` and `stylelint --fix`),
not prettier: there is no prettier config file, no npm script invoking it,
and no ESLint integration (e.g. eslint-config-prettier). It was already an
orphaned, script-less devDependency at the monorepo-creation commit
(c943ed6859, "Mono repo -> Master").
Prettier remains in use elsewhere via separate, self-contained setups
(e2e-tests/playwright pins its own prettier 3.x; some GitHub Actions use
`npx prettier`); none of them reference this channels devDependency.
Remove the dependency from webapp/channels/package.json and prune its
entries from webapp/package-lock.json (the channels devDep reference and
the node_modules/prettier package block). prettier has no dependents in
the lockfile, so no other entries are affected.
prettier dep was originally introduced into mattermost-webapp in PR 5743.
https://github.com/mattermost/mattermost-webapp/pull/5743
Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* Mattermost Blocks
* Rethink some block props and styles
* Remove obsolete comment
* Style fixes and add examples
* Add mention, search, and image metadata support
* Several UI improvements
* Validate blocks by translating them
* Add initial e2e tests
* Fix lint
* Fix tests and lint
* Fix lint
* Improve e2e and simplify doPostAction
* server side cleanup
* Fix typo
* Fix style
* Fix some tests
* Fix more tests
* Fix cypress tests
* Fix playwhright tests
* Fix flaky system console test
* Frontend cleanup
* Add blocks editor
* Fix CI
* Limit all blocks width
* Fix test
* Enable webhook service on playwhright CI
* fix flaky test
* Fix style
* Cleanups
* Address coderabbit comments
* Address coderabbit comments
* Address CI errors
* Fix tests
* Address changes in valid actions
* UX fixes
* Fix test
* Fix danger buttons and add allow emojis in buttons
* style tweaks
use semantic color tokens for buttons and accents, update max-heights for scollables, adjustments to containers, removed btn-sm (using default button size for mm blocks with height and padding adjustments for use within blocks. removed hover selector from utils to prevent hover state issue with primary button, refined semantic-color-warning.
* Address feedback
* Add interactive content to post previews
* Add collapse transitions
* Address autocomplete position
* Handle columns within column sets
* Fix css lint
* Fix tests
* Use feature flag
* Address feedback
* Fix lint and add missing tests
* Fix e2e tests
* Fix e2e test
* Allow interactive posts without a message
* Fix lint
* Address feedback
* Fix ci
* Fix lint
* Add limits to block translations
* Fix lint
* Address feedback
* Address feedback
* Update snapshot
* Fix collapsible not defaulting to the right value
* Add total text limit
* Sync translations with mobile
* Fix snapshot
---------
Co-authored-by: Matthew Birtch <mattbirtch@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* MM-69172 Ensure note on post preview is always displayed for DM channels
* Replace snapshot tests for direct and group messages
* Fixed typos caused by last minute change
* Add CI check to prevent renumbering or renaming existing DB migrations
Backporting or rebasing a PR can accidentally change the sequence number
or description of a migration that already shipped on master, which
corrupts the upgrade path for existing installations (see MM-68848).
This adds a migration_check tool that compares the working tree's
migration files against the base branch and fails when an existing
migration's version or name differs. Brand new migrations are ignored.
It is wired into the existing "Check migration files" CI job via a new
`make check-migration-changes` target.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Apply go fix strings.SplitSeq in migration_check
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Retrigger CI after transient Enterprise npm failure
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Use github.ref_name as migration check base ref fallback on push
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Flag shipped migrations missing from branch by version and name
Add reverse comparison so deletions and simultaneous renumber+rename are
caught, per CodeRabbit review feedback.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Address PR feedback: 0 answered, 2 resolved, 0 declined
* Address PR feedback: 2 answered, 1 resolved, 1 declined
* Fix migration check direction and scope to release branches
Address isacikgoz review feedback:
- Reverse the comparison so it flags migration files the branch HAS that
the base branch (origin/master) does NOT, instead of flagging base
migrations missing from the branch. A backport branch is an older subset
of master, so the old direction reported every newer master migration as
an error.
- Include the up/down kind in the comparison key so a one-sided rename of
only the .up or .down file is no longer masked by its surviving partner.
- Restrict the CI step to PRs targeting release-* branches, where the head
is expected to be a subset of master; on master-targeted PRs new
migrations are normal and would otherwise be flagged as stray.
* Scope migration check to PR-added Postgres migrations
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Fix Max Users Per Team description to reflect active-only enforcement
The System Console description for TeamSettings.MaxUsersPerTeam incorrectly
stated that inactive users count toward the limit. Enforcement only counts
active team members with active user accounts, so update the help text to
match actual behavior.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Simplify Max Users Per Team description per review feedback
Update help text to remove mention of removed members, per hanzei's
review suggestion.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Include team membership data in user CSV export
Add a Teams column to the System Console user CSV export so that the
teams each user belongs to are included in the exported data.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add tests for team membership data in user CSV export
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Strengthen tests for user CSV export team membership
Cover ordering, soft-deleted team/membership exclusion, exact CSV header
order, and report row column positions.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* [MM-69328] Preserve option ranks across property field type changes
Non-rank property fields no longer strip rank values from their options,
so converting a field rank -> select -> rank keeps the original ordering.
On conversion into rank, arbitrary option ranks (missing, duplicated, or
non-sequential) are renumbered to a clean, gap-free 1..N sequence that
preserves relative order. Directly authoring a rank field still requires
valid ranks, and that validation now runs on every rank path as the single
source of truth so invalid rank data is never persisted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* [MM-69328] Preserve values across select<->rank type changes
select and rank store values in the same format (a single option-ID
string), so TypeChangeValueCleanupHook now skips cleanup when
transitioning between the two types.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* [MM-69328] Construct fresh opts per subtest in cleanup hook test
Shared opts were mutated in place by sanitizeAndValidateOptions during
field creation, so the second subtest was seeing the already-processed
canonical form instead of the original input.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* [MM-69351] Fix membership store queries for users without AttributeView rows
Native user attributes resolve against the Users table, so a policy can now
match users who have no row in the AttributeView materialized view. Two latent
assumptions in attributes_store.go broke for such users:
- SearchUsers ordered by Users.Id but paginated with a cursor on the
LEFT-JOINed AttributeView.TargetID, which is NULL for users with no custom
attributes. The membership sync always seeds a cursor, so it silently added
zero members while the Test modal (no cursor) showed the full match set.
Page on Users.Id instead.
- GetChannelMembersToRemove / GetTeamMembersToRemove did not join Users (native
expressions failed to resolve) and removed any member lacking an AttributeView
row via "OR AttributeView.TargetID IS NULL". Join Users and drop that clause;
NOT COALESCE(expr, FALSE) already removes non-matching members, while letting
attribute-less users who satisfy a native policy stay. Member SELECT columns
are table-qualified to avoid ambiguity with the joined Users columns.
Adds store regression tests covering an attribute-less user paged by SearchUsers
and kept by both members-to-remove paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
* [MM-69351] Skip file-attachment sanitization when there is no requesting user
The ABAC membership sync adds members in a background job with no session, and
the resulting channel-join system posts flow through CreatePost ->
SanitizePostMetadataForUser(rctx, post, rctx.Session().UserId) with an empty
user id. That made sanitizeFileAttachmentsForUser call GetUser("") and log
"Failed to get user for file attachment sanitization" once per added member.
There is no reader to sanitize for in that path, so return early when userID is
empty. A genuine reader re-runs sanitization with their own session id when the
post is served, so download enforcement is unaffected.
Co-authored-by: Cursor <cursoragent@cursor.com>
* store mocks
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
The GetAllSessionsWithActiveDeviceIds method added in PR #36945 was
placed after GetSessionsWithActiveDeviceIds in the generated files, but
the code generator sorts methods alphabetically. "GetAll..." (A) sorts
before "GetLRU..." (L) and "GetSessions..." (S), so the method must
appear before GetLRUSessions in retrylayer.go, timerlayer.go, and
mocks/SessionStore.go.
This was causing the Server CI check-store-layers and check-mocks steps
to fail on master.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix feature discovery Learn more links to point to corresponding docs pages
The auto-translation and Mobile Ephemeral Mode feature discovery upsells
linked their Learn more button to the generic docs.mattermost.com landing
page instead of the corresponding feature documentation. Point them at the
specific docs pages so each feature leads to its own documentation.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Expand auto-translation feature discovery test coverage
Assert the rendered body copy and feature image in addition to the
Learn more docs link, for parity with sibling feature discovery tests.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add test coverage for Mobile Ephemeral Mode learn more URL
Assert the feature discovery config points at the mobile-security docs
page, mirroring the auto-translation test coverage pattern.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* sends wipe signal ro mobile devices when revoking user sessions
there is a session notification type that can be used with no content
to indicate the session has been revoked and data should be wiped client
side. This complements the use of session typed notifications to indicate
expiry of user sessions carrying containing some message.
empty push session typed notifications are sent to mobile devices on
revoking sessions only when mobile ephemeral mode is enabled.
* move send wipe push notifications to goroutines
* wraps goroutine launch in Srv().Go() for proper shutdown
* query active sessions to wipe only when ephemeral mode is enabled
* address review comments
* guard to prevent sending wipe notification to removed tokens
Add synthetic PropertyField descriptors for the native user attributes
(email/verified/isbot/createat) and prepend them to the access-control fields
autocomplete on the first page. Booleans reuse the session-attribute true/false
select pattern; createat advertises only the youngerThanDays operator. Fields
are marked native via Attrs so editors build user.<name> rather than
user.attributes.<name>.
Co-authored-by: Cursor <cursoragent@cursor.com>
Skipping the "Should preserve file attachments and edit history when
keeping flagged post" subtest while the root cause is investigated
under MM-69511.
Tests-only change.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Fix operator symbol hover color in channel permissions policy editor
The TableEditor operator selector button in the Channel Settings >
Permissions Policy rule editor fell back to the global primary-button
hover (blue background, white label) because the gray-hover override
applied by the Membership Policy and System Console editors was missing
on the permissions-policy expression wrapper. The operator glyph keeps
its hard-coded gray colour, so the '≥' symbol looked mismatched against
the white text on hover.
Scope the same .table-editor__cell button override (center-channel-color
text + subtle gray hover) to the permissions-policy expression section so
the hover state matches the rest of the policy editors.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Address PR feedback: 1 answered, 1 resolved, 0 declined
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add tests for channel member role scope validation
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Restrict channel member roles to channel scope
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Expand channel member role validation tests
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Use exact built-in role ID matching for channel member scope validation
Replace prefix-based GetBuiltInRoleScope with a map of known built-in role
IDs so custom roles with team_/system_ prefixes are not misclassified.
Also fix golangci modernize lint by using strings.FieldsSeq.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Simplify channel member role validation
- Remove GetBuiltInRoleScope function and builtInRoleScopes map
- Replace with direct check against channelScopedBuiltInRoles set
- Add isBuiltInRole helper to check if role is built-in
- Update app layer to use IsValidChannelMemberRoles function
- Remove TestGetBuiltInRoleScope test (function no longer exists)
This simplifies the validation by only defining the channel-scoped
roles we need to check against, rather than maintaining a full map
of all built-in roles and their scopes.
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Fix golangci-lint: use slices.Contains in isBuiltInRole
Replace manual loop with slices.Contains for better performance
and to satisfy the modernize linter rule.
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Remove channelScopedBuiltInRoles map, check roles directly
Simplify IsValidChannelMemberRoles by directly checking against the
3 channel role constants instead of maintaining a separate map.
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Use role.BuiltIn property instead of isBuiltInRole helper
- App layer now uses role.BuiltIn directly since it has the role object
- Model layer checks BuiltInSchemeManagedRoleIDs inline without helper
- Removed isBuiltInRole helper function entirely
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Fix dual-layer drift in channel member role validation
Use MakeDefaultRoles/role.BuiltIn as the single source of truth for
built-in role detection. Introduces IsChannelScopedBuiltInRole and a
lazy builtInRoleSet so both the model (IsValidChannelMemberRoles) and
the app layer (updateChannelMemberRolesInternal) share one allow-list.
Closes the system_custom_group_admin gap: it has BuiltIn=true but was
absent from BuiltInSchemeManagedRoleIDs, so the model layer silently
passed it while the app layer correctly rejected it. Now both layers
reject it consistently.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix builtInRoleSet discriminant to use BuiltInSchemeManagedRoleIDs
The previous commit derived the built-in role set from MakeDefaultRoles()
role.BuiltIn, which caused custom_group_user (BuiltIn=false, for unrelated
WebSocket broadcast-scope reasons) to be treated as a custom role and pass
IsValidChannelMemberRoles, contradicting the API-layer test.
Fix:
- Add SystemCustomGroupAdminRoleId to BuiltInSchemeManagedRoleIDs (the
original gap that started this work)
- Derive builtInRoleSet from BuiltInSchemeManagedRoleIDs, which correctly
covers both custom_group_user and system_custom_group_admin
- Revert custom_group_user model-test expectation to valid: false, now
consistent with the API integration test
Co-authored-by: Cursor <cursoragent@cursor.com>
* Build builtInRoleSet in init() instead of sync.OnceValue
* Align app-layer channel role check with model predicate
Introduce model.IsBuiltInRole so IsValidChannelMemberRoles (API/model) and
updateChannelMemberRolesInternal (app) share one source of truth for which
roles are built-in. The app layer previously keyed off role.BuiltIn, which is
false for custom_group_user, so plugin/bulk-import callers bypassing the API
check could assign it as a channel member role. Also correct the comments
that mislabeled BuiltInSchemeManagedRoleIDs as all scheme-managed.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
* Fix extra gap at bottom of Add Permission Rule modal
The permission rule editor view reused the list view's padding-bottom: 60px,
which exists only to clear the position: fixed SaveChangesPanel. The editor
renders its Cancel / Add rule buttons inline and has no fixed panel, so the
reserved space showed up as an empty gap below the action buttons.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* ci: re-trigger Enterprise CI after transient npm network failure
Enterprise CI/tests failed with npm ECONNRESET during node_modules install,
unrelated to this CSS-only change. Re-triggering pipelines.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Remove explanatory comment per review feedback
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* [MM-69464] Fix data race in pluginapi.ConfigureLogrus
ConfigureLogrus registered the hook via logger.Hooks.Add, which mutates
the hook map without holding the logger mutex. logrus copies that map
under the mutex when firing hooks, so configuring the logger while another
goroutine logs through it is a data race that can panic with "concurrent
map read and map write". This is reachable when a plugin re-runs its
activation while goroutines from a prior activation still log through
logrus.StandardLogger() (originally reported as MM-52096).
Use logger.AddHook, which acquires the logger mutex. Also configure the
passed-in logger instead of the global standard logger: SetReportCaller
and SetLevel previously called the package-level logrus functions, silently
mutating logrus.StandardLogger() regardless of the logger argument.
Adds a -race regression test that configures the logger concurrently with
logging.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Use WaitGroup.Go in the regression test (golangci modernize)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Remove obvious comment on SetReportCaller
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restrict OAuth deauthorization and personal access token lifecycle
actions to direct user sessions, denying delegated OAuth app tokens,
consistent with the existing OAuth authorize and access token creation
handlers. Adds regression tests covering the OAuth-session case.
Co-authored-by: Cursor <cursoragent@cursor.com>
Native user attributes (user.email/verified/isbot/createat and the
youngerThanDays helper) describe the requester themselves, not who they can
include, so they must not gate the self-inclusion / requester validation
query. Add SubjectSearchOptions.ExcludeNativeAttributes and set it from
ValidateExpressionAgainstRequester so only the CPA parts are validated
against the saving admin. The actual stripping lives in the enterprise PDP.
Co-authored-by: Cursor <cursoragent@cursor.com>
Exclude AI-generated posts from consecutive-post collapsing so each
agent message keeps a visible header and sparkle badge. Also simplify
the badge render condition to always show the indicator for AI posts
in the badges area when appropriate.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
* [MM-69366] Scope property field lookups by object type
Add GetFieldByNameForObjectType and route the access-control attribute
lookups through it, so a user custom profile attribute is no longer
confused with the internal classification fields that share its name.
Deprecate the name-only GetFieldByName (kept only for the plugin API)
and move internal callers onto the scoped variant.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Add test store mock expectations for GetFieldByNameForObjectType
The startup migrations now look up fields via the scoped method, so the
testlib mock store needs matching expectations — notably the managed
category field, whose ID is cached at startup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Fix store test to create valid PSAv2 property fields
Setting ObjectType makes a field PSAv2, which requires a valid target
type, so the test fields now use the system target level (with an empty
target ID) instead of an unset target type.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Fix flaky TestCheckTeamsTeamMembersIntegrity
Integrity checks scan the full database for orphaned TeamMembers rows,
so parallel sqlstore tests and leftover rows from sibling tests can
inflate global record counts and flip index-based assertions.
Reset tables at test start and scope the one-record assertion to the
team parent ID created in that subtest.
Tests-only change. Verified package compiles locally; full test loop
requires PostgreSQL (CI).
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Remove unused orphanedRecordsWithChildIDs helper
Fixes golangci-lint unused check failure in check-style CI.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Address PR feedback: 1 item resolved, 1 declined
* Use real users in TestCheckTeamsTeamMembersIntegrity fixtures
createTeamMember with model.NewId() also creates Users-side orphans that
can pollute TestCheckUsersTeamMembersIntegrity when tests share a store.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Don't show guest tag for bot and webhook posts
When a user who created a webhook is demoted to a guest, the post's
author profile rendered a GUEST tag next to the BOT tag, which is
confusing. Suppress the GUEST tag for bot and webhook posts.
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Add tests for hiding guest tag on bot and webhook posts
Co-authored-by: mattermost-code <matty-code@mattermost.com>
* Expand guest tag tests to cover compact, mobile and consecutive layouts
Co-authored-by: mattermost-code <matty-code@mattermost.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>