Mattermost
mattermost.orgMattermost has an open source edition, which can be self-hosted. It makes a good Slack alternative, with native desktop, mobile and web apps and a wide variety of integrations.
- Homepage: mattermost.org
- GitHub: github.com/mattermost/mattermost
- Privacy: mattermost.com/privacy-policy
- iOS App: apps.apple.com/us/app/mattermost/id1257222717
- Android App: play.google.com/.../com.mattermost.rn
- Web info: web-check.xyz/check/mattermost.org
Mattermost Source Code
Author
Description
Mattermost is an open source platform for secure collaboration across the entire software development lifecycle..
Homepage
https://mattermost.comLicense
NOASSERTION
Created
15 Jun 15
Last Updated
12 Jul 26
Latest version
Primary Language
TypeScript
Size
1,215,008 KB
Stars
38,406
Forks
8,823
Watchers
38,406
Language Usage
Star History
Top Contributors
-
@jwilander (1741)
-
@hmhealey (1636)
-
@coreyhulen (1469)
-
@crspeller (1351)
-
@agnivade (881)
-
@it33 (685)
-
@lieut-data (531)
-
@enahum (522)
-
@hanzei (459)
-
@jespino (393)
-
@isacikgoz (351)
-
@rgarmsen2295 (342)
-
@grundleborg (328)
-
@saturninoabril (322)
-
@weblate (317)
-
@cpanato (254)
-
@streamer45 (243)
-
@sbishel (229)
-
@ConorMacpherson (229)
-
@mgdelacroix (222)
-
@pvev (202)
-
@sig1nt (196)
-
@ccbrown (196)
-
@devinbinnie (190)
-
@wiggin77 (183)
-
@M-ZubairAhmed (172)
-
@harshilsharma63 (171)
-
@nickmisasi (170)
-
@asaadmahmood (168)
-
@larkox (152)
-
@cpoile (144)
-
@DavidLu1997 (137)
-
@jprusch (129)
-
@JulienTant (126)
-
@jasonblais (124)
-
@marianunez (120)
-
@reflog (110)
-
@BenCookie95 (108)
-
@kayazeren (108)
-
@florianorben (104)
-
@calebroseland (100)
-
@rvillablanca (99)
-
@johnsonbrothers (97)
-
@Aryakoste (97)
-
@AGMETEOR (94)
-
@fsilye (92)
-
@kaakaa (89)
-
@mkraft (89)
-
@mattermod (85)
-
@agarciamontoro (84)
-
@amyblais (84)
-
@cursor[bot] (82)
-
@matt-w99 (76)
-
@unified-ci-app[bot] (69)
-
@DSchalla (66)
-
@noxer (58)
-
@plant99 (58)
-
@mvitale1989 (57)
-
@mickmister (56)
-
@lfbrock (53)
-
@GoldUniform (52)
-
@niklabh (52)
-
@matthewbirtch (51)
-
@catalintomai (51)
-
@neallred (48)
-
@metanerd (45)
-
@davidkrauser (44)
-
@koox00 (44)
-
@ethervoid (44)
-
@levb (42)
-
@esarafianou (42)
-
@avasconcelos114 (40)
-
@Syed-Ali-Abbas-Zaidi (39)
-
@MusikPolice (38)
-
@Willyfrog (38)
-
@Gesare5 (36)
-
@Camillarhi (36)
-
@yasserfaraazkhan (36)
-
@toninis (35)
-
@RS-labhub (34)
-
@iomodo (34)
-
@hahmadia (34)
-
@fmunshi (34)
-
@vish9812 (33)
-
@haardikdharma10 (32)
-
@emmyni (30)
-
@ashishbhate (30)
-
@Reinkard (28)
-
@mattermost-build (28)
-
@hereje (27)
-
@AshishDhama (27)
-
@gbochora (26)
-
@csduarte (26)
-
@SaurabhSharma-884 (24)
-
@carlisgg (23)
-
@ZubairImtiaz3 (23)
-
@fmartingr (22)
-
@mansil (22)
-
@Morgansvk (22)
-
@enzowritescode (22)
Recent Commits
-
Ben Schumacher (10 Jul 26)
[MM-69561] Add ability to rotate (regenerate) Personal Access Tokens (#37295) * MM-69561: Add ability to rotate (regenerate) Personal Access Tokens - Add UpdateTokenRotate to UserAccessTokenStore interface and implement in sqlstore: deletes sessions on the old secret, then updates the token row with the new secret and expiry in one transaction - Regenerate store retrylayer, timerlayer, and mocks - Add RotateUserAccessToken app method: validates expiry (bot-exempt), captures old session for cache eviction, generates new secret, and sends a notification email - Register POST /api/v4/users/tokens/rotate handler with full permission checks (create_user_access_token + edit_other_users + manage_system for sysadmin targets); rejects OAuth sessions and disabled tokens - Add RotateUserAccessToken to the Go client (client4.go) - Add storetest covering secret rotation and old-session cleanup - Add API4 tests: happy path, permission denials, OAuth rejection, and max-lifetime enforcement Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Add dedicated rotate email and i18n strings - Add SendUserAccessTokenRotatedEmail (subject/body distinct from the 'added' email so users aren't confused by a rotation event) - Add SendUserAccessTokenRotatedEmail to ServiceInterface + mock - Add en.json strings for the rotate email and the two new error ids (rotate.app_error, disabled_token.app_error) - Switch RotateUserAccessToken to call SendUserAccessTokenRotatedEmail Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Add mmctl token rotate subcommand - Add RotateUserAccessToken to the mmctl Client interface and mock - Add 'mmctl token rotate <token-id> [--expires-in <duration>]' command reusing the existing resolveTokenExpiry/parseExpiresIn helpers from 'generate'; prints the new secret once on success - Add unit tests: happy path, --expires-in passed through, server error, invalid --expires-in Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Regenerate mmctl docs for token rotate Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Add API docs for POST /users/tokens/rotate Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Fix i18n string ordering after extract Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Add missing API4 test cases for token rotate Cover the three untested access-control branches flagged by the test analysis bot: - Rotating a disabled token returns 400 - Non-system-admin rotating a sysadmin's token returns 403 - Rotating a remote user's token returns 403 Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Address review comments - Fix handler authorization order: check SessionHasPermissionToUserOrBot and manage_system before IsRemote/IsActive to avoid leaking token state to unauthorized callers; matches revokeUserAccessToken/disableUserAccessToken - Fix API docs minimum server version: 10.8 -> 10.10 Co-Authored-By: Claude Sonnet 4.6 <[email protected]> * MM-69561: Restore i18n strings accidentally deleted by extract The earlier i18n-extract run stripped ~164 unrelated translation keys (mostly enterprise-only strings like app.pap.* and api.ldap.*) because the enterprise codebase isn't present in this checkout, so the extractor treated them as unused. Restore them while keeping the 5 new keys added for token rotation. * comment * [MM-69561] Add webapp Regenerate option for Personal Access Tokens Adds a "Regenerate" link to Account Settings > Security > Personal Access Tokens that calls the POST /users/tokens/rotate endpoint added in the server-side rotate PAT work. Regenerating shows a confirmation modal naming the token, then reveals the new secret via the existing one-time-copy flow used for token creation. - webapp Client4.rotateUserAccessToken - mattermost-redux rotateUserAccessToken action - Regenerate link/confirm modal/reveal flow in user_access_token_section - i18n strings - Playwright e2e coverage * Fix regenerate PAT e2e test: confirm modal is not nested in the Profile dialog ConfirmModal renders via react-bootstrap's Modal, which portals to document.body as a sibling of the Profile dialog rather than a descendant, so it must be located via #confirmModal on the page instead of scoped to the Profile dialog locator. * Let users pick a new expiry when regenerating a Personal Access Token Previously, regenerating a token always called rotateUserAccessToken with no expiresAt, so the rotated secret never expired even if the original token did. The Regenerate confirmation modal now includes the same expiry picker used by token creation (extracted into a shared renderExpiryPicker helper), enforces MaximumPersonalAccessTokenLifetimeDays the same way, and disables the confirm button until a valid expiry is selected. * Scope the red background in the Regenerate modal to the warning text only The confirmation question, expiry picker, and its hints were sitting inside the same alert-danger box as the warning, making the whole modal read as an error. Only the warning paragraph keeps the red background now. * Move the regenerate confirmation question below the expiry picker * Align rotate-token wording with UI: use 'regenerate/regenerated' Co-Authored-By: Claude Sonnet 5 <[email protected]> * [MM-69561] rename pat_expiry_notify job to notify_expiring_access_tokens Unifies naming with the sibling cleanup_expired_access_tokens job and fixes the "expiry" vs "expiring" ambiguity: this job warns about tokens approaching expiry, not ones that have already expired. Safe to rename outright since the job hasn't shipped yet. Co-Authored-By: Claude Sonnet 5 <[email protected]> * [MM-69561] remove dead session lookup from EnableUserAccessToken The GetSessionContext call and its result were never used: both branches returned nil regardless. Leftover from mirroring DisableUserAccessToken's shape, which does use its session (to revoke it) unlike Enable. Co-Authored-By: Claude Sonnet 5 <[email protected]> * [MM-69561] rename remaining PAT identifiers to match AccessToken convention The job-level rename (pat_expiry_notify -> notify_expiring_access_tokens) left the app-layer function and its helpers using the old PAT/ PersonalAccessToken naming. Rename them to match: - NotifyPersonalAccessTokensExpiring -> NotifyExpiringAccessTokens - patExpiryBucket -> accessTokenExpiryBucket - sendPATExpiryNotification -> sendAccessTokenExpiryNotification - patExpiryNotifyBatchLimit -> expiringAccessTokenBatchLimit - patExpiryThresholds -> expiringAccessTokenThresholds - maxPersonalAccessTokenExpiry -> maxUserAccessTokenExpiry Also reword the package doc on notify_expiring_access_tokens, which no longer needs to explain a PAT/UserAccessToken naming split now that the app-layer method matches the job name. Pure rename, no behavior change. Co-Authored-By: Claude Sonnet 5 <[email protected]> --------- Co-authored-by: Claude Sonnet 4.6 <[email protected]>
-
cursor[bot] (10 Jul 26)
Fix interactive message action buttons overflowing on long text (#37142) Constrain post attachment action buttons to the container width and allow their labels to wrap, including long unbroken strings. Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: mattermost-code <[email protected]>
-
Ben Schumacher (10 Jul 26)
[MM-69403] Push WebSocket events on job status changes (#37130) * Add WebSocket push for job status changes, remove System Console polling Server now broadcasts a job_updated WebSocket event whenever a job transitions state (pending, in_progress, success, error, warning, canceled). The webapp handles this event by updating the Redux store immediately, so the LDAP (and any other) job table in the System Console reflects changes in real time without a polling interval. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Address security review: strip job Data from WS event, guard JSON.parse - publishJobStatus now strips job.Data before broadcasting so sensitive job-type-specific fields (requesting_user_id, team_id, policy_id, role) are not exposed to WebSocket clients without permission checks; status, progress, and timestamps are sufficient for real-time UI updates - handleJobUpdated wraps JSON.parse in try/catch to prevent a malformed payload from breaking WebSocket event handling Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Fix import/order ESLint errors for @mattermost/types/jobs The Job type import must appear after @mattermost/types/integrations alphabetically in both websocket_actions.ts and websocket_messages.ts. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Add unit tests for job status WebSocket broadcasting - Server: TestPublishJobStatus covers nil callback safety, Data stripping, and per-method status verification (ClaimJob→in_progress, SetJobWarning→ warning, SetJobSuccess→success, SetJobError nil/non-nil→error, SetJobCanceled→canceled, SetJobPending→pending) - Reducer: jobs.test.ts covers RECEIVED_JOB on jobsByTypeList (type absent, id absent, id found/updated, multi-entry list preserves other entries) - Webapp: handleJobUpdated tests cover valid JSON dispatch and malformed JSON no-op Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Fix run time display by using DB-returned job for WebSocket publish UpdateStatus now returns the full job via RETURNING (same pattern as UpdateStatusOptimistically), so SetJob* methods can pass the DB result to publishJobStatus. This ensures last_activity_at and start_at are populated from the DB in the broadcasted event rather than from the potentially-stale in-memory worker struct. Before this change, polling masked the issue by re-fetching jobs via REST API after completion. Without polling, the WebSocket event was the only update and could carry zero timestamps → "--" run time. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Return ErrNotFound from UpdateStatus when no rows matched and remove nil guards UpdateStatus targets a specific job by ID unconditionally, so zero rows updated means the job doesn't exist — an error, not a silent no-op. Returning store.ErrNotFound makes callers fail loudly (rather than silently falling back to stale in-memory data) and removes the need for nil-guard boilerplate in every SetJob* caller. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Re-fetch job list on terminal status to populate run time and error details The WebSocket payload intentionally omits job Data for security, so fields like the error message and accurate last_activity_at are only available via the REST API. On receiving a terminal status (success/error/warning/canceled), dispatch getJobsByType to fill in those details immediately after the status update lands in the store. Also set job.LastActivityAt before publishing in SetJobError's non-nil branch so the WebSocket event carries a reasonable run time approximation even before the re-fetch completes (UpdateOptimistically updates last_activity_at in the DB but not the in-memory struct). Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Change UpdateOptimistically to return (*model.Job, error) via SQL RETURNING Returns the full updated row on success; returns nil, nil when the precondition status doesn't match (expected outcome, not an error). Drops the manual LastActivityAt assignment in SetJobError — the DB timestamp is now authoritative via the returned job. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Tighten UpdateOptimistically precondition-fail assertion in storetest The previous require.False(t, err != nil && ret != nil) would incorrectly pass if the function returned (job, nil) instead of the expected (nil, nil). Use explicit require.NoError + require.Nil to pin both return values. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Scope job_updated WebSocket events to system admins only Set ContainsSensitiveData=true so the hub only delivers the event to connections where the user holds manage_system permission. The job system is admin-only; regular users have no UI that consumes this event. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Pass publish func through NewJobServer, remove SetPublish SetPublish was called immediately after NewJobServer in its only production call site with no initialization ordering constraint. Passing it as a constructor parameter removes the unnecessary setter. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Fix four gaps in job status WebSocket push coverage - Remove ContainsSensitiveData=true from publishJobStatus: the payload carries no sensitive fields (Data is stripped), so sysadmins with delegated roles (e.g. sysconsole_read_authentication_ldap) receive events instead of seeing a frozen table. - SetJobProgress now publishes in_progress events so the progress bar advances via WebSocket rather than staying frozen at 0%. - RequestCancellation pending→canceled path now publishes a canceled event, matching the behavior of all other terminal-state transitions. - jobsByTypeList RECEIVED_JOB reducer now prepends a newly-seen job when the type list is already loaded, so brand-new jobs appear immediately via WebSocket push without waiting for a page reload. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Revert finding 1: restore ContainsSensitiveData=true on job WebSocket events Co-Authored-By: Claude Sonnet 4.6 <[email protected]> Claude-Session: https://claude.ai/code/session_01LfrXSZQY7oV6EzW3yFBB6A * Add non-admin polling fallback and fix missing WS publish in RequestCancellation - JobTable now polls every 15s as a fallback for non-system-admin viewers, since job_updated WebSocket events are scoped to system admins only (addresses PR #37130 review comment r3462905643). - RequestCancellation now publishes a job_updated event when a job transitions from in_progress to cancel_requested, matching the existing publish on the pending->canceled branch (addresses r3462940359). - Add test coverage for both. Co-Authored-By: Claude Sonnet 5 <[email protected]> * Stop stripping Data from job_updated WebSocket event publishJobStatus broadcasts are already restricted to system admins via ContainsSensitiveData, and system admins can already read job Data through the permissioned REST API. Stripping it here provided no additional protection. MM-69695 tracks scoping the broadcast to per-job-type permissions instead of system-admin-only; that follow-up needs to reintroduce appropriate Data filtering once the audience widens. Co-Authored-By: Claude Sonnet 5 <[email protected]> --------- Co-authored-by: Claude <[email protected]>
-
Jesse Hallam (10 Jul 26)
MM-69585: remove AttributeBasedAccessControl feature flag (#37366) * MM-69585: remove AttributeBasedAccessControl feature flag * Gate channel ABAC UI on EnableAttributeBasedAccessControl config
-
Adam Schildkraut (10 Jul 26)
Preserve 429/503 retry status codes through DoActionRequest (#36700) * Preserve 429/503 retry status codes through DoActionRequest DoActionRequest collapsed all plugin non-200 responses to 400, losing the retry semantics carried by 429 and 503 (RFC 6585, RFC 7231). This preserves 429/503 verbatim, maps other 5xx to 502 Bad Gateway, and leaves other non-200 responses wrapped as 400. * update api documentation for new errors * fix tests affected by change --------- Co-authored-by: Mattermost Build <[email protected]> Co-authored-by: Scott Bishel <[email protected]>
-
Jesse Hallam (10 Jul 26)
Adopt per-target .PHONY directives in server Makefiles (#37447)
-
Jesse Hallam (10 Jul 26)
Bucket server test-timing cache by date to cut cache churn (#37425)
-
Pablo Vélez (10 Jul 26)
MM-69392 - Make DCR redirect URI allowlist matching URL-component aware (#37170) * MM-69392 - Make DCR redirect URI allowlist matching URL-component aware * Refactor parseDCRRedirectURIPattern to simplify query extraction
-
Eva Sarafianou (10 Jul 26)
docs: fix broken path links, anchors, and tab rendering from RST-to-MDX migration (#37433) * docs: resolve cross-file anchor mismatches from RST-to-MDX migration The Sphinx-to-Docusaurus migration converted `:ref:`/`{ref}` links using naive text-slugification, so anchors that pointed to headings in a different file (e.g. release-summary tables linking into their respective changelog pages) were emitted as same-page fragments and silently resolved to nothing. Built a label registry from the original Sphinx `.. _label:` / `(label)=` targets to recover the true source file for each cross-reference, then rewrote the affected links to point at the correct file + heading anchor. Fixes 282 broken cross-file anchors, primarily in the mobile/ desktop/server release-summary pages, plus assorted same-page anchor mismatches caught by re-auditing after the prior admonition/anchor fix. Co-authored-by: Cursor <[email protected]> * docs: manually resolve remaining anchor mismatches after cross-file audit Hand-verified fixes for anchors that fuzzy-matching alone couldn't safely resolve (confirmed against actual heading text/context, and in a few cases against the original RST source, before applying): - Typos and dropped words carried over from the original Sphinx docs (e.g. "bot-acocunts", "auto-follow-all-new-channel-threads" -> "follow-all-new-channel-threads"). - Sphinx auto-generated duplicate-heading IDs (#id1/#id3/#id4) resolved to their real target headings. - Numbered-step TOC links in enterprise-roll-out-checklist.mdx that dropped the leading "N. " used in the actual heading slugs. - Push-notification docs pointing at the wrong file entirely (environment-configuration-settings instead of push-notification-server-configuration-settings). - SAML "saml-enterprise" label resolved to its true cross-file target (authentication-configuration-settings#saml-2-0), recovered from the original RST label definition that the automated registry missed because it sat after an RST transition marker. - sso-saml-technical references converted from broken same-page/ malformed-path anchors to correct page links. Co-authored-by: Cursor <[email protected]> * docs: fix SAML 2.0 anchor slug (saml-2-0 -> saml-20) github-slugger strips periods rather than hyphenating them, so "SAML 2.0" slugifies to saml-20, not saml-2-0 as previously fixed. Co-authored-by: Cursor <[email protected]> * docs: fix broken path links found during docs/main migration cleanup Co-authored-by: Cursor <[email protected]> * docs: convert div.tab blocks to Docusaurus Tabs/TabItem components Co-authored-by: Cursor <[email protected]> * docs: restore missing Kubernetes deployment architecture diagrams The RST-to-MDX migration never copied over the AWS/Azure/Oracle architecture diagrams referenced by the deployment-architecture-at-scale page, leaving broken images in each Tabs/TabItem. Co-authored-by: Cursor <[email protected]> * docs: fix 7 anchor mismatches from the fragment/heading audit Covers three root causes from the anchor mismatch breakdown: - Fragment repeated the target page's own title instead of a real heading, so the link is simplified to point at the bare page. - Heading exists verbatim but lives on a sibling settings page (experimental-configuration-settings, push-notification-server- configuration-settings) rather than environment-configuration-settings. - A page path was mistakenly pasted into a same-page #fragment instead of being used as a real cross-page link. Co-authored-by: Cursor <[email protected]> * docs: fix 8 anchor slugs that were close but didn't match the real heading Repoints links whose fragment was a plausible guess (typo, reworded heading, or wrong section) at the actual auto-generated slug of the target heading, confirmed by inspecting each target page directly. Co-authored-by: Cursor <[email protected]> * docs: merge split Tabs blocks so tabs render horizontally The div.tab conversion script split some sibling tab groups into separate single-item Tabs blocks whenever a stray blockquote marker sat between them, causing them to render stacked instead of as one horizontal tab bar. Merges the MySQL/PostgreSQL and Team/Enterprise Edition tab groups back into single Tabs blocks. Co-authored-by: Cursor <[email protected]> * docs: remove Azure tab and restore Kubernetes deploy content The Mattermost Operator, Azure, and Oracle platform tabs on the Kubernetes deployment guide were split across two separate Tabs blocks (rendering stacked instead of as one tab bar) and all three tab bodies were empty because the migration never flattened the original RST include directives. Removes the unsupported Azure tab and restores the Mattermost Operator and Oracle content from the pre-migration RST sources as a single merged Tabs block. Co-authored-by: Cursor <[email protected]> * addresscoderabbitreview * docs: unify Linux/Kubernetes/Containers deploy pages and fix FIPS/STIG placement Kubernetes and Containers duplicated full install content across a top-level page (Tabs) and orphaned sidebar subpages that nothing linked to. Reworked both to follow the Linux page's pattern: shared content on the landing page, platform-specific instructions live once in their own subpage. Also removed configure-fips-at-install-time.mdx, which claimed FIPS is available for native Linux installs — FIPS/STIG in Mattermost is a container image property (Chainguard-based build), not available outside Docker/ Kubernetes. Consolidated all FIPS/STIG references onto containers/fips-stig.mdx and pointed the Mattermost Operator subpage (not Oracle OKE, which doesn't expose image selection) at it. Co-authored-by: Cursor <[email protected]> * docs: fix review findings — image alt text, Important callout markup, typo - Replace generic alt="image" on scaling diagrams with descriptive text identifying cloud provider and user scale. - Convert raw div.important markup in deploy-containers.mdx to the repo's <Important> component, matching usage elsewhere in the file. - Fix "Matermost" typo in manage-your-display-options.mdx. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]>
-
Eva Sarafianou (10 Jul 26)
Remove internal only pages from develop (#37436)
-
cursor[bot] (10 Jul 26)
[MM-69589] Remove ExperimentalAuditSettingsSystemConsoleUI feature flag (#37385)
-
Pablo Vélez (10 Jul 26)
MM-69408 - Fix quadratic markdown autolink trimming (#37201)
-
Jesse Hallam (10 Jul 26)
Move e2e npm registry cache out of the node-cache- namespace (#37427) The e2e npm registry cache keyed on node-cache-<os>-<arch>-npm-e2e-, sharing the node-cache- prefix that actions/setup-node generates automatically for its built-in npm cache (node-cache-<os>-<arch>-npm-). Because the arch segment differs only by case (setup-node uses Node's process.arch 'x64'; this action uses runner.arch 'X64') and GitHub matches restore-key prefixes case-insensitively, the two buckets share a common prefix. A future broad restore-key such as node-cache-<os>-<arch>-npm- could then cross-restore one bucket's ~/.npm into the other. Rename the key to e2e-npm-registry-<os>-<arch>-, giving it a distinct namespace that is not a prefix of node-cache- in either direction and matches the repo's content-descriptive e2e cache keys (e2e-cypress-deps-, e2e-playwright-deps-, e2e-platform-pkgs-). Existing entries orphan and age out; the daily warm job repopulates under the new key on next run.
-
Scott Bishel (10 Jul 26)
Add file upload element to interactive dialogs (#36881) * Add file upload element to interactive dialogs Adds a new file element type to interactive dialogs, letting users upload files in a dialog and forward the file IDs to the integration. Server: - model: new file DialogElement type with validation, AllowMultiple field, and SubmitDialogRequest.FileIds. - SubmitInteractiveDialog validates submitted file IDs (existence + ownership) from both file_ids and any file IDs referenced in submission values; bounded and batched. - client4.getFileInfo / Client4.GetFileInfo. Webapp: - AppsFormFileUpload component: upload, progress, removal, and hydration of pre-set file IDs; single vs allow_multiple selection. - Wired into the dialog -> apps-form conversion (file field type). - Submit is blocked while any field has an upload in progress (per-field pending tracking). Tests: - Go unit tests for model + submit-time file-ID validation. - Jest tests for the upload component. - Cypress e2e spec (file_upload_spec.js) + webhook fixtures. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> * coderabbit review fixes, linter fixes * update openAPI spec for file upload * revert changes to package-lock.json * review fixes, add correct ids to E2Etests * fix dryrun security issue * lint fixes * Address dialog file upload review feedback and UI file cap * test fixes * add several unit tests * lint fix --------- Co-authored-by: Scott Bishel <[email protected]>
-
Scott Bishel (09 Jul 26)
MM-69219: Add multiple concurrent dialogs via action_button element type (#37119) * Add multiple concurrent dialogs support with action_button element type Enable plugins to open child dialogs from within an existing dialog via a new action_button dialog element and POST /actions/dialogs/execute endpoint. Parent dialogs stay open while children stack (cap of 3). Dialog handlers derive the team permission and forwarded team from the server-loaded channel, not the client-supplied TeamId. * update docs, code rabbit review fixes * update comment per coderabbit * fix tests * increase test coverage * fix bad merge * Replace PostActionAPIResponse with ExecuteDialogActionResponse; replace single-dialog Redux slot with dialogs map --------- Co-authored-by: Mattermost Build <[email protected]>
-
Scott Bishel (09 Jul 26)
MM-68754: Add silent post delivery for bots and integrations (#36771) * MM-68754: Add silent post delivery for bots and integrations Bot, OAuth, incoming webhook, and plugin posts can request silent delivery via ?silent=true (REST), silent:true (webhook payload), or silent_notification:true (plugin Props). Silent posts are visible in the channel but produce no notifications, unread, or New Messages line. force_notification overrides silent. Non-integration senders requesting silent receive HTTP 403. Also tightens SanitizeProps to strip from_webhook, from_bot, from_oauth_app, from_plugin, force_notification, and silent_notification from client input. These props are now set server-side based on session and entry-point flags, preventing identity spoofing. Legitimate callers see no behavior change since the server already controlled these props at the response shape; the hardening only affects callers attempting to forge them. * Drop redundant prop-bag silent_notification path from webhooks * Address CodeRabbit feedback + rebase test fixup * Update tests to use CreatePostFlags.FromIncomingWebhook instead of forging from_webhook prop * update api documentation * test fixes * added additional tests * review fixes, update comments * code review changes, fix test * fix formatting issues * fix lint errors * avoid backward compatibility issues, by no longer stripping the Post properties. will add them back in v12 when breaking changes are allowed --------- Co-authored-by: Mattermost Build <[email protected]>
-
Harrison Healey (09 Jul 26)
Prevent broken draft state when uploads fail or are interrupted, allowing users to send messages again (#37266) * fix(upload): prevent broken draft state when uploads fail or are interrupted, allowing users to send messages again * Revert "fix(upload): prevent broken draft state when uploads fail or are interrupted, allowing users to send messages again" This reverts commit 21040d6166d43d781e65f4be740227f98af23f88. * Clear uploads in progress from persisted drafts on rehydration * lint: remove unused deps * fix(tests): update persistStore mock to detect if initialized * test(store): add test to verify store hydration status * test(store): add test to verify uploadsInProgress is cleared on rehydration * Only change redux-persist mock and use fake timers for new tests --------- Co-authored-by: Aurelien SBERRO <[email protected]>
-
Joram Wilander (09 Jul 26)
On successful SAML auth log the user's email (#37428)
-
Eva Sarafianou (09 Jul 26)
docs: fix broken admonitions and anchors in product-overview changelog pages (#37423) * docs: fix broken admonitions and anchors in product-overview changelog pages The Sphinx-to-Docusaurus migration script only converted lowercase admonition directives (e.g. ```{note}```), so capitalized/indented/ same-line variants (```{Important}```, ```{Attention}```) were left as literal text, causing whole sections to render as a single broken code block. Also convert unconverted MyST `.. meta::` blocks and `(label)=` anchors (as escaped MDX heading ids) so existing cross-reference links keep resolving. Affects: v10/v11 server changelogs, server/mobile/desktop releases, release policy, unsupported legacy releases, mobile/desktop app changelogs. Co-authored-by: Cursor <[email protected]> * docs: fix under-indented Important callouts in v10 changelog The <Important>/**Critical Fixes**/</Important> blocks nested under several release-entry bullets were indented with only 1 space instead of the 2-space list-item content column used by sibling sub-bullets, risking the callout breaking out of the list item during rendering. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]>
-
Ben Schumacher (09 Jul 26)
[MM-24529] Preserve hyphenated compound words in Postgres search (#37360) * [MM-24529] Preserve hyphenated compound words in Postgres search Postgres full-text search stripped every hyphen to a space before building a to_tsquery, so an unquoted search for "t-shirt" degraded into a loose "t AND shirt" match instead of the compound-word match the quoted version already got. Fix is Postgres-only; MySQL is gone and Elasticsearch/Bleve use a different tokenizer/query mechanism (verified empirically against a live ES instance - out of scope here). - Remove "-" from the shared specialSearchChars strip list in store.go, and add neutralizeNonWordHyphens (utils.go), which keeps a hyphen only when flanked by a letter/digit on both sides, neutralizing malformed usage (leading/trailing/standalone/repeated) that would otherwise reach to_tsquery as a parse error. - Wire the new helper into post_store.go's tsquery-building path. - file_info_store.go keeps the old hyphen-to-space behavior: real filenames glue a hyphenated name directly to an extension (e.g. "photo-2024.jpg"), which Postgres's parser tokenizes as an opaque "host"-type token that a hyphen-preserving compound query can never match - verified against Postgres. Re-skip the two FileInfo dash acceptance tests with an accurate reason instead of "Not working". - Re-enable the two previously-skipped Postgres post-search dash acceptance tests, and extend them with excluded-term, wildcard, and letters-digits-compound cases. Co-Authored-By: Claude Sonnet 5 <[email protected]> * Revert file_info_layer.go changes Restore the two FileInfo dash acceptance tests to their original Skip:true/SkipMessage state, matching master exactly. The underlying fix (file_info_store.go keeps the old hyphen-to-space behavior since Postgres tokenizes hyphenated-filename+extension as an opaque token) is unaffected - this only reverts the test scaffolding tweak. Co-Authored-By: Claude Sonnet 5 <[email protected]> --------- Co-authored-by: Claude Sonnet 5 <[email protected]>
-
Eva Sarafianou (09 Jul 26)
docs: fix broken images, cross-links, and layout overflow after docs-experimental migration (#37418) * docs: restore missing e2e/mobile push-notification images These developer-docs images existed in mattermost-developer-documentation's static assets but were never copied into the monorepo during the docs migration, leaving broken image links in e2e-cheatsheets.md and the mobile push-notification pages. Also fixes e2e-cheatsheets.md's image paths, which used Hugo-style relative paths that don't resolve under Docusaurus. Co-authored-by: Cursor <[email protected]> * docs: fix broken outgoing webhooks screenshot path The image reference used an absolute path left over from the old Hugo site (/integrate/faq/images/...), which doesn't resolve under Docusaurus since no matching file exists under site/static. The image already lives co-located in docs/develop/integrate/faq/images/, so point to it with a relative path instead. Co-authored-by: Cursor <[email protected]> * docs: delete Azure AKS deployment guide page The page's screenshots never made it into the monorepo during migration and don't exist under any known source (docs, docs-experimental, or mattermost-developer-documentation). Remove the page rather than ship broken images; drop it from the PDF book manifest and repoint its legacy redirect to the general Kubernetes deployment guide accordingly. Co-authored-by: Cursor <[email protected]> * docs: fix heading levels on Kubernetes deploy guides deploy-k8s.mdx and deploy-k8s-oke.mdx used H1 (#) for their top-level in-page sections (Installation steps, Common Errors, etc.) instead of H2. Docusaurus' contentTitle extraction grabs the first H1 it finds anywhere in the doc, which stole the page title slot from the actual frontmatter title, so no title rendered at the top of the page. The flat H1/H2 mix also meant TOC entries for install steps rendered as a flat list at the page's TOC root instead of nested under their section, which made the TOC sidebar overflow/misrender on narrower/zoomed viewports. Bump every heading in both files one level (H1->H2->H3->H4) so the page title renders and the TOC nests correctly. Co-authored-by: Cursor <[email protected]> * docs: fix TOC/layout horizontal overflow on wide code blocks The Kubernetes prerequisites page's TOC sidebar overflowed off-screen at higher browser zoom levels. Root cause: `.docMainContainer` has `max-width: none !important` (intentional, so OpenAPI's 2-column layout gets full width), but that removes the container's only width ceiling. Combined with the default flexbox `min-width: auto` on both the main container (in its outer flex row with the left sidebar) and the doc content column (in the inner content/TOC row), a sufficiently wide code block's intrinsic min-content size could drag the whole row wider than the viewport instead of scrolling within itself. Add `min-width: 0` at both flex levels so `overflow-x: auto` on code blocks and tables actually contains overflow locally, and make the responsive table-scroll CSS apply unconditionally instead of only under the 996px breakpoint (zoom shrinks effective layout width without re-triggering the media query). Also shorten the illustrative base64 example values in the AWS Aurora Postgres secret example, which were long enough on their own to be a secondary contributor to the same overflow. Co-authored-by: Cursor <[email protected]> * docs: restore additional missing images found via full static-resolution scan Docusaurus's build-time image validator doesn't reliably warn on every broken absolute-path reference, so npm run build alone missed these. A direct scan of every image reference in docs/develop and docs/main against the filesystem turned up 38 more genuinely missing images (desktop architecture, VPN/Pritunl setup, docker dev environment, i18n-extract tooling, MVP program, onboarding, schema migration guide, plugin best-practices, and interactive-message screenshots) that were never copied over from mattermost-developer-documentation during migration. Two references (interactive-dialog-date.png and interactive-dialog-datetime.png) remain unresolved because no source image exists anywhere in the legacy repo. Co-authored-by: Cursor <[email protected]> * docs: fix broken cross-links after .md to .mdx migration Several Calls admin guide pages and the air-gapped quick-start runbook were renamed from .md to .mdx during migration, but their internal cross-links still pointed at the old .md filenames (and, for setup-tls, the old flattened path), so Docusaurus couldn't resolve them. Found via a full scan of every relative markdown link under docs/main and docs/develop against the filesystem, since the build's own "couldn't be resolved" warnings don't reliably surface every broken link. Co-authored-by: Cursor <[email protected]> * docs: remove broken date/datetime element screenshots These screenshots were never captured before migration (broken on the currently live docs.mattermost.com too), and no source image exists anywhere in the legacy repos to restore. Remove the broken references rather than leave a dead image link. Co-authored-by: Cursor <[email protected]> * docs: move newly-restored desktop architecture images to static/ These 4 images were restored co-located next to their content files, matching an existing (if inconsistent) convention elsewhere in docs/develop. Since these are new additions rather than pre-existing working references, move them to docs/site/static/ instead of perpetuating the co-located pattern. Repo-wide normalization of the other ~70 existing co-located image references is left for a separate follow-up PR. Co-authored-by: Cursor <[email protected]> * docs: remove deleted AKS page from sidebar generator's manual grouping master (#37402) fixed the sidebar generator's SRC path but this branch's deletion of deploy-k8s-aks.mdx still left a dangling reference in the Deployment Guide's manual Kubernetes grouping, which fails Docusaurus's sidebar-doc-id validation at build time. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]>
-
Eva Sarafianou (09 Jul 26)
ci: add docs CD workflow (#37421) * ci: add docs CD workflow (P9) Builds the Docusaurus site and deploys to S3 on every push to master touching docs/** or api/**, then invalidates CloudFront. Splits the S3 sync into two passes so content-hashed build assets get long-lived immutable caching while unhashed HTML stays no-cache for near-instant propagation. Co-authored-by: Cursor <[email protected]> * ci: remove workflow_dispatch trigger from docs-cd Deploys should only happen via push to master, not manual trigger. Co-authored-by: Cursor <[email protected]> * ci: typecheck before building docs in CD docusaurus build strips TypeScript types via babel without validating them, so a type error could still deploy. docs-ci.yaml typechecks the same commit, but as an uncoupled parallel workflow it doesn't gate CD — this catches it if CI fails or a required check is bypassed on master. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]>
-
Vishal Kumar Singh (09 Jul 26)
Stop leaking message body via the Notifications API tag (#36364) * Stop leaking message body via the Notifications API tag showNotification was passing the rendered chat body as the Web Notifications API tag option. On Chromium-based browsers (Chrome, Edge, Brave), the tag is serialised into the notification-activation command line via the --notification-launch-id argument, where endpoint detection tooling such as CrowdStrike Falcon FDR, Microsoft Defender for Endpoint, and Sysmon Event ID 1 captures the full process-start command line and forwards it to the customer's SIEM. That meant private message content (including incident-response messages, credentials accidentally pasted into chat, and customer PII) was being copied into telemetry pipelines that were never in scope to receive it. Use the title - which already carries only the sender / channel context - as the tag instead. As a side benefit this is closer to the spec-intended use of tag: subsequent notifications from the same conversation now replace the prior one rather than stacking. Add a regression test covering the leak: the test pushes a body with a plausible secret pattern (token=AKIA-...) and asserts the tag never echoes any of it. Signed-off-by: Vishal Kumar Singh <[email protected]> * Allow callers to pass an explicit notification tag Threads channelId through dispatchNotification so per-conversation notifications coalesce by a stable opaque id rather than the user-visible title. The title remains as a safe fallback when callers do not supply a tag, preserving the existing behaviour for the session-expired notification emitted from login.tsx where no channel context exists. Signed-off-by: Vishal Kumar Singh <[email protected]> * fix: explain desktop notification path * Avoid title fallback for notification tags Signed-off-by: Vishal Kumar Singh <[email protected]> * test: align notification action payload expectations Signed-off-by: Vishal Kumar Singh <[email protected]> * test: align notification tag e2e expectation --------- Signed-off-by: Vishal Kumar Singh <[email protected]> Co-authored-by: Mattermost Build <[email protected]>
-
Eva Sarafianou (09 Jul 26)
Migrate docs site: Docusaurus config, Algolia, OpenAPI pipeline, and CI (#37402) * Align Docusaurus config for monorepo, wire Algolia DocSearch (P6) Fixes projectName/editUrl/path references left over from the docs-unified repo split, adds trailingSlash for predictable CloudFront 404 handling, and wires an Algolia search block into themeConfig that's only included when credentials are present (Docusaurus's schema rejects an empty appId/apiKey, so this keeps builds green with or without them). Also fixes the sidebar/redirect generator scripts, which still pointed at the pre-rename docs/ directory instead of main/, and adds docs/Makefile, .env.local.example, and an updated README for local dev. Co-authored-by: Cursor <[email protected]> * Wire OpenAPI generation to api/v4/source and add docs-ci.yaml (P7) Replaces build-openapi.mjs's custom YAML-merge implementation with a thin wrapper around the canonical `make -C api build` target, keeping only the MDX sanitization step (quote/autolink fixes) that docusaurus-plugin-openapi-docs needs. Adds a "prebuild" npm script so `npm run build` regenerates the spec automatically, and ignores the generated api/v4/html artifacts (narrow form, since ssr_template.hbs and static/favicon.ico under that path are committed). Also adds docs-ci.yaml as a path-scoped PR/master build+typecheck gate for the docs site, replacing the legacy `docs` repo's Sphinx-based ci.yml now that docs live in this monorepo. Co-authored-by: Cursor <[email protected]> * Rename OpenAPI prebuild script for clarity "prebuild" is an npm lifecycle hook name (auto-runs before "npm run build"), not a descriptive name, so `npm run prebuild` didn't signal it's specifically about OpenAPI generation. Split it into "build:openapi" (the actual script, runnable directly and self-explanatory) with "prebuild" now just delegating to it, preserving the automatic pre-build trigger. Co-authored-by: Cursor <[email protected]> * Regenerate sidebars automatically before dev/build (P7 fixup) documentation.generated.json and developers.generated.json are gitignored and nothing produced them on a fresh checkout, so both `npm start` and `npm run build` failed with MODULE_NOT_FOUND outside a working tree that happened to have stale copies lying around. Wire the sidebar generators into `prestart`/`prebuild` so they're always regenerated first. Co-authored-by: Cursor <[email protected]> * Remove docs/site/.env.local.example There's a single Algolia DocSearch app for docs.mattermost.com; credentials aren't distributed to individual developers, so a per-dev .env.local workflow doesn't apply. Credentials are only ever injected in CI/CD via repository variables. Local builds/dev server run fine without them (the Algolia block in docusaurus.config.ts is conditional). Co-authored-by: Cursor <[email protected]> * Wire OpenAPI doc generation into prestart/prebuild, drop unused Makefile docusaurus-plugin-openapi-docs requires a separate `docusaurus gen-api-docs` CLI step to populate docs/api/reference/ (gitignored) — nothing was invoking it, so a fresh checkout's npm start/build failed the same way the sidebar JSONs did. Split build:openapi into build:openapi:spec (slow, runs make -C api build) and build:openapi:docs (fast, generates MDX from the existing spec), and wire prestart to reuse an existing spec instead of rebuilding it every dev-server start. Also drops docs/Makefile: four of its five targets were pure passthroughs to npm scripts, unreferenced by CI or anything else, and there's no repo-wide `make -C <dir>` convention to fit into. Note: a duplicate-doc-id build failure (operationId `status` in the Playbooks OpenAPI spec colliding with the main API's `status` tag) is being fixed separately in mattermost-plugin-playbooks. Co-authored-by: Cursor <[email protected]> * Fix stale docs/ reference in sidebar generator's error message The existence check still hardcoded "docs/" in its error text after SRC was repointed to main/. Use the SRC constant in the message so it can't drift out of sync with the actual path again. Co-authored-by: Cursor <[email protected]> * remove code comment * Drop unused artifact upload from docs-ci.yaml Nothing consumes it: P9's docs-cd.yml will rebuild independently on push to master rather than downloading it via workflow_run (avoids workflow_run trigger footguns for an infrequent, cheap-enough rebuild), and P10's preview build always needs its own independent build anyway (bakes a per-PR BASE_URL). This was carried over from the old docs repo's ci.yml out of habit; that repo's own PR-time uploads had the same unused-artifact issue (only cd.yml's post-merge run ever consumed it). Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]>
-
Ben Schumacher (09 Jul 26)
[MM-69693] notify token owners when an expired PAT is deleted (#37349) * MM-69693: notify token owners when an expired PAT is deleted Send an at-expiry DM from the cleanup_expired_access_tokens job at the moment it deletes an expired personal access token. This complements the pre-expiry warning cascade (MM-69215): for the silent-integration case, where a fire-and-forget caller swallows the rejection error, the owner is now told their token stopped working. The notification fires in the same step as the delete, so no grace period, tombstone, or new schema is needed and re-notification is inherently impossible. It is best-effort: sent before the delete (while the token->owner mapping still exists) and the delete proceeds regardless of the result. Bot-owned tokens and tokens owned by deactivated users are skipped, matching the pre-expiry job. An app-layer notify callback is injected into the worker, mirroring how expirynotify is wired, so cleanupExpired stays unit-testable with a fake notifier. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014Am6a5P8tpkd9AeEHbCBqg * MM-69693: add app-layer notify tests and isolate notifier panics Add expired_access_token_notify_test.go covering NotifyExpiredAccessTokensDeleted: empty list, happy-path DM, bot-owned skip, deactivated-user skip, and unknown-owner skip with continued processing. Wrap the notifyExpired call in the cleanup worker with its own recover so a panic in the best-effort notifier can't abort execute() before DeleteByIds runs, and add a worker test asserting deletion still happens after a notify panic. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014Am6a5P8tpkd9AeEHbCBqg * MM-69693: drop notifier panic recover from cleanup worker The job-level HandleJobPanic in execute() is already the panic boundary for the run, and NotifyExpiredAccessTokensDeleted logs and swallows its own errors, so the local recover around notifyExpired added no real protection. Remove it (and its test) along with the now-redundant inline comment; the notify-before-delete rationale stays documented on cleanupExpired. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014Am6a5P8tpkd9AeEHbCBqg * MM-69693: thread request.CTX into NotifyExpiredAccessTokensDeleted Pass the job's request context from the cleanup worker down through cleanupExpired into the notify callback instead of building a fresh EmptyContext inside the app function, so notification logging is correlated with the job's logger. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_014Am6a5P8tpkd9AeEHbCBqg --------- Co-authored-by: Claude <[email protected]>
-
Daniel Espino García (09 Jul 26)
[MM-68652] Fix saved state on channel settings shared channels (#37173) * [MM-68652] Fix saved state on channel settings shared channels * Address feedback and simplify flow * Address comments
-
Ben Schumacher (09 Jul 26)
[MM-69215] warn users before their personal access tokens expire (#37272) * MM-69215: warn users before their personal access tokens expire Adds a new pat_expiry_notify job that proactively DMs the owner of a personal access token as it approaches expiry, on a fixed 7/3/1 day cascade. Previously the only signal was a passive badge in Profile > Security, so PAT-backed scripts and integrations broke silently the moment a token lapsed. Behavior: - Hourly PeriodicScheduler + SimpleWorker, modeled on expirynotify and gated on ServiceSettings.EnableUserAccessTokens. - Applies to any active token with a non-zero ExpiresAt. Bot-account tokens and tokens owned by deactivated users are excluded by the store query. - Delivery is a single system-bot DM (GetSystemBot -> GetOrCreateDirectChannel -> CreatePost) localized to the recipient's locale, including the token description. - Only the most urgent applicable bucket is ever sent, so a token that first becomes visible already inside the window (short-lived token, or a just-reactivated owner) gets a single warning rather than a catch-up burst of every threshold it has already passed. Schema/dedup: - New nullable UserAccessToken.LastNotifiedThreshold column (migration 000203). NULL means never notified; it decreases monotonically (7 -> 3 -> 1) and prevents the hourly job from re-sending a warning. - New store methods GetExpiringTokens(now, horizon, limit) and UpdateLastNotifiedThreshold, wired through the retry/timer layers and mocks. Covered by unit tests for the bucket math and store query, plus app-level tests for the dedup, single-warning, and bot-exclusion cases. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: only fetch actionable tokens to avoid notification starvation Address review feedback on the pat_expiry_notify job. GetExpiringTokens previously returned every token in the 7-day window whose marker had not reached the terminal bucket (LastNotifiedThreshold IS NULL OR > 1), including tokens already warned at their current bucket. Ordered by ExpiresAt ASC and capped at the batch limit, a backlog of >1000 already-warned tokens could permanently crowd out a less-urgent unnotified token past the limit, so it never got warned. GetExpiringTokens now takes the notification thresholds and returns only *actionable* rows: for each threshold T, a token qualifies when it has entered the T-day bucket and has not been notified at T or a more urgent bucket. Already-warned rows no longer consume a result slot, so a backlog drains across runs without starving the least-urgent tokens. The worker keeps recomputing each bucket and re-checking the marker as a race guard. Also add a store-test assertion locking down the ExpiresAt-ascending ordering contract that the worker relies on. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: regenerate store layers and mocks to fix CI drift The "Check store layers" and "Check mocks" CI jobs failed because the hand-added GetExpiringTokens and UpdateLastNotifiedThreshold methods were placed in a different order than the generators emit. Regenerate the timer/retry layers with `go generate ./channels/store` and reorder the mock methods to match mockery's alphabetical output. No behavior change. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: allow admins to trigger pat_expiry_notify on demand Add JobTypePatExpiryNotify to the create-job permission allowlist (PermissionManageJobs), consistent with its siblings expiry_notify and cleanup_expired_access_tokens. This lets operators run the warning sweep on demand via POST /api/v4/jobs instead of only on the hourly schedule, and makes the job creatable from API-level tests. Add an api4 test covering the new path: a user without manage_jobs is forbidden, a system admin can create the job. (The notification behavior itself is covered deterministically by the app-layer tests; the api4 harness does not execute job workers.) Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: store last-notified timestamp instead of day bucket Replace UserAccessToken.LastNotifiedThreshold (the smallest day bucket already warned) with LastNotifiedAt (the time of the last warning). Storing the moment rather than a cascade-specific bucket keeps the column independent of the 7/3/1 day cascade and stays correct if the buckets are later changed or refined — the bucket already covered is recovered from (ExpiresAt - LastNotifiedAt). The actionable-only store query is equally clean: a token still needs a warning for threshold T when its last warning (if any) was sent while more than T days remained, i.e. LastNotifiedAt < ExpiresAt - T*day. Also reword the warning DM to drop the awkward "day(s)" plural: the 7/3-day buckets now render "in N days or less", and the 1-day bucket uses a dedicated "within 24 hours" message. Migration 000203 renamed accordingly (column lastnotifiedat bigint); layers regenerated, mock/tests updated. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: read expiring tokens from master to avoid duplicate warnings GetExpiringTokens dedups against LastNotifiedAt, which UpdateLastNotifiedAt writes to master after each warning. Reading the dedup query from a replica could miss a just-written LastNotifiedAt under replication lag and re-surface an already-warned token, sending a duplicate DM — a window that on-demand re-runs of the job (now that the job type is allowlisted) make reachable. Switch the read to master; it is a once-per-run batch query, so there is no read-scaling cost. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: shorten GetExpiringTokens master-read comment Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 * MM-69215: point expiry warning at regenerating the token MM-69561 adds PAT rotation (regenerate a token's secret in place, keeping its id/description). Reword the pre-expiry warning DMs to tell the owner to regenerate the token rather than create a new one — regeneration is the right action for a token that backs an integration, since only the secret changes. Assert the "regenerate" CTA in the app test. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_018SmTd6i2fqt3YWaaPyorF7 --------- Co-authored-by: Claude <[email protected]>
-
sabril (09 Jul 26)
Bump Playwright v2 CI workers from 10 to 15 (#37414)
-
Dylan Haussermann (09 Jul 26)
Add Playwright E2E test for maximum login attempts lockout (#36932) Tests that a user account is locked after exceeding the configured MaximumLoginAttempts limit and can be unlocked via the admin API. Co-authored-by: Claude Sonnet 4.6 (1M context) <[email protected]> Co-authored-by: Mattermost Build <[email protected]>
-
cursor[bot] (08 Jul 26)
[MM-69591] Remove WebSocketEventScope feature flag (#37384) * Remove WebSocketEventScope feature flag gating on server Leave the typing/reaction WebSocket event scoping permanently enabled. Co-authored-by: mattermost-code <[email protected]> * Remove WebSocketEventScope feature flag usage in webapp Always update the active channel/team/thread over the WebSocket so the event scoping stays permanently enabled. Co-authored-by: mattermost-code <[email protected]> * Remove WebSocketEventScope feature flag from e2e default config Co-authored-by: mattermost-code <[email protected]> --------- Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: mattermost-code <[email protected]> Co-authored-by: Jesse Hallam <[email protected]>
Mattermost Security
Mattermost Website
Website
301 Moved Permanently
Redirects
Redirects to https://mattermost.com/?&redirect_source=mm-org
Security Checks
1 security checks failed (64 passed)
- External Redirect Detected
Server Details
- IP Address 104.18.10.136
- Location San Francisco, California, United States of America, NA
- ISP CloudFlare Inc.
- ASN AS13335
Associated Countries
-
US
Safety Score
Website marked as safe
100%
Blacklist Check
mattermost.org was found on 0 blacklists
- AntiSocial Blacklist
- Artists Against 419
- Badbitcoin
- Bambenek Consulting
- CERT Polska
- CoinBlockerLists
- CRDF
- CryptoScamDB
- EtherAddressLookup
- EtherScamDB
- Fake Website Buster
- MetaMask EthPhishing
- NABP Not Recommended Sites
- OpenPhish
- PetScams
- PhishFeed
- PhishFort
- Phishing.Database
- PhishStats
- PhishTank
- Phishunt
- RPiList Not Serious
- Scam.Directory
- SecureReload Phishing List
- Spam404
- StopGunScams
- Suspicious Hosting IP
- ThreatFox
- ThreatLog
- TweetFeed
- URLhaus
- ViriBack C2 Tracker
Website Preview
Mattermost Android App
APK Info
- App Mattermost
- Creation Date 17 Dec 17
- Last Updated 19 Jul 24
- Current Version 1.5.1
- Creator Mattermost
- Downloads 10,000+ downloads
- Privacy Report View on Exodus →
De-Googled Compatibility
Permissions
- Access Network State
- Camera
- Internet
- Read App Badge
- Read External Storage
- Receive Boot Completed
- System Alert Window
- Vibrate
- Wake Lock
- Write External Storage
- Update Count
- Receive
- Send
- Read Settings
- Update Shortcut
- Change Badge
- Read Settings
- Write Settings
- Update Badge
- C2d Message
- Read Settings
- Write Settings
- Read
- Write
- Broadcast Badge
- Provider Insert Badge
- Badge Count Read
- Badge Count Write
Mattermost iOS App
App Info
Mattermost
Requires Mattermost Server v10.11.0+. Older servers may not be able to connect or have unexpected behavior. ------- Mattermost is the leading collaborative workflow platform for defense, intelligence, security, and critical infrastructure. The platform runs on-premises and in private clouds, delivering secure messaging, file sharing, workflow automation, audio/screenshare, and project management—all with full data and operational control. - Securely share messages, files, and links across from your preferred mobile devices. - Start 1:1 and group voice calls with a single click without leaving Mattermost. - Keep critical workflows moving forward with Playbook. - Get the message out without having to manage every endpoint with Enterprise Mobility Management (AppConfig) support. - Private mobility with ID-only push notifications to keep sensitive data protected while keeping stakeholders informed. To use this app, you need a URL for a Mattermost server. ------- Deploy your own server: https://docs.mattermost.com/guides/deployment.html Terms of Service: https://mattermost.com/terms-of-service/ Contribute to the project: https://github.com/mattermost/mattermost-mobile
Rating
Version Info
- Current Version 2.40.0
- Last Updated 15 May 26
- First Released 10 Jul 17
- Minimum iOS Version 16.0
- Device Models Supported 127
App Details
- IPA Size 92.03 Mb
- Price Free (USD)
- Age Advisory 4+
- Supported Languages 21
- Developer Mattermost, Inc.
- Bundle ID com.mattermost.rn
Screenshots
Mattermost Reviews
More Team Collaboration
-
Privacy-focused messenger using the Matrix protocol. The Element client allows for group chat rooms, media sharing voice and video group calls.
-
An IRC-based solution is another option, being decentralized there is no point of failure, and it's easy to self-host. However it's important to keep security in mind while configuring your IRC instance and ensure that channels are properly encrypted - IRC tends to be better for open communications. There's a variety of clients to choose from - popular options include: The Longe (Web-based), HexChat (Linux), Pidgin (Linux), WeeChat (Linux, terminal-based), IceChat (Windows), XChat Aqua (MacOS), Palaver (iOS) and Revolution (Android).
-
Easy-to-deploy, self-hosted team collaboration platform with stable, feature-rich cross-platform client apps. The UI is fast, good looking and intuitive, so very little technical experience is needed for users of the platform. Rocket.Chat's feature set is similar to Slack's, making it a good replacement for any team looking to have greater control over their data.
-
Open source team chat organized around topic-based threading, which keeps busy conversations easier to follow than channel-only tools. Can be self-hosted, or used as a paid cloud service. The threading model takes some getting used to.
About the Data: Mattermost
Change History
- Amended (androidApp, iosApp)
API
You can access Mattermost's data programmatically via our API. Simply make a GET request to:
https://api.awesome-privacy.xyz/v1/services/mattermost The REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.
Share Mattermost
Help your friends compare Team Collaboration, and pick
privacy-respecting software and services.
Share Mattermost and Awesome Privacy with your network!