Skip to content

Mattermost: refresh slash callback command validation#72923

Merged
drobison00 merged 17 commits intoopenclaw:mainfrom
eleqtrizit:mattermost-slash-token-refresh
May 1, 2026
Merged

Mattermost: refresh slash callback command validation#72923
drobison00 merged 17 commits intoopenclaw:mainfrom
eleqtrizit:mattermost-slash-token-refresh

Conversation

@eleqtrizit
Copy link
Copy Markdown
Contributor

Summary

  • Refreshes Mattermost native slash callback validation against the current command registration.
  • Keeps callbacks fail-closed when the current command cannot be confirmed.

Changes

  • Stores the callback URL with registered Mattermost slash commands.
  • Checks the current command id, team, trigger, method, URL, and token before processing callbacks.
  • Adds regression coverage for rotated, deleted, drifted, and fallback command lookup paths.

Validation

  • Ran pnpm test extensions/mattermost/src/mattermost/slash-http.test.ts extensions/mattermost/src/mattermost/slash-http.send-config.test.ts extensions/mattermost/src/mattermost/slash-state.test.ts extensions/mattermost/src/mattermost/slash-commands.test.ts.
  • Ran pnpm check:changed -- --base upstream/main.
  • Ran local agentic review with claude -p "/review local" and addressed the actionable feedback.

Notes

  • Callback validation now depends on the Mattermost API being reachable and fails closed when the current command cannot be confirmed.

@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 27, 2026

🔒 Aisle Security Analysis

We found 2 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium DoS risk: per-command token validation forces upstream lookup on every callback and rate-limits to 2/s sustained
2 🟡 Medium Incomplete secret redaction in Mattermost slash-command error logging (URL credentials/query tokens may leak)
1. 🟡 DoS risk: per-command token validation forces upstream lookup on every callback and rate-limits to 2/s sustained
Property Value
Severity Medium
CWE CWE-400
Location extensions/mattermost/src/mattermost/slash-http.ts:69-388

Description

The Mattermost slash callback handler now calls validateMattermostSlashCommandToken() on every accepted callback (after matching the startup token) and does not cache successful validations.

As implemented:

  • Each callback triggers an upstream Mattermost API lookup (GET /commands/{id} with fallback GET /commands?team_id=...) to confirm the command definition and token.
  • Successful validations are not cached, so normal traffic continuously consumes the lookup budget.
  • A per-command token-bucket limiter (COMMAND_VALIDATION_LOOKUP_BURST=20, COMMAND_VALIDATION_LOOKUP_REFILL_MS=500) denies further validations once exhausted, returning false which results in a 401 for otherwise-valid callbacks.

Impact:

  • If an attacker obtains a valid slash command token (via logs, misconfig, insider access, etc.), they can spam callbacks to exhaust the per-command lookup bucket and cause legitimate invocations of that command to be rejected (availability/DoS).
  • Even without an attacker, legitimate bursts (deploys, retries, users concurrently invoking the command) can exceed 20 calls and then be throttled to ~2 validations/sec.

Vulnerable code (rate-limit + always-lookup behavior):

const COMMAND_VALIDATION_LOOKUP_BURST = 20;
const COMMAND_VALIDATION_LOOKUP_REFILL_MS = 500;
...
if (!commandLookupInflight.has(lookupKey)) {
  const reservation = reserveCommandValidationLookup({ key: lookupKey, accountId: params.accountId });
  if (!reservation.allowed) {
    return false;
  }
}
const current = await fetchCurrentMattermostCommand(...);
...
return true;

and the handler rejects on false:

const tokenIsCurrent = await validateMattermostSlashCommandToken(...);
if (!tokenIsCurrent) {
  sendJsonResponse(res, 401, ...);
  return;
}

Recommendation

Cache successful validations for a short TTL to avoid performing an upstream lookup on every callback and to make token-bucket exhaustion harder.

For example, add a small success cache keyed by (apiBaseUrl, accountId, teamId, commandId):

const SUCCESS_TTL_MS = 5_000;
const successCache = new Map<string, { expiresAt: number }>();

function hasSuccess(key: string, now = Date.now()): boolean {
  const entry = successCache.get(key);
  if (!entry) return false;
  if (entry.expiresAt > now) return true;
  successCache.delete(key);
  return false;
}// In validateMattermostSlashCommandToken:
if (hasSuccess(lookupKey)) return true;
...
if (/* all checks pass */) {
  successCache.set(lookupKey, { expiresAt: Date.now() + SUCCESS_TTL_MS });
  return true;
}

Additionally:

  • Consider returning 503 (or a distinct error) when rate-limited rather than 401 (which can mislead operators and trigger retries).
  • Consider scoping rate-limits per source IP / per team / per user in addition to per command, or raising burst/refill to accommodate realistic concurrency.
  • Ensure rate limiting does not block legitimate traffic during transient Mattermost API issues (e.g., allow a grace period using last-known-good validations).
2. 🟡 Incomplete secret redaction in Mattermost slash-command error logging (URL credentials/query tokens may leak)
Property Value
Severity Medium
CWE CWE-532
Location extensions/mattermost/src/mattermost/slash-http.ts:128-135

