Skip to content

fix(agents): prefer sessionKey in sessions_send#74009

Closed
openclaw-clownfish[bot] wants to merge 1 commit into
mainfrom
clownfish/ghcrawl-166009-agentic-merge
Closed

fix(agents): prefer sessionKey in sessions_send#74009
openclaw-clownfish[bot] wants to merge 1 commit into
mainfrom
clownfish/ghcrawl-166009-agentic-merge

Conversation

@openclaw-clownfish

Copy link
Copy Markdown
Contributor

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

  • Keep the runtime change narrow in src/agents/tools/sessions-send-tool.ts.
  • Add or preserve focused regression coverage in src/agents/tools/sessions.test.ts for sessionKey plus label and sessionId plus label/agentId cases.
  • Update the public tool description so callers understand sessionKey precedence.
  • Do not edit generated docs.

Review and validation

  • Address or prove stale the hydrated bot findings on fix(agents): prefer sessionKey in sessions_send #59324, including the generated-docs warning, tool-description wording, and redundant trim feedback.
  • Run /review after repair and address every finding.
  • Run pnpm -s vitest run src/agents/tools/sessions.test.ts.
  • Run pnpm check:changed.

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:

@openclaw-clownfish openclaw-clownfish Bot added the clawsweeper Tracked by ClawSweeper automation label Apr 29, 2026
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S r: too-many-prs Auto-close: author has more than twenty active PRs. and removed r: too-many-prs Auto-close: author has more than twenty active PRs. labels Apr 29, 2026
@greptile-apps

greptile-apps Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes the early-rejection guard that rejected sessions_send calls when both sessionKey and label were provided, replacing it with a simple precedence rule: when sessionKey is present the label-resolution block is skipped entirely. The description in tool-description-presets.ts is updated accordingly and two regression tests are added. The implementation change is correct and the description update is accurate.

Confidence Score: 4/5

Safe 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 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.

Reviews (1): Last reviewed commit: "fix(agents): prefer sessionKey in sessio..." | Re-trigger Greptile

Comment on lines +687 to +695
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 {};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

@clawsweeper

clawsweeper Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 30, 2026, 12:57 AM ET / 04:57 UTC.

Summary
Review failed before ClawSweeper could summarize the requested change.

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: 🌊 off-meta tidepool
Proof: 🌊 off-meta tidepool
Patch quality: 🌊 off-meta tidepool
Result: rating does not apply to this item.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] No close action taken because the review did not complete.

Maintainer options:

  1. Decide the mitigation before merge
    Retry the Codex review after fixing the execution failure.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • Review did not complete, so no work-lane recommendation was made.
Review details

Best 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 changes

Label justifications:

  • rating: 🌊 off-meta tidepool: Overall readiness is 🌊 off-meta tidepool; proof is 🌊 off-meta tidepool and patch quality is 🌊 off-meta tidepool.
Evidence reviewed

PR surface:

Source -7, Tests +91, Docs +1. Total +85 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 1 8 -7
Tests 1 91 0 +91
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 93 8 +85

What I checked:

  • failure reason: codex execution failed.
  • codex failure detail: Codex review failed for this PR with exit 1.
  • codex stdout: Per-item Codex failure; continuing with the rest of the shard.

Likely related people:

  • unknown: Codex failed before it could trace repository history. (role: review did not complete; confidence: low)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@vincentkoc vincentkoc force-pushed the clownfish/ghcrawl-166009-agentic-merge branch 2 times, most recently from bb397fb to 4d198db Compare April 29, 2026 05:54
@vincentkoc vincentkoc force-pushed the clownfish/ghcrawl-166009-agentic-merge branch from 4d198db to 115455e Compare April 29, 2026 06:08
@aisle-research-bot

aisle-research-bot Bot commented Apr 29, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

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

# Severity Title
1 🟡 Medium Session key disclosure via sessionId resolution in sessions_send when access is denied
1. 🟡 Session key disclosure via sessionId resolution in sessions_send when access is denied
Property Value
Severity Medium
CWE CWE-200
Location src/agents/tools/sessions-send-tool.ts:235-248

Description

The sessions_send tool accepts a sessionKey that may actually be a UUID sessionId. It resolves that sessionId to a canonical session key via sessions.resolve (with includeGlobal/includeUnknown when not sandbox-restricted), and then enforces visibility/A2A policy.

When the visibility/A2A check fails, the tool returns an error including sessionKey: displayKey, which is derived from the resolved canonical key. This allows a caller who is not allowed to send (e.g., tools.agentToAgent.enabled=false or tools.sessions.visibility not all) to probe sessionIds and learn the existence and canonical keys of otherwise-hidden sessions.

Impact:

  • Confirms whether a given sessionId exists (enumeration)
  • Leaks the canonical session key format (e.g., agent:main:subagent:worker) for sessions the caller cannot access
  • Enables targeted follow-on attempts elsewhere that accept session keys, and reveals internal structure/agent names

Vulnerable code:

const access = visibilityGuard.check(resolvedKey);
if (!access.allowed) {
  return jsonResult({
    ...,
    error: access.error,
    sessionKey: displayKey, // leaks resolved key
  });
}

Recommendation

Do not reveal the resolved/canonical session key when the requester is not authorized.

Suggested changes:

  • On denied access, return only the original identifier provided by the caller (or omit sessionKey entirely).
  • Additionally, consider tightening sessionId resolution so it does not search includeGlobal/includeUnknown unless visibility actually permits those sessions.

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 sessions.resolve for sessionIds.


Analyzed PR: #74009 at commit 115455e

Last updated on: 2026-04-29T06:10:35Z

@Mocha-s

Mocha-s commented May 12, 2026

Copy link
Copy Markdown

+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 sessions_send flow always includes both sessionKey (resolved from a prior sessions.list) and label (carried over from earlier turn context), and gets the early "Provide either sessionKey or label (not both)." rejection before send resolution — exactly what this PR removes.

Reproduce:

  1. openclaw@2026.5.7, two configured agents (coordinator + script in my case).
  2. From coordinator call sessions_send with { sessionKey: "agent:script:main", label: "script", message: "ping" } (label carried from earlier turn metadata, sessionKey resolved freshly).
  3. Without this fix: tool returns status: error, error: "Provide either sessionKey or label (not both)." and never hits sessions.resolve / agent.
  4. With this PR's diff applied locally to dist/openclaw-tools-*.js: send proceeds, sessions.list is called once, then agent with the explicit sessionKey — confirming the "sessionKey wins" semantics the new test asserts.

The added regression tests (prefers sessionKey over a redundant label, etc.) cover the exact path I'd want to lock in. From an operator's POV the current behavior is the worse default: callers naturally accumulate both fields and there's no way to express "I know the sessionKey, ignore the stale label" without a special-case codepath.

Would help unblock my A2A workflows without local patching. Anyone available to take a review pass?

@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label May 30, 2026
@clawsweeper clawsweeper Bot added the rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. label May 30, 2026
@barnacle-openclaw barnacle-openclaw Bot removed the stale Marked as stale due to inactivity label May 30, 2026
vincentkoc added a commit that referenced this pull request Jun 10, 2026
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>
vincentkoc added a commit that referenced this pull request Jun 10, 2026
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>
vincentkoc added a commit that referenced this pull request Jun 10, 2026
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>
vincentkoc added a commit that referenced this pull request Jun 10, 2026
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>
@vincentkoc

Copy link
Copy Markdown
Member

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.

@vincentkoc vincentkoc closed this Jun 10, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 11, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling clawsweeper Tracked by ClawSweeper automation rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants