Commit graph

22570 commits

Author SHA1 Message Date
Julien Tant
34b43b09eb
Merge 3a8e887afc into 25bf5edc4f 2026-05-25 07:00:06 -07:00
Harrison Healey
25bf5edc4f
MM-68773 Fix bug with HTML encoding in proxied image URL (#36555)
Some checks are pending
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / OpenSearch v2 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* MM-68773 Fix bug with HTML encoding in proxied image URL

* Remove some now-unneeded hasImageProxy props
2026-05-25 09:14:14 -04:00
unified-ci-app[bot]
b609ec59fc
chore: Update NOTICE.txt file with updated dependencies (#36729)
Automatic Merge
2026-05-25 13:54:05 +02:00
Alejandro García Montoro
c6b59cc9a7
MM-68663: Admin console support and Test Connection generalization for Azure Blob Storage (#36583)
* Generalize the file storage Test Connection endpoint

Replaces the S3-only /api/v4/file/s3_test handler with a backend-agnostic
POST /api/v4/file/test that validates mandatory fields per driver and
runs a write/read/delete probe against the configured backend. The
legacy /file/s3_test route stays as a thin wrapper so existing clients
keep working.

The driver switch validates S3 and Azure mandatory fields explicitly,
treats Local as a no-op (no required credentials), and rejects unknown
or empty driver names with a 400 and a specific error code so admins
get a useful message instead of a generic backend failure.

Reuses config.Desanitize (renamed from the package-private desanitize)
so the FakeSetting placeholder swap for secrets is shared with the
PUT /api/v4/config save path. Adding a new driver-secret in the future
only requires touching config.Desanitize once. Desanitize is also made
nil-safe on every pointer dereference so callers can hand it a partial
config without first running SetDefaults().

Mattermost-redux and the webapp client gain a corresponding
TestFileStoreConnection method that the admin console action layer
calls instead of the deprecated S3-specific method.

------
AI assisted commit

* Wire Azure Blob Storage into the file storage admin console

Adds the Azure Blob Storage option to the File Storage panel in the
System Console. Selecting it enables Azure-specific fields for the
storage account name, container, optional path prefix, shared key,
optional endpoint override, secure-connections toggle, and request
timeout. The fields are hidden and disabled when the driver is set to
Local or S3, matching the existing pattern.

Help text and placeholders are added in the webapp i18n catalog so
admins see the same field labels documented in the admin guide.

The same set of fields is repeated for the Files Export panel when
DedicatedExportStore is enabled, keeping the export backend
configurable independently of the primary file store.

------
AI assisted commit

* Document /api/v4/file/test in the OpenAPI spec

Adds the new backend-agnostic file storage Test Connection endpoint to
the public OpenAPI surface. The request body is optional: callers that
omit it test the running server configuration, callers that include a
full AdminConfig test the supplied configuration without persisting
anything. The deprecated /api/v4/file/s3_test endpoint is left
unchanged in the spec for the existing S3-only flow.

------
AI assisted commit

* Add UI-only Cypress coverage for the Azure file storage panel

Adds a Cypress spec that drives the System Console File Storage panel,
switches the driver to Azure Blob Storage, fills in the Azure fields,
and asserts the expected fields appear (and S3 fields are hidden). The
spec is UI-only and does not depend on an Azure backend or Azurite, so
it can run in CI without external infrastructure.

Updates the existing environment_spec.js so it tolerates the new Azure
option in the driver dropdown.

------
AI assisted commit

* Nil-guard file storage mandatory-field checks

CheckMandatoryS3Fields and CheckMandatoryAzureFields built a
FileBackendSettings via NewFileBackendSettingsFromConfig before
validating, but that constructor dereferences pointers
unconditionally and would panic if a caller skipped the api
handler's reflective nil check. Validate the required pointers
directly against FileSettings instead, dropping the throwaway
constructor call so the methods are safe to call from any path.

------
AI assisted commit

* Check permission before validating file settings

The /file/test handler ran checkHasNilFields before
SessionHasPermissionTo, so an unauthorized caller posting a partial
config got a 400, leaking config shape, rather than a 403. Swap the two
blocks so the permission decision happens first.

------
AI assisted commit

* Preserve FakeSetting when desanitize has no actual

The Azure access key, export Azure access key, and S3 secret access key
branches in Desanitize reassigned target to actual without checking
actual for nil. When the running config had no value, the FakeSetting
placeholder in target was replaced with nil, dropping the field from the
round-trip. Guard the assignment so the placeholder stays in place when
actual is unset.

------
AI assisted commit

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-25 11:36:02 +00:00
Felipe Martin
4d8c25f040
[MM-68736] Reconcile partial GM membership in bulk import (#36542)
* [MM-68736] Reconcile partial GM membership in bulk import

importDirectChannel failed with "ChannelMember not found" when the
group channel hash already existed in Channels but one or more
participants were missing from ChannelMembers (concurrent import
workers, a prior import that crashed mid SaveMember loop, or a
pre-existing GM whose membership has drifted).

The function only used existingMembers to compare LastViewedAt and
still appended absent participants to UpdateMultipleMembers, whose
UPDATE-then-SELECT returns sql.ErrNoRows for the missing row.

Insert the missing ChannelMembers row via SaveMember (logging the
join event) before the UPDATE path. ErrConflict is treated as benign
so concurrent workers racing on the same MPIM hash do not fail each
other.

* [MM-68736] Add missing i18n key for new bulk import error

The save_member.error key was added in the importDirectChannel fix but
not registered in i18n/en.json.

* [MM-68736] Address review feedback

- Broaden the save_member.error translation to also cover DM imports,
  since importDirectChannel runs the same SaveMember reconciliation
  path for both 2-participant DMs and 3+-participant GMs.
- In the idempotent re-import test, assert that
  ChannelMemberHistory.GetMembershipChanges returns no rows after the
  second import. LogJoinEvent is only invoked when the missing-member
  branch runs, so an empty result proves SaveMember was not called
  for any already-present participant.
2026-05-25 12:17:08 +02:00
Harshil Sharma
cfafefe58c
Used short mode of data spillage report card in threads view to fix spacing issue (#36709)
Some checks are pending
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / OpenSearch v2 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
2026-05-25 09:36:01 +05:30
cursor[bot]
508f1551e3
Fix flaky TestScrubPost (#36686)
The should_preserve_non-content_fields subtest asserted UpdateAt was
unchanged after scrubPost, but scrubPost refreshes UpdateAt via
model.GetMillis(). When the scrub runs in a later millisecond than the
fixture setup, the strict equality fails intermittently.

Align the assertion with scrubPost behavior (UpdateAt >= pre-scrub value).

Tests-only change. Verified with `go test -run '^TestScrubPost$' -race
-count=100` and 10000 runs of the subtest locally.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-05-25 09:13:25 +05:30
cursor[bot]
7e75035cb6
Add Data Spillage discovery page (#36697)
Some checks failed
Server CI / Check migration files (push) Has been cancelled
Server CI / Generate email templates (push) Has been cancelled
Server CI / Check store layers (push) Has been cancelled
Server CI / Check mmctl docs (push) Has been cancelled
Server CI / Postgres (shard 0) (push) Has been cancelled
Server CI / Postgres (shard 1) (push) Has been cancelled
Server CI / Postgres (shard 2) (push) Has been cancelled
Server CI / Postgres (shard 3) (push) Has been cancelled
Server CI / Merge Postgres Test Results (push) Has been cancelled
Server CI / Elasticsearch v8 Compatibility (push) Has been cancelled
Server CI / OpenSearch v2 Compatibility (push) Has been cancelled
Server CI / Postgres FIPS (shard 0) (push) Has been cancelled
Server CI / Postgres FIPS (shard 1) (push) Has been cancelled
Server CI / Postgres FIPS (shard 2) (push) Has been cancelled
Server CI / Postgres FIPS (shard 3) (push) Has been cancelled
Server CI / Merge Postgres FIPS Test Results (push) Has been cancelled
Server CI / Run mmctl tests (push) Has been cancelled
Server CI / Run mmctl tests (FIPS) (push) Has been cancelled
Server CI / Build mattermost server app (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
* Add Data Spillage feature discovery page

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Strengthen Data Spillage discovery tests

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Fix Data Spillage discovery precommit issues

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Address PR feedback: 1 items resolved, 0 declined

* Remove Entry SKU hide condition for content flagging discovery

* Update Data Spillage discovery illustration

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Replace Data Spillage discovery illustration

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>
2026-05-22 14:44:44 -04:00
Jesse Hallam
b60ba8b6b4
chore(ci): allow build-server-image to build and push from release branches (#36716) 2026-05-22 14:15:23 -04:00
Jesse Hallam
44ba06ee3c
MM-68248: Handle missing OpenSearch indexes gracefully before reindex (#36712)
* MM-68248: Handle missing indexes gracefully before reindex

OpenSearch v3 rejects _update_by_query and _delete_by_query with no index
argument (405), and returns index_not_found_exception (404) when querying
an exact index name that hasn't been created yet. Both arise before any
reindex has run, since indexes are created on first document write.

Return nil/empty instead of an error from all affected operations, and add
test coverage for each in the no-indexes state.

* MM-68248: Fix copy-paste operation names in DeleteFilesBatch

* MM-68248: Add i18n string for delete_files_batch error

* MM-68248: Also check error type in isIndexNotFound
2026-05-22 16:05:03 +00:00
Pablo Vélez
b0185d9817
update packages to Fix npm audit vulnerabilities (#35810)
* Fix npm audit vulnerabilities and replace image-webpack-loader with sharp

* remove dead webp config and restore SVG optimization via svgoMinify

* fix import order

* removed unused gif from testing, and add missing peer dependency

* make sure only svgs are parsed

* scope svgoMinify to src- SVGs via loader rule

* remove redundant npm overrides per review feedback

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-22 17:57:53 +02:00
Jesse Hallam
834a86b5e3
MM-68248: Support OpenSearch v3 (#36617)
* Remove build-opensearch-image.yml -- the published image is unused

* MM-68248: Support OpenSearch v3

* MM-68248: Add CI job to test OpenSearch v2 backwards compatibility

* MM-68248: Handle missing indexes gracefully before reindex

OpenSearch v3 rejects _update_by_query and _delete_by_query with no index
argument (405), and returns index_not_found_exception (404) when querying
an exact index name that hasn't been created yet. Both arise before any
reindex has run, since indexes are created on first document write.

Return nil/empty instead of an error from all affected operations, and add
test coverage for each in the no-indexes state.

* MM-68248: Fix copy-paste operation names in DeleteFilesBatch

* MM-68248: Add i18n string for delete_files_batch error

* Revert "MM-68248: Add i18n string for delete_files_batch error"

This reverts commit e885678088.

* Revert "MM-68248: Fix copy-paste operation names in DeleteFilesBatch"

This reverts commit 4b7caacf59.

* Revert "MM-68248: Handle missing indexes gracefully before reindex"

This reverts commit 2d2d522f86.
2026-05-22 15:37:50 +00:00
Ben Cooke
f8e233cc39
Fix Group Details role dropdown not updating UI when changing role (#36561) 2026-05-22 11:07:10 -04:00
David Krauser
e8632bd456
[MM-68777] Add admin property field permission level (#36558) 2026-05-22 11:01:41 -04:00
cursor[bot]
4e01dae534
Fix flaky TestPreparePostForClient/files (#36631)
The files subtest polled for post file metadata with assert.Eventually
using only a one-second total wait. Under CI load, PreparePostForClient
can take longer than that to see persisted file rows, causing intermittent
timeouts while the final assert would still pass if given time.

Tests-only change. Verified with go test -run
'^TestPreparePostForClient$/^files$' -race -count=100 locally.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
2026-05-22 10:40:49 -04:00
Doug Lauder
c63154598c
MM-66162: harden GET /sharedchannels/{id}/remotes error path and add WS guard (#36696)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* MM-66162: harden GET /sharedchannels/{id}/remotes error path and add WS guard

  Two small follow-ups on top of the existing fix that returns 200 with an
  empty list when a channel is not shared.

  Server: getSharedChannelRemotes built its 500 AppError with nil params,
  so the i18n template "Could not fetch status for secure connections:
  {{.Error}}." rendered as "<no value>" in logs and response bodies when a
  genuinely unexpected error occurred. Pass map[string]any{"Error":
  err.Error()} so the underlying error surfaces, matching the pattern
  already used by the slash command caller in
  channels/app/slashcommands/command_share.go.

  Webapp: handleSharedChannelRemoteUpdatedEvent dispatched
  fetchChannelRemotes unconditionally on every shared_channel_remote_updated
  WS event, including for channels the local state already knows are not
  shared. The server publishes this event from the onInvite callback after
  a remote accepts a channel invitation, by which point the channel has
  already been flipped to shared and the channel_updated event that did so
  has already fired, so the local channel should reflect shared=true when
  this event arrives. If it does not, the event is not actionable and we
  skip the fetch.

  Adds jest coverage for the four cases of the new guard.

* add regression test for stale shared channel state

  Pins the DB inconsistency scenario suggested in the original ticket
  investigation: Channel.shared is true and a SharedChannelRemote row
  exists, but the SharedChannels row is missing. The endpoint should
  return 200 with an empty list rather than surfacing the stale state
  as an internal server error. Also tightens the existing
  TestGetSharedChannelRemotes by asserting the status code on the
  success path.
2026-05-22 09:59:15 -04:00
cursor[bot]
27d144226f
Fix inactive team icon active styling (#36683)
Prevent decorative team icons from showing the active sidebar highlight when clicked, and pass the channel ID needed by the access-control subject builder so the current checkout can build.

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>
2026-05-22 18:31:23 +05:30
cursor[bot]
efdebec6ad
Fix flaky TestPatchTeam GroupConstrained subtest (#36689) 2026-05-22 08:38:27 -04:00
cursor[bot]
182049583b
Skip flaky TestGetLogs (MM-68910) (#36659)
* Skip flaky TestGetLogs

Skipping while the root cause is investigated under MM-68910.

Tests-only change.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Address PR feedback: 2 items resolved, 0 declined

* Address PR feedback: 2 items resolved, 0 declined

* Address PR feedback: 2 items resolved, 0 declined

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-05-22 12:50:24 +02:00
Andre Vasconcelos
b4aa46a4be
Bumping version of prepackaged boards plugin (#36701)
Automatic Merge
2026-05-22 10:53:37 +02:00
Ben Schumacher
209606f15b
MM-68419: Add expires_at to PAT data model and enforce expiry at token validation (#36243)
* Add expires_at to PAT data model and enforce expiry at token validation

Adds an ExpiresAt field (int64 millis, 0 = never expires) to the
UserAccessToken model and DB table, enforces expiry when a PAT is used
to create a session, clamps the resulting session's ExpiresAt to the
token's expiry so cached sessions also honor it, ships a background job
(cleanup_expired_access_tokens) that periodically deletes expired
tokens along with any sessions minted from them, and emits audit events
for rejected and reaped expired tokens.

Refs: MM-68419

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix govet shadow warnings in DeleteExpired

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Stabilize expired PAT test by persisting an already-expired token

The previous variant created a live token, used it to mint a session,
then backdated the row and revoked the cached session to force a
re-validation. That flow was race-prone under parallel test execution
and was flagged as flaky in CI. Replace it with a direct store write
that persists the PAT with ExpiresAt already in the past, so
createSessionForUserAccessToken is exercised deterministically on the
first HTTP call and no session cache races are possible.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Address PR review: batched cleanup, consistent filters, audit ordering

- server.go: initialize s.Audit before initJobs() so the cleanup worker
  never captures a nil audit logger.

- Replace DeleteExpired(cutoff) with DeleteByIds([]string) on
  UserAccessTokenStore. The worker now fetches a batch via
  GetExpiredBefore, emits one audit record per token, then deletes
  exactly that batch by id — guaranteeing 1:1 audit/delete pairing
  and eliminating the IsActive-filter mismatch between reads and
  deletes. The worker loops up to maxBatches (=1000) x batchLimit
  (=1000) rows per run and stops when GetExpiredBefore returns less
  than batchLimit or zero rows.

- GetExpiredBefore now selects an explicit column set that omits the
  secret Token column, so the PAT secret never travels from DB to app.

- DeleteByIds surfaces an error from RowsAffected instead of silently
  returning 0.

- Remove dead job.Data initialization in the worker.

- api4 test: set IsActive: true explicitly, walk the AppError chain
  and assert the specific Id app.user_access_token.expired so future
  401 regressions are caught.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Use named returns in DeleteByIds and clean up expired fixture in test

- DeleteByIds now declares (deleted int64, err error) and uses bare
  returns on every error path so finalizeTransactionX can append a
  rollback failure to the returned error via merror.Append. Previously
  early returns short-circuited the deferred rollback's error
  contribution.
- Add the expired token to the test cleanup so all three fixtures are
  removed even on early test exit.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Guard GetExpiredBefore against non-positive limit + tighten store test

- GetExpiredBefore now short-circuits when limit <= 0 and returns an
  empty slice without hitting the DB. This prevents the int -> uint64
  cast on a negative value from wrapping into an effectively unbounded
  query.
- Store test now asserts row.Token is empty for every row returned by
  GetExpiredBefore (not just the matched one) to catch any future
  query change that accidentally re-introduces the secret column.
- Added store-level coverage for the limit=0 and limit<0 short-circuit
  contract.

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Add session-clamping and worker tests; bump migration to 172

Address PR test-coverage analysis (issuecomment-4336010565):

- api4/user_test.go: add two subtests covering session.ExpiresAt
  behavior — clamped to token.ExpiresAt when the PAT has a non-zero
  ExpiresAt, and untouched (long-lived) when the PAT has no expiry.
- cleanup_expired_access_tokens/worker.go: extract the batching/audit/
  error orchestration into a package-private cleanupExpired() taking
  small interfaces (expiredTokenStore, auditRecorder) so it can be
  unit-tested without spinning up a job server.
- cleanup_expired_access_tokens/worker_test.go (new): seven unit tests
  cover happy path, empty result, full-batch -> next iteration,
  maxIter cap, GetExpiredBefore error propagation, DeleteByIds error
  propagation, and nil auditLogger guard.
- Bump migration 000170_add_expiresat_to_user_access_tokens to 000172
  to slot in behind the master-side 000170 (property_groups_version)
  and 000171 (drop_property_fields_protected_index).

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix PAT expiry audit ordering and cleanup scheduler gate

- Move IsExpired() check after EnableUserAccessTokens gate in
  createSessionForUserAccessToken so the AuditEventRejectExpiredUserAccessToken
  event only fires when PATs are active for the user, not when the feature
  is globally disabled.
- Tie the cleanup_expired_access_tokens scheduler to EnableUserAccessTokens
  so the hourly job does not schedule on servers where PATs are disabled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove per-token audit logging from expired PAT cleanup job

Background system jobs do not emit audit events in this codebase —
only user/admin-initiated actions do. The cleanup worker's per-token
AuditEventExpireUserAccessToken records were inconsistent with that
pattern (cleanup_desktop_tokens and other session jobs log nothing).

Also removes the early s.Audit init in NewServer that existed solely
to supply a non-nil logger to the worker.

The AuditEventRejectExpiredUserAccessToken event (emitted by
createSessionForUserAccessToken when a live request is rejected) is
unchanged — that is an auth gate firing in response to a request and
warrants auditing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Replace hand-rolled IN-clause helpers with squirrel query builder

Remove placeholders() and idsToArgs() from DeleteByIds — squirrel's
sq.Eq{"column": slice} generates the IN clause and argument list
automatically, matching the pattern used throughout the sqlstore package.

Also restructures the sessions delete from a PostgreSQL-specific
USING join to a portable subquery, keeping both statements expressible
via the query builder.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Drop redundant logger.Error calls in cleanup worker

SimpleWorker already logs any error returned from execute at the
Error level (base_workers.go:86). The extra logger.Error calls before
return were double-logging every failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Use mlog.CreateConsoleTestLogger in cleanup worker tests

Replaces the hand-rolled newTestLogger helper with the established
mlog.CreateConsoleTestLogger(t) pattern used by other job tests in
this package (jobs_test.go, recap/worker_test.go). It wires cleanup
and test-runner output automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Consolidate cleanup worker tests into subtests

Groups the six top-level TestCleanupExpiredXxx functions under a single
TestCleanupExpired parent with t.Run subtests. One shared logger is
created at the parent level; each subtest gets its own fakeStore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Revert incidental configureAudit restructure in server.go

The separation of s.Audit init from configureAudit was an unintended
side effect of an earlier commit. Restore the original pattern where
configureAudit is only called when s.Audit was nil at startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Remove api4 PAT expiry tests until API endpoint exists

The three tests (expired token rejected, session clamped, no-expiry
default) bypass the API to inject ExpiresAt via the store directly,
since no API endpoint exists yet to create tokens with an expiry.
They belong in the PR that adds that endpoint.

The same behaviors are covered at the appropriate layer by
storetest/user_access_token_store.go and model/user_access_token_test.go.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Prevent ExtendSessionExpiryIfNeeded from overriding PAT session expiry

PAT-authenticated sessions have their ExpiresAt clamped to the token's
ExpiresAt in createSessionForUserAccessToken. However, ExtendSessionExpiryIfNeeded
was resetting that expiry to now+SessionLengthWebInHours on the first
subsequent request, effectively bypassing PAT expiry for cached sessions.

Guard the extension to skip SessionTypeUserAccessToken sessions until
GetSessionLengthInMillis learns to return a length bounded by token.ExpiresAt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Strip ExpiresAt in create-token handler until API officially supports it

The JSON decoder populates the full accessToken struct from the request body,
and only UserId and Token were being overwritten before the store call. This
allowed clients to set an arbitrary expires_at (including 0 for non-expiring)
through the existing endpoint, contradicting the PR description.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Clear session cache for affected users after DeleteByIds in cleanup worker

DeleteByIds removes sessions from the DB but did not invalidate the in-memory
session cache. This left stale sessions readable from cache until eviction,
inconsistent with the RevokeSession path.

Thread a clearSessionCache callback through MakeWorker and cleanupExpired.
After each successful batch delete, call it for each unique UserId in the
batch. The callback is deduplicated per batch to avoid redundant cache
invalidations when a user has multiple expired tokens.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add partial index on useraccesstokens.expiresat

The cleanup job queries expiresat on every scheduled run (hourly). Without an
index this is a full sequential scan. Add a partial index WHERE expiresat > 0
to match the query's filter, keeping the index small since most tokens have no
expiry set. Mirrors the idx_sessions_expires_at pattern on the sessions table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Register JobTypeCleanupExpiredAccessTokens in job permission switches

Without entries in SessionHasPermissionToReadJob, SessionHasPermissionToCreateJob,
and SessionHasPermissionToManageJob, the job type falls through to (false, nil),
which API handlers treat as HTTP 400. This made the cleanup job invisible to
System Console and unmanageable via API (list, cancel, manual trigger all 400).

Add the job type to the PermissionManageJobs / PermissionReadJobs groups in
all three switches, matching how other internal jobs like JobTypeMigrations
are handled.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Teach GetSessionLengthInMillis to honor PAT ExpiresAt

Replace the blunt guard in ExtendSessionExpiryIfNeeded with proper logic in
GetSessionLengthInMillis: for PAT sessions with a fixed ExpiresAt, return the
remaining lifetime instead of the configured web-session hours.

This means newExpiry = now + (ExpiresAt - now) = ExpiresAt, so extension never
pushes the session past the token's own expiry. The elapsed threshold
collapses to zero for such sessions, so no spurious DB writes occur either.

Non-expiring PAT sessions (ExpiresAt == 0) continue to use normal web-session
extension, which is correct behavior.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Split expiresat index into separate non-transactional migration (000175)

CREATE INDEX CONCURRENTLY cannot run inside a transaction block. The morph
migration runner wraps each file in a transaction by default, causing the
combined migration to fail.

Split the index creation out of 000174 into a new 000175 migration file
with the -- morph:nontransactional directive, following the same pattern
used by 000135, 000155, 000173 and others. The 174 down migration no longer
needs to drop the index since 175 owns it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Update Beginx call to renamed Begin (sqlx wrapper API change on master)

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 10:30:30 +02:00
Weblate (bot)
b0d2f83620
Translations update from Mattermost Weblate (#36695)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Translated using Weblate (Lithuanian)

Currently translated at 62.6% (4601 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lt/

* Translated using Weblate (Lithuanian)

Currently translated at 62.6% (4601 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lt/

* Translated using Weblate (Estonian)

Currently translated at 0.4% (31 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/et/

* Translated using Weblate (Estonian)

Currently translated at 0.4% (31 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/et/

* Translated using Weblate (Danish)

Currently translated at 8.1% (266 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/da/

* Translated using Weblate (Danish)

Currently translated at 8.1% (266 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/da/

* Translated using Weblate (Italian)

Currently translated at 44.6% (3281 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/it/

* Translated using Weblate (Italian)

Currently translated at 44.6% (3281 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/it/

* Translated using Weblate (Belarusian)

Currently translated at 88.6% (6509 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/be/

* Translated using Weblate (Khmer (Central))

Currently translated at 0.6% (48 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/km/

* Translated using Weblate (Khmer (Central))

Currently translated at 0.6% (48 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/km/

* Translated using Weblate (Latin)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/la/

* Translated using Weblate (Latin)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/la/

* Translated using Weblate (Latin)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/la/

* Translated using Weblate (Persian)

Currently translated at 54.5% (4006 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fa/

* Translated using Weblate (Persian)

Currently translated at 54.5% (4006 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fa/

* Translated using Weblate (Portuguese)

Currently translated at 27.1% (1993 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt/

* Translated using Weblate (Portuguese)

Currently translated at 27.1% (1993 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt/

* Translated using Weblate (Albanian)

Currently translated at 3.1% (228 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sq/

* Translated using Weblate (Albanian)

Currently translated at 3.1% (228 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sq/

* Translated using Weblate (Catalan)

Currently translated at 33.3% (1089 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ca/

* Translated using Weblate (Lao)

Currently translated at 0.1% (1 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/lo/

* Translated using Weblate (Macedonian)

Currently translated at 1.7% (126 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mk/

* Translated using Weblate (Macedonian)

Currently translated at 1.7% (126 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mk/

* Translated using Weblate (Hungarian)

Currently translated at 62.9% (2058 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/hu/

* Translated using Weblate (Estonian)

Currently translated at 0.5% (19 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/et/

* Translated using Weblate (Georgian)

Currently translated at 7.1% (525 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ka/

* Translated using Weblate (Georgian)

Currently translated at 7.1% (525 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ka/

* Translated using Weblate (Georgian)

Currently translated at 7.1% (525 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ka/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 4.4% (147 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nb_NO/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/

* Translated using Weblate (Nepali)

Currently translated at 0.1% (6 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ne/

* Translated using Weblate (Malayalam)

Currently translated at 3.7% (272 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ml/

* Translated using Weblate (Malayalam)

Currently translated at 3.7% (272 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ml/

* Translated using Weblate (Mongolian)

Currently translated at 0.6% (21 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/mn/

* Translated using Weblate (French)

Currently translated at 65.2% (4788 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fr/

* Translated using Weblate (French)

Currently translated at 65.2% (4788 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fr/

* Translated using Weblate (Swedish)

Currently translated at 83.6% (2733 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sv/

* Translated using Weblate (Japanese)

Currently translated at 91.4% (6715 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ja/

* Translated using Weblate (Japanese)

Currently translated at 91.4% (6715 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ja/

* Translated using Weblate (Croatian)

Currently translated at 25.8% (1896 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hr/

* Translated using Weblate (Croatian)

Currently translated at 25.8% (1896 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hr/

* Translated using Weblate (Filipino)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fil/

* Translated using Weblate (Filipino)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fil/

* Translated using Weblate (Filipino)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fil/

* Translated using Weblate (Romanian)

Currently translated at 48.3% (3551 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ro/

* Translated using Weblate (Romanian)

Currently translated at 48.3% (3551 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ro/

* Translated using Weblate (Amharic)

Currently translated at 0.1% (4 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/am/

* Translated using Weblate (Amharic)

Currently translated at 0.1% (4 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/am/

* Translated using Weblate (Sinhala)

Currently translated at 0.3% (12 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/si/

* Translated using Weblate (French)

Currently translated at 65.1% (2129 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/fr/

* Translated using Weblate (Bengali)

Currently translated at 0.9% (70 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bn/

* Translated using Weblate (Bengali)

Currently translated at 0.9% (70 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bn/

* Translated using Weblate (Bengali)

Currently translated at 0.9% (70 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bn/

* Translated using Weblate (Georgian)

Currently translated at 3.6% (120 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ka/

* Translated using Weblate (Georgian)

Currently translated at 3.6% (120 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ka/

* Translated using Weblate (Romanian)

Currently translated at 58.0% (1897 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ro/

* Translated using Weblate (Frisian)

Currently translated at 56.6% (4161 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fy/

* Translated using Weblate (Frisian)

Currently translated at 56.6% (4161 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fy/

* Translated using Weblate (Frisian)

Currently translated at 56.6% (4161 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fy/

* Translated using Weblate (Russian)

Currently translated at 80.7% (2638 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ru/

* Translated using Weblate (Kazakh)

Currently translated at 12.7% (938 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk/

* Translated using Weblate (Kazakh)

Currently translated at 12.7% (938 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk/

* Translated using Weblate (Kazakh)

Currently translated at 12.7% (938 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk/

* Translated using Weblate (English (Australia))

Currently translated at 88.0% (2875 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/

* Translated using Weblate (English (Australia))

Currently translated at 88.0% (2875 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/

* Translated using Weblate (Hindi)

Currently translated at 26.7% (1961 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hi/

* Translated using Weblate (Hindi)

Currently translated at 26.7% (1961 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hi/

* Translated using Weblate (Dutch)

Currently translated at 98.4% (7230 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/

* Translated using Weblate (Dutch)

Currently translated at 98.4% (7230 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/

* Translated using Weblate (Galician)

Currently translated at 19.8% (1458 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gl/

* Translated using Weblate (Galician)

Currently translated at 19.8% (1458 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gl/

* Translated using Weblate (Swedish)

Currently translated at 88.4% (6497 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sv/

* Translated using Weblate (Swedish)

Currently translated at 88.4% (6497 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sv/

* Translated using Weblate (Arabic)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar/

* Translated using Weblate (Arabic)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar/

* Translated using Weblate (Albanian)

Currently translated at 0.9% (32 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sq/

* Translated using Weblate (Vietnamese)

Currently translated at 66.5% (2174 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/vi/

* Translated using Weblate (German)

Currently translated at 90.6% (2962 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/de/

* Translated using Weblate (German)

Currently translated at 90.6% (2962 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/de/

* Translated using Weblate (Latvian)

Currently translated at 0.3% (24 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lv/

* Translated using Weblate (Latvian)

Currently translated at 0.3% (24 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lv/

* Translated using Weblate (Latvian)

Currently translated at 0.3% (24 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lv/

* Translated using Weblate (Thai)

Currently translated at 1.0% (77 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/th/

* Translated using Weblate (Thai)

Currently translated at 1.0% (77 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/th/

* Translated using Weblate (English (Australia))

Currently translated at 94.2% (6922 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en_AU/

* Translated using Weblate (Serbian)

Currently translated at 8.4% (275 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sr/

* Translated using Weblate (Turkish)

Currently translated at 83.4% (2725 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/tr/

* Translated using Weblate (Turkish)

Currently translated at 83.4% (2725 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/tr/

* Translated using Weblate (Portuguese)

Currently translated at 6.3% (207 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pt/

* Translated using Weblate (Greek)

Currently translated at 25.3% (829 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/el/

* Translated using Weblate (Gujarati)

Currently translated at 0.1% (9 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gu/

* Translated using Weblate (Gujarati)

Currently translated at 0.1% (9 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/gu/

* Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar_SA/

* Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ar_SA/

* Translated using Weblate (English (Pirate))

Currently translated at 0.1% (2 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en@pirate/

* Translated using Weblate (English (Pirate))

Currently translated at 0.1% (2 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en@pirate/

* Translated using Weblate (English (Pirate))

Currently translated at 0.1% (2 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en@pirate/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.1% (3208 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hans/

* Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 98.1% (3208 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hans/

* Translated using Weblate (Bulgarian)

Currently translated at 61.5% (2011 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 61.5% (2011 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/bg/

* Translated using Weblate (Korean)

Currently translated at 79.5% (2600 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ko/

* Translated using Weblate (Korean)

Currently translated at 79.5% (2600 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ko/

* Translated using Weblate (Indonesian)

Currently translated at 27.0% (883 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/id/

* Translated using Weblate (Basque)

Currently translated at 1.3% (43 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/eu/

* Translated using Weblate (Slovenian)

Currently translated at 13.8% (1015 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sl/

* Translated using Weblate (Slovenian)

Currently translated at 13.8% (1015 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sl/

* Translated using Weblate (Arabic (Saudi Arabia))

Currently translated at 0.0% (0 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ar_SA/

* Translated using Weblate (Breton)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/br/

* Translated using Weblate (Breton)

Currently translated at 0.1% (7 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/br/

* Translated using Weblate (Bulgarian)

Currently translated at 59.0% (4335 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bg/

* Translated using Weblate (Bulgarian)

Currently translated at 59.0% (4335 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/bg/

* Translated using Weblate (Amharic)

Currently translated at 3.0% (101 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/am/

* Translated using Weblate (Thai)

Currently translated at 0.7% (23 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/th/

* Translated using Weblate (Polish)

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/

* Translated using Weblate (Polish)

Currently translated at 99.4% (7304 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/

* Translated using Weblate (Korean)

Currently translated at 84.1% (6179 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ko/

* Translated using Weblate (Korean)

Currently translated at 84.1% (6179 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ko/

* Translated using Weblate (Slovenian)

Currently translated at 33.4% (1092 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sl/

* Translated using Weblate (Slovenian)

Currently translated at 33.4% (1092 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/sl/

* Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 75.3% (5535 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hant/

* Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 75.3% (5535 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hant/

* Translated using Weblate (Finnish)

Currently translated at 38.2% (1249 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/fi/

* Translated using Weblate (Japanese)

Currently translated at 81.5% (2665 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ja/

* Translated using Weblate (Japanese)

Currently translated at 81.5% (2665 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ja/

* Translated using Weblate (Catalan)

Currently translated at 1.6% (121 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ca/

* Translated using Weblate (Catalan)

Currently translated at 1.6% (121 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ca/

* Translated using Weblate (Mongolian)

Currently translated at 1.6% (124 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mn/

* Translated using Weblate (Mongolian)

Currently translated at 1.6% (124 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/mn/

* Translated using Weblate (Polish)

Currently translated at 96.6% (3159 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/

* Translated using Weblate (Polish)

Currently translated at 96.6% (3159 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/

* Translated using Weblate (Hebrew)

Currently translated at 0.6% (50 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/he/

* Translated using Weblate (Hebrew)

Currently translated at 0.6% (50 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/he/

* Translated using Weblate (Belarusian)

Currently translated at 85.6% (2799 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/be/

* Translated using Weblate (Belarusian)

Currently translated at 85.6% (2799 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/be/

* Translated using Weblate (Turkish)

Currently translated at 91.8% (6747 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/tr/

* Translated using Weblate (Turkish)

Currently translated at 91.8% (6747 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/tr/

* Translated using Weblate (Turkish)

Currently translated at 91.8% (6747 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/tr/

* Translated using Weblate (Italian)

Currently translated at 62.0% (2026 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/it/

* Translated using Weblate (Spanish)

Currently translated at 60.2% (4426 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/es/

* Translated using Weblate (Spanish)

Currently translated at 60.2% (4426 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/es/

* Translated using Weblate (Basque)

Currently translated at 0.1% (11 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/eu/

* Translated using Weblate (Basque)

Currently translated at 0.1% (11 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/eu/

* Translated using Weblate (Vietnamese)

Currently translated at 62.1% (4562 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/vi/

* Translated using Weblate (Vietnamese)

Currently translated at 62.1% (4562 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/vi/

* Translated using Weblate (Czech)

Currently translated at 82.2% (6037 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/cs/

* Translated using Weblate (Czech)

Currently translated at 82.2% (6037 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/cs/

* Translated using Weblate (Icelandic)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/is/

* Translated using Weblate (Icelandic)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/is/

* Translated using Weblate (Icelandic)

Currently translated at 0.0% (0 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/is/

* Translated using Weblate (Danish)

Currently translated at 8.9% (659 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/da/

* Translated using Weblate (Danish)

Currently translated at 8.9% (659 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/da/

* Translated using Weblate (Serbian)

Currently translated at 7.6% (559 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sr/

* Translated using Weblate (Serbian)

Currently translated at 7.6% (559 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/sr/

* Translated using Weblate (Breton)

Currently translated at 0.8% (29 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/br/

* Translated using Weblate (German)

Currently translated at 96.2% (7071 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/de/

* Translated using Weblate (German)

Currently translated at 96.2% (7071 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/de/

* Translated using Weblate (Indonesian)

Currently translated at 2.6% (191 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/id/

* Translated using Weblate (Indonesian)

Currently translated at 2.6% (191 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/id/

* Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 73.3% (2396 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/zh_Hant/

* Translated using Weblate (Arabic)

Currently translated at 0.5% (18 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ar/

* Translated using Weblate (Kazakh (Latin script))

Currently translated at 3.2% (235 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk_Latn/

* Translated using Weblate (Kazakh (Latin script))

Currently translated at 3.2% (235 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk_Latn/

* Translated using Weblate (Kazakh (Latin script))

Currently translated at 3.2% (235 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/kk_Latn/

* Translated using Weblate (Gujarati)

Currently translated at 0.5% (19 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/gu/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 74.5% (2436 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pt_BR/

* Translated using Weblate (Czech)

Currently translated at 81.7% (2670 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/cs/

* Translated using Weblate (Czech)

Currently translated at 81.7% (2670 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/cs/

* Translated using Weblate (Persian)

Currently translated at 60.0% (1963 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/fa/

* Translated using Weblate (Hungarian)

Currently translated at 59.6% (4383 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/

* Translated using Weblate (Hungarian)

Currently translated at 59.6% (4383 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/

* Translated using Weblate (Hungarian)

Currently translated at 59.6% (4383 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/

* Translated using Weblate (Hebrew)

Currently translated at 1.1% (39 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/he/

* Translated using Weblate (Finnish)

Currently translated at 20.9% (1538 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fi/

* Translated using Weblate (Finnish)

Currently translated at 20.9% (1538 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/fi/

* Translated using Weblate (Croatian)

Currently translated at 8.0% (264 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/hr/

* Translated using Weblate (Sinhala)

Currently translated at 0.1% (10 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/si/

* Translated using Weblate (Sinhala)

Currently translated at 0.1% (10 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/si/

* Translated using Weblate (Greek)

Currently translated at 6.5% (482 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/el/

* Translated using Weblate (Greek)

Currently translated at 6.5% (482 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/el/

* Translated using Weblate (Malayalam)

Currently translated at 8.9% (292 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ml/

* Translated using Weblate (Galician)

Currently translated at 1.7% (58 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/gl/

* Translated using Weblate (Ukrainian)

Currently translated at 80.4% (5905 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 80.4% (5905 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/uk/

* Translated using Weblate (Nepali)

Currently translated at 5.7% (424 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ne/

* Translated using Weblate (Nepali)

Currently translated at 5.7% (424 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ne/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 76.4% (5613 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 76.4% (5613 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/

* Translated using Weblate (Norwegian Bokmål)

Currently translated at 76.4% (5613 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nb_NO/

* Translated using Weblate (Hindi)

Currently translated at 58.5% (1913 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/hi/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 62.0% (4557 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt_BR/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 62.0% (4557 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pt_BR/

* Translated using Weblate (Khmer (Central))

Currently translated at 0.7% (26 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/km/

* Translated using Weblate (Lithuanian)

Currently translated at 6.7% (221 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/lt/

* Translated using Weblate (Ukrainian)

Currently translated at 78.5% (2567 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/uk/

* Translated using Weblate (Ukrainian)

Currently translated at 78.5% (2567 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/uk/

* Translated using Weblate (Spanish)

Currently translated at 67.0% (2191 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/es/

* Translated using Weblate (Spanish)

Currently translated at 67.0% (2191 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/es/

* Translated using Weblate (Spanish)

Currently translated at 67.0% (2191 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/es/

* Translated using Weblate (Dutch)

Currently translated at 95.8% (3131 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nl/

* Translated using Weblate (Macedonian)

Currently translated at 6.7% (221 of 3267 strings)

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/mk/

* Translated using Weblate (Lao)

Currently translated at 3.9% (290 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lo/

* Translated using Weblate (Lao)

Currently translated at 3.9% (290 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lo/

* Translated using Weblate (Russian)

Currently translated at 76.7% (5636 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/

* Translated using Weblate (Russian)

Currently translated at 76.7% (5636 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/

* Translated using Weblate (Russian)

Currently translated at 76.7% (5636 of 7343 strings)

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Mattermost/webapp
Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Mattermost/server
Translate-URL: https://translate.mattermost.com/projects/mattermost/server/

---------

Co-authored-by: jprusch <rs@schaeferbarthold.de>
Co-authored-by: Martin Popp Fredslund (SektorCERT) <martin@sektorcert.dk>
Co-authored-by: Tom De Moor <tom@controlaltdieliet.be>
Co-authored-by: Ekaterine Papava <papava.e@gtu.ge>
Co-authored-by: Sharuru <mave@foxmail.com>
Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au>
Co-authored-by: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>
Co-authored-by: Kaya Zeren <kayazeren@gmail.com>
Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com>
Co-authored-by: master7 <marcin.karkosz@rajska.info>
Co-authored-by: DeepL <noreply-mt-deepl@weblate.org>
Co-authored-by: Takayuki Maruyama <bis5.wsys@gmail.com>
Co-authored-by: Vadim Asadchi <vadim.asadchi@codex-soft.com>
Co-authored-by: Martin Mičuda <micuda@rematiptop.cz>
Co-authored-by: ritchierope <ritchierope@users.noreply.translate.mattermost.com>
Co-authored-by: Frank Paul Silye <frankps@gmail.com>
Co-authored-by: Serhii Khomiuk <sergiy.khomiuk@gmail.com>
Co-authored-by: Ricardo Obregón <robregonm@gmail.com>
Co-authored-by: Carloswaldo <waldosaurio@gmail.com>
Co-authored-by: Dmitriy Q <krotesk@mail.ru>
2026-05-22 01:47:43 +00:00
cursor[bot]
6ee3fb9af1
Fix membership policy edit action navigation (#36690)
Automatic Merge
2026-05-22 01:23:39 +02:00
Nick Misasi
3570814ddd
MM-68316: add mattermost db ping subcommand (#36406)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* MM-68316: add `mattermost db ping` subcommand

Adds a one-shot DB-readiness CLI that opens a connection to the
configured PostgreSQL DSN and exits 0 when reachable. Honours
--timeout (default 5m) and --retry-interval (default 2s); reads the
DSN from --config / MM_CONFIG / MM_SQLSETTINGS_DATASOURCE matching
the existing `db init`/`db migrate` semantics.

Intended primarily as an init-container readiness check for the
mattermost-operator, removing its dependency on a separate
postgres:13 image (relevant for air-gapped deployments).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68316: address PR feedback (sanitize ping retry log)

Drop mlog.Err(err) from the per-attempt "Waiting for database" log line in
pingWithRetry: lib/pq error strings can echo DSN fragments back at operators
when DSN parsing fails. Replace with a non-sensitive status field. Also
clarifies the TestDBPingInvalidDSN comment to reflect actual lib/pq behavior
(parse error surfaces at PingContext, not Open, so the retry loop treats it
as transient — desired for a readiness probe).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68316 Preserve safe db ping DSN errors

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-05-21 18:46:52 +00:00
Christopher Poile
03f2eaaa0b
[MM-68400] Four plugin hooks and ChannelGuard enforcement (#36152)
* allow workflow_dispatch trigger for Server CI (for plugins CI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* [MM-68402] MBE Phase 2: declare four generic plugin hooks (#36291)

* new hooks-only phase 2

* remove ChannelWillBeMoved

* remove RecapWillBeProcessed and MessageWillBeRewrittenByAI

Drop the AI/recap hooks from the new-hook surface; AI-LLM paths
remain uncovered in tech preview and are documented as residuals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68403] MBE Phase 3: ChannelGuards primitive (storage + cache + plugin API) (#36365)

* phase 3

* phase 3: register ChannelGuard mock in test setup helper

NewChannels' startup-time call to reloadGuardCache invokes
s.ChannelGuard().GetAll(); without an expectation on the mock store,
every test that sets up the server with GetMockStoreForSetupFunctions
panics during init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* phase 3: register ChannelGuard mock in retrylayer test

retrylayer.New walks every store getter to wrap it; without the mock
expectation on ChannelGuard, TestRetry panics during layer construction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* use rctx properly in the store methods

* phase 3: match rctx arg in testlib ChannelGuard mock

GetAll now takes request.CTX, so the testify expectation must include
mock.Anything; otherwise the call panics under the mocked store.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* phase 3: set api.ctx in TestChannelGuardLowercaseNormalization

The test constructs PluginAPI directly without a ctx, which used to
work when App.RegisterChannelGuard built its own EmptyContext. Now
that the App methods take rctx from the caller, the nil ctx panics
inside RequestContextWithMaster.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68404] MBE Phase 4: App-layer plugin hook wiring (#36407)

* phase 4

* Fix nil rctx in TestChannelGuardLowercaseNormalization

The PluginAPI struct literal was missing ctx: rctx after a refactor
moved the rctx declaration below the struct construction, leaving
api.ctx as nil. This caused a nil pointer dereference in reloadGuardCache
when RegisterChannelGuard called store.RequestContextWithMaster(nil).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* Remove ChannelWillBeMoved hook call from MoveChannel (phase 4)

The hook and its ID were removed from mbe-phase-2 but the call site in
MoveChannel and its i18n string were not cleaned up during the rebase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* remove channel will be moved test

* Remove RecapWillBeProcessed and MessageWillBeRewrittenByAI hook calls (phase 4)

The hooks and their IDs were removed from mbe-phase-2 but the call sites
in ProcessRecapChannel and RewriteMessage, their i18n strings, and their
tests were not cleaned up during the rebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Revert channel_id plumbing on rewrite endpoint (phase 4)

The channel_id field on RewriteRequest was added in phase 4 to feed the
synthetic post passed to MessageWillBeRewrittenByAI. With that hook
removed from mbe-phase-2, channel_id has no consumer; revert the field,
the api4 validation, the app.RewriteMessage parameter, and the
corresponding webapp client + hook plumbing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68555] MBE Phase 5: Channel-guard enforcement + two-phase dispatch (#36473)

* phase 5

* Bake plugin counter-file paths into source instead of env vars

t.Setenv panics when an ancestor test calls t.Parallel, so the two
channel-guard tests broke under ENABLE_FULLY_PARALLEL_TESTS in CI.
Build each plugin source per-subtest with its temp file path embedded
as a Go literal — same pattern as TestPluginUploadsAPI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove guarded helpers and tests for dropped hooks (phase 5)

The runGuardedRecapWillBeProcessed and runGuardedMessageWillBeRewrittenByAI
helpers were never wired (their app-layer call sites were already removed
in the phase-4 cleanup), and the corresponding sub-tests across panic /
allow / reject / partial plugins reference hooks that no longer exist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [MM-68405] MBE Phase 6: fire MessagesWillBeConsumed on the edit path (#36475)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* rebase onto master

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 18:16:05 +00:00
Jesse Hallam
b9e8d5ce82
MM-68763: fix BuildAccessControlSubject call missing channelID argument (#36681) 2026-05-21 19:18:30 +02:00
Ibrahim Serdar Acikgoz
e6c59693af
MM-68763: Discoverable Private Channels — Server feature complete (visibility, ABAC, queue API) (#36580) 2026-05-21 17:10:51 +02:00
Sven Hüster
29fe2789a0
Exclude webhook posts from thread participation check (#36673)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Exclude webhook posts from thread participation check

When determining if the current user has replied to a thread for
comment mention notifications, ignore posts made by webhooks even if
they use the owning user's user_id.

Co-authored-by: Sven Hüster <svelle@users.noreply.github.com>

* Add missing isFromWebhook import in posts selector

Co-authored-by: Sven Hüster <svelle@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Sven Hüster <svelle@users.noreply.github.com>
2026-05-21 15:22:43 +02:00
Asaad Mahmood
eeb3c1ec04
MM-67237 - Open file preview modal when clicking draft attachment thumbnails. (#36590)
* Open file preview modal when clicking draft attachment thumbnails.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Document draft thumbnail preview handler for CodeRabbit/doc checks.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix ESLint import/order in FilePreview connector and tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add tests for archived and deleted draft attachment preview guards.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Enable draft attachment preview for all file types.

Draft thumbnails were only clickable for images and SVGs; other attachments now open the standard file preview modal like post attachments do.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 18:12:25 +05:00
Ibrahim Serdar Acikgoz
ba1cec51a5
[MM-68693] Resource level permission policies and new simulation (#36472) 2026-05-21 14:40:05 +02:00
Ben Schumacher
7739b349a0
[MM-68578] Add support packet DB performance diagnostics (#36324)
* Add support packet DB diagnostics for pool and pg_stat

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix support packet mock store for new DB diagnostics

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Add context timeouts to support packet pg diagnostics

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Move support packet DB diagnostics queries into sqlstore

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix support packet diagnostics lint and partial data handling

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Stabilize support packet pool idle assertion

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Relax live support packet DB counter assertions

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix deterministic pool diagnostics test wiring

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Mock support packet diagnostics in app test store

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Move SupportPacketDatabaseDiagnostics out of public model

The struct is an internal store→platform transport (no yaml tags, never
serialized directly) so it doesn't belong in server/public/model where
it would form a public API contract for plugins. Move it into the store
package as the natural return type of GetSupportPacketDatabaseDiagnostics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Describe SupportPacketDatabaseDiagnostics by content, not history

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* wording

* Align store diagnostics with sqlstore conventions

- Rename Store.GetSupportPacketDatabaseDiagnostics to Store.GetDiagnostics
  and rename the holding files to diagnostics{,_test}.go.
- Drop the queryRowScanner / rowScanner / sqlQueryRowScanner test seam.
  The collectors now use the sqlxDBWrapper master handle and bind result
  rows into local structs via sqlx GetContext, matching how the rest of
  the sqlstore package talks to Postgres.
- Replace the hand-rolled mock-based unit tests for the Postgres
  collector with an integration test driven through StoreTest, the
  pattern used by the other sqlstore tests (e.g. schema_dump_test.go).
  The pure pool-stats unit test (TestApplyDBPoolStats) is kept.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop MasterDBStats/ReplicaDBStats from the Store interface

After GetDiagnostics moved into the store layer, no caller outside the
sqlstore package itself reads MasterDBStats/ReplicaDBStats through the
Store interface — the diagnostics collector calls them on the concrete
*SqlStore receiver. Remove them from the interface, the retry/timer
layer wrappers, the storetest fake, and the generated mock; drop the
now-redundant fixedDBStatsStore shim methods and mock setups in the
support packet tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Rename SupportPacketDatabaseDiagnostics to DatabaseDiagnostics

Now that the type lives in the store package and is returned by
Store.GetDiagnostics, the SupportPacket prefix is just legacy framing —
support packets are one consumer of the data, not its identity. Rename
to store.DatabaseDiagnostics for consistency with the package and method
name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Inline diagnostics SQL into the collector functions

Each pg_stat query has a single caller, so a package-level constant just
adds indirection between the function and the SQL it owns. Move the
query strings to local consts inside the collectors that use them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix Connectios typo to Connections

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix sqlstore diagnostics build: call GetMaster().DB() method

The recent rebase brought in a change that turned the SqlStore DB
field into a method, so passing ss.GetMaster().DB to
collectPostgresDatabaseDiagnostics (which expects *sqlx.DB) no longer
compiles. Call the method instead.

* Fix gofmt alignment in SupportPacketDiagnostics

The post-merge struct had extra spaces on MasterConnections /
ReplicaConnections that broke gofmt alignment.

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 12:45:18 +02:00
cursor[bot]
bc757c5c54
Fix content flagging update for unloaded posts (#36504)
* Fix content flagging update for unloaded posts

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Strengthen content flagging reducer tests

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Guard content flagging reducer updates

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* Add non-array content flagging reducer test

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>
2026-05-21 15:14:16 +05:30
Ben Schumacher
2ab07701b5
[MM-68577] Add OAuth2/OpenID Connect provider status to support packet (#36451)
* [MM-68577] Add OAuth2/OpenID Connect provider status to support packet

Probe configured GitLab, Google, Office365, and OpenID providers and report
their connectivity status in the support packet diagnostics. For providers
with a DiscoveryEndpoint, the probe verifies a valid OIDC discovery document
(JSON with an "issuer" field) is returned; otherwise it probes the
TokenEndpoint host, treating any HTTP response as reachable since token
endpoints reject GETs.

Disabled providers report status: disabled, enabled providers report ok or
fail with the underlying error. No secrets are read or transmitted; only
public endpoint URLs are probed.

* [MM-68577] Drain response body in probeOAuthTokenEndpoint

Closing resp.Body without first reading it leaves unread bytes on the wire,
which prevents net/http from returning the underlying TCP connection to the
idle pool for keep-alive reuse. Drain with io.Copy + io.LimitReader (1MB
cap to bound a misbehaving server) and use defer for the close.

* [MM-68577] Extract drainAndCloseBody helper for HTTP probe responses

Three call sites in this file (probeOIDCDiscovery, probeOAuthTokenEndpoint,
testPushProxyConnection) now share the same drain-then-close idiom needed
to keep TCP connections eligible for keep-alive reuse. Replace the inline
copies with a single drainAndCloseBody helper that bounds the discard at
1 MiB to limit exposure to a misbehaving server.

Also fixes the same un-drained Close() bug in the pre-existing
testPushProxyConnection while we're here.

* Add comment explaining 1 MiB discovery response size cap

Addresses review feedback asking for clarity on the 1<<20 limit.
2026-05-21 09:09:20 +00:00
Miguel de la Cruz
6b20092e7a
Fix MM-57406: prevent IPv6 hex segments from parsing as emoji (#36541)
* Fix MM-57406: prevent IPv6 hex segments from parsing as emoji

Add word-boundary lookbehind and lookahead to EMOJI_PATTERN so a
:name: token is only matched when neither side abuts an
alphanumeric/underscore. Without this, hex runs in IPv6
addresses (e.g. :beef: in 2001:18:1:beef::/64) were tokenized and
rendered as custom emoji. The new semantics align with the server
parser at server/public/shared/markdown/emoji.go.

Bump the webapp babel safari target from 16.2 to 16.4 since regex
lookbehind is a syntax feature and is not lowered by
@babel/preset-env. The actual supported minimum is well above 16.4, so
the previous target was stale.

Add regression tests for the IPv6 case and guardrail tests for
back-to-back, paren-wrapped, and punctuation-terminated emoji.  Update
the existing asdf🐐asdf💨asdf test to reflect the
new (server-aligned) semantics.

* Dedupe word-char class in EMOJI_PATTERN

Use \w in the lookarounds and inside the name matcher ([\w+-])
so the word-char set is expressed once instead of being repeated
as two slightly different literal character classes. Same set,
same semantics; addresses review feedback on PR #36541.

---------

Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
2026-05-21 10:34:30 +02:00
Miguel de la Cruz
02bae8c3a1
Fix: Global Threads view shows only 1 quick reaction emoji instead of 3 (MM-68681) (#36512)
* Fix: Global Threads shows 1 quick reaction emoji instead of 3 (MM-68681)

When posts are viewed in the Global Threads full-width view, the hover
toolbar was incorrectly showing only 1 quick reaction emoji instead of 3.

Root cause: In post/index.tsx, the isExpanded prop (which controls whether
the toolbar shows 3 or 1 emojis) was derived only from
state.views.rhs.isSidebarExpanded. When navigating to Global Threads,
suppressRHS is dispatched (setting state.views.rhsSuppressed = true), but
isSidebarExpanded remains false. Since posts in the thread viewer use
RHS_ROOT/RHS_COMMENT locations (not CENTER), and the #sidebar-right element
is suppressed (width = 0), the showMoreReactions check in post_options.tsx
always fell through to showing only 1 emoji.

Fix: Include state.views.rhsSuppressed in the isExpanded computation so that
when the RHS is suppressed (i.e., we are in a full-width context like Global
Threads or Drafts), the toolbar correctly renders 3 quick reaction emojis.

Tests: Added post_options.test.tsx with 4 unit tests verifying:
- CENTER location → 3 emojis (existing behavior)
- RHS_ROOT + isExpanded=false → 1 emoji (narrow RHS, existing behavior)
- RHS_ROOT + isExpanded=true → 3 emojis (expanded RHS or Global Threads)
- RHS_COMMENT + isExpanded=true → 3 emojis

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Refactor: use getIsGlobalThreadsView selector instead of rhsSuppressed (MM-68681)

Replace the broad state.views.rhsSuppressed check (which also fires for the
Drafts view) with a precise getIsGlobalThreadsView() selector that reads the
already-existing state.views.lhs.currentStaticPageId field.

When global_threads.tsx mounts it dispatches selectLhsItem(LhsItemType.Page,
LhsPage.Threads) which sets currentStaticPageId to LhsPage.Threads ('threads').
This is the existing, canonical signal that the Global Threads full-width view
is active; the selector wraps it with a name that conveys intent directly.

Changes:
- selectors/lhs.ts: add getIsGlobalThreadsView() — returns true iff
  state.views.lhs.currentStaticPageId === LhsPage.Threads
- selectors/lhs.test.ts: 3 new tests covering Threads, Drafts, and empty page
- post/index.tsx: import getIsGlobalThreadsView and use it in isExpanded
- post_options.test.tsx: update test description to match new mechanism

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix tests: use renderWithContext + real component tree, not jest.mock

The previous post_options.test.tsx used jest.mock() to replace
PostRecentReactions, DotMenu, and several other components. That pattern
is not established in this codebase — post_component.test.tsx and
post_reaction.test.tsx both exercise the real connected component tree
via renderWithContext with a partial Redux state.

Rewrite to match:
- Drop all jest.mock() calls for child components.
- Provide minimal Redux state (roles with ADD_REACTION + user with
  system_user role) so that ChannelPermissionGate lets the emoji
  buttons render — the same pattern used in post_reaction.test.tsx.
- Use proper SystemEmoji shaped objects (with short_name) as
  recentEmojis so that getEmojiName() does not crash.
- Assert on the real rendered emoji buttons (data-testid=
  'post-menu__item_emoji') rather than a mocked prop capture.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Remove selector comment; add e2e test for Global Threads quick reactions (MM-68681)

- selectors/lhs.ts: remove JSDoc block from getIsGlobalThreadsView; the
  name is self-explanatory and the comment was narrating the code.

- emoji_recently_used_spec.js:
  * Add group tag @collapsed_reply_threads (test now requires CRT config).
  * Add MM-T4261_3: verifies that hovering a post in the Global Threads
    full-width panel shows 3 quick reaction emojis, matching the center
    channel and unlike the narrow RHS sidebar which shows 1.
  * Add GLOBAL_THREADS case to validateQuickReactions helper (uses
    rhsPost id prefix, numReactions=3).

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix lint: correct import order in post_options.test.tsx and post/index.tsx

- post_options.test.tsx: move @mattermost/types/emojis type import before
  mattermost-redux/constants; add missing blank line between import groups.
- post/index.tsx: move selectors/lhs import before selectors/posts
  (alphabetical order within the selectors/* group).

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Fix types: use correct EmojiCategory value 'people-body' not 'people'

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

* Remove dead RHS_EXPANDED branch from validateQuickReactions helper

No call site ever passes 'RHS_EXPANDED' to validateQuickReactions — the
branch was unreachable. Keep only the 'GLOBAL_THREADS' case that the new
MM-T4261_3 test actually exercises.

Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Miguel de la Cruz <mgdelacroix@users.noreply.github.com>
2026-05-21 10:33:56 +02:00
Eva Sarafianou
5cacd26776
Fix config-change-checker to use merge-base for per-file diffs (#36670)
Automatic Merge
2026-05-21 10:23:44 +02:00
Ben Schumacher
a7ef484fee
[MM-68576] Add SAML connectivity status to support packet diagnostics (#36321)
* Add SAML connectivity status to support packet diagnostics

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Fix SAML diagnostics tests for config validation

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Add enterprise SAML diagnostics hook for support packet

Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>

* Cleanup

* Fix SAML support packet tests to use enterprise mock interface

Tests were expecting the platform layer to perform HTTP metadata URL
checks directly, but that logic belongs in the enterprise SAML
diagnostic implementation. Updated tests to install a mock enterprise
interface (matching the existing pattern in the override test) instead
of relying on bare HTTP calls that only work without the enterprise
interface registered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Simplify SamlDiagnosticInterface to return error instead of (string, string)

The status return was always either StatusOk or StatusFail, which maps
directly to nil/non-nil error. Removing the redundant status string
makes the interface idiomatic Go and lets the call site derive status
from error presence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* lint fix

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Ben Schumacher <hanzei@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 10:21:34 +02:00
cursor[bot]
981e5341ca
Fix flaky TestUserHasJoinedChannel (#36660)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Fix flaky TestUserHasJoinedChannel

The UserHasJoinedChannel plugin hook is invoked from AddChannelMember via
Srv().Go, so the hook post can appear after the join system post. Under CI
load the 5s Eventually window was sometimes too short. Confirm the plugin
is active before triggering the hook, poll posts in channel order like the
sibling subtest, and extend the wait to 10s.

Tests-only change. Verified with `go test -run '^TestUserHasJoinedChannel$' -race
-count=50` locally.

Co-authored-by: mattermost-code <matty-code@mattermost.com>

* test: add plugin activation assertion messages

* test: deduplicate plugin hook post assertion

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: mattermost-code <matty-code@mattermost.com>
2026-05-20 22:19:54 +00:00
Jesse Hallam
77f9ecdfde
Upgrade Go to 1.26.3 and update deps in tool modules (#36658) 2026-05-20 17:25:49 -04:00
Maria A Nunez
c4b36dee16
Add user attribute validation banners (#36595)
Some checks failed
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
BuildEnv Docker Image / build-image (push) Has been cancelled
BuildEnv Docker Image / build-image-fips (push) Has been cancelled
* Add user attribute validation banners

Add row-level and banner validation coverage for user attribute names so admins get clearer feedback before saving invalid attributes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* UX Feedback

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-20 17:23:18 -04:00
Jesse Hallam
2c925ccf88
MM-68151: Update server dependencies (#36571) 2026-05-20 18:20:19 -03:00
Scott Bishel
448a642835
Add inline action buttons for bot-posted markdown (#36219)
* Add inline action buttons for bot-posted markdown

Bots, webhooks, and plugins can now embed clickable action buttons
inside markdown (including table cells) using mmaction://actionId
links, with row-specific parameters forwarded to the integration on
click. This enables use cases like a per-row "Mx Plan" button in a
fleet-status table that opens a dialog scoped to the clicked row.

Design
- New post prop inline_actions maps actionId (alphanumeric) to a
  PostActionIntegration {URL, Context}, capped at 50 entries.
- Markdown link with scheme mmaction:// emits a placeholder span that
  messageHtmlToComponent converts to the InlineActionButton component.
- Click POSTs inline_context (parsed from the URL query string) to the
  existing /posts/{id}/actions/{action_id} endpoint; the server merges
  it into the integration request as context.inline_params while
  preserving the post-level context.
- Only bot, webhook, and plugin posts render the button; non-integration
  posts have inline_actions stripped on create, update, and ephemeral
  broadcast. Hardened-mode also covers the new prop.
- Reuses the existing PostAction dialog pipeline: plugin handlers reply
  with a trigger_id and call /actions/dialogs/open as before.

Security
- InlineContext capped at 50 entries / 128-char keys / 2 KB values.
- Integration Context cloned per click so per-click inline_params and
  selected_option cannot leak into the cached post for other clickers.
- Plugin response updates cannot add inline_actions to a post that did
  not already have them; invalid entries are dropped with a warn log.
- Label content and data attributes are escaped; labels are flattened
  to plain text (tags stripped, entities decoded, then escaped).
- Malformed JSON request bodies now return 400 instead of falling
  through with an empty inline_context.

Tests
- Model: validators, normalization, GetInlineAction, strip, fallback.
- App: create strip, update guard (4 subtests including
  AllowInlineActionsUpdate bypass), ephemeral strip, inline_params
  merge, context-map isolation, plugin-response guards, from_bot and
  from_plugin retention across plugin updates.
- API: inline_context validation (size bounds + error id),
  omitempty backward compat, malformed JSON 400.
- Webapp: renderer scheme handling, allow/deny flags, size caps,
  HTML escape, tag strip, entity decode, attribute-injection defense;
  component click dispatch, double-click race guard, unmount safety,
  error-result recovery, aria state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* lint fix

* i18n-extract

* Review fixes for inline action buttons

- renderer: preserve actionId case; reject opaque mmaction: URI
- app: require bot AND integration session to preserve inline_actions
- app: restore original inline_actions when plugin response is invalid
- i18n: rename key to ...app_error to match convention

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tighten UpdatePost inline_actions guard; fix test seeds

- app: UpdatePost now requires AllowInlineActionsUpdate to modify
  inline_actions. Integration session alone is insufficient — a
  PAT-wielding user could otherwise inject inline_actions on any
  post they could edit.
- tests: seed bot posts with inline_actions via an integration
  session (intSeedCtx) so they survive the create-time strip.
- renderer: lint fix (blank line before comment block).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Reject malformed inline-action authorities at render time

- renderer: enforce ^[A-Za-z0-9]+$ on actionId, mirroring the server
  regex. Authorities like mmaction://plan:443 or mmaction://user@plan
  now fall through to plain text instead of rendering a dead button.
- post: clarify in the strip comment that webhooks and plugins bypass
  CreatePostAsUser entirely (they call CreatePost / CreatePostMissingChannel
  directly), so the strip block does not apply to them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Tighten inline-action renderer tests

- Replace oversized-params test with boundary pair (at-cap and over-cap)
  to lock in the > vs >= behavior of the size-limit check.
- Add a "surrounding text survives" assertion for the tag-strip path so
  a future swap from regex strip to a DOM sanitizer won't silently
  drop legitimate content along with tags.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Inline action buttons via mmaction:// markdown links

Adds inline action buttons rendered from mmaction:// links in markdown,
with the click pipeline reusing the existing post-action infrastructure.
Aligned with the broader mm_blocks_actions framework (Daniel's PR).

* fix lint, DoS hardening, fix and rename test

* Address review feedback

* lint fix

* Reject percent-encoded path traversal in validateIntegrationURL (e.g. %2e%2e%2f) by parsing the URL and checking the decoded path.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-20 13:34:44 -06:00
Scott Bishel
a84941bec1
Remove Legacy Interactive Dialog code (#35874) 2026-05-20 13:34:13 -06:00
Ben Cooke
6189a3f54a
[MM-66489] Pull and populate certificate from metadata endpoint (#36557) 2026-05-20 14:51:24 -04:00
Jesse Hallam
0790fc7281
Upgrade Go to 1.26.3 (#36656) 2026-05-20 13:21:14 -03:00
Jesse Hallam
c74e51f35e
chore(ci): upgrade Go to 1.26.3 in build container Dockerfiles (#36648) 2026-05-20 17:56:19 +03:00
Jesse Hallam
51c6d5219f
Fix config Sanitize fields missing from desanitize, causing FakeSetting to be persisted (#36619)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Add TestDesanitizeRemovesAllFakeSettings to catch future omissions

Walks every string field in the config after a Sanitize+desanitize
round-trip and fails if any still holds FakeSetting. This catches the
case where a field is added to Sanitize without a corresponding
desanitize entry.

* Fix ElasticsearchSettings.ClientKey being incorrectly masked as a secret

ClientKey is a file path, not a secret value. Masking it caused the
asterisk string to be persisted to the database on config writes, which
broke TLS client auth on restart.

* Fix desanitize missing entries for fields added in 504fb96fdd

504fb96fdd masked five fields in Sanitize without adding the
corresponding desanitize entries, meaning a config save through the
API would permanently overwrite those fields with FakeSetting:

- FileSettings.ExportAmazonS3SecretAccessKey
- ServiceSettings.GoogleDeveloperKey
- ServiceSettings.GiphySdkKey
- CacheSettings.RedisPassword
- AutoTranslationSettings.LibreTranslate.APIKey

* fixup! Add TestDesanitizeRemovesAllFakeSettings to catch future omissions

* fixup! Fix desanitize missing entries for fields added in 504fb96fdd

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-20 10:04:21 +00:00
Jesse Hallam
41f3b22679
Fix flaky E2E tests (Cypress + Playwright) (#36637)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* Fix flaky email sort test by ignoring punctuation in localeCompare

PostgreSQL's en_US.UTF-8 collation ignores hyphens at the primary sort
level, but JS localeCompare() on a C-locale CI runner uses byte order,
causing the expected and actual sort orders to diverge for emails
containing hyphens. Passing ignorePunctuation:true aligns JS collation
with Postgres behavior.

* E2E/Cypress: re-enable CYPRESS_* env var overrides

allowCypressEnv: false was introduced in the v15.13 upgrade (PR #36091)
but broke the existing CYPRESS_adminUsername / CYPRESS_adminPassword
override mechanism that local and CI runners depend on.

* E2E/Cypress: fix MM-T1508 accessibility image test flakiness

The test was failing because the admin user could have a stale
compact display mode preference from a previous spec, causing
post avatars to render with pointer-events: none and blocking
the .status-wrapper click.

Two fixes:
- resetUserPreference() now resets message_display to 'clean'
  so compact mode doesn't leak across spec files
- accessibility_image_spec before() now runs as a fresh user
  with default preferences rather than the shared admin account
2026-05-20 10:46:17 +08:00
Maria A Nunez
2db507464d
Add auth token to flaky test webhook (#36636)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 20:34:27 -04:00
Pablo Vélez
345a0b76a6
Mm 68506 fe abac mask fe table editor cel and e2e (#36517)
Some checks are pending
Server CI / Check mmctl docs (push) Blocked by required conditions
Server CI / Postgres (shard 0) (push) Blocked by required conditions
Server CI / Postgres (shard 1) (push) Blocked by required conditions
Server CI / Postgres (shard 2) (push) Blocked by required conditions
Server CI / Postgres (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres Test Results (push) Blocked by required conditions
Server CI / Elasticsearch v8 Compatibility (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 0) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 1) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 2) (push) Blocked by required conditions
Server CI / Postgres FIPS (shard 3) (push) Blocked by required conditions
Server CI / Merge Postgres FIPS Test Results (push) Blocked by required conditions
Server CI / Run mmctl tests (push) Blocked by required conditions
Server CI / Run mmctl tests (FIPS) (push) Blocked by required conditions
Server CI / Build mattermost server app (push) Blocked by required conditions
Tools CI / check-style (mattermost-govet) (push) Waiting to run
Tools CI / Test (mattermost-govet) (push) Waiting to run
Web App CI / check-lint (push) Waiting to run
Web App CI / check-i18n (push) Blocked by required conditions
Web App CI / check-external-links (push) Blocked by required conditions
Web App CI / check-types (push) Blocked by required conditions
Web App CI / test (platform) (push) Blocked by required conditions
Web App CI / test (mattermost-redux) (push) Blocked by required conditions
Web App CI / test (channels shard 1/4) (push) Blocked by required conditions
Web App CI / test (channels shard 2/4) (push) Blocked by required conditions
Web App CI / test (channels shard 3/4) (push) Blocked by required conditions
Web App CI / test (channels shard 4/4) (push) Blocked by required conditions
Web App CI / upload-coverage (push) Blocked by required conditions
Web App CI / build (push) Blocked by required conditions
YAML Lint / yamllint (push) Waiting to run
* MM-68501 - implement GetMaskedVisualAST and wire API handler

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* add missing test and fix style issues

* fix styles

* implement coderabbit feedback

* MM-68501 - PR review: split masking file, model-level access mode, reject contradictory config

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68501 - apply shared_only filter to non-option field values (binary masking)

* MM-68501 - consolidate masking flag check and log corrupt text value during masking

* MM-68503 - add CEL utilities, write-path validation, and merge helpers

Combined set of helpers consumed by BE-5's save path:

CEL construction / serialization
  - extractStringValues, buildCELFromConditions, conditionToCEL,
    celStringLiteral, celValueLiteral. Used to rebuild a CEL string from a
    VisualExpression, including for GetMaskedExpression on the read-side
    of policy GET / search responses.

Merge-on-save helpers
  - getHiddenValues (per-condition, with pre-fetched fields map for N+1
    avoidance) — finds which stored values are not visible to the caller.
  - mergeConditionValues — re-injects the hidden values into a submitted
    condition without duplicates.
  - Together, these let BE-5 preserve attribute values the caller cannot
    see while still letting them edit the visible parts of a policy.

Write-path value-hold validation
  - validatePolicyExpressionValues, invalidValueError, validateConditionValues.
  - Generic "Invalid value." error on every rejection — no signal about
    whether the value exists or is merely not held (prevents enumeration).
  - Rejects the masked-token sentinel "--------" if submitted as a literal.

These all live in access_control_masking.go alongside the masking primitives
that BE-2 introduced. i18n entries added for the two new error IDs
(app.pap.save_policy.invalid_value, app.pap.validate_expression_values.app_error).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68503 - handle the masked-token sentinel in validation and merge

When the GET /policies endpoint returns a policy via MaskPolicyExpressions,
the raw expression contains the masked-token sentinel "--------" in place
of hidden values. If the frontend round-trips that expression unchanged
back to the server (e.g., the admin only modified channel assignment, not
the rules), the sentinel reaches the save path.

The previous code in validateConditionValues rejected the sentinel as
"Invalid value." This blocks the legitimate round-trip case.

Fix:
  - validateConditionValues: treat the sentinel as a placeholder and skip
    it during visibility / source-only / unknown-mode checks. Other values
    are still validated normally.
  - mergeConditionValues: strip the sentinel from submitted values before
    appending hidden values, so it never propagates to the stored result.
    Both array and single-value forms (string == "--------") are handled.

TestMaskedTokenRejection (which asserted the old rejection behavior) is
replaced by TestMaskedTokenConstant which only verifies the sentinel
string itself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68504 - integrate save-path masking: 403 block on delete, merge-on-save, response masking

Save path (CreateOrUpdateAccessControlPolicy):
  * validatePolicyExpressionValues runs on the submitted expression before
    merge so re-injected hidden values are never validated against the
    caller's holdings.
  * mergeStoredPolicyExpressions re-injects hidden values from the stored
    policy and blocks (HTTP 403) any attempt to remove a condition that
    contained values the caller cannot see — closes the row-deletion gap
    in classified environments.
  * mergeExpressionWithMaskedValues unwraps single-element arrays for scalar
    operators after restoring the stored operator (avoids "attr == [val]"
    invalid CEL when the frontend submits "attr in []" as the masked-row
    placeholder for an originally-scalar condition).
  * checkSelfInclusion is bypassed for system admins (they may legitimately
    write conditions for values they do not hold); masking and value-hold
    validation still apply to system admins.

Delete path (DeleteAccessControlPolicy):
  * Same masked-values 403 block — a caller with masked values cannot delete
    the policy at all (UI Delete button is also disabled in FE-3).

Response masking:
  * createAccessControlPolicy and setAccessControlPolicyActiveStatus run
    MaskPolicyExpressions on the response so even a save reply doesn't
    leak the values the caller does not hold.

GetMaskedExpression, maskConditionValuesWithToken, replaceHiddenValuesWithToken,
MaskPolicyExpressions live alongside the rest of the masking helpers in
access_control_masking.go.

team_access_control.go: corrects ValidateChannelEligibilityForAccessControl
call site (drops the spurious receiver and rctx; it's a package-level helper
that only takes channel).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68503 - address PR review: batch field fetches, propagate errors, fail-closed write path

* MM-68503 - restore team-admin api4 tests accidentally dropped during BE-5 rebuild

* MM-68503 - address review and CodeRabbit feedback on save-path masking

* add tests for delete masking, self-inclusion, GET mask

* add assertions to strengten tests

* MM-68505 - add has_masked_values type and MaskedChip component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* MM-68506 - add masking support to TableEditor and team settings modal

TableEditor (table_editor.tsx, table_editor.scss):
  - hasMaskedValues plumbed through rows; lock operator/attribute selectors on
    masked rows.
  - Row remove (trash) button disabled on masked rows; disabled-state CSS so
    the icon doesn't show the destructive hover colour or a pointer cursor.
  - Test Rules button disabled when any row has masked values, with tooltip.
  - onMaskedStateChange callback to notify the parent for cross-component
    states (CEL editor read-only, Save disabled, banners).

Value selectors (single_value_selector_menu.tsx, multi_value_selector_menu.tsx,
selector_menus.scss, value_selector_menu.tsx):
  - Append MaskedChip after visible chips on multi-value rows.
  - Render MaskedChip as the sole value on single-value rows where the caller
    holds no visible value.

Policy details (policy_details.tsx, .scss, .test.tsx):
  - Track hasMaskedRows state; receive from TableEditor via onMaskedStateChange.
  - Show masked-values warning banner above the editor when present.
  - Same banner on the Delete confirmation modal so admins understand why
    deletion is consequential.

Team settings modal (team_policy_editor.tsx, .scss):
  - Same masked-values plumbing; delete button uses the disabled state when
    a policy has masked values, regardless of whether channels are assigned.
  - Pre-save check no longer treats "in []" as an incomplete rule — that
    placeholder comes from fully-masked rows that merge-on-save will fill in.

i18n entries added for the new strings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68506 - fix hook order in SingleValueSelector when masked state changes

The early return for `hasMaskedValues && !value` sat between useState
and useCallback declarations, so when a parent re-render flipped the
masked state (e.g. after deleting a sibling rule) React saw a different
hook count and crashed with "Rendered fewer hooks than expected".

Move the read-only short-circuit after all hook declarations so the hook
order stays stable across renders.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68507 - CEL editor read-only when masked + system console wiring

CEL editor (editor.tsx, editor.scss):
  - hasMaskedRows prop: when true, Monaco is set to read-only and a banner
    explains why ("This expression contains restricted values. Switch to
    Simple mode to edit the values you have access to, or delete the entire
    rule.").
  - Test Rules button disabled in CEL mode when hasMaskedRows is true.

Policy details (policy_details.tsx, .scss):
  - hasMaskedRows state plumbed to CELEditor, TableEditor, and the Save /
    Delete buttons.
  - Save button disabled while masked rows are present (kept after the
    save-allowed-with-masked-values change in BE-5? — no, here we keep Save
    enabled so admins can add/modify rules; only row removal of masked rows
    is blocked).
  - Delete Policy button disabled when hasMaskedRows; a SectionNotice above
    the Delete card explains why ("This policy contains restricted values
    - Deletion not allowed").
  - New save error messages: invalid_value and self_exclusion are surfaced
    from the server's generic responses.

Policies list (policies.tsx): minor wiring change for the new state plumbing.

Table editor (table_editor.tsx): cross-component coordination — emits
onMaskedStateChange and respects the disabled-for-masked-row policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68508 - E2E suite for attribute-value masking

Covers the full read+write masking flow against a real server:
  - Masked chip rendering, operator/attribute lock, Test Rules disabled.
  - System admin subject to masking like any other caller (no role bypass).
  - Save with masked values: hidden values preserved by merge-on-save.
  - Trash button disabled on masked rows; server returns 403 on direct
    API attempt to remove a masked condition.
  - Delete Policy button disabled + server 403 when policy has masked values
    (both system console and team settings modal paths).
  - Self-inclusion failure only fires when the caller holds full visibility.
  - CEL editor read-only with banner when masked rows present.
  - Direct API validation: non-held values and the masked-token sentinel
    rejected with a generic "Invalid value." error.
  - Feature-flag-off path: no masking, all values visible.
  - Text-field shared_only masking (binary) with `in` and `==` operators.

A pluggable DB-setup helper marks specific CPA fields as shared_only for
the duration of a test (with per-test cleanup) since the API blocks setting
access_mode=shared_only without a source_plugin_id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68506 - fix lint, jest mock factory, and unreachable delete-modal test

* MM-68506 - localize masked-condition-deleted save error

* MM-68506 - fix masked-policy delete warning detection and localize masked_rule_deleted

* fix linter issues

* MM-68506 - surface delete error, lock value selector on masked rows, drop dead remove-modal

* fix linter, add translations, adjust specs

* import wittoltip from shared

* fix linter and use the correct button variant

* MM-68506 - drop dangling rationale comment in access_control_field_test

* fix linter, translation and e2e tests

* use pg ts types and dependencies for e2e types mocks

* adjust switch mode persistance restriction

* fix team settings style buttons

* fail-closed guard for advanced expressions in  merge-on-save, plus  helper unit tests, and FF/test-helper cleanups

* MM-68505 - add has_masked_values type and MaskedChip component

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* MM-68506 - add masking support to TableEditor and team settings modal

TableEditor (table_editor.tsx, table_editor.scss):
  - hasMaskedValues plumbed through rows; lock operator/attribute selectors on
    masked rows.
  - Row remove (trash) button disabled on masked rows; disabled-state CSS so
    the icon doesn't show the destructive hover colour or a pointer cursor.
  - Test Rules button disabled when any row has masked values, with tooltip.
  - onMaskedStateChange callback to notify the parent for cross-component
    states (CEL editor read-only, Save disabled, banners).

Value selectors (single_value_selector_menu.tsx, multi_value_selector_menu.tsx,
selector_menus.scss, value_selector_menu.tsx):
  - Append MaskedChip after visible chips on multi-value rows.
  - Render MaskedChip as the sole value on single-value rows where the caller
    holds no visible value.

Policy details (policy_details.tsx, .scss, .test.tsx):
  - Track hasMaskedRows state; receive from TableEditor via onMaskedStateChange.
  - Show masked-values warning banner above the editor when present.
  - Same banner on the Delete confirmation modal so admins understand why
    deletion is consequential.

Team settings modal (team_policy_editor.tsx, .scss):
  - Same masked-values plumbing; delete button uses the disabled state when
    a policy has masked values, regardless of whether channels are assigned.
  - Pre-save check no longer treats "in []" as an incomplete rule — that
    placeholder comes from fully-masked rows that merge-on-save will fill in.

i18n entries added for the new strings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68506 - fix hook order in SingleValueSelector when masked state changes

The early return for `hasMaskedValues && !value` sat between useState
and useCallback declarations, so when a parent re-render flipped the
masked state (e.g. after deleting a sibling rule) React saw a different
hook count and crashed with "Rendered fewer hooks than expected".

Move the read-only short-circuit after all hook declarations so the hook
order stays stable across renders.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68507 - CEL editor read-only when masked + system console wiring

CEL editor (editor.tsx, editor.scss):
  - hasMaskedRows prop: when true, Monaco is set to read-only and a banner
    explains why ("This expression contains restricted values. Switch to
    Simple mode to edit the values you have access to, or delete the entire
    rule.").
  - Test Rules button disabled in CEL mode when hasMaskedRows is true.

Policy details (policy_details.tsx, .scss):
  - hasMaskedRows state plumbed to CELEditor, TableEditor, and the Save /
    Delete buttons.
  - Save button disabled while masked rows are present (kept after the
    save-allowed-with-masked-values change in BE-5? — no, here we keep Save
    enabled so admins can add/modify rules; only row removal of masked rows
    is blocked).
  - Delete Policy button disabled when hasMaskedRows; a SectionNotice above
    the Delete card explains why ("This policy contains restricted values
    - Deletion not allowed").
  - New save error messages: invalid_value and self_exclusion are surfaced
    from the server's generic responses.

Policies list (policies.tsx): minor wiring change for the new state plumbing.

Table editor (table_editor.tsx): cross-component coordination — emits
onMaskedStateChange and respects the disabled-for-masked-row policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68508 - E2E suite for attribute-value masking

Covers the full read+write masking flow against a real server:
  - Masked chip rendering, operator/attribute lock, Test Rules disabled.
  - System admin subject to masking like any other caller (no role bypass).
  - Save with masked values: hidden values preserved by merge-on-save.
  - Trash button disabled on masked rows; server returns 403 on direct
    API attempt to remove a masked condition.
  - Delete Policy button disabled + server 403 when policy has masked values
    (both system console and team settings modal paths).
  - Self-inclusion failure only fires when the caller holds full visibility.
  - CEL editor read-only with banner when masked rows present.
  - Direct API validation: non-held values and the masked-token sentinel
    rejected with a generic "Invalid value." error.
  - Feature-flag-off path: no masking, all values visible.
  - Text-field shared_only masking (binary) with `in` and `==` operators.

A pluggable DB-setup helper marks specific CPA fields as shared_only for
the duration of a test (with per-test cleanup) since the API blocks setting
access_mode=shared_only without a source_plugin_id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* MM-68506 - fix lint, jest mock factory, and unreachable delete-modal test

* MM-68506 - localize masked-condition-deleted save error

* MM-68506 - fix masked-policy delete warning detection and localize masked_rule_deleted

* fix linter issues

* MM-68506 - surface delete error, lock value selector on masked rows, drop dead remove-modal

* fix linter, add translations, adjust specs

* import wittoltip from shared

* fix linter and use the correct button variant

* MM-68506 - drop dangling rationale comment in access_control_field_test

* fix linter, translation and e2e tests

* use pg ts types and dependencies for e2e types mocks

* adjust switch mode persistance restriction

* fix team settings style buttons

* fail-closed guard for advanced expressions in  merge-on-save, plus  helper unit tests, and FF/test-helper cleanups

* Refactor access control methods to use GetPropertyGroup for CPA group ID retrieval

* fix styles

* disable delete on masked policies in list view and remove dead modal warnings

* fix unit tests

* preserve hasAnyOf operator display for fully-masked multiselect conditions

* address PR feedback: lock Actions on masked save, filter source/shared_only from /attributes, add unit tests and e2e tests

* fix e2e tests

* comment out e2e to isolate issue

* completely remove the files to pass linter

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2026-05-19 21:25:14 +02:00