Description

The sanitizeCommandLookupError() helper is used to log errors from Mattermost API calls during slash-command validation/handling, but it only redacts a limited set of secret patterns.

Because it does not redact:

  • URL userinfo credentials (e.g. https://user:pass@​host/...)
  • common OAuth/secret fields in error payloads/messages (e.g. access_token, client_secret, refresh_token, botToken)
  • secrets embedded in query strings (e.g. ?token=... beyond the simple token= key match, or other key names)

…secrets can be written to logs if upstream/network errors include request URLs or JSON error bodies.

This is particularly relevant because the Mattermost client builds full request URLs from configurable baseUrl (which can legally contain credentials) and fetch/network layers commonly include the URL in thrown error messages.

Vulnerable code:

function sanitizeCommandLookupError(error: unknown): string {
  const raw = error instanceof Error ? error.message : String(error);
  return raw
    .replace(/[\r\n\t]/gu, " ")
    .replace(/\b(Bearer|Token)\s+[A-Za-z0-9._~+/=-]+/giu, "$1 [redacted]")
    .replace(/\b(token|authorization)(=|:)\s*[^,\s;]+/giu, "$1$2[redacted]")
    .slice(0, 300);
}

Recommendation

Harden redaction to cover additional common secret-bearing patterns, especially URLs with credentials and query parameters.

Suggested approach:

  1. Parse and redact URLs (userinfo + query params):
function redactUrls(input: string): string {
  return input.replace(/https?:\/\/[^\s)\]}]+/gi, (rawUrl) => {
    try {
      const u = new URL(rawUrl);
      if (u.username || u.password) {
        u.username = "[redacted]";
        u.password = "[redacted]";
      }// Redact common secret params
      for (const k of ["token","access_token","refresh_token","client_secret","authorization"]) {
        if (u.searchParams.has(k)) u.searchParams.set(k, "[redacted]");
      }
      return u.toString();
    } catch {
      return rawUrl;
    }
  });
}
  1. Redact additional key names in k=v and JSON-like text:
const SECRET_KEYS = /(token|access_token|refresh_token|client_secret|botToken|authorization)/i;
output = output.replace(new RegExp(`\\b${SECRET_KEYS.source}\\b\\s*(=|:)\\s*[^,\\s;]+`, "gi"), "$&[redacted]");
  1. Prefer logging structured error metadata (status code, endpoint path without credentials) rather than full raw error messages when possible.

Analyzed PR: #72923 at commit 96a9e65

Last updated on: 2026-04-27T19:09:29Z

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: mattermost Channel integration: mattermost size: M maintainer Maintainer-authored PR labels Apr 27, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR refreshes Mattermost slash command callback validation by adding live Mattermost API verification on every callback, ensuring stale startup tokens from deleted or rotated commands are no longer accepted without a restart. The new validation layer introduces per-command rate limiting, inflight coalescing, a short failure cache, and a multi-account command-ownership fallback for routing when startup tokens have changed.

Confidence Score: 5/5

Safe to merge — no P0 or P1 bugs found; logic is internally consistent and well-tested.

The changes are tightly scoped to the slash command validation path, all edge cases (rotated tokens, deleted commands, fallback team-list lookup, rate limiting, cross-command cache poisoning) have explicit test coverage, and log injection/token leakage mitigations are verified by tests. Module-level cache state is properly cleared on account deactivation.

No files require special attention.

Reviews (5): Last reviewed commit: "fix(mattermost): rate-limit slash valida..." | Re-trigger Greptile

Comment thread extensions/mattermost/src/mattermost/slash-http.ts
Comment thread extensions/mattermost/src/mattermost/slash-http.ts
@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Addressed the command-method drift case in 3daddb2ae0: owned Mattermost slash commands now reconcile back to POST even when the callback URL already matches, with regression coverage.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 749526fbe9 also bounds current-command lookups with a 1s timeout, coalesces concurrent lookups for the same command, and sanitizes/redacts fallback error logs.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 90f472a0f2 adds a 5s success/failure cache for current-command validation results, keeping stale-token acceptance bounded to seconds while preventing accepted or recently rejected callbacks from forcing a Mattermost API lookup on every request. Local targeted Mattermost tests and pnpm check:changed -- --base upstream/main are green after the change.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 229d2d0efa addresses the latest Aisle pass: upstream validation now accepts rotated/regenerated current tokens instead of requiring the startup token set, multi-account routing can fall back to registered team/trigger ownership, validation cache keys include the account id, and slash log fields are sanitized. Local targeted Mattermost tests and pnpm check:changed -- --base upstream/main are green.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 17ca0ed4c2 addresses the latest Aisle DoS finding by adding a generated callback URL secret to native Mattermost slash command registrations and enforcing it locally before any Mattermost API lookup. Local targeted Mattermost tests, pnpm check:changed -- --base upstream/main, and pnpm check:architecture are green.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 5e908fdd38 replaces the URL-secret approach: validation now fails closed on command id mismatch and rate-limits unknown-token validation attempts before upstream Mattermost lookup. Local targeted Mattermost tests, pnpm check:changed -- --base upstream/main, pnpm check:architecture, and git diff --check are green.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 738fb8179a refines the unknown-token guard to a bounded per-command throttle with a short 1s backoff and no remote-address key. Local targeted Mattermost tests, pnpm check:changed -- --base upstream/main, pnpm check:architecture, and git diff --check are green.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up ae86bcf0c4 removes upstream validation for locally unknown tokens, bounds/sweeps the live command lookup cache, and clears per-account lookup cache entries on slash command deactivation. Local targeted Mattermost tests, pnpm check:changed -- --base upstream/main, pnpm check:architecture, and git diff --check are green.

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

