* test(ci): route plugin prerelease coverage to plugin shard
* test(ci): add plugin prerelease suite to CI
* fix(ci): preserve pnpm path in plugin prerelease shard
* fix(ci): avoid inheriting secrets for plugin prerelease suite
For 771846c5fa: docs/providers/bedrock.md "Advanced configuration" now
includes a "Claude Opus 4.7 temperature" accordion describing that
OpenClaw automatically omits `temperature` for Opus 4.7 Bedrock refs
(foundation model ids, named profiles, application inference profiles
whose underlying model resolves to Opus 4.7, and dotted `opus-4.7`
variants with regional prefixes), since Bedrock rejects the parameter on
that model. The fix has no user-facing knob, but Opus 4.7 Bedrock users
need to know the request shape changes silently.
Three findings from the second pass:
1. **MEDIUM — Cross-chat short message ID guard bypassed on empty chat
context (CWE-285).** When `requireKnownShortId=true` and `chatContext`
was missing or `{}`, `resolveBlueBubblesMessageId` would still resolve
the short id. Short ids are allocated from a single global counter
across every account and chat, so an action call without a chat
scope could silently apply to the wrong conversation. Throw "requires
a chat scope" instead. The previous behavior was an explicit
"fail-open" choice with a comment acknowledging the risk; the
underlying assumption (downstream call carries chatGuid) does not
hold for every action handler. Test rewritten to expect fail-closed.
2. **LOW — Unsanitized messageId reflected in cross-chat guard error
(CWE-117 / CWE-200).** The thrown error embedded the raw inputId
(and the raw chatGuid / chatIdentifier from the cached entry until
the previous pass). Replace the inputId with a shape descriptor
(`<short:N-digit>` or `<uuid:prefix…>`) so cross-chat errors no
longer leak any concrete identifier. Combined with the chat
identifier redaction in describeChatForError (already in place),
the error is fully redacted.
3. **LOW — PII exposure via verbose logs (CWE-532).** Untrusted webhook
identifiers (senderId / messageId / action) were already passed
through `sanitizeForLog`, but the helper only stripped control
characters — it did not redact secrets such as `?password=` query
strings or `Authorization: Bearer …` headers that occasionally
bleed into error chains. Extend `sanitizeForLog` to redact those
patterns. All call sites benefit immediately.
Four findings on this PR, all addressed in this commit:
1. **Cross-chat guard bypass when ctx.chatGuid present but cached lacks chatGuid**
(CWE-697). Earlier `isCrossChatMismatch` gated chatIdentifier and chatId
fallback comparisons on `!ctxChatGuid`, which let any non-empty
ctx.chatGuid suppress the fallback checks when the cached entry happened
to lack chatGuid — letting a short id from chat A be reused while acting
in chat B. Rewrite the function so chatIdentifier/chatId comparisons
run independently based on availability on each side, not on whether
ctx.chatGuid happens to be present.
2. **Sensitive chat identifiers exposed via thrown cross-chat error**
(CWE-200). `describeChatForError` interpolated raw chatGuid /
chatIdentifier / chatId into the error message — these can leak phone
numbers / email addresses / chat GUIDs into agent transcripts, tool
results, remote channel deliveries, or third-party log aggregators.
Surface only the *shape* of the chat target with `=<redacted>` values.
3. **Group reaction drop-guard bypass via whitespace chatIdentifier**.
Earlier guard treated "" as missing but accepted " " / "\t". Trim
chatGuid/chatIdentifier before the missing-check so a webhook sender
supplying whitespace cannot satisfy the guard and have peerId degrade
to the literal "group".
4. **Log injection via webhook senderId/messageId in verbose log lines**
(CWE-117). Untrusted webhook fields were interpolated directly into
`logVerbose` calls without sanitization, allowing log forging if a
sender carried CR/LF/control bytes. Wrap with the existing
`sanitizeForLog()` helper at all such sites.
Test updates: monitor-reply-cache.test.ts cross-chat error assertions
now expect `chatGuid=<redacted>` instead of raw values.