fix(agents): prefer sessionKey in sessions_send#74009
fix(agents): prefer sessionKey in sessions_send#74009openclaw-clownfish[bot] wants to merge 1 commit into
Conversation
Greptile SummaryThis PR removes the early-rejection guard that rejected Confidence Score: 4/5Safe to merge; the implementation change is a clean one-block removal with correct precedence semantics. Only P2 findings present. The core fix and description update are straightforward and well-tested. The one concern is test isolation: callGatewayMock.mockImplementation in the new sessionId test persists into later tests because the local beforeEach uses mockClear() rather than mockReset(), creating a risk of false positives in downstream tests within the same describe block. src/agents/tools/sessions.test.ts — callGatewayMock mock-isolation in sessions_send gating describe block Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/agents/tools/sessions.test.ts
Line: 687-695
Comment:
**`callGatewayMock` implementation leaks into subsequent tests**
The `sessions_send gating` `beforeEach` calls `callGatewayMock.mockClear()`, which clears call history but **not** the registered implementation. After this test installs its implementation via `mockImplementation(...)`, the subsequent tests ("blocks cross-agent sends" and "does not reuse a stale assistant reply") will inherit it — specifically, `sessions.list → {}` instead of `undefined`. `loadConfigMock` is correctly reset by the outer `beforeEach` calling `mockReset()`, but `callGatewayMock` is not. To fix, either change the local `beforeEach` to use `callGatewayMock.mockReset()`, or restore the mock after this test:
```ts
afterEach(() => {
callGatewayMock.mockReset();
});
```
Alternatively, use `mockImplementationOnce` for each individual call to avoid a persistent override.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(agents): prefer sessionKey in sessio..." | Re-trigger Greptile |
| callGatewayMock.mockImplementation(async (opts: unknown) => { | ||
| const request = opts as { method?: string; params?: Record<string, unknown> }; | ||
| if (request.method === "sessions.resolve" && request.params?.sessionId === sessionId) { | ||
| return { key: resolvedSessionKey }; | ||
| } | ||
| if (request.method === "agent") { | ||
| return { runId: "run-session-id-send" }; | ||
| } | ||
| return {}; |
There was a problem hiding this comment.
callGatewayMock implementation leaks into subsequent tests
The sessions_send gating beforeEach calls callGatewayMock.mockClear(), which clears call history but not the registered implementation. After this test installs its implementation via mockImplementation(...), the subsequent tests ("blocks cross-agent sends" and "does not reuse a stale assistant reply") will inherit it — specifically, sessions.list → {} instead of undefined. loadConfigMock is correctly reset by the outer beforeEach calling mockReset(), but callGatewayMock is not. To fix, either change the local beforeEach to use callGatewayMock.mockReset(), or restore the mock after this test:
afterEach(() => {
callGatewayMock.mockReset();
});Alternatively, use mockImplementationOnce for each individual call to avoid a persistent override.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/sessions.test.ts
Line: 687-695
Comment:
**`callGatewayMock` implementation leaks into subsequent tests**
The `sessions_send gating` `beforeEach` calls `callGatewayMock.mockClear()`, which clears call history but **not** the registered implementation. After this test installs its implementation via `mockImplementation(...)`, the subsequent tests ("blocks cross-agent sends" and "does not reuse a stale assistant reply") will inherit it — specifically, `sessions.list → {}` instead of `undefined`. `loadConfigMock` is correctly reset by the outer `beforeEach` calling `mockReset()`, but `callGatewayMock` is not. To fix, either change the local `beforeEach` to use `callGatewayMock.mockReset()`, or restore the mock after this test:
```ts
afterEach(() => {
callGatewayMock.mockReset();
});
```
Alternatively, use `mockImplementationOnce` for each individual call to avoid a persistent override.
How can I resolve this? If you propose a fix, please make it concise.|
Codex review: needs maintainer review before merge. Reviewed May 30, 2026, 12:57 AM ET / 04:57 UTC. Summary PR surface: Source -7, Tests +91, Docs +1. Total +85 across 4 files. Reproducibility: unclear. The review failed before ClawSweeper could establish a reproduction path. Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Review detailsBest possible solution: Retry the Codex review after fixing the execution failure. Do we have a high-confidence way to reproduce the issue? Unclear. The review failed before ClawSweeper could establish a reproduction path. Is this the best way to solve the issue? Unclear. Retry the review first so ClawSweeper can evaluate the actual issue and fix direction. AGENTS.md: unclear because the file could not be read completely. Codex review notes: model gpt-5.5, reasoning high; reviewed against b9933b2ec119. Label changesLabel justifications:
Evidence reviewedPR surface: Source -7, Tests +91, Docs +1. Total +85 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
bb397fb to
4d198db
Compare
4d198db to
115455e
Compare
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟡 Session key disclosure via sessionId resolution in sessions_send when access is denied
DescriptionThe When the visibility/A2A check fails, the tool returns an error including Impact:
Vulnerable code: const access = visibilityGuard.check(resolvedKey);
if (!access.allowed) {
return jsonResult({
...,
error: access.error,
sessionKey: displayKey, // leaks resolved key
});
}RecommendationDo not reveal the resolved/canonical session key when the requester is not authorized. Suggested changes:
Example fix: const access = visibilityGuard.check(resolvedKey);
if (!access.allowed) {
return jsonResult({
runId: crypto.randomUUID(),
status: access.status,
error: access.error,
// Avoid leaking resolved key; echo the caller input or omit.
sessionKey: sessionKeyParam ?? labelParam ?? undefined,
});
}And/or gate the sessionId resolution flags based on effective visibility/A2A policy before calling Analyzed PR: #74009 at commit Last updated on: 2026-04-29T06:10:35Z |
|
+1 — hit this in production today on v2026.5.7 (Linux, embedded PI runtime, custom OpenAI-compatible provider at private baseUrl). My agent-to-agent Reproduce:
The added regression tests ( Would help unblock my A2A workflows without local patching. Anyone available to take a review pass? |
|
This pull request has been automatically marked as stale due to inactivity. |
Honor caller-provided sessionKey values when stale label metadata is also present, and keep denied session-id sends from echoing the resolved canonical session key. Supersedes #74009 and fixes #64699. Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Honor caller-provided sessionKey values when stale label metadata is also present, and keep denied session-id sends from echoing the resolved canonical session key. Supersedes #74009 and fixes #64699. Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Honor caller-provided sessionKey values when stale label metadata is also present, and keep denied session-id sends from echoing the resolved canonical session key. Supersedes #74009 and fixes #64699. Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Honor caller-provided sessionKey values when stale label metadata is also present, and keep denied session-id sends from echoing the resolved canonical session key. Supersedes #74009 and fixes #64699. Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
|
Closed as superseded. This source branch was dirty/unmergeable and maintainer_can_modify=false, so I landed a maintainer replacement in #92047 with the same behavior plus the review/security fixes: explicit sessionKey wins over redundant label metadata, and denied session-id/thread sends no longer disclose the resolved canonical session key. Contributor credit was preserved in the changelog and commit. Landed as 3659ff8. |
Honor caller-provided sessionKey values when stale label metadata is also present, and keep denied session-id sends from echoing the resolved canonical session key. Supersedes openclaw#74009 and fixes openclaw#64699. Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Summary
Repair #59324 so sessions_send treats sessionKey/sessionId as the authoritative target selector when redundant label or agentId values are also present, instead of rejecting the call before send resolution.
Scope
Review and validation
Attribution
This repairs the contributor path from #59324 by @Mintalix and should credit the overlapping non-security source PR #56203 by @RevisitMoon if its test or implementation shape is carried forward. It covers #64699 and the sessions_send portion of #41199 after merge.
ProjectClownfish replacement details:
! [remote rejected] HEAD -> fix/sessions-send-prefer-session-key (refusing to allow a GitHub App to create or update workflow
.github/workflows/ci-build-artifacts-testbox.ymlwithoutworkflowspermission)error: failed to push some refs to 'https://github.com/Mintalix/openclaw.git'