1 similar comment
@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up c33f4e4279 addresses the latest Aisle pass:

  • Tightened the per-callback startup gate to compare payload.token against the resolved registered command's startup token (constant-time) instead of any startup token in the account. A token leaked for command A no longer reaches the validator for command B, so the per-command failure cache cannot be poisoned across commands (Aisle finding fix: add @lid format support and allowFrom wildcard handling #1).
  • Replaced the multi-account routing path's manual body buffering loop with the shared readRequestBodyWithLimit helper so a slow/never-finishing client gets a 408 instead of tying up the dispatcher (Aisle finding Login fails with 'WebSocket Error (socket hang up)' ECONNRESET #2).
  • Removed the now-unused commandTokens parameter from createSlashCommandHttpHandler and the obsolete cross-token tests; added regression coverage for the cross-command token rejection.

Local targeted Mattermost tests (4 files, 36 tests) and pnpm check:changed -- --base upstream/main are green.

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

Follow-up 96a9e65cc4 addresses the latest review pass:

  • Added a per-account/per-command token bucket before starting non-inflight upstream Mattermost command validation lookups. This keeps current-command validation fresh without restoring a success cache, while bounding sequential valid-token callback floods before they can drive unbounded Mattermost API traffic.
  • Kept concurrent lookup coalescing and brief failed-validation caching; over-limit callbacks fail closed without caching a successful validation result.
  • Carried the slash routing source through ambiguous multi-account matches so logs now distinguish via token from via command, and command-based conflicts no longer use token-specific wording.
  • Updated Mattermost docs/changelog and added regression coverage for sequential lookup rate limiting plus token-vs-command routing source reporting.

Validation is green locally: targeted Mattermost slash tests passed (4 files, 37 tests), formatting/diff checks passed, and pnpm check:changed -- --base upstream/main passed.

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

@greptile review

@eleqtrizit
Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@drobison00 drobison00 force-pushed the mattermost-slash-token-refresh branch from 96a9e65 to 3eaa427 Compare April 29, 2026 20:28
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 30, 2026

Codex review: needs maintainer review before merge.

What this changes:

The PR updates the bundled Mattermost plugin to store callback URLs on native slash command registrations, validate slash callbacks against current Mattermost command state with bounded lookups, harden multi-account routing/body reads/log redaction, and refresh docs, tests, and changelog.

Maintainer follow-up before merge:

Protected maintainer-labeled implementation PR with no remaining mechanical repair finding; the next action is maintainer review, coordination with the related Mattermost auth PR, and merge judgment.

Security review:

Security review cleared: The diff is auth-sensitive but narrows Mattermost slash callback acceptance, bounds body and lookup work, sanitizes logs, and adds no dependency, workflow, package, or secret-permission expansion.

Review details

Best possible solution:

Keep this PR open for maintainer review, preserve the plugin-local auth boundary, coordinate the overlapping Mattermost callback hardening work, and merge once maintainers accept the fail-closed live-validation policy and final CI remains green.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main behavior is reproducible by source inspection: the handler accepts any registered account token without current-command verification, and the PR's focused tests cover rotated, deleted, drifted, fallback, cache, and rate-limit paths. I did not run local tests in this read-only pass, but the latest head check-runs are green.

Is this the best way to solve the issue?

Yes, with maintainer policy approval. The fix stays in the Mattermost plugin, uses Mattermost's command APIs rather than adding a core seam, adds regression coverage and docs, and the remaining concern is operational policy rather than a concrete patch bug.

Acceptance criteria:

  • pnpm test extensions/mattermost/src/mattermost/slash-http.test.ts extensions/mattermost/src/mattermost/slash-http.send-config.test.ts extensions/mattermost/src/mattermost/slash-state.test.ts extensions/mattermost/src/mattermost/slash-commands.test.ts
  • pnpm check:changed -- --base upstream/main
  • pnpm check:architecture
  • pnpm docs:check

What I checked:

