mirror of
https://github.com/mattermost/mattermost.git
synced 2026-09-19 02:06:37 +08:00
85acba42e1f9ae8a6bfb2f724bbf819b21a45c7a
3383
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
85acba42e1 |
Skip flaky TestExtractConcurrency (#37834)
Automatic Merge |
||
|
|
c7eff70026 |
ABAC: plugin-keyed resource types, trusted plugin PAP/CEL APIs, and AuthZEN-style decision API (#37509)
* MM: add v0.5 plugin access control policy model, registry, and decision outcomes Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: add plugin access control PDP/PAP app-layer methods with fail-closed semantics Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: expose plugin access control API surface (EvaluateAccessControl + PAP/CEL methods) Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: add store-layer round-trip tests for v0.5 plugin access control policies Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: extract plugin access control app code into plugin_access_control.go Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: add atomic type-guarded AccessControlPolicyStore.DeleteIfType Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: plugin PAP hardening — atomic typed delete, indistinguishable 404s, audit every attempt Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: close plugin Get-by-ID TOCTOU via GetPolicyOfType; stamp save audit operation at entry Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Fix gob RPC poisoning from native attribute select options NativeUserAttributeFields stored bool-select options as []map[string]string inside PropertyField.Attrs (map[string]any). gob requires concrete types inside interface values to be registered, and []map[string]string is not registered in client_rpc.go, so encoding the GetAccessControlFieldsAutocomplete reply failed and net/rpc shut down the shared plugin API connection, breaking every subsequent plugin API call. Build the options from gob-registered containers ([]any/map[string]any) instead; JSON output is byte-identical. Add gob round-trip regression tests covering every plugin access control API reply payload: the autocomplete response including native attribute fields (fails against the old code), policies with JSON-decoded Props, visual AST condition values of every runtime shape, expression check errors, query users responses, and evaluation decisions. Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Move plugin access control gob-safety tests into their own file Pure move: plugin_access_control_test.go crossed 1000 lines; the gob-safety helper and TestPluginAccessControlGobSafety now live in plugin_access_control_gob_test.go, unchanged. Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * MM: resolve plugin policy existence when ABAC is unavailable (Option B) Every evaluation-impossible branch of EvaluatePluginAccessRequest (service nil / unlicensed / flag off / user load or subject build failure / evaluator infra error / unknown outcome) now performs a raw open-core store read on the already-validated resource ID: no stored row returns no_policy so the caller can safely apply legacy behavior; any stored row (with a Warn on a foreign-type anomaly) or a failed read returns unavailable so the caller must fail closed. This lets the plugin drop its local policy index entirely. Strengthens the EvaluateAccessControl doc contract accordingly and reworks the fail-closed test matrix with with/without-row splits per branch, a foreign-type-row case, a store-read-error case on the store mock, and passthrough rows pinning that the fallback read never runs when the evaluator answers. Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Clarify EvaluateAccessControl failure-mapping doc A failure with a definitive store miss maps to no_policy under the Option B semantics, so 'failures never map to allow or no_policy' was inaccurate. State precisely: never allow; no_policy only on positively determined non-existence; deny for defensive failures on a resolved policy; unavailable otherwise. Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Tighten ABAC comments Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Document AccessDecision.Outcome as plugin-API-only The evaluator populates Outcome on every lane, but the only production reader is the app layer's EvaluatePluginAccessRequest, which maps it into PluginAccessControlDecision; core channel/team enforcement reads the collapsed Decision bool alone. State that on the field. Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Retrigger CI to rebuild enterprise image with updated enterprise branch Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Document that only the evaluator's plugin lane sets AccessDecision.Outcome Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: key plugin resource types as plugin_id:type and drop the static registry Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: replace AccessDecision.Outcome with the AuthZEN decision context reason Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: drop type-scoped policy get/delete and check the type in the app layer Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: compare plugin policy type ownership exactly instead of case-insensitively Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: bound the whole policy type to the Type column width Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: require an allow before treating a decision as the no-policy fallback Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: treat a colliding foreign-type policy row as no_policy, not a deny Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: gate plugin policy reads on a raw store read before normalization Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: pin policy type immutability on save in the store tests Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: reuse a single unavailable-error constructor in the existence fallback Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: re-check plugin policy ownership on the normalized get read Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * ABAC: confirm plugin policy ownership before surfacing a normalization error Co-authored-by: nick.misasi <nick.misasi@mattermost.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
cd920652fb | Bumping prepackaged github version to v2.8.0 (#37831) | ||
|
|
f4185af07a |
Update latest minor version to 11.11.0 (#37827)
Automatic Merge |
||
|
|
7130ae598f |
MM-70054 - Enable Team Membership ABAC feature flag by default (#37781)
Automatic Merge |
||
|
|
ae0bec4d67 |
Add MFI plugin signature public key behind feature flag (#37793)
* Add MFI plugin signature public key stub behind feature flag * Replace MFI plugin signing key stub with actual public key * Add federal-signed test plugin fixtures and verify against MFI key * Rename federal test plugin fixtures to match mfiPluginPublicKey * Test verifyPlugin's feature-flagged MFI key path |
||
|
|
c17064f72c |
Fix flaky TestImportValidateDirectPostImportData (#37795)
Automatic Merge |
||
|
|
5152df2418 |
Mm 70056 missing info banner team abac team admin (#37790)
* [MM-70056] Return imported parent policies so team admins see the system policy banner * [MM-70055] Resolve parent policy expressions for team admins in the mode-flip modal * [MM-70057] Let team admins read team sync jobs for their own team policy |
||
|
|
3019460ac5 |
MM-69445: Markdown fixes (#37388)
* Cap markdown block nesting depth blockQuoteStart and listStart recursed once per nested '>' or list marker on a line, guarded only by an indentation check that bounds CommonMark indentation, not nesting count. A single crafted line (e.g. "- " repeated tens of thousands of times) forced recursion and slice-copy work that grew super-linearly with nesting depth, letting an authenticated user burn a disproportionate amount of server CPU per request. Thread a depth counter through blockStart, blockStartOrParagraph, blockQuoteStart, and listStart, and stop opening new nested blocks past maxNestingDepth. This bounds nesting whether it is built by one line or accrued across many, and caps the recursion and copy cost to a small constant regardless of input size. Also apply the existing maxLen byte cap directly inside Parse(), not just Inspect(), so any caller of Parse is protected uniformly. * Add tests for markdown block nesting depth cap Cover the new maxNestingDepth guard: rejecting a well-formed block quote/list item once the depth limit is reached, capping recursion for a single deeply-nested line, and honoring depth already accrued by open ancestor blocks. Also cover Parse()'s byte-length cap and add benchmarks showing the nesting-depth cases now scale roughly linearly with input size instead of super-linearly. * Reject oversized posts before markdown parsing createPost, updatePost, and patchPost ran PostWithProxyRemovedFromImageURLs, which parses the raw message, before the message-length check inside Post.IsValid ever ran. An oversized message paid the full parsing cost even though it was always going to be rejected. Add rejectOversizedMessage, mirroring the rune-count check in Post.IsValid, and call it in all three handlers before any markdown processing touches the message. * Add tests for oversized post/patch rejection Cover the rejectOversizedMessage check added for createPost, updatePost, and patchPost: a message over MaxPostSize is rejected with a 400 in all three handlers before it reaches markdown processing. * Sync markdown parse cap with real max post size Parse and Inspect capped input at a hardcoded ~128KB, assuming a 64KB max post size. The real configured limit comes from the posts.message column and can be raised past that default, so on installations with an enlarged column, markdown parsing (mentions, links, formatting) was silently skipped for legitimately-sized posts. Have the markdown package pull its cap from a function registered via SetMaxPostSizeFunc, defaulting to the old conservative constant only if nothing was ever registered. PlatformService.New registers PlatformService.MaxPostSize itself once the store is ready, so the cap always reflects the real limit regardless of which code path parses markdown first, and the store layer stays unaware that markdown parsing exists. * Add tests for markdown max post size sync Cover SetMaxPostSizeFunc raising the cap and being called on every MaxLen invocation. Also verify, end to end against a real database, that PlatformService.New wires markdown.MaxLen to the real configured max post size. * Fix tests * Address review comments - Simplify setting the maximum number of runes for a post - Simplify comments - Rename variables and functions to reflect whether they represent bytes or runes. |
||
|
|
466b5bb783 |
redact logs (#37757)
Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
c6db95f35d |
Preserve relative redirect_to on root SiteURL (#37725)
* Preserve relative redirect_to on root SiteURL fullyQualifiedRedirectURL cleaned an empty SiteURL path to "." and required the redirect target to have that as a prefix, so on a root SiteURL every same-origin relative redirect (e.g. the /oauth/authorize resume after SSO login) was discarded and only the site origin returned. Normalize an empty prefix path to "/". Add root-SiteURL cases to TestFullyQualifiedRedirectURL. Signed-off-by: Matt Rogers <mrogers@palantir.com> * Use segment-aware path check for redirect prefix Address review: replace the empty-prefix normalization with pathWithinPrefix, which compares on path segments. This fixes the root SiteURL case (empty path) and also stops a non-root prefix like /mm from matching /mmfoo, and preserves same-origin absolute targets with only a query/fragment (?foo=bar, #section). Signed-off-by: Matt Rogers <mrogers@palantir.com> * Add /mmfoo regression test for segment-aware prefix check Signed-off-by: Matt Rogers <mrogers@palantir.com> --------- Signed-off-by: Matt Rogers <mrogers@palantir.com> Co-authored-by: Matt Rogers <mrogers@palantir.com> |
||
|
|
5ef9e70d95 |
Mm 69832 abac review nits (#37640)
* MM-69831 - Add configurable interval for the ABAC membership sync schedulers * MM-69832 - Hoist the ManageSystem permission check in createAccessControlPolicy * MM-69832 - Add policy-scoped search term to the ABAC team invite candidate endpoint * MM-69832 - Switch strict ABAC invite picker to server-side policy-scoped typeahead * MM-69832 - Rename the ABAC invite candidate search param to term for consistency * MM-69832 - Gate ABAC invite full-name term search behind ShowFullName for non-admins * MM-69832 - Add API and jest coverage for the ABAC invite term search and full-name privacy gate * MM-69832 - Clean up comments |
||
|
|
d4d216e93e |
Add ClusterInterface.Shutdown to surface skipped cluster sends (#37753)
* Add ClusterInterface.Shutdown to surface skipped cluster sends * Defer cluster interface shutdown so it runs on every exit path |
||
|
|
b021e5be06 | [MM-69734] Add no session data, ensure session attributes are not leaked through evaluation trace to non sysadmins (#37600) | ||
|
|
8a9aacb0fb |
MM-69831 - Add configurable interval for the ABAC membership sync schedulers (#37623)
* MM-69831 - Add configurable interval for the ABAC membership sync schedulers * Validate ABAC sync job interval with a 60s minimum |
||
|
|
0b034ca9a7 |
Fix flaky TestExtractConcurrency (#37527)
Automatic Merge |
||
|
+3 |
cdbc92639c |
Translations update from Mattermost Weblate (#37689)
* Translated using Weblate (Polish) Currently translated at 98.6% (7582 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Polish) Currently translated at 98.7% (7592 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Hungarian) Currently translated at 58.2% (4479 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/ * Translated using Weblate (Hungarian) Currently translated at 58.2% (4479 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/ * Translated using Weblate (Polish) Currently translated at 98.9% (7604 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Ukrainian) Currently translated at 76.8% (5904 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/uk/ * Translated using Weblate (Hungarian) Currently translated at 58.2% (4479 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/ * Translated using Weblate (Russian) Currently translated at 74.9% (5759 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Translated using Weblate (Dutch) Currently translated at 93.6% (7200 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/ * Translated using Weblate (Polish) Currently translated at 98.9% (7607 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Polish) Currently translated at 99.1% (7618 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Dutch) Currently translated at 92.1% (3136 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nl/ * Translated using Weblate (Dutch) Currently translated at 93.6% (7200 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/ * Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (3402 of 3402 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 100.0% (7687 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/zh_Hans/ * Translated using Weblate (Dutch) Currently translated at 92.2% (3137 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nl/ * Translated using Weblate (Dutch) Currently translated at 93.7% (7210 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/nl/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 87.0% (2961 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/en_AU/ * Translated using Weblate (English (Australia)) Currently translated at 89.6% (6895 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/en_AU/ * Translated using Weblate (Polish) Currently translated at 99.5% (7651 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Lithuanian) Currently translated at 59.5% (4574 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/lt/ * Translated using Weblate (Polish) Currently translated at 99.5% (7656 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Polish) Currently translated at 99.7% (7664 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Polish) Currently translated at 92.8% (3160 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Polish) Currently translated at 100.0% (7687 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/pl/ * Translated using Weblate (Russian) Currently translated at 75.0% (5766 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Translated using Weblate (Polish) Currently translated at 93.8% (3192 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Russian) Currently translated at 75.1% (5776 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Translated using Weblate (German) Currently translated at 87.0% (2962 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/de/ * Translated using Weblate (German) Currently translated at 93.0% (7150 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/de/ * Translated using Weblate (Polish) Currently translated at 94.4% (3212 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Dutch) Currently translated at 92.2% (3138 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/nl/ * Translated using Weblate (Hungarian) Currently translated at 58.2% (4479 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/hu/ * Translated using Weblate (Polish) Currently translated at 96.2% (3273 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Russian) Currently translated at 77.8% (2649 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ru/ * Translated using Weblate (Russian) Currently translated at 75.6% (5818 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Translated using Weblate (Polish) Currently translated at 96.5% (3283 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Polish) Currently translated at 97.0% (3303 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Ukrainian) Currently translated at 77.8% (5981 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/uk/ * Translated using Weblate (Polish) Currently translated at 97.3% (3313 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Polish) Currently translated at 98.2% (3343 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Russian) Currently translated at 76.1% (5851 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Translated using Weblate (Russian) Currently translated at 76.1% (5854 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Translated using Weblate (Polish) Currently translated at 98.8% (3363 of 3402 strings) Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/pl/ * Translated using Weblate (Russian) Currently translated at 76.7% (5903 of 7687 strings) Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ru/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Mattermost/server Translate-URL: https://translate.mattermost.com/projects/mattermost/server/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: Mattermost/webapp Translate-URL: https://translate.mattermost.com/projects/mattermost/webapp/ --------- Co-authored-by: master7 <marcin.karkosz@rajska.info> Co-authored-by: ritchierope <ritchierope@users.noreply.translate.mattermost.com> Co-authored-by: s0k0l -_- <salarysalo@gmail.com> Co-authored-by: Dmitriy Q <krotesk@mail.ru> Co-authored-by: Tom De Moor <tom@controlaltdieliet.be> Co-authored-by: Sharuru <mave@foxmail.com> Co-authored-by: Roy Orbitson <roy-orbitson@devo.net.au> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Simonas Audickas <simonas.audickas@gmail.com> Co-authored-by: jprusch <rs@schaeferbarthold.de> Co-authored-by: Bohdan <bshumylo@yahoo.com> Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
10804f80f5 |
Prepackage mattermost-plugin-agents v2.5.1 (#37727)
* Prepackage mattermost-plugin-agents v2.5.0. Co-authored-by: Cursor <cursoragent@cursor.com> * Prepackage mattermost-plugin-agents v2.5.1. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
9de0027868 |
[MM-69982] Fix intermittent remote cluster ping failures from stale keep-alive connection reuse (#37694)
* [MM-69982] Fix intermittent remote cluster ping failures from stale keep-alive reuse The remote cluster HTTP transport set IdleConnTimeout to 90s while pings fire every PingFreq (60s) and peers close idle keep-alive connections after their own IdleTimeout (default 60s). Because 90s > 60s, the pooled ping connection outlived the peer's reaping, so each 60s ping reused a connection the peer had already closed, racing the FIN and failing intermittently with EOF / connection reset. Set IdleConnTimeout to PingFreq/2 so the pool always discards the connection before the next ping fires, making the reuse race structurally impossible while keeping the invariant (IdleConnTimeout < PingFreq) explicit and tied to PingFreq. Co-authored-by: mattermost-code <matty-code@mattermost.com> * chore: retrigger Server CI after check-style Docker Hub flake Server CI check-style failed pulling buildenv (Docker Hub Client.Timeout / missing buildenv-image artifact); unrelated to IdleConnTimeout changes. Enterprise CI check-style already passed on the same commit. 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> |
||
|
|
9230eb6f6a |
MM-69725: Propagate context through Extractor.Extract using new mattermost/pdf fork (#37579)
* Propagate context through Extractor.Extract Adds ctx context.Context to the Extractor interface and all implementations so callers can cancel in-flight extractions. pdfExtractor passes the context down to GetPlainText(ctx), which checks ctx.Done() at each page boundary. When extractWithTimeout fires (deadline exceeded or parent cancel), it cancels the derived context via defer cancel(), and the PDF goroutine stops at the next page rather than running to completion, eliminating the heap growth that caused OOM on complex documents. For non-context-aware extractors (docconv, plain, archive) the context is accepted but not yet acted on; they continue to run to completion on a detached goroutine after the timeout, as before. The call site in channels/app/file.go passes rctx.Context() so request cancellation (e.g. HTTP disconnect) also propagates. * Use new mattermost/pdf fork * Update notice reflecting the new fork * Fail archiveExtractor.Extract early on ctx errors * Bump mattermost/pdf to cd8a834041c4 --------- Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
6fefcc80a4 |
MM-67336: Request structured JSON output for AI message rewrites (#37581)
Co-authored-by: Cursor Agent <cursoragent@cursor.com> |
||
|
|
f6c1459ebf | MM-69612: Add opt-in EnableAuditLogging setting for ABAC (#37322) | ||
|
|
d33ad5a7e9 | [MM-69810] Update golang.org/x/image dep (#37595) | ||
|
|
dc41b72fdd | Prepackage mattermost-plugin-agents v2.5.0-rc2. (#37691) | ||
|
|
1dacc2d514 |
Mm 69830 abac membership messaging fixes (#37618)
* MM-69828 - Fix ABAC team Access-tab stuck-public cards, parent-policy mode-flip count * Add fallback handling for parent-policy fetch failure in AccessTab component * MM-69829 - Show Attribute Based indicator for policy-governed teams in admin Teams list * MM-69829 - Clear stale navigation-block flag when opening a membership policy in the editor * MM-69829 - Save cleanly when removing a team membership policy instead of prompting to re-apply * MM-69829 - Count qualifying team members correctly in the apply-policy confirmation modal * fix failing test * do not show apply policy confirmation modal on policy unlink * Refactor TableEditor state management and integrate deleteAccessControlPolicy action * fix ci linter for playwright test * adjust e2e to the new flow - no policy/rule , no blocking, clean state abac off * MM-69830 - Return an OK body when deleting an access policy so rule removal saves cleanly * MM-69830 - Soften the self-exclusion message on public teams to reflect advisory enforcement * MM-69830 - Soften membership-policy notices to advisory copy on public teams * MM-69830 - Uncheck auto-add when the last team membership rule is removed * MM-69830 - Warn that removing all rules drops attribute enforcement instead of showing the save-count modal * MM-69830 - Dispatch the deleted policy id so removing team rules doesn't crash the reducer * MM-69830 - Skip the self-exclusion block on public teams instead of rewording it * MM-69830 - Use advisory wording in the save-rules confirmation on public teams * MM-69830 - Use advisory auto-add descriptions on public teams * MM-69830 - Block switching a team to private when the admin would be self-excluded by the rules * fix prettier issues and adjust comments * MM-69830 - Assert advisory confirmation copy for team admins on public teams * MM-69830 - Show a saving state on the membership save panel while a confirmed save runs * MM-69830 - Save immediately when confirming the switch-to-private mode flip * MM-69829 - Surface delete failures and page through all members in the ABAC team save flow * MM-69830 - Align the remove-all-rules confirmation with performSave's parent-import check * MM-69830 - Drop an unnecessary cast on the team policy result and memoize the self-exclusion modal handler |
||
|
|
1cc20031fe |
MM-69857 - Keep parent imports and team scope system-managed on the policy update endpoint (#37625)
Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
bc3ad86a23 | Update Playbooks plugin to v2.11.1 (incl. FIPS) (#37631) | ||
|
|
f06971b657 |
Fix two Session Attribute issues (#37620)
Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
38b66d2262 |
[MM-69845] Add Global Attributes access gate to System Console (#37580)
* [MM-69845] Add Global Attributes access gate to System Console Adds a hidden "Manage Attributes" shell page under the System Attributes section, gated by a new FeatureFlags.GlobalAttributes flag, Enterprise license tier, and sysadmin role. Also fixes admin_sidebar.tsx never threading isCurrentUserSystemAdmin into its isHidden(...) calls, which would have kept any sysadmin-gated subsection permanently hidden from the menu regardless of role. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Match Manage Attributes gating to the Classification Markings pattern Ticket was clarified: the sysadmin condition restricts edit access (isDisabled), not visibility (isHidden) — the page stays reachable to anyone who can already see the System Attributes section, matching how Classification Markings gates its own page, rather than the uniform three-way hide this PR originally built. This removes the need for the admin_sidebar.tsx/index.ts plumbing fix from the previous commit: the sidebar only ever evaluates isHidden, never isDisabled, so no changes to shared sidebar code are needed. Also adds a one-line placeholder to the shell per reviewer request. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Add e2e test for Global Attributes access gate Covers the two QA-relevant states from the PR: feature flag off hides the page regardless of license, and flag-on with an Enterprise+ license shows the empty shell with its placeholder text. Modeled on classification_markings.spec.ts, the closest existing precedent for a feature-flag + license-tier gated System Console page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Address review feedback on e2e/unit test coverage - Restore the GlobalAttributes flag to its pre-test value in afterAll instead of forcing it to false, so the e2e spec doesn't leave a config side effect on environments where it was already on. - Remove the redundant systemConsolePage.goto() before navigating straight to the Manage Attributes path. - Scope the flag-off absence assertion to the sidebar instead of the whole page, so an unrelated "Manage Attributes" string elsewhere can't produce a false pass. - Add an unlicensed-server case to the isHidden predicate matrix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Scope remaining e2e assertions to testid, drop ambiguous .first() Switch the sidebar locator from a CSS class to getByTestId('admin-sidebar'), matching the data-testid already on that element. Split the flag-on test's single .first() assertion into two testid-scoped assertions (sidebar entry, page heading) instead of relying on DOM-order luck between the two elements that both render "Manage Attributes". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Fix prettier formatting in global_attributes.spec.ts Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Skip flag cleanup when env/SplitKey overrides GlobalAttributes getConfig() returns the effective value, which reflects any env var or SplitKey override rather than what's actually persisted. Writing that effective value back in afterAll would silently corrupt the persisted config on environments where an override is active. Add isGlobalAttributesFlagOverridden() (checks getEnvironmentConfig() for an env override and ServiceSettings.SplitKey for live flag sync) and skip capturing/restoring the flag entirely when either is true. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * [MM-69845] Revert override-detection layer in e2e cleanup No other spec in this suite checks env/SplitKey overrides before restoring a feature flag (classification_markings.spec.ts and global_classification_banner.spec.ts both toggle flags directly with no such guard). Matching that established convention over the theoretically-more-correct-but-unprecedented approach; the simple capture-and-restore is enough. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
a8f55e5327 |
[MM-69885] Allow integrations to update mm_blocks_actions on their own posts (#37583)
* [MM-69885] Allow integrations to update mm_blocks_actions on their own posts * prune mm_blocks_actions on post updates to match remaining buttons |
||
|
|
1bfa2e5113 | Bumping prepackaged boards version to 9.3.1 (#37594) | ||
|
|
25f3a75cb7 |
[MM-67163] Scheduled Recaps (#35495)
* docs: map existing codebase with focus on recaps
- STACK.md - Technologies and dependencies
- ARCHITECTURE.md - System design and patterns
- STRUCTURE.md - Directory layout
- CONVENTIONS.md - Code style and patterns
- TESTING.md - Test structure
- INTEGRATIONS.md - External services
- CONCERNS.md - Technical debt and issues
* docs: initialize project
Scheduled AI Recaps — enable recurring scheduled recaps instead of only manual one-off summaries
* chore: add project config
Mode: yolo
Depth: standard
Parallelization: enabled
* docs: complete domain research for scheduled recaps
Research files:
- STACK.md: Job server patterns, ScheduledPosts reference implementation
- FEATURES.md: Table stakes vs differentiators, anti-features to avoid
- ARCHITECTURE.md: Component boundaries, data flow, 5-phase build order
- PITFALLS.md: Timezone, cluster, schema critical pitfalls
- SUMMARY.md: Synthesized findings and roadmap implications
Key findings:
- Use ScheduledPosts polling pattern, not JobServer schedulers
- Store user intent + pre-computed NextRunAt for efficient polling
- Leverage existing recap worker, extend with time_period support
- Critical: Get timezone/schema right in Phase 1 to avoid migrations
* docs: define v1 requirements
35 requirements across 5 categories:
- Scheduling (7)
- Management (8)
- Backend Infrastructure (10)
- Frontend Wizard (7)
- Frontend Scheduled Tab (7)
Topic-based recaps deferred to v2
* docs: create roadmap (5 phases)
* docs(01): capture phase context
Phase 01: Database Foundation
- OpenCode discretion on implementation patterns
- Implicit requirements from downstream phases noted
* docs(01-database-foundation): research phase domain
Phase 1: Database Foundation
- Analyzed existing Recap and ScheduledPost patterns
- Documented schema design for recurring schedules
- Identified timezone/DST handling approach using IANA zones
- Catalogued store interface patterns
- Documented common pitfalls and anti-patterns
* docs(01): create phase plan for database foundation
Phase 01: Database Foundation
- 2 plans in 2 waves
- Wave 1: Model + migration (01-01-PLAN.md)
- Wave 2: Store layer + tests (01-02-PLAN.md)
- Ready for execution
* feat(01-01): create ScheduledRecap model with DST-aware NextRunAt computation
- Add ScheduledRecap struct with all required fields for schedule configuration
- Add day-of-week bitmask constants matching Go's time.Weekday (Sunday=0)
- Add channel mode constants (specific, all_unreads)
- Add time period constants (last_24h, last_week, since_last_read)
- Implement ComputeNextRunAt with timezone-aware scheduling using time.LoadLocation
- Implement IsValid for input validation
- Add PreSave/PreUpdate lifecycle methods
- Add Auditable method for audit logging
* feat(01-01): create database migration for ScheduledRecaps table
- Create ScheduledRecaps table with all required columns
- Add index for user queries (idx_scheduled_recaps_user_id)
- Add index for scheduler polling (idx_scheduled_recaps_next_run_at)
- Add composite index for efficient scheduler query (idx_scheduled_recaps_enabled_next_run)
- Add index for user + soft delete queries (idx_scheduled_recaps_user_delete)
- Add down migration to drop all indexes and table
* test(01-01): add unit tests for ScheduledRecap with DST edge cases
- Test day-of-week bitmask constants and operations
- Test ComputeNextRunAt for Monday-only, weekday, and every-day schedules
- Test timezone handling - different timezones produce different UTC millis
- Test DST spring forward edge case (March 2024) - Go normalizes non-existent times
- Test DST fall back edge case (November 2024) - Go uses first occurrence
- Test error cases: invalid timezone, invalid time format, zero days
- Test IsValid method for all validation rules
- Test PreSave and PreUpdate lifecycle methods
- Test Auditable method returns expected fields
- Fix ComputeNextRunAt to validate time format using regex before parsing
* docs(01-01): complete ScheduledRecap model and migration plan
Tasks completed: 3/3
- Task 1: Create ScheduledRecap model with constants and NextRunAt computation
- Task 2: Create database migration for ScheduledRecaps table
- Task 3: Add unit tests for ComputeNextRunAt with DST edge cases
SUMMARY: .planning/phases/01-database-foundation/01-01-SUMMARY.md
* feat(01-02): add ScheduledRecapStore interface to store.go
- Add ScheduledRecapStore interface with CRUD operations (Save, Get, Update, Delete)
- Add query operations (GetForUser, GetDueBefore)
- Add state update methods (UpdateNextRunAt, MarkExecuted, SetEnabled)
- Register ScheduledRecap() method in main Store interface
* feat(01-02): create SqlScheduledRecapStore implementation
- Implement CRUD operations (Save, Get, Update, Delete with soft delete)
- Implement GetForUser with pagination for user's scheduled recaps
- Implement GetDueBefore for scheduler polling query
- Implement efficient state updates (UpdateNextRunAt, MarkExecuted, SetEnabled)
- Handle JSON serialization/deserialization of ChannelIds array
- Follow existing patterns from recap_store.go
* feat(01-02): register ScheduledRecapStore in SqlStore
- Add scheduledRecap field to SqlStoreStores struct
- Initialize newSqlScheduledRecapStore in NewSqlStore
- Add ScheduledRecap() accessor method to SqlStore
* test(01-02): add comprehensive tests for ScheduledRecapStore
- Test CRUD operations (Save, Get, Update, Delete)
- Test GetForUser with pagination
- Test GetDueBefore scheduler query filtering
- Test state update methods (UpdateNextRunAt, MarkExecuted, SetEnabled)
- Test ChannelIds JSON serialization (array, empty, nil)
- All 13 test cases pass
* docs(01-02): complete ScheduledRecapStore plan
Tasks completed: 4/4
- Add ScheduledRecapStore interface to store.go
- Create SqlScheduledRecapStore implementation
- Register ScheduledRecapStore in SqlStore
- Create comprehensive store tests
SUMMARY: .planning/phases/01-database-foundation/01-02-SUMMARY.md
* fix(01): regenerate store mocks for ScheduledRecapStore
* docs(01): complete Database Foundation phase
Phase 1: Database Foundation
- 2 plans executed (model + store)
- 3 requirements complete (INFRA-01, INFRA-02, INFRA-10)
- Goal verified ✓
* docs(03): research phase scheduler integration domain
Phase 03: Scheduler Integration
- Standard stack identified (Mattermost job system)
- Architecture patterns documented (Scheduler + Worker pattern)
- Cluster-safe execution via leader-only scheduling
- Pitfalls catalogued (duplicate jobs, race conditions)
- Code examples from existing codebase patterns
* docs(02): create phase 2 API layer plans
Phase 02: API Layer
- 2 plans in 2 waves
- Plan 01 (Wave 1): App layer methods for CRUD + pause/resume
- Plan 02 (Wave 2): API handlers, routes, params, audit events
- Ready for execution
* feat(02-01): create App layer CRUD methods for ScheduledRecap
- Add CreateScheduledRecap with session-based userId, validation, NextRunAt computation
- Add GetScheduledRecap to retrieve by ID
- Add GetScheduledRecapsForUser with pagination
- Add UpdateScheduledRecap with NextRunAt recomputation when enabled
- Add DeleteScheduledRecap for soft delete
- Add PauseScheduledRecap to disable without deleting
- Add ResumeScheduledRecap with NextRunAt recomputation before enabling
- Regenerate store layer files for ScheduledRecapStore interface
* docs(02-01): complete App layer CRUD methods plan
Tasks completed: 3/3
- Regenerate store mocks (already complete from Phase 1)
- Create App layer file with CRUD methods
- Verify app layer interfaces (no interface file exists)
SUMMARY: .planning/phases/02-api-layer/02-01-SUMMARY.md
* feat(02-02): add audit event constants for scheduled recaps
- AuditEventCreateScheduledRecap for recap configuration creation
- AuditEventGetScheduledRecap for viewing single recap
- AuditEventGetScheduledRecaps for listing user recaps
- AuditEventUpdateScheduledRecap for configuration updates
- AuditEventDeleteScheduledRecap for recap deletion
- AuditEventPauseScheduledRecap for pausing execution
- AuditEventResumeScheduledRecap for resuming execution
* feat(02-02): add ScheduledRecapId to params and context
- Add ScheduledRecapId field to Params struct
- Parse scheduled_recap_id from URL path variables
- Add RequireScheduledRecapId validation method
* feat(02-02): add route registration for scheduled recaps
- Add ScheduledRecaps and ScheduledRecap routes to Routes struct
- Initialize route prefixes in Init function
- Add InitScheduledRecap call in initialization
* feat(02-02): create API handlers for scheduled recaps
- InitScheduledRecap registers all 7 API routes
- createScheduledRecap validates required fields and creates recap
- getScheduledRecap retrieves with authorization check
- getScheduledRecaps lists user's recaps with pagination
- updateScheduledRecap updates with ownership verification
- deleteScheduledRecap soft deletes with authorization
- pauseScheduledRecap disables execution with ownership check
- resumeScheduledRecap re-enables with NextRunAt recomputation
- All handlers include audit logging and feature flag check
* docs(02-02): complete API handlers plan
Tasks completed: 4/4
- Add audit event constants for scheduled recaps
- Add ScheduledRecapId to params and context
- Add route registration in api.go
- Create API handler file
SUMMARY: .planning/phases/02-api-layer/02-02-SUMMARY.md
* docs(02): complete API Layer phase
Phase 2: API Layer
- 2 plans executed in 2 waves
- 16/16 must-haves verified
- INFRA-05 through INFRA-09 complete
- Ready for Phase 3: Scheduler Integration
* docs(03): create phase plan for scheduler integration
Phase 03: Scheduler Integration
- 2 plans in 2 waves
- Wave 1: Job constant, scheduler, worker
- Wave 2: Job registration, App method
- Ready for execution
* fix(03): revise plan 03-02 Task 2 for worker context compatibility
- CreateRecapFromSchedule now creates recap directly via store
- Uses sr.UserId instead of rctx.Session().UserId (unavailable in worker)
- Creates JobTypeRecap job directly instead of delegating to CreateRecap
- Updated key_links to reflect store and job linkage
* docs(04): capture phase context
Phase 04: Scheduled Tab
- Implementation decisions documented
- Phase boundary established
- Figma references captured (123:62940, 123:19772)
* feat(03-01): add JobTypeScheduledRecap constant
- Add JobTypeScheduledRecap constant with value 'scheduled_recap'
- Add to AllJobTypes slice for job type validation
* feat(03-01): create ScheduledRecap scheduler
- Add Scheduler struct wrapping PeriodicScheduler
- 1-minute polling interval (SchedulerPollingInterval constant)
- Enabled when cfg.FeatureFlags.EnableAIRecaps is true
- ScheduleJob polls GetDueBefore for due recaps
- Creates job with CreateJobOnce for deduplication
- Job data: scheduled_recap_id, user_id, channel_ids, agent_id
* feat(03-01): create ScheduledRecap worker
- Define AppIface interface with CreateRecapFromSchedule method
- Use SimpleWorker pattern following recap/worker.go pattern
- Enabled when cfg.FeatureFlags.EnableAIRecaps is true
- Extract job data: scheduled_recap_id, user_id, channel_ids, agent_id
- Verify ScheduledRecap exists and is enabled before execution
- Call app.CreateRecapFromSchedule to create the actual recap
- Compute next run time using sr.ComputeNextRunAt
- Call MarkExecuted to update LastRunAt, NextRunAt, RunCount atomically
- Disable non-recurring schedules after execution
* docs(03-01): complete job system components plan
Tasks completed: 3/3
- Add JobTypeScheduledRecap constant
- Create scheduler implementation
- Create worker implementation
SUMMARY: .planning/phases/03-scheduler-integration/03-01-SUMMARY.md
* docs(04): create phase 4 plans - Scheduled Tab UI
Phase 04: Frontend - Scheduled Tab
- 4 plans in 4 waves
- Wave 1: TypeScript types + Client4 API methods
- Wave 2: Redux layer (action types, actions, reducer, selectors)
- Wave 3: ScheduledRecapItem component (card UI with toggle, menu)
- Wave 4: Scheduled tab integration with human verification
Covers requirements TAB-01 through TAB-07 and MGMT-01 through MGMT-08
* feat(03-02): add ScheduledRecap job registration in initJobs
- Register JobTypeScheduledRecap with worker and scheduler
- Import scheduled_recap package for job components
- Worker uses App interface for CreateRecapFromSchedule
- Scheduler polls for due recaps at 1-minute intervals
* feat(03-02): implement CreateRecapFromSchedule App method
- Create Recap from ScheduledRecap configuration
- Use sr.UserId instead of session (worker context has no session)
- Create recap record directly via store
- Create JobTypeRecap job to trigger processing
- Handle both specific channels and all_unreads mode
* docs(03-02): complete app integration plan
Tasks completed: 3/3
- Add job registration in initJobs
- Implement CreateRecapFromSchedule App method
- Verify full integration compiles
SUMMARY: .planning/phases/03-scheduler-integration/03-02-SUMMARY.md
* docs(phase-3): complete scheduler integration phase
* feat(04-01): add ScheduledRecap TypeScript types
- Add ScheduledRecap type matching Go model fields
- Add ScheduledRecapInput type for create/update operations
- Types exported via @mattermost/types/recaps
* feat(04-01): add Client4 scheduled recap route and imports
- Add getScheduledRecapsRoute() method returning /scheduled_recaps endpoint
- Import ScheduledRecap and ScheduledRecapInput types
* feat(04-01): add Client4 scheduled recap API methods
- createScheduledRecap: POST /scheduled_recaps
- getScheduledRecaps: GET /scheduled_recaps (paginated)
- getScheduledRecap: GET /scheduled_recaps/:id
- updateScheduledRecap: PUT /scheduled_recaps/:id
- deleteScheduledRecap: DELETE /scheduled_recaps/:id
- pauseScheduledRecap: POST /scheduled_recaps/:id/pause
- resumeScheduledRecap: POST /scheduled_recaps/:id/resume
* docs(04-01): complete TypeScript types and Client4 methods plan
Tasks completed: 3/3
- Add ScheduledRecap TypeScript type
- Add Client4 scheduled recap route helper
- Add Client4 scheduled recap API methods
SUMMARY: .planning/phases/04-scheduled-tab/04-01-SUMMARY.md
* feat(04-02): add scheduled recap action types
- GET_SCHEDULED_RECAPS_REQUEST/SUCCESS/FAILURE
- RECEIVED_SCHEDULED_RECAP and RECEIVED_SCHEDULED_RECAPS
- PAUSE_SCHEDULED_RECAP_REQUEST/SUCCESS/FAILURE
- RESUME_SCHEDULED_RECAP_REQUEST/SUCCESS/FAILURE
- DELETE_SCHEDULED_RECAP_REQUEST/SUCCESS/FAILURE
* feat(04-02): add scheduled recap Redux actions
- getScheduledRecaps: fetches paginated scheduled recaps
- pauseScheduledRecap: pauses a scheduled recap
- resumeScheduledRecap: resumes a paused scheduled recap
- deleteScheduledRecap: deletes a scheduled recap
* feat(04-02): add scheduled recaps to reducer
- Add scheduledRecaps to RecapsState type
- Handle RECEIVED_SCHEDULED_RECAP for single recap
- Handle RECEIVED_SCHEDULED_RECAPS for bulk updates
- Handle DELETE_SCHEDULED_RECAP_SUCCESS for removal
* feat(04-02): add scheduled recap selectors
- getScheduledRecapsState: base selector for raw state
- getAllScheduledRecaps: returns all scheduled recaps as array
- getActiveScheduledRecaps: filters enabled, non-deleted recaps
- getPausedScheduledRecaps: filters disabled, non-deleted recaps
- getScheduledRecapById: returns single recap by ID
* feat(04-02): update GlobalState type for scheduled recaps
- Import ScheduledRecap type from recaps
- Add scheduledRecaps field to recaps entity state
* docs(04-02): complete Redux store and actions plan
Tasks completed: 5/5
- Add scheduled recap action types
- Add scheduled recap Redux actions
- Add scheduled recaps to reducer
- Add scheduled recap selectors
- Update GlobalState type for scheduled recaps
SUMMARY: .planning/phases/04-scheduled-tab/04-02-SUMMARY.md
* feat(04-03): add i18n strings for scheduled recap UI
- Add scheduled tab label
- Add active/paused toggle states
- Add run stats strings (last run, run count, never run, next run)
- Add toast messages for pause/resume/delete
- Add kebab menu labels (edit, delete)
- Add delete confirmation modal strings
- Add empty state strings (title, description, cta)
- Add day formatting strings (weekdays, weekend, everyday, individual days)
- Add schedule format string
* feat(04-03): create useScheduleDisplay hook for schedule formatting
- Add bitmask constants matching Go model (Sun=1, Mon=2, etc.)
- formatDaysOfWeek: smart groupings (Every day, Weekdays, Weekends) or comma-separated
- formatTimeOfDay: locale-appropriate 12/24hr time from HH:MM
- formatSchedule: combines days and time with i18n format string
- formatNextRun: smart relative formatting (Today, Tomorrow, Day name, Date)
- formatLastRun: formatted date or 'Never run'
- formatRunCount: pluralized run count
* feat(04-03): create ScheduledRecapItem component
- Render card with title and schedule pattern subtitle
- Show next run time when schedule is active
- Toggle between Active/Paused states with pause/resume actions
- Run stats (last run, run count) appear on hover
- Kebab menu with Edit and Delete options
- Delete confirmation modal with FormattedMessage
- Use useScheduleDisplay hook for all formatting
* feat(04-03): add ScheduledRecapItem styles
- Card with border, radius, and hover state
- Flexbox layout with title/subtitle and actions
- Title with truncation (ellipsis) for long names
- Subtitle with metadata separator styling
- Run stats with opacity transition on hover
- Toggle button min-width for consistent sizing
- Kebab menu button hover state
* docs(04-03): complete ScheduledRecapItem component plan
Tasks completed: 4/4
- Add i18n strings for scheduled recap UI
- Create useScheduleDisplay hook for schedule formatting
- Create ScheduledRecapItem component
- Add ScheduledRecapItem styles
SUMMARY: .planning/phases/04-scheduled-tab/04-03-SUMMARY.md
* feat(04-04): create ScheduledRecapsEmptyState component
- Empty state displays when no scheduled recaps exist
- Shows illustration with icons, title, description
- CTA button to create first recap
- Supports disabled state when agents bridge is disabled
* feat(04-04): create ScheduledRecapsList component
- Renders empty state when no scheduled recaps exist
- Maps over scheduled recaps to render ScheduledRecapItem
- Passes edit and create handlers through to children
* feat(04-04): add Scheduled tab to main Recaps component
- Add Scheduled tab after Unread and Read tabs
- Fetch scheduled recaps on mount with getScheduledRecaps
- Display ScheduledRecapsList when on scheduled tab
- Wire up edit handler (opens create modal - Phase 5 adds pre-fill)
- Import scheduled_recap_item.scss for styling
* style(04-04): add SCSS styles for scheduled recaps
- Add .scheduled-recaps-list styles (flex column, centered, gap)
- Add .scheduled-recaps-empty-state styles (centered, illustration, text)
- Consistent with existing recap UI styling patterns
* docs(04-04): complete Scheduled tab integration plan
* docs(04): update STATE.md for phase 4 completion
* docs(04): complete Scheduled Tab phase
Phase 4: Scheduled Tab
- 4 plans executed across 4 waves
- 15/15 requirements verified
- Human verified UI works correctly
* docs(05): capture phase context
Phase 05: Enhanced Wizard
- Implementation decisions documented
- Phase boundary established
* docs(05): add research hints for component discovery
* docs(05): research phase domain for enhanced wizard
Phase 05: Enhanced Wizard - Frontend Implementation
- Standard stack identified (existing codebase components)
- Architecture patterns documented (multi-step modal, bitmask days)
- Pitfalls catalogued (timezone, validation, edit mode)
- Code examples from codebase referenced
* docs(05): create phase plan for enhanced wizard
Phase 05: Frontend - Enhanced Wizard
- 6 plans in 3 waves
- Wave 1: Redux actions, DayOfWeekSelector
- Wave 2: ScheduleConfiguration, Run once toggle
- Wave 3: Modal integration, Edit wiring
- Ready for execution
* feat(05-01): add action type constants for create/update scheduled recap
- CREATE_SCHEDULED_RECAP_REQUEST/SUCCESS/FAILURE
- UPDATE_SCHEDULED_RECAP_REQUEST/SUCCESS/FAILURE
* feat(05-02): create DayOfWeekSelector component
- Bitmask-based day selection matching server model
- Monday-first ordering for work schedule intuition
- XOR toggle for clean state management
- aria-pressed accessibility support
* feat(05-01): add createScheduledRecap async action
- Takes ScheduledRecapInput parameter
- Calls Client4.createScheduledRecap
- Dispatches RECEIVED_SCHEDULED_RECAP on success
- Follows existing pauseScheduledRecap pattern
* feat(05-02): add DayOfWeekSelector styles
- Flexbox layout with 8px gap between buttons
- 40x40px day buttons with hover states
- Selected state uses button-bg color
- Error and disabled state styling
* feat(05-01): add updateScheduledRecap async action
- Takes id and ScheduledRecapInput parameters
- Calls Client4.updateScheduledRecap
- Dispatches RECEIVED_SCHEDULED_RECAP on success
- Follows existing action patterns
* docs(05-02): complete DayOfWeekSelector plan
Tasks completed: 2/2
- DayOfWeekSelector component with bitmask state
- Styled button group with toggle/hover/error states
SUMMARY: .planning/phases/05-enhanced-wizard/05-02-SUMMARY.md
* docs(05-01): complete Redux actions for scheduled recaps plan
Tasks completed: 3/3
- Add action type constants for create/update scheduled recap
- Add createScheduledRecap async action
- Add updateScheduledRecap async action
SUMMARY: .planning/phases/05-enhanced-wizard/05-01-SUMMARY.md
* feat(05-04): add run once toggle to RecapConfiguration
- Add runOnce, setRunOnce, and isEditMode props to Props type
- Import Toggle component
- Add run once toggle section at bottom of Step 1
- Toggle hidden when isEditMode is true
- Include descriptive text below toggle
* feat(05-03): create ScheduleConfiguration component for Step 3
- Add day-of-week selection using DayOfWeekSelector
- Add time picker with 30-minute intervals and locale-aware formatting
- Add time period dropdown (Previous day, Last 3 days, Last 7 days)
- Add custom instructions textarea with 500 char limit
- Add next run preview with timezone support
- Use getCurrentTimezone selector for user timezone
* feat(05-04): add run once toggle styles
- Add .run-once-group with top separator border
- Style toggle and label with proper alignment
- Add description text with left margin for alignment
- Use consistent spacing and typography
* feat(05-03): add Step 3 schedule configuration styles
- Add step-three layout with vertical flex and gap
- Add form-group styling with label and error states
- Add next-run-preview styling with background and subtle text
- Add textarea overrides for custom instructions input
* docs(05-04): complete run once toggle plan
Tasks completed: 2/2
- Add run once toggle to RecapConfiguration
- Add run once toggle styles
SUMMARY: .planning/phases/05-enhanced-wizard/05-04-SUMMARY.md
* docs(05-03): complete ScheduleConfiguration plan
Tasks completed: 2/2
- Create ScheduleConfiguration component
- Add Step 3 styles to SCSS
SUMMARY: .planning/phases/05-enhanced-wizard/05-03-SUMMARY.md
* feat(05-05): add schedule state and edit mode props to modal
- Add editScheduledRecap prop for edit mode detection
- Add schedule state (daysOfWeek, timeOfDay, timePeriod, customInstructions)
- Add runOnce state and validation state (daysError, timeError)
- Add useEffect to pre-fill form in edit mode
- Import createScheduledRecap, updateScheduledRecap actions
- Import ScheduleConfiguration component and getCurrentTimezone selector
* feat(05-06): update handleEditScheduledRecap to pass scheduled recap to modal
- Find scheduled recap by ID from scheduledRecaps array
- Pass editScheduledRecap via dialogProps to CreateRecapModal
- Early return if scheduled recap not found
* feat(05-05): update step navigation for run once and schedule flows
- Update handleNext to clear validation errors on navigation
- Update handlePrevious to clear validation errors on navigation
- Update getTotalSteps for run once (2-3 steps) vs scheduled (always 3)
- Update getActualStep for proper step indicator mapping
* feat(05-05): update renderStep for schedule vs run once flows
- Pass runOnce, setRunOnce, and isEditMode props to RecapConfiguration
- Show ChannelSummary for run once mode at step 3
- Show ScheduleConfiguration for scheduled mode at step 3
- Pass all schedule state props to ScheduleConfiguration component
* feat(05-05): update handleSubmit for immediate and scheduled recaps
- Add schedule field validation for non-run-once mode
- Dispatch createRecap for run once mode (existing behavior)
- Dispatch updateScheduledRecap for edit mode
- Dispatch createScheduledRecap for new scheduled recaps
- Navigate to ?tab=scheduled after creating/editing scheduled recap
- Add proper error messages for schedule validation failures
* feat(05-05): update modal header and button text for edit mode
- Update canProceed to validate schedule fields in step 3
- Add getConfirmButtonText helper for context-aware button text
- Show 'Start recap' for run once, 'Save changes' for edit mode
- Show 'Create schedule' for new scheduled recaps
- Update headerText to show 'Edit your recap' in edit mode
* docs(05-05): complete wizard integration plan
Tasks completed: 5/5
- Add schedule state and edit mode props
- Update step navigation for run once and schedule flows
- Update renderStep for schedule vs run once flows
- Update handleSubmit for immediate and scheduled recaps
- Update modal header and button text for edit mode
SUMMARY: .planning/phases/05-enhanced-wizard/05-05-SUMMARY.md
* fix(05-06): JSON.stringify body in scheduled recap API calls
createScheduledRecap and updateScheduledRecap were passing objects
directly to doFetch body, causing '[object Object]' to be sent instead
of JSON. Fixed to match createRecap pattern.
* fix(05-06): align time period values with server model
Frontend was using 'last_3_days' and 'last_7_days' but server expects
'last_24h', 'last_week', and 'since_last_read'. Updated options to match.
* fix(05-06): remove duplicate border on custom instructions textarea
- GenericModal adds a border to all .form-control elements
- Input widget's Input_fieldset already provides a border container
- This caused a double-border visual glitch on the textarea
- Added border: none to the inner textarea to fix the issue
* fix(05-06): reserve space for next run preview to prevent modal height jump
- Always render next-run-preview container (previously conditionally rendered)
- Use visibility:hidden instead of not rendering when no preview available
- Add non-breaking space placeholder to maintain consistent element height
- Prevents jarring visual jump when user selects a day of the week
* fix(05-06): remove border/background from next-run-preview
- Remove padding, border-radius, and background-color from .next-run-preview
- Style as plain text with subtle color and smaller font size
- Keep margin for appropriate spacing from time selector
* fix(05-06): use abbreviated timezone in next recap preview
- Use Intl.DateTimeFormat with timeZoneName: 'short' to get timezone
abbreviation (e.g., EST, PST, EDT) instead of full label
- Remove unused getCurrentTimezoneLabel selector import
- Preview now shows 'Monday at 9:00 AM (EST)' instead of
'Monday at 9:00 AM ((UTC-05:00) Eastern Time (US & Canada))'
* fix(05-06): prevent modal height jump when next run preview appears
- Move next-run-preview inside time-selection-group as helper text
- Add min-height: 16px to reserve space when preview is hidden
- Use visibility: hidden instead of display: none for consistent height
- Reduce step-three gap from 20px to 16px for better spacing
- Add margin-bottom: 0 to form-group to override default spacing
* fix(05-06): add section titles and fix spacing in schedule configuration
- Add section titles per Figma design (Heading 100 style):
- 'When would you like your summary sent?' as main header
- 'On which days should your recap run?' for days section
- 'At what time?' for time section
- 'Select a time period for your recap to cover' for time period
- 'Additional instructions for {agentName}' for custom instructions
- Pass agentName prop from parent to show selected agent name
- Fix spacing: reserve space for next-run preview with container
to prevent time period section from jumping when preview appears
- Update SCSS with schedule-section groups and proper spacing
* fix(05-06): remove duplicate title and fix subtitle-dropdown spacing
- Remove 'When would you like your summary sent?' duplicate title
- Add scoped CSS rule for 12px total spacing between subtitle and dropdown
* fix(05-06): use standard Toggle without text labels for active/paused state
- Remove onText/offText props from Toggle component
- Add ariaLabel for accessibility (describes toggle state and action)
- Update SCSS to remove min-width constraint that was for text display
- Navigation to scheduled tab after creating scheduled recap already works correctly
* fix(05-06): toggle color and tab navigation after creating scheduled recap
- Use btn-toggle-primary class for scheduled recap toggle to display proper button-bg color
- Add useQuery hook to read tab query parameter from URL
- Sync activeTab state with URL tab parameter to enable navigation after modal close
* fix(05-06): sync tab state with URL bidirectionally
- Add handleTabChange callback that updates both state and URL
- Use history.replace() to update URL without polluting browser history
- Remove tab param from URL when switching to 'unread' (default tab)
- Simplify URL sync useEffect to always update from tabParam
- This enables proper navigation after creating scheduled recaps
* fix(05-06): fix navigation to scheduled tab after creating scheduled recap
- Replace useRouteMatch() with getCurrentRelativeTeamUrl selector
- Modal was using route match which returned wrong URL context (modal is rendered at root level)
- Use team selector to get correct team URL for navigation
- Update test to remove unnecessary useRouteMatch mock
* fix(05-06): sort scheduled recaps by newest first
- Update getAllScheduledRecaps selector to sort by create_at descending
- Follows same pattern as other recap selectors (getUnreadRecaps, getReadRecaps)
- Derived selectors (getActiveScheduledRecaps, getPausedScheduledRecaps) inherit sort order
* docs(05-06): complete edit wiring and UI polish plan
* docs(phase-05): complete Enhanced Wizard phase
Phase 5: Enhanced Wizard
- 6 plans executed across 3 waves
- 13 requirements verified
- Multi-step wizard for creating/editing scheduled recaps
- Run once and scheduled flows
- Full edit mode with pre-fill
- Extensive UI polish based on human feedback
All 39 requirements complete. Milestone ready for audit.
* docs(v1): milestone audit complete - all requirements satisfied
- 39/39 requirements verified
- 5/5 phases passed
- 100% cross-phase integration
- 5/5 E2E flows complete
- 2 minor tech debt items (non-blocking)
* chore: remove .planning from git tracking
- Add .planning to .gitignore
- Remove .planning files from git index (kept locally)
- Planning files are for local development only
* feat(06-01): add AIRecapSettings and RecapLimitSettings structs
- RecapLimitSettings with 7 limit fields (recaps/day, scheduled, channels, posts, tokens, posts/day, cooldown)
- AIRecapSettings with master toggle and per-limit enforcement toggles
- SetDefaults methods with sensible defaults (10 recaps/day, 5 scheduled, etc.)
- isValid/IsValid validation methods enforcing natural minimums
* feat(06-01): integrate AIRecapSettings into Config struct
- Add AIRecapSettings field to Config struct
- Call AIRecapSettings.SetDefaults() in Config.SetDefaults()
- Call AIRecapSettings.IsValid() in Config.IsValid()
* test(06-01): add tests for AIRecapSettings and RecapLimitSettings
- TestAIRecapSettingsSetDefaults: verifies all defaults match spec
- TestRecapLimitSettingsValidation: verifies validation rejects invalid values
- TestAIRecapSettingsPreservesExistingValues: verifies SetDefaults preserves existing
- TestAIRecapSettingsIsValid: verifies IsValid delegates to DefaultLimits
* feat(06-02): create EffectiveRecapLimits struct
- Add EffectiveRecapLimits struct with 7 resolved limit fields
- Add LimitSource type with system/group/user constants
- Add UnlimitedValue constant (-1) for disabled limits
- Add IsLimitEnabled helper function for enforcement code
* feat(06-02): create GetEffectiveLimits resolution function
- Add GetEffectiveLimits(userID) returning resolved limits for any user
- Resolve limits from AIRecapSettings.DefaultLimits config
- Apply per-limit enforcement toggles (disabled = -1 unlimited)
- Add helper functions getValueOrDefault and getBoolOrDefault
- Structure for Phase 8 group/user resolution with TODOs
* test(06-02): add tests for GetEffectiveLimits function
- TestGetEffectiveLimitsDefaults verifies system defaults returned
- TestGetEffectiveLimitsWithDisabledToggle verifies -1 returned for disabled limits
- TestGetEffectiveLimitsWithCustomDefaults verifies custom config honored
- TestGetEffectiveLimitsAllTogglesDisabled verifies all -1 when all disabled
- TestGetEffectiveLimitsUnlimitedConfigValue verifies -1 config value honored
- TestIsLimitEnabled verifies helper correctly identifies enabled limits
* feat(07-01): add RecapStatusSkipped constant and SkipReason field
- Add RecapStatusSkipped constant for recaps skipped due to limit violations
- Add SkipReasonDailyLimit and SkipReasonCooldown skip reason constants
- Add ScheduledRecapId field to Recap struct for tracking scheduled recaps
- Add SkipReason field to Recap struct for tracking why recap was skipped
- Update Auditable() method to include new fields
- Update recapColumns and recapToMap to include new fields
* feat(07-01): add store interface methods for limit enforcement
- Add CountForUserSince to RecapStore for daily limit enforcement
- Add GetLastCompletedManualRecap to RecapStore for cooldown checking
- Add CountForUser to ScheduledRecapStore for max scheduled recaps limit
- Update mock implementations for both stores
* feat(07-01): implement store methods in SQL stores
- Implement CountForUser in SqlScheduledRecapStore
- Counts active (non-deleted, enabled) scheduled recaps for a user
- Implement CountForUserSince in SqlRecapStore
- Counts recaps since timestamp, excluding skipped recaps
- Implement GetLastCompletedManualRecap in SqlRecapStore
- Returns most recent completed manual recap (no ScheduledRecapId)
- Returns nil, nil when no manual recap exists
* feat(07-03): add daily limit check to scheduled recap worker
- Add GetEffectiveLimits and GetUser to AppIface for limit checking
- Check MaxRecapsPerDay before executing scheduled recap
- Create skipped recap record when daily limit exceeded
- Use user's timezone for midnight calculation
- Update next run time even when skipping (scheduler moves on)
* feat(07-03): add cooldown check to manual recap creation
- Check CooldownMinutes before allowing manual recap creation
- Return HTTP 429 with retry-after info when cooldown active
- Only checks against completed manual recaps (per CONTEXT.md)
- Failed recaps don't consume cooldown (checks completed only)
* feat(07-03): add i18n messages for cooldown errors
- Add cooldown_active error with retry info template
- Add cooldown_check_failed error message
- Uses "Your organization's policy limits..." pattern
* feat(07-02): add limit checks to CreateScheduledRecap
- Add max scheduled recaps limit check using CountForUser store method
- Add max channels per recap limit check against ChannelIds length
- Return HTTP 400 with clear error messages when limits exceeded
- Uses GetEffectiveLimits for limit resolution (ENF-01, ENF-02, ENF-08)
* feat(07-02): add i18n error messages for scheduled recap limits
- Add max_scheduled_reached message with "Your organization's policy limits..." pattern
- Add max_channels_exceeded message with limit and requested count
- Add count_failed internal error message
* test(07-04): add unit tests for post/token truncation
- Test proportional post distribution across channels
- Test minimum 1 post per channel guarantee
- Test empty channel handling
- Test token estimation (4 chars/token heuristic)
- Test token limit truncation removes from largest channels
Verifies ENF-05, ENF-06 truncation implementation.
* test(07-05): add ENF-07 permission preservation tests
- Add tests verifying over-limit users can view/edit/delete existing recaps
- Tests confirm management operations do NOT check limits (grandfathering)
- Tests confirm creation IS still blocked when over limit
- Add migration 000151 for missing ScheduledRecapId/SkipReason columns
ENF-07: Limits only block creation, not management of existing resources
* feat(08-01): create UnlimitedNumberSetting component
- Number input with Unlimited checkbox for admin console settings
- When checked: disables input and sets value to -1 (unlimited)
- When unchecked: enables input and sets value to defaultValue
- Supports disabled state and setByEnv footer
* test(08-01): add unit tests for UnlimitedNumberSetting
- Tests rendering with numeric and unlimited values
- Tests checkbox toggle behavior (check/uncheck)
- Tests number input changes
- Tests disabled state and setByEnv footer
- Tests custom unlimited label and placeholder
- 11 test cases covering core functionality
* feat(08-02): add Recaps subsection to admin_definition.tsx
- Import UnlimitedNumberSetting component
- Add 'recaps' subsection under site configuration section
- Include master enable toggle for AI Recap Limits
- Add 3 grouped sections: Quota Limits, Content Limits, Time Limits
- Configure all 7 limit settings with proper config keys
- Add AIRecapSettings and RecapLimitSettings TypeScript types
- All settings disabled when master toggle is off
* feat(08-02): add i18n strings for Recaps admin section
- Add admin.sidebar.recaps for navigation
- Add admin.site.recaps for section title
- Add admin.recaps.enable.* for master toggle
- Add admin.recaps.sections.* for section descriptions
- Add admin.recaps.max*.* for all limit field labels/descriptions
- Add admin.recaps.cooldownMinutes.* for time limit settings
- Add admin.recaps.unlimited for checkbox label
- Total: 24 new i18n strings
* style(08-02): remove section comments to fix lint errors
Remove inline comments that triggered lines-around-comment lint rule
* feat(09-01): add RecapLimitStatus model and App layer logic
- Add RecapLimitStatus, DailyUsageStatus, CooldownStatus structs
- Implement App.GetRecapLimitStatus with daily usage count and cooldown calculation
* feat(09-01): add GET /api/v4/recaps/limit_status endpoint
- Register route and handler
- Return structured limit status
- Add error translation
* feat(09-01): add TypeScript types for limit status
- Export RecapLimitStatus and related types
* feat(09-02): add recap limit status redux integration
- Add Client4.getRecapLimitStatus method
- Add Redux action, reducer, and selector for limit status
- Update GlobalState and initial state to include limitStatus
* fix(09-02): update CreateRecapModal error handling and tests
- Check dispatch result.error instead of try/catch to handle server errors
- Display server error message (e.g. policy limits) inline
- Fix TypeScript errors: displayName property and missing props in tests
* feat(09-03): implement user-facing limit status UI
* Verify Phase 9: User-Facing UX
* Remove UAT artifact
* fix: UI/UX issues (badge, toggle, input, tooltip)
* fix: Increase RecapUsageBadge tooltip z-index
* blank lines
* [MM-67163] checkpoint: scheduled recaps feature working
All phases (01-09) complete and verified:
- Database foundation with DST-aware scheduling
- API layer for CRUD operations
- Job scheduler and worker
- Scheduled tab UI with list/create/edit/delete
- Enhanced wizard with schedule configuration
- Config settings and admin console section
- Limit enforcement (daily, cooldown, token, post)
- User-facing limit status badge
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* [MM-67163] simplify: reduce duplication and fix issues across scheduled recaps
- Extract requireScheduledRecapOwnership helper for 5 API handlers
- Consolidate ResumeScheduledRecap from 4 store calls to 2
- Remove redundant Get() in PauseScheduledRecap
- Extract advanceSchedule helper in worker to deduplicate skip/success paths
- Remove double PreSave() in store Save method
- Remove dead code fallback in GetEffectiveLimits
- Deduplicate ScheduledRecapInput construction in create modal
- Fix missing fetchRecapLimitStatus import (TS error)
- Extract day-of-week bitmask constants to @mattermost/types/recaps
- Fix hardcoded English strings in schedule_display formatNextRun
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address CodeRabbit review feedback on scheduled recaps
Server fixes:
- Gate getRecapLimitStatus with requireRecapsEnabled guard
- Normalize error mapping (404 vs 500) in scheduled recap handlers
- Enforce MaxChannelsPerRecap limit in UpdateScheduledRecap
- Return explicit error for unsupported all_unreads mode in scheduled recaps
- Add compensation logic to clean up orphan recaps on job creation failure
- Fix proportional post truncation to strictly enforce maxPosts cap
- Add missing CountForUser retry wrapper in RetryLayerScheduledRecapStore
- Handle NULL ScheduledRecapId in manual recap cooldown lookup
- Exclude soft-deleted rows in scheduled recap Get query
Frontend fixes:
- Pass isCreationBlocked to ScheduledRecapsList empty state
- Fix same-day nextRunAt mislabeled as "Tomorrow" in schedule display
- Handle thunk error results in scheduled recap item actions
- Replace scheduled recaps map on full refresh instead of merging
Made-with: Cursor
* Handle thunk error results in scheduled recap toggle handler
Check dispatch result for errors in handleToggle to prevent
false-success UI flows when pause/resume operations fail.
Made-with: Cursor
* Fix CI failures: mock store, permissions, migrations, lint, and Playwright config
- Add ScheduledRecap() to storetest.Store mock and retrylayer test setup
- Register sysconsole_read_ai_recaps / sysconsole_write_ai_recaps permissions
- Renumber scheduled_recaps migration from 150→156 and recap_skip_fields from 151→157 to resolve version conflicts
- Fix ESLint errors in recap components (operator-linebreak, import order, labels, headers, etc.)
- Add AIRecapSettings to Playwright default_config.ts
Made-with: Cursor
* Address CodeRabbit Round 2 review feedback
- Add OpenAPI spec for GET /api/v4/recaps/limit_status with schema
definitions for RecapLimitStatus, EffectiveRecapLimits,
DailyUsageStatus, and CooldownStatus
- Set ScheduledRecapId when creating recaps from schedules to prevent
cooldown logic from treating scheduled recaps as manual
- Handle past nextRunAt timestamps in schedule display: show "Yesterday"
for -1 day and full date for older past dates
Made-with: Cursor
* Add missing variable declarations for AI recaps permissions
Made-with: Cursor
* Fix jsx-max-props-per-line lint errors in schedule_configuration.tsx
Made-with: Cursor
* Fix stylelint property order in recap SCSS files
Made-with: Cursor
* Update admin sidebar snapshots to include Recaps section
Made-with: Cursor
* Fix Go lint issues and add OpenAPI specs for scheduled_recap endpoints
- Use max/min builtins instead of if-statements (modernize/minmax)
- Use range-over-int syntax for for-loops (modernize/rangeint)
- Fix tautological Monday&Monday test (staticcheck/SA4000)
- Add OpenAPI specs for all 7 scheduled_recap API routes
- Add ScheduledRecap model definition to definitions.yaml
Made-with: Cursor
* Regenerate i18n en.json for recap-related strings
Made-with: Cursor
* Fix gofmt indentation in recap.go
Made-with: Cursor
* Fix scheduled recap CI regressions
Align the scheduled recap soft-delete store test with the current Get behavior and add the missing scheduled recap i18n strings so server and enterprise checks stay in sync.
Made-with: Cursor
* Address CodeRabbit review feedback on scheduled recaps
- Use session user ID instead of client-controlled recap.UserId for
limit enforcement in UpdateScheduledRecap (security hardening)
- Add missing i18n entry for app.recap.fetch_posts.app_error
- All other review comments were already addressed in prior commits
Made-with: Cursor
* Fix schedule configuration import order
Reorder the moment import so the webapp lint job passes again on the scheduled recap PR.
Made-with: Cursor
* Allow selecting "all unreads" recap type when no current unreads exist
With scheduled recaps, users should be able to select "all unreads" even
without current unread channels since unreads will exist when the schedule
runs. The "run once" toggle is now disabled when all unreads is selected
with no current unreads, preserving the pre-scheduling behavior of
preventing an immediate recap with nothing to summarize.
Made-with: Cursor
* Fix indentation in recap_configuration.tsx to satisfy eslint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix Recaps test mocks for scheduled recap state.
Keep the webapp test shard green by mirroring the new selectors and mount-time actions used by the Recaps page.
Made-with: Cursor
* Update server/channels/app/recap.go
* Update server/channels/app/recap.go
* Update server/channels/app/recap_limits.go
* Update server/channels/app/recap_limits.go
* Update server/channels/app/scheduled_recap.go
* Update server/channels/app/scheduled_recap.go
* Update webapp/channels/src/components/recaps/scheduled_recaps_empty_state.tsx
* Update server/channels/app/scheduled_recap.go
* Fix gofmt formatting in recap limits
Made-with: Cursor
* Fix recap limits for soft-deleted recaps
Keep deleted recaps in quota and cooldown checks so soft deletion cannot bypass AI usage enforcement.
Made-with: Cursor
* Fix translation
* Fix server check-style: concurrent indexes and lint cleanups
- Use CREATE/DROP INDEX CONCURRENTLY in 000168 scheduled recaps migrations
(required by mattermost-govet concurrentIndex check).
- gofmt validation constants in scheduled_recap.go.
- Replace string += loops in recap tests with strings.Repeat for modernize linter.
Made-with: Cursor
* Fix 000168 migration: run CONCURRENTLY indexes outside transaction
PostgreSQL rejects CREATE/DROP INDEX CONCURRENTLY inside a transaction.
Morph requires -- morph:nontransactional for these migrations, matching
other index migrations in the repo.
Made-with: Cursor
* Stabilize scheduled Recaps for review
Bring the scheduled Recaps work back into a shippable state by tightening backend scheduling and limit semantics, cleaning up the UI flows, and adding focused Recaps E2E coverage.
Made-with: Cursor
* Fix scheduled recaps lint failures
Made-with: Cursor
* Fix scheduled recap Go lint
Made-with: Cursor
* Fix scheduled recaps Playwright check
Made-with: Cursor
* Sync scheduled recaps i18n catalog
Made-with: Cursor
* Fix server recaps CI checks
Made-with: Cursor
* Stabilize recap server CI setup
Made-with: Cursor
* Recaps: enforce token limit, remove dead truncation code, simplify scheduled worker
- Delete unused multi-channel truncation subsystem (FetchAndTruncatePostsForRecap, truncatePostsProportionally)
- Enforce MaxTokensPerRecap in the live recap path (previously a silent no-op)
- Drop redundant non-atomic daily-limit pre-check in the scheduled worker; rely on the atomic check in CreateRecapFromSchedule
- Disable non-recurring schedules on all terminal paths (including daily-limit skips) via finalizeSchedule
- Trim scheduled-recap job payload to scheduled_recap_id
- Exclude skipped recaps from GetRecapsForUser
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps webapp: format schedule times in the schedule timezone, static day i18n, typed schedule fields
- Display next-run and schedule times using the scheduled recap's timezone (shared schedule_time_format helper) instead of browser-local time
- Replace dynamic day-of-week i18n message IDs with static descriptors so strings are extractable/translatable
- Add ScheduledRecapTimePeriod/ScheduledRecapChannelMode union types
- Use shared Button in the scheduled recaps empty state
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps e2e: cover scheduled edit/delete/all-unreads/empty-state and token-limit enforcement
- Add UI coverage for editing, deleting, and the empty state of scheduled recaps
- Add all-unreads scheduled recap modal flow
- Add immediate-recap token-limit enforcement tests (single and per-channel), validating MaxTokensPerRecap truncation end-to-end
- Extend recaps page object and helpers
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: regenerate store layers/mocks and i18n after cleanup; fix lint
- Regenerate timerlayer/retrylayer/RecapStore mock to canonical order
- Drop orphaned app.recap.fetch_posts.app_error i18n key (removed with dead fetch helper)
- Add missing semicolon in UnlimitedNumberSetting props
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: regenerate default roles permissions and admin sidebar snapshot
- Regenerate Cypress default_roles_permissions fixture to include AI Recaps sysconsole permissions
- Update admin sidebar snapshot for the new Recaps section
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: stabilize flaky cooldown round-up test
The cooldown round-up subtest placed the prior recap 30s before a 2-minute
cooldown, leaving only ~30s of slack before the rounded remaining time would
flip from 2 to 1 minute. Under heavily loaded CI this could intermittently fail
the exact-minute assertion. Move the prior recap to 1s ago so the remaining time
sits near the top of the 2-minute band (~59s slack) while still exercising
ceiling rounding.
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: store ScheduledRecap.ChannelIds as jsonb
Postgres is the only supported database, so the prior TEXT+JSON-string
workaround for MySQL compatibility is unnecessary. Store ChannelIds in a
jsonb column and type the model field as model.StringArray, which removes the
bespoke marshal/unmarshal and intermediate scan struct in the store.
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: gate recap limit settings on the ai_recaps permission
Add access:"ai_recaps" to DefaultLimits and all RecapLimitSettings fields so a
delegated admin with sysconsole_write_ai_recaps can save the limit values,
instead of falling back to requiring manage_system.
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: drop bespoke Users row lock for limit enforcement
The recap limit savers were the only SELECT ... FOR UPDATE in the sqlstore.
Conform to the prevailing pattern (e.g. channel_bookmark_store.Save): enforce
MaxScheduledRecaps / MaxRecapsPerDay with a transactional count + insert and no
row lock, accepting the same best-effort behavior under concurrency as channels,
team members, and bookmarks.
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: document SaveOnceByTypeAndData dedup semantics
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: use SERIALIZABLE isolation for limit-check inserts
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: mark orphaned recap skipped when job enqueue fails
When CreateJob fails after the recap row is committed, flag the recap
skipped with reason job_creation_failed instead of leaving it pending.
Skipped recaps are excluded from the daily-limit count, so this frees
the quota slot for a recap that will never run, and keeps CreateRecap
consistent with CreateRecapFromSchedule.
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* ci: retrigger CI (flaky enterprise npm cache EEXIST)
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* ci: retrigger CI (flaky Vet API container init)
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* Recaps: re-check channel read permission at recap execution time
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* fix scheduled recap job server test setup
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* ci: retry flaky webapp test
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* ci: retry documentation impact review
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* MM-67163: Address review feedback: remove unused userID param, return AppError from GetRecapLimitStatus
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* MM-67163: Bulk channel permission check for recap creation, bounded by channel limit
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* chore: rerun CI
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
* chore: rerun CI after network failure
Co-authored-by: nick.misasi <nick.misasi@mattermost.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
|
||
|
|
518b6b2c39 |
Updated minimum supported Edge and Chrome versions (#37589)
Automatic Merge |
||
|
|
f84dd25754 |
Prepackage mattermost-plugin-agents v2.5.0-rc1. (#37582)
Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
9e51e325f5 |
Add --active flag to mmctl user list (#37560)
Mirror the existing --inactive filter so admins can list only active users. Reject using --active and --inactive together, and update unit, e2e, and docs coverage. Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Sven Hüster <svelle@users.noreply.github.com> |
||
|
|
28113e5a7a | Bumping prepackaged mscalendar version to v1.7.0 (#37575) | ||
|
|
2851af059d |
Add admin-locked profile fields for email users and pre-provisioned names on invites (#37458)
* Add TeamSettings.LockProfileFieldsForEmailUsers with server-side enforcement Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Add API tests for LockProfileFieldsForEmailUsers enforcement Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Hide admin-locked profile fields in user settings and add System Console dropdown Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Support pre-set username and name on team email invites Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Add tests for invite profiles; fix resend worker channel-list parsing Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Add pre-set profile inputs to member invite modal Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Prefill and lock pre-set username on signup page Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Add first/last name editing to System Console user detail and document new setting Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Fix lint issues in invite modal profile inputs Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Fix double outline on invite modal profile inputs inside GenericModal Co-authored-by: Nick Misasi <nick13misasi@gmail.com> * Refactor invite emails to InviteEmailData struct and harden invite profile validation Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Centralize profile-lock permission exemption in app layer and add config coverage Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Per-field name locking in profile settings, typed lock setting, and shared invite profile helpers Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Add Playwright E2E coverage for locked profile fields and pre-set invite profiles Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Sync playwright package-lock with merged workspace versions Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Restore upstream playwright package-lock (fix npm ci drift) Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Assert invite input cleared instead of chip text after adding email Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Fix invite modal scroll, username error layout, and clipped autocomplete Keep the footer pinned while tall profile rows scroll, show username validation full-width after blur, and portal select menus so they are not clipped by the scroll container. Co-authored-by: Cursor <cursoragent@cursor.com> * fixes for autocomplete items not aligning properly * Make invite autocomplete menu portal opt-in and fix modal chrome Confine document.body menu portaling to the invite modal via a menuPortal prop, and restore click-away, slide-in animation, and header alignment for the scrolling invite modal layout. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix eslint lines-around-comment on menuPortal props Co-authored-by: Cursor <cursoragent@cursor.com> * Fix stylelint property order in invitation modal SCSS. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix stylelint property order in invitation_modal.scss Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Adapt invite modal E2E to portaled autocomplete menus Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Simplify locked profile invite implementation Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Fix invite modal review and E2E feedback Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Retry flaky enterprise CI Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Retry Docker image export CI Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Minimize locked profile fields diff Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Fix locked profile E2E documentation Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Address minimized test review feedback Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Fix email test whitespace Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Retry OpenSearch download CI Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Retry flaky Cypress thread navigation Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Preserve legacy invite behavior without profiles Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Clarify invite profile validation Co-authored-by: nick.misasi <nick.misasi@mattermost.com> * Retry flaky enterprise E2E Co-authored-by: nick.misasi <nick.misasi@mattermost.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Matthew Birtch <2040554+matthewbirtch@users.noreply.github.com> |
||
|
|
d6d2c50189 |
Clear session cache on OAuth token refresh (#37459)
newSessionUpdateToken removed the old session row from the DB but did not clear the in-memory session cache. Because GetSession returns the cached entry without querying the DB, the rotated (old) access token remained valid for up to SessionCacheInMinutes (default 10 min) after rotation. Add a ClearSessionCacheForUser call after the DB removal, matching what RevokeAccessToken already does, so the old token is rejected immediately. Add a regression test that verifies the old token hits the cache before refresh and is rejected right after rotation. |
||
|
|
3a820143a1 |
MM 69100 - Team ABAC Membership - members sync and end user surfaces (#37054)
* MM-69063 - Add team ABAC model and constants foundation * Add team ABAC store EXISTS, channel Type retrofit, policy count split, and index migration * Add team ABAC app layer: access gate, hydrators, assign/unassign, cleanup, and GetTeamMembersToRemove store * Enforce team membership ABAC on join and hide policy governed teams from non-qualifying users in the directory * Add team_ids to access policy assign/unassign, expose per-team policy GET, and support abac_match_only for not_in_team user listing * Add team ABAC client methods, websocket handler, per-team System Console policy UI, and hide policy-governed teams from non-qualifying users * Make team ABAC mode-aware: advisory on public teams, strict on private, and surface governed private teams to qualifying users in directory listings * Flag-gate team ABAC mutation/read APIs and fix policy-save error handling, member-removal limit, team-id validation, export, and audit cleanup * coderabbit feedback; Broadcast team policy enforcement updates on policy create/update and activation, not only on delete * Update team access control policy schema to allow nullable policies and enhance test cases with channel counts * Enhance access control policy tests to include team policy search alongside channel policy search * Add team membership access control feature flag to docker-compose generation * Implement team access control policy checks and refactor related components * MM-69100 - add team membership ABAC sync worker with mode-aware removal and auto-add * Add team ABAC removal/auto-add notifications, cascade audit, and team custom-rules save backend * Add Team Settings team membership tab with custom-rules editor, auto-add toggle, save confirmation, and mode-flip sync trigger * Add team access control policy panels, job details team list, and e2e coverage for membership tab and discoverability cards * ix save double-submit with loading state, team privacy via updateTeamPrivacy, mode-flip count accuracy, sync trigger logic, i18n keys, and e2e test cleanup * Add team membership policy notices to invite and add-to-team flows, team access control system messages, and a team policy attributes endpoint * Add team membership recommended tag for qualifying users and team requirements notice in the members modal * temp * adjust styling, add new e2e, fix team admin job permissions issues * e2e clean items created * fix directory and team integration e2e tests * Surface team sync results in the Sync Job Details modal via a Teams tab linked from the chained channel job * code clean up, adjust styling * Add access control attributes endpoint and enhance E2E tests for team membership * Enhance team access control by updating permission checks and syncing jobs * Add API-level enforcement gate tests for ABAC team membership * Fix formatting in team channel settings component by adding missing semicolon * Fix formatting in Client4 class by adjusting type annotations for clarity * revert unwanted changes in package-lock * Refactor job permission test and simplify error handling in team details component * Update test assertions and enhance auto-add functionality in team membership tab * Update onboarding tests to use 'Public Team' card for team access settings * Refactor AccessSettings and TeamPolicyEditor components to replace allowOpenInviteCheckbox with public and private team buttons, and update access control job dispatching logic. * Remove redundant state updates for channel assignments in access control policy reducer * Implement email suppression for team membership notifications and add related tests * Authorize ABAC team self-join by attribute match instead of the join_private_teams role * comments clean up * Gate team privacy type normalization behind active ABAC, keep legacy allow_open_invite-only path otherwise * adjust job details styles * Add team membership policy disconnect confirmation, fix linked-policy affected-member count, and polish job details modal * Combine custom rules with system policy expressions for accurate confirm counts * Implement child resource count stamping and deletion gating for access control policies * Enhance team sync job triggering logic for membership changes without auto-add * Refactor team privacy handling to align with open-directory model; update comments for clarity on allow_open_invite logic. * Deduplicate team ABAC sync jobs per policy to prevent concurrent runs emitting duplicate DMs and audit records on HA clusters * fix linter warnings * Add confirmation for policy removal in TeamDetails tests * Update delete policy message to include Teams in the warning * Add linked teams warning to policy deletion and update translations * Add Auto-add feature for policy selection and team management - Enhanced PolicySelectionModal to include an Auto-add checkbox for each policy. - Updated PolicyList to manage Auto-add state and reflect changes in the UI. - Modified TeamAccessControl to handle Auto-add functionality and persist changes. - Added tests to ensure Auto-add behavior works as expected in various scenarios. - Updated translations for Auto-add related strings. * Add team membership sync footer and enhance job fetching with policy ID * Refactor team membership policy handling and sync footer implementation * Add team sync channel cascade test for private channel membership --------- Co-authored-by: Mattermost Build <build@mattermost.com> |
||
|
|
3b64a2ac84 | Property owners for property fields and values, new audit logs for cpa value changes and new pluginapis (#37299) | ||
|
|
5f7f967a7d | MM-69268 - Add ChannelTypeSpace backing-channel type for Docs (#37321) | ||
|
|
57fe965ac7 |
Session Attributes: System Console management page and permission-policy picker integration (#37362)
* Add Session Attributes system console page shell Register the gated System Console "Session Attributes" subsection backed by a component page that loads the session_attributes property fields, plus a feature discovery upsell. Removes the former config toggles from the UI. Includes display helpers and unit tests. Co-authored-by: Cursor <cursoragent@cursor.com> * Add Session Attributes listing table Render the read-only session attributes table with Display Name, Name (with server-sourced label), derived Type, platform availability icons, TTL, grace period, and status columns, plus loading and empty states. Includes status chip, platform icon, and table unit tests. Co-authored-by: Cursor <cursoragent@cursor.com> * Add Session Attributes row actions and staged save Add a per-row actions menu to tune TTL and grace period via presets and to disable/enable each attribute, with a destructive disable confirmation modal. Edits stage locally and persist on save via a per-field property patch thunk, with an unsaved-changes guard. Includes the patch thunk and component tests. Co-authored-by: Cursor <cursoragent@cursor.com> * Surface session attributes in permission policy editors only Include session attributes in the permission policy attribute picker (both advanced and table editor modes) and group them under a dedicated section, while excluding them from membership and parent access-rule editors via a shared helper. Surface the server rejection message when a membership rule references session attributes. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix lint formatting in session attributes table test Split single-line renderWithContext JSX in session_attributes_table.test.tsx onto multiple lines to satisfy react/jsx-max-props-per-line, matching the existing test formatting convention. Surfaced by the pre-commit ESLint gate. Co-authored-by: Cursor <cursoragent@cursor.com> * Add Session Attributes E2E specs Add Playwright end-to-end coverage for the Session Attributes console page: listing render, staged TTL/grace/enable edits with save persistence, disable confirmation modal, dirty navigation guard with cancel revert, and permission-versus-membership picker polarity. Includes the page object and sidebar wiring. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix playwright-lib build to resolve @/* tsconfig path alias The lib rollup build (@rollup/plugin-typescript) compiled the @/* tsconfig path alias but never rewrote it, so with preserveModules the emitted dist files still imported the unresolved @/ specifier. Node could not load these, failing Playwright config loading for the entire suite (Cannot find module @/ui/components). Add a minimal inline rollup resolveId plugin that maps @/* to the real src file so emitted dist uses correct relative imports. No new dependency required. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix session attribute group identity to use real group id The webapp conflated the property group NAME (session_attributes) with the group's real DB id. The server keys every field under a 26-char group UUID, so the listing page selected fields under the name and always rendered "No session attributes found." on a real server, and the ABAC editors compared field.group_id against the name, which never matched live data. Resolve the group properly instead: - fetchPropertyFields now also dispatches RECEIVED_PROPERTY_GROUP (mirroring the managed-channel-categories flow) so the group name -> id mapping is available, and the listing page selects fields by the resolved group id via getPropertyGroupByName. - Add isSessionAttributeField, keyed on the session object_type, and use it in the ABAC consumers (attribute picker, excludeSessionAttributes, permission policy picker, simulate-access modal). object_type is intrinsic to the autocomplete fields and avoids the name/UUID conflation entirely. - Relax UserPropertyField.group_id to string since the server returns a UUID; the group name is only ever a client-side placeholder for an unsaved field. Harden the unit tests to use realistic group UUIDs distinct from the group name and correct object_type values, so fixtures can no longer pass with a group_id the server never produces. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix SaveChangesPanel footer Cancel to revert in place The admin SaveChangesPanel rendered its onCancel handler through a BlockableButton, which intercepts clicks while navigation is blocked and defers the action via deferNavigation instead of invoking it. On the Session Attributes page this meant footer Cancel never reverted staged edits directly: it re-opened the Discard Changes guard and only reverted if a deferred navigation was later confirmed. BlockableButton is only appropriate for the cancelLink (navigation) path. For an in-place revert handler, wire onCancel to a plain button so it calls the hook cancel() directly, reverting staged edits, clearing the dirty state, releasing setNavigationBlocked, and never showing the discard modal. Repair the page-level jest test to exercise the real footer Cancel and assert direct revert plus nav-guard release without confirming a deferred navigation. Co-authored-by: Cursor <cursoragent@cursor.com> * Merge enabled session attributes into permission policy editors Inject enabled session attributes into the two permission-policy attribute pickers (CEL and table editors) while keeping membership/parent-policy surfaces restricted to long-lived user attributes via excludeSessionAttributes. Adds a useEnabledSessionAttributeFields hook plus the shared mergeSessionAttributes/celPrefixForField helpers so the editors can build CEL across the user.attributes.* and user.session.* namespaces. Addresses two review nits: - Resolve the picked attribute by its unique field id (not bare name) so a session attribute sharing a name with a CPA attribute still maps to object_type 'session' and emits user.session.<name>; the picker also uses id-based DOM ids to avoid collisions. - Make celPrefixForField the single source of CEL-prefix truth by consuming it in rowToCEL instead of inlining the namespace check. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix Session Attributes E2E spec: id-based picker selectors and per-test state isolation The attribute picker menu items are keyed by field id (#attribute-<id>) rather than name, so the permission/membership picker assertions now resolve session attribute ids from the property-fields API and the Department user-attribute id from the CPA fields API instead of targeting stale name-based ids. Add an afterEach that restores every seeded session attribute to a baseline captured at suite start, replacing the per-test finally restores. This keeps the suite order-independent so the listing test "Disabled by default" assertions no longer depend on whether another test has enabled a field first. Co-authored-by: Cursor <cursoragent@cursor.com> * UX Polish * Linting * Removed styled components * Fix session attributes unit tests Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Fix invalid Sass '&&&' selector breaking production build Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Stabilize session attributes duration-preset e2e interaction Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Fix broken session attributes doc link in feature discovery Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Fix session attributes test type error from non-union group id Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Revert unnecessary playwright-lib rollup @/* alias resolver @rollup/plugin-typescript already resolves the @/* tsconfig path alias; building with and without the added resolveSrcAlias plugin produces byte-identical dist JS, so the change was a no-op. Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Allow session-attribute row defaults and resolve table-editor lookups by namespace findFirstAvailableAttributeFromList now treats session attributes as selectable (mirroring AttributeSelectorMenu), so a session-only attribute set no longer fails addRow. The operator menu reads row.attribute_type and the value options match on name + object_type, so a user/session name collision resolves the correct namespace. Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Type session-attribute platforms on the shared property attrs Add platforms?: string[] to UserPropertyField.attrs so the attribute picker reads it without an unsafe cast, and narrow the platform filter in getSessionAttrs with a type guard. Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Session Attributes page: surface load errors, propagate read-only, and improve a11y Handle a failed property-fields fetch with an explicit error state instead of leaving the rejection uncaught and showing the empty state. Thread the page's disabled flag through to the row dot menus so read-only admins cannot stage edits. Convey each platform icon's active/inactive state in its accessible name, and document the table border override. Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * SaveChangesPanel: use shared Button for the in-place cancel control Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Cover fetchPropertyFields group name to uuid mapping Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * E2E: scope session-attribute submenu trigger to its row and document single-field save Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Comment linting * scss cleanup * linting * PR feedback * PR Feedback. Removed IP + version icons * PR feedback * PR feedback * Fix session attributes table test after IP/Version display types were removed Co-authored-by: maria.nunez <maria.nunez@mattermost.com> * Session Attributes admin console UX fixes - Reduce table row height and shrink-wrap the panel to the table - Reorder LHS sidebar so Session Attributes follows User Attributes - Cap attribute selector popover at 400px max-height with scroll Co-authored-by: Cursor <cursoragent@cursor.com> * Fix native attribute selection by assigning synthetic field IDs The ABAC editors resolve the selected attribute by field ID, but the synthetic native user attribute fields were created without an ID. Every built-in attribute therefore resolved to the first empty-ID field (Email), so no other built-in could be selected. Assign each native field a stable, unique, non-empty ID so id-based resolution works for all built-ins. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
86888cbac6 |
[MM-69007] Speed up Support Packet tests by shortening the CPU profile sample (#36761)
* [MM-69007] Add CPU profile duration option to support packet API Support packet generation always blocks on a 5s CPU profile sample. Add cpu_profile_duration_seconds to GET /api/v4/system/support_packet so callers can shorten or skip it; nil keeps the 5s default, 0 skips CPU profile generation, positive values override the duration. Validated as an integer in [0, 300]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Add test for zero CPU profile duration skipping cpu.prof Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Add API-level validation tests for cpu_profile_duration_seconds Cover negative, above-max, non-integer, and clearly out-of-range values. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Document cpu_profile_duration_seconds query parameter Adds the new optional query parameter to the support_packet endpoint in the API reference spec so the generated docs match the handler behavior added in this PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * MM-69007: Drop HTTP API surface, keep test-only CPU profile speedup Rescope this PR to not expose CPU profile duration control via the GET /api/v4/system/support_packet endpoint: - Remove the cpu_profile_duration_seconds query parameter, its validation, and audit metadata from api4/system.go - Remove the corresponding api4 validation test - Remove the OpenAPI documentation for the query parameter model.SupportPacketOptions.CPUProfileDurationSeconds and the platform.GenerateSupportPacket/getCPUProfile plumbing remain, since they're what let the platform/app support-packet tests pass a short duration (1s, or 100ms for TestGetCPUProfile) instead of waiting on the real 5s default. Clarify the field's doc comment to reflect that it's for programmatic/test callers only, not the HTTP API. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * MM-69007: Cut CPU profile test duration from 1s to 100ms Change model.SupportPacketOptions.CPUProfileDuration from *int (whole seconds, so the minimum non-zero value was 1s) to *time.Duration, so test callers can pass a sub-second duration. Update all GenerateSupportPacket test call sites to use a shared 100ms duration instead of 1s, and extract it into a package-level shortCPUProfileDuration var in each test file to avoid repeating the literal. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * MM-69007: Remove unused SupportPacketOptions JSON plumbing Neither SupportPacketOptionsFromReader nor the json tags on IncludeLogs/PluginPackets are used anywhere in this repo - api4/system.go builds SupportPacketOptions directly from request form values, never from JSON. Drop the unused JSON tags, decode helper, and now-unused encoding/json and io imports. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
1388ba477c | Update Playbooks plugin to v2.11.0 (incl. FIPS) (#37528) | ||
|
|
8d10e91d38 | MM-69798: Add AccessControlSettings setting to disable channel access indicators (#37519) | ||
|
|
b9179642f3 | update Calls to v1.12.2 (#37502) | ||
|
|
7778bb79d1 |
MM-69792: Recover shared channel sync after a brief remote outage (#37499)
* MM-69792: Recover shared channel sync after a brief remote outage When a remote went offline for less than the 5-minute IsOnline() threshold, sync recovery never ran. IsOnline() never flipped, so no connection-state-change event fired and ForceSyncForRemote was never triggered. Posts created during the outage stayed unsynced until the next organic change in the channel. The root cause was that send failures are reported asynchronously through a callback that sendSyncMsgToRemote discarded. On a failed send syncForRemote still returned nil, so processTask saw success: the retry loop and the failure-notification hook were effectively dead code for delivery failures. Changes: - sendSyncMsgToRemote now propagates the delivery error reported via the callback instead of swallowing it. A failed send is retried rather than silently dropped. This applies to every sync type (posts, users, memberships, reactions, statuses); the success path is unchanged. - remotecluster tracks a per-remote "sync failed since last ping" flag (NotifySyncFailed). On the next successful ping, PingNow fires a connection-state-change event even when IsOnline() never flipped, driving a single ForceSyncForRemote on recovery. - Sync retries are now spaced by SyncRetryDelay (15s) instead of retrying immediately, giving a short outage time to recover and guaranteeing a failed ping before retries exhaust. Also adds a post/offline-recovery case to the sharedchannel-test integration tool (stop and restart Server B mid-run) and disables metrics on the two test servers so they do not collide on the metrics port when the loaded config has metrics enabled. * fix linter error * Fix Rabbit nit * fix CI * Delete pr37499-fix-findings-1-and-4.md * address review comments * MM-69792: Keep a per-remote retry task when a shared channel sync fans out A sync task with no specific remote (remoteID == "") fans out to every remote sharing the channel. On failure each remote's retry was a copy of the original task that still carried the original, remote-less task id. Because addTask merges on task id, all of those per-remote retries collapsed into a single entry, so only one failed remote was ever retried and the rest were silently dropped. Delivery failures were partly masked by the ping-driven ForceSyncForRemote recovery, but non-delivery errors for the other remotes had no path back. Give each per-remote retry a remote-specific id (task.id + remoteId) when the originating task had no remote, so every failed remote keeps its own retry task. Single-remote tasks already have a remote-specific id and are left untouched, since recomputing would grow the id on each retry. Also harden the tests: assert the retry is scheduled the full SyncRetryDelay out (no tolerance), assert the result callback is not invoked on delivery failures or unconfirmed responses (so the cursor stays un-advanced), and add a regression test covering fan-out to multiple failing remotes. * fix one more pre-existing edge case. * fix linter |
||
|
|
901b4256bd | Fix assorted down migrations, add additional testing (#37464) | ||
|
|
d3ebd0ff65 |
MM-69751 Replace concurrent React user setting with feature flag and add to root.html (#37422)
* MM-69751 Replace concurrent React user setting with feature flag and add to root.html * Address Coderabbit feedback |
||
|
|
b959e88bf6 | [MM-69721] Fix empty text/plain part in transactional emails (#37383) |