Likely related people:

  • steipete: Recent main history shows Peter Steinberger hardened Mattermost slash token validation and handled adjacent Mattermost runtime/helper refactors on the affected files. (role: recent maintainer and hardening owner; confidence: high; commits: 2a65bfee966e, 0141471dd5a7, 9e1b524a0019; files: extensions/mattermost/src/mattermost/slash-http.ts, extensions/mattermost/src/mattermost/slash-state.ts, extensions/mattermost/src/mattermost/slash-commands.ts)
  • mukhtharcm: Main history shows Muhammed Mukhthar CM introduced native Mattermost slash command support and later worked in the same slash-command/model-picker path. (role: introduced behavior; confidence: high; commits: b1b41eb44323, 4f08dcccfd71; files: extensions/mattermost/src/mattermost/slash-http.ts, extensions/mattermost/src/mattermost/slash-state.ts, extensions/mattermost/src/mattermost/slash-commands.ts)
  • Vincent Koc: Recent main history rewrote the Mattermost docs section that this PR updates, including the AccordionGroup structure involved in the prior docs finding. (role: recent docs maintainer; confidence: medium; commits: 06d409dc2738; files: docs/channels/mattermost.md)

Remaining risk / open question:

  • Maintainers still need to accept the operational tradeoff that valid callbacks now depend on a reachable Mattermost API lookup path and per-command lookup rate limiting.
  • Open PR fix: harden Mattermost slash callback auth #65655 overlaps the same Mattermost slash-auth area and still tracks a separate HTTPS callback URL policy, so landing order should be coordinated.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 7df025f45781.

@drobison00 drobison00 force-pushed the mattermost-slash-token-refresh branch from 77cbebe to dfaa96c Compare April 30, 2026 15:58
@drobison00 drobison00 force-pushed the mattermost-slash-token-refresh branch from 9fda491 to 250b3e7 Compare May 1, 2026 15:05
@drobison00 drobison00 merged commit 9c0975c into openclaw:main May 1, 2026
95 checks passed
ihnotic added a commit to ihnotic/openclaw that referenced this pull request May 1, 2026
* refactor: trim provider discovery internal exports

* refactor: trim voice runtime internal exports

* fix(whatsapp): stage qrcode runtime dependency

* refactor: trim stream helper internal exports

* refactor: trim provider constant exports

* fix: make Discord voice reconnect timing resilient

* refactor: trim onboarding internal helpers

* docs(sandboxing): clarify sandbox setup scripts require source checkout (openclaw#75594)

Add inline docker build commands for npm-installed users who don't have the
source checkout scripts. Update all docs referencing sandbox-setup.sh,
sandbox-common-setup.sh and sandbox-browser-setup.sh to note they are
source-checkout-only and link to the new inline instructions.

Fixes openclaw#75485.

* fix(plugins): skip update when bundled plugin version is newer than installed clawhub/marketplace version (openclaw#75604)

* fix(plugin-sdk): restore deprecated reply pipeline compat exports

* refactor: trim test support helper exports

* test: stabilize Parallels update smokes

* refactor: trim sessions spawn harness type exports

* fix(gateway): refresh stale channel health cache

* fix(agent): apply configured fast mode to embedded runs

* fix(agent): default missing model cost metadata

* fix(agent): honor explicit OpenAI SSE transport

* fix(extensions): guard model and Twilio fetches

* fix(cli): repair agent runtime deps during startup

* fix(whatsapp): mirror qrcode from root runtime deps

* refactor: trim sanitize history harness exports

* refactor: trim subagent test helper exports

* [codex] Defer status reaction cleanup (openclaw#75582)

Summary:
- The PR updates the shared status reaction controller to track active remove-capable reactions, defer cleanup until clear/restoreInitial, adjust controller and Slack lifecycle tests, add a changelog entry, and carries qrcode runtime-dependency mirror hunks from its older base.

ClawSweeper fixups:
- Included follow-up commit: fix: limit status reaction restore cleanup
- Included follow-up commit: chore: merge main into status reaction cleanup
- Included follow-up commit: fix: mirror qrcode runtime dependency

Validation:
- ClawSweeper review passed for head f3efcb4.
- Required merge gates passed before the squash merge.

Prepared head SHA: f3efcb4
Review: openclaw#75582 (comment)

Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>

* refactor: trim runtime test helper type exports

* refactor: delete unused test helpers

* refactor: delete unused test support modules

* fix(agents): trim trailing assistant turns and rewrite blank user messages in session repair (openclaw#75606)

* fix(agents): trim trailing assistant turns and rewrite blank user messages in session repair

Session-file repair now:
- Trims trailing assistant messages so the JSONL never ends on
  role=assistant, preventing the Anthropic 400 prefill-loop that
  fires when thinking is enabled. (openclaw#75271)
- Rewrites blank-only user messages to a synthetic '(continue)'
  placeholder instead of dropping them, so strict providers
  (Qwen/mlx-vlm, Anthropic) no longer reject transcripts missing
  a user turn. (openclaw#75313)

Closes openclaw#75271, closes openclaw#75313.

* refactor: clean up comments in session-file repair

* fix(agents): preserve trailing assistant tool-call turns during session trim

Mirror the outbound guard (stripTrailingAssistantPrefillTurns):
skip assistant entries containing toolCall/toolUse/functionCall
blocks so transcript repair can synthesize missing tool results.

Addresses PR review feedback from clawsweeper on openclaw#75606.

* refactor: delete unused contract test helpers

* test: use built-in OpenAI provider in Windows smoke

* fix: recover Discord voice auto-join after resume

* refactor: trim cli test helper exports

* fix: send twilio notify twiml directly

* Prefer Codex native workspace tools (openclaw#75308)

Summary:
- The PR adds Codex dynamic-tool profile config defaulting to `native-first`, filters duplicate workspace/process/planning tools from Codex app-server thread payloads, keeps managed `web_search`, updates docs/manifest/config baselines/changelog, and adds regression tests.

ClawSweeper fixups:
- Included follow-up commit: test(codex): pin native-first tool catalog
- Included follow-up commit: chore(config): refresh generated schema baseline
- Included follow-up commit: chore: add codex native-first changelog
- Included follow-up commit: chore: move native-first changelog entry
- Included follow-up commit: chore: refresh config baseline after rebase

Validation:
- ClawSweeper review passed for head 30e5cec.
- Required merge gates passed before the squash merge.

Prepared head SHA: 30e5cec
Review: openclaw#75308 (comment)

Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: pashpashpash <[email protected]>

* refactor: trim cli program test exports

* refactor: trim command test helper exports

* ci: stop parity gate on pull requests

* chore: update dependencies

* chore: sync whatsapp dependency lockfile

* fix(agents): dedupe messaging tool replies by route

* fix: handle EPIPE errors on child process stdin writes (openclaw#75602)

Fix three child-process stdin write paths that let async EPIPE errors
escape to uncaughtException and crash the gateway.

extensions/imessage/src/client.ts (the actual openclaw#75438 crash path):
- Add child.stdin.on('error') listener in start() to catch async EPIPE
  and reject all pending requests via failAll().
- Add write callback to request() stdin.write() that rejects the
  specific pending request on error, instead of leaving it hanging
  until timeout.

src/agents/mcp-stdio-transport.ts:
- Fix write callback race in send(): previously resolved the promise
  immediately when write() returned true, then the write callback with
  EPIPE would fire after the promise was already fulfilled. Now always
  settles the promise from the write callback so the outcome is known
  before resolving.

src/process/exec.ts:
- Add stdin.on('error') before writing input so EPIPE from a
  prematurely-exited child is swallowed — the process exit handler
  reports the real status.

One reporter observed a gateway crash after 10.5 hours of stable
uptime — a single EPIPE on an iMessage RPC child process stdin write
killed the gateway with code 1.

Fixes: openclaw#75438

* refactor: trim cron test helper exports

* refactor: delete unused repo scan helper

* fix: default Discord voice to explicit opt-in

* refactor: trim test utility exports

* fix: show google meet twilio call diagnostics

* build: refresh a2ui bundle hash

* refactor: trim auto reply test helper exports

* fix(app): retry device tokens on pinned gateways (openclaw#75537)

* test(e2e): add bundled plugin runtime smoke

* test(e2e): activate channel rows for runtime smoke

* test(e2e): let channel runtime smoke load channels

* test(e2e): tolerate missing pgrep in runtime smoke

* test(e2e): assert canonical TTS provider in smoke

* test(e2e): satisfy runtime smoke lint

* test(e2e): account for lazy plugin commands in smoke

* test(e2e): give plugin runtime RPCs more headroom

* test(e2e): share runtime deps across matrix probes

* test(e2e): skip lazy tool catalog probes

* test(e2e): isolate plugin matrix runtime deps

* test(e2e): configure tts provider sections in matrix

* fix(plugins): preserve requested speech fallback

* test(e2e): harden bundled plugin runtime smoke

* docs(changelog): credit plugin runtime smoke fix

* fix(plugins): scope requested speech providers

* fix(test): satisfy plugin smoke lint

* fix(test): tolerate channel readiness degradation

* refactor: trim gateway test helper exports

* fix: allow doctor repair size drops

* fix: async transcript I/O to unblock gateway event loop (openclaw#75595)

* fix: async transcript I/O to unblock gateway event loop

Two related fixes for event-loop starvation caused by synchronous file
operations on session transcript files during gateway hot paths.

## sessions.list: yield between transcript reads (openclaw#75330)

Extract filterAndSortSessionEntries() from listSessionsFromStore() and
add a new listSessionsFromStoreAsync() that yields to the event loop
via setImmediate every 10 session rows. The sessions.list RPC handler
now uses the async version.

The synchronous version is kept for callers that need it (sessions-
resolve visibility checks, embedded backends, subagent tools).

The dominant blocker is readSessionTitleFieldsFromTranscript(), which
performs fs.statSync + fs.openSync + fs.readSync (head) + fs.readSync
(tail) for every session row that requests derived titles or last-
message previews. With 100+ sessions, this blocks the event loop for
32-64 seconds, starving WebSocket heartbeats, channel I/O, and
concurrent RPC.

## session compaction: async file copy (openclaw#75414)

Add captureCompactionCheckpointSnapshotAsync() using fs.promises for
stat, copyFile, and unlink instead of fsSync equivalents. Switch both
compact.ts and compact.queued.ts to the async version.

The synchronous copyFileSync of large transcript files (20MB+ observed
in production) was blocking the event loop for the entire copy duration
— one reporter measured a 43-minute event loop block from a single
compaction checkpoint capture.

Refs: openclaw#75330, openclaw#75414

* test: cover async transcript I/O responsiveness

* fix: avoid sync checkpoint metadata reads

* refactor: trim agent test helper exports

* fix(gateway): preflight strict agent delivery

* fix(onboard): run noninteractive migration imports

* fix(discord): send component-only native replies

* fix(slack): send block-only slash replies

* fix(telegram): send interactive-only button replies

* fix(line): send quick-reply-only payloads

* fix(auto-reply): keep docking in direct chats

* fix(discord): pin text dm main route owner

* fix(channels): pin dm main route owners

* fix(update): verify daemon restart port

* fix(update): use service env for doctor

* refactor: trim status scan test exports

* slack: persist thread participation best-effort (openclaw#75583)

* refactor: delete unused test helper code

* fix(gateway): defer session store read maintenance

* discord: persist component registries best-effort (openclaw#75584)

* test: retry Windows Parallels agent turn

* fix: type non-interactive onboard prompter

* refactor: trim gateway test helper barrel

* fix: declare deepinfra manifest model discovery

* refactor: derive deepinfra catalog from manifest

* docs: note deepinfra model catalog migration

* refactor: trim gateway helper state exports

* fix: allow onboarding config size drops

* fix: declare groq setup auth metadata

* fix: declare groq manifest model catalog

* docs: note groq manifest catalog migration

* fix: carry matrix dm allowlist state

* refactor: trim shared test helper exports

* fix: preserve OpenAI Codex xhigh thinking policy

* fix(infra): block ambient Homebrew env vars from brew resolution (openclaw#74463)

* fix: address issue

* fix: address issue

* fix: address PR review feedback

* fix: address PR review feedback

* fix: address codex review feedback

* docs: add changelog entry for PR merge

* fix: declare venice manifest catalog metadata

* refactor: derive venice fallback catalog from manifest

* docs: note venice manifest catalog migration

* refactor: trim extension internal type exports

* fix(infra): block Windows system path env vars from workspace .env injection (openclaw#74456)

* fix: address issue

* fix: address PR review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* fix: address codex review feedback

* docs: add changelog entry for PR merge

* Update CHANGELOG.md

* fix: block workspace CLOUDSDK_PYTHON override and always set trusted interpreter for gcloud (openclaw#74492)

* fix: address issue

* docs: add changelog entry for PR merge

* refactor: trim extension runtime barrels

* fix(plugins): scope install slot selection

* fix(plugins): satisfy slot registry type

* fix: declare zai manifest model catalog

* docs: note zai manifest catalog migration

* refactor: trim private extension exports

* test(docker): install procps for plugin watchdogs

* refactor: delete unused extension shared shims

* fix: declare stepfun setup auth metadata

* test(pairing): clear allowlist cache before read spy (openclaw#74147)

* fix: declare qianfan setup auth metadata

* fix(doctor): keep plugin runtime deps repair explicit (openclaw#75603)

* fix(doctor): keep plugin runtime deps repair explicit

* fix(doctor): keep plugin runtime deps repair explicit

* fix(doctor): keep plugin runtime deps repair explicit

---------

Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* feat(slack): publish App Home tab views

* fix(onboarding): scope post-config runtime deps (openclaw#75653)

* fix(whatsapp): drop stale qrcode runtime dependency

* fix(zai): satisfy catalog lint

* refactor: trim internal extension seams

* test: require parallels agent responses

* refactor: trim extension runtime reexports

* fix(feishu): recover WebSocket after SDK retry exhaustion (openclaw#73739)

* fix(feishu): recover WebSocket after SDK retry exhaustion

* fix(feishu): recover WebSocket after SDK retry exhaustion

---------

Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>

* feat(google-meet): add transcribe caption health

* refactor: trim extension test hooks

* test: configure parallels smoke provider timeout

* fix(doctor): keep noninteractive service repair explicit

* fix(plugins): use built code for tool discovery

* test(pairing): pass read spy path after cache reset

* refactor: trim extension helper shims

* fix(slack): declare Slack type dependency

* test(plugins): mock install slot registry

* docs(changelog): backfill 84e9463 qianfan and a4fd45c stepfun setup auth metadata

* test: quote parallels provider config json

* refactor: trim messaging runtime barrels

* test(plugin-sdk): align facade loader windows fast path

* refactor: trim extension barrel leftovers

* test(ci): stabilize pricing and codex web config checks

* refactor: trim channel dead exports

* fix(config): accept optional Codex search location

* test(config): isolate codex web schema acceptance

* refactor: trim extension shim reexports

* test(config): type fresh codex schema import

* refactor: trim browser action barrel

* docs(changelog): finalize 2026.4.30 notes

* refactor: trim provider model constants

* fix(channels): honor module loader native opt-out

* refactor: trim core command dead exports

* refactor: trim provider internal exports

* refactor: trim extension helper exports

* test(parallels): write Windows provider config via batch file

* refactor: trim browser route exports

* refactor: trim qqbot helper exports

* refactor: trim qqbot bridge exports

* test(parallels): expose portable Git to Windows agent turns

* refactor: trim qqbot utility exports

* fix(context-engine): honor assembled prompt authority in precheck (openclaw#74255)

Merged via squash.

Prepared head SHA: 650b023
Co-authored-by: 100yenadmin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* refactor: trim qqbot internal types

* refactor: trim mattermost helper exports

* refactor: trim matrix helper exports

* refactor: trim tlon helper exports

* test(parallels): retry Windows agent idle exits

* refactor: trim browser helper types

* test(parallels): budget Windows agent retry

* fix(ci): keep tool display serialization local

* refactor: trim voice-call helper exports

* refactor: trim bluebubbles helper exports

* refactor: trim bluebubbles config helper exports

* fix(webchat): create dashboard sessions from New Chat (openclaw#73725)

Summary:
- The PR rewires Control UI/WebChat New Chat to create and switch to a dashboard session through `sessions.create`, adds guarded UI/session helper logic and regression tests, and updates the changelog.

ClawSweeper fixups:
- Included follow-up commit: fix(webchat): create dashboard sessions from New Chat

Validation:
- ClawSweeper review passed for head 983c634.
- Required merge gates passed before the squash merge.

Prepared head SHA: 983c634
Review: openclaw#73725 (comment)

Co-authored-by: vincentkoc <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* refactor: trim brave and diffs helper exports

* fix(discord): avoid resolving token during action discovery (openclaw#75424)

Summary:
- The PR changes Discord message-action discovery to inspect configured accounts without resolving bot tokens, resolves scoped channel SecretRefs during message-tool execution even with an injected config snapshot, adds regression tests and a changelog entry, and restores a tool-display serializer export.

ClawSweeper fixups:
- Included follow-up commit: fix(discord): avoid resolving token during action discovery
- Included follow-up commit: fix(tools): restore tool display serializer export

Validation:
- ClawSweeper review passed for head a2cd832.
- Required merge gates passed before the squash merge.

Prepared head SHA: a2cd832
Review: openclaw#75424 (comment)

Co-authored-by: Clawdbot <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>

* Mattermost: refresh slash callback command validation (openclaw#72923)

* fix(mattermost): refresh slash callback tokens

* fix(mattermost): reconcile slash callback method

* fix(mattermost): bound slash command lookups

* fix(mattermost): cache slash validation lookups

* fix(mattermost): refresh slash routing

* fix(mattermost): require slash callback secret

* fix(mattermost): rate limit slash validation

* fix(mattermost): throttle slash validation

* fix(mattermost): bound slash token cache

* fix(mattermost): sanitize slash callback logs

* fix(mattermost): avoid stale slash token cache

* fix(mattermost): scope slash token gate to command

* fix(mattermost): rate-limit slash validation

* fix(mattermost): redact slash validation errors

* fix(mattermost): satisfy slash sanitizer lint

* Move Mattermost slash refresh changelog entry to Unreleased Fixes

* Apply oxfmt accordion blank-line on Mattermost slash docs

---------

Co-authored-by: Devin Robison <[email protected]>

* refactor: trim discord helper exports

* refactor: trim discord internal helper exports

* refactor: trim discord monitor helper exports

* refactor: trim discord test helper exports

* refactor: trim feishu helper exports

* docs(doctor): clarify service repair prompts

Clarify when doctor reports service repair state versus when gateway install performs launcher writes.\n\nThanks @vincentkoc

* fix(security): keep plain audit off plugin runtimes

Keep routine security audit on config/filesystem checks by default, reserving plugin runtime collectors for deep audit paths.\n\nThanks @vincentkoc

* test(e2e): bound telegram rtt warm samples

* test(rtt): expose warm sample metrics

* test(e2e): target successful rtt samples

* test(e2e): measure telegram normal reply rtt

* test(e2e): allow rtt retries to reach sample target

* refactor: trim provider helper exports

* fix(ci): satisfy rtt lint rules

* refactor: trim google meet helper exports

* refactor: trim google meet transport exports

* refactor: trim google chat helper exports

* test(rtt): support main package measurements

* refactor: trim irc helper exports

* refactor: trim signal helper exports

* refactor: trim line helper exports

* test(plugins): materialize runtime deps fixtures

* test(parallels): force Windows OpenAI SSE smoke

* refactor: trim mattermost helper exports

* refactor: trim nextcloud talk helper exports

* refactor: trim provider helper exports

* fix(gateway): bound session transcript hot paths

Bound recent transcript reads and oversized injected-message writes across gateway session paths.\n\nThanks @vincentkoc

* fix(plugins): reuse cold inspect registry snapshots (openclaw#75620)

Summary:
- The PR reuses a request-scoped cold manifest registry/runtime context across plugin status and inspect report paths, threads that context through provider/setup/metadata helpers, adds targeted coverage, and adds a changelog entry.

ClawSweeper fixups:
- Included follow-up commit: fix(plugins): preserve setup auto-enable lookup

Validation:
- ClawSweeper review passed for head 4d8e8e2.
- Required merge gates passed before the squash merge.

Prepared head SHA: 4d8e8e2
Review: openclaw#75620 (comment)

Co-authored-by: Vincent Koc <[email protected]>

* fix(plugins): avoid source rebuilds for policy toggles

Reuse current installed-plugin registry records for policy-only enable and disable refreshes.\n\nThanks @vincentkoc

* refactor: trim msteams helper exports

* test(parallels): force POSIX OpenAI SSE smoke

* refactor: trim telegram helper exports

* refactor: trim whatsapp helper exports

* test(parallels): batch POSIX provider config

* refactor: trim slack helper exports

* refactor: trim matrix helper exports

* test(release): repair release validation checks

* refactor: trim voice call helper exports

* refactor: trim memory wiki helper exports

* refactor: trim nostr helper exports

* test(release): forward validation fixes

* test(release): run doctor fix in setup-entry e2e

* refactor: trim qa matrix helper exports

* refactor: trim memory core helper exports

* test(release): fix setup fallback loader validation

* refactor: trim file transfer helper exports

* refactor: trim tlon helper exports

* refactor: trim browser helper exports

* test(release): harden channel add setup fallback

* refactor: trim imessage helper exports

* test(ci): update imessage runtime api guard

* test(release): include mirrored root runtime deps

* refactor: trim qa lab helper exports

* fix(bluebubbles): UTI-aware audio attachment detection (openclaw#75488)

Co-authored-by: Omar Shahine <[email protected]>

* test(release): remove stale runtime deps local

* refactor: trim qqbot helper exports

* refactor: trim codex internal exports

* refactor: trim whatsapp test helper exports

* refactor: trim telegram test harness exports

* refactor: remove stale openrouter runtime barrel

* refactor: trim zalo helper exports

* test(release): harden docker release validation

* fix(rtt): parse telegram scenario list

* refactor: trim feishu lifecycle helper exports

* test(plugins): use valid plugin origin in loader test

* fix(rtt): wait between telegram samples

* fix(config): surface backup restore copy failures in audit and logs (openclaw#70515)

Merged via squash.

Prepared head SHA: 7c77974
Co-authored-by: davidangularme <[email protected]>
Co-authored-by: jalehman <[email protected]>
Reviewed-by: @jalehman

* refactor: trim zalouser helper exports

* fix: stop stale OpenAI Responses replay in Telegram

Drop incomplete OpenAI/Codex tool-call replay turns and avoid previous_response_id deltas when Responses store is disabled. Verified on Zeus with focused tests, build, UI build, channel probe, and live Telegram-session canary.

* fix: stop stale Telegram final-answer replay

Suppress stale replayed final answers after newer Telegram/tool turns, supersede overlapping runs, and preserve current anchored output when replay frames contain old finals. Verified locally and on live Zeus with Telegram multi-skill expected-answer checks and ZeusChat model-switch browser checks.

* Stop direct NO_REPLY fallback chatter (#11)

Co-authored-by: Zeus3000 <[email protected]>

* Repair mismatched reset transcript files (#13)

Co-authored-by: Zeus3000 <[email protected]>

* Promote substantive stale-replay commentary (#15)

Co-authored-by: Zeus3000 <[email protected]>

* fix: preserve Telegram transcript user turns

---------

Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Alex Knight <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Co-authored-by: pashpashpash <[email protected]>
Co-authored-by: Shakker <[email protected]>
Co-authored-by: Pavan Kumar Gondhi <[email protected]>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Andrew <[email protected]>
Co-authored-by: 100yenadmin <[email protected]>
Co-authored-by: jalehman <[email protected]>
Co-authored-by: vincentkoc <[email protected]>
Co-authored-by: Conan-Scott <[email protected]>
Co-authored-by: Clawdbot <[email protected]>
Co-authored-by: Agustin Rivera <[email protected]>
Co-authored-by: Devin Robison <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: Omar Shahine <[email protected]>
Co-authored-by: Omar Shahine <[email protected]>
Co-authored-by: Fred David blum <[email protected]>
Co-authored-by: davidangularme <[email protected]>
Co-authored-by: Zeus3000 <[email protected]>
lxe pushed a commit to lxe/openclaw that referenced this pull request May 6, 2026
* fix(mattermost): refresh slash callback tokens

* fix(mattermost): reconcile slash callback method

* fix(mattermost): bound slash command lookups

* fix(mattermost): cache slash validation lookups

* fix(mattermost): refresh slash routing

* fix(mattermost): require slash callback secret

* fix(mattermost): rate limit slash validation

* fix(mattermost): throttle slash validation

* fix(mattermost): bound slash token cache

* fix(mattermost): sanitize slash callback logs

* fix(mattermost): avoid stale slash token cache

* fix(mattermost): scope slash token gate to command

* fix(mattermost): rate-limit slash validation

* fix(mattermost): redact slash validation errors

* fix(mattermost): satisfy slash sanitizer lint

* Move Mattermost slash refresh changelog entry to Unreleased Fixes

* Apply oxfmt accordion blank-line on Mattermost slash docs

---------

Co-authored-by: Devin Robison <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: mattermost Channel integration: mattermost docs Improvements or additions to documentation maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants