Skip to content

fix(agents): preserve operator.write scope for in-process subagent spawns#99199

Open
xiaobao-k8s wants to merge 1 commit into
openclaw:mainfrom
xiaobao-k8s:fix/token-auth-operator-write-98614
Open

fix(agents): preserve operator.write scope for in-process subagent spawns#99199
xiaobao-k8s wants to merge 1 commit into
openclaw:mainfrom
xiaobao-k8s:fix/token-auth-operator-write-98614

Conversation

@xiaobao-k8s

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where sessions_spawn fails with missing scope: operator.write when triggered from a channel plugin (e.g. Google Chat) using token auth. This is a regression introduced by commit 58bab0c2761 which added in-process dispatch optimization to callSubagentGateway.

Before the optimization, all callSubagentGateway calls went through the WebSocket connection path where callGatewayLeastPrivilege correctly resolves operator.write scope for the agent method. After the optimization, when hasInProcessGatewayContext() is true (the common case for channel-triggered sessions), the dispatch uses dispatchGatewayMethodInProcess which inherits the outer request scope's client. Channel plugin clients may not carry operator.write, causing the gateway method authorizer to reject the dispatch.

Why This Change Was Made

Always set forceSyntheticClient: true when dispatching in process from callSubagentGateway, so that non-admin methods like agent use the synthetic operator client (defaults to WRITE_SCOPE) instead of inheriting the calling channel plugin client's scopes. Admin-only methods (e.g. sessions.delete) continue to pass explicit syntheticScopes: [ADMIN_SCOPE].

User Impact

Users deploying OpenClaw with token auth and triggering subagent spawns from channel plugins (Google Chat, WhatsApp, Telegram, etc.) will no longer see missing scope: operator.write errors. Multi-agent delegation works correctly again.

Evidence

Tests pass locally:

✓ src/agents/subagent-spawn.test.ts (25 tests) 
✓ src/agents/tools/sessions-spawn-tool.test.ts (53 tests)

The in-process dispatch test now verifies forceSyntheticClient: true for non-admin "agent" dispatches, and admin-scoped cleanup test continues to verify forceSyntheticClient: true, syntheticScopes: ["operator.admin"] for admin methods.

Real behavior proof

Behavior or issue addressed: After the fix, sessions_spawn triggered from a channel plugin (e.g. Google Chat) via token auth no longer fails with "missing scope: operator.write". The in-process dispatch for "agent" method uses the synthetic operator client with WRITE_SCOPE instead of inheriting the channel plugin client's scopes.
Real environment tested: Repository openclaw/openclaw, branch fix/token-auth-operator-write-98614, commit 4a43bcec234, using the project's test runner from a git worktree on latest main (826c84e).
Exact steps or command run after this patch:

npx vitest run src/agents/subagent-spawn.test.ts --config test/vitest/vitest.agents.config.ts --reporter=verbose

Evidence after fix: Terminal output from the verification:

✓ agents src/agents/subagent-spawn.test.ts > spawnSubagentDirect seam flow > dispatches spawned agent runs in process when a gateway context is available 16ms
✓ agents src/agents/subagent-spawn.test.ts > spawnSubagentDirect seam flow > keeps admin-scoped cleanup on in-process spawn failure 9ms
...all 25 tests passed

Observed result after fix: The in-process dispatch test confirms forceSyntheticClient: true is set for the "agent" method (which requires operator.write), ensuring the synthetic client with [WRITE_SCOPE] is used. Admin-scoped cleanup test still passes with correct admin-tier scope override.
What was not tested: End-to-end Google Chat channel trigger with token auth — requires a live Google Chat deployment. The fix is verified at the unit level through the in-process dispatch mock assertions.

Closes #98614

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS labels Jul 2, 2026
@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 10, 2026, 5:56 AM ET / 09:56 UTC.

Summary
The PR forces in-process subagent Gateway calls to use a write-scoped synthetic operator client while retaining explicit admin scope for privileged cleanup calls.

PR surface: Source +3, Tests +1. Total +4 across 2 files.

Reproducibility: yes. at source level: current main can inherit a channel or plugin client without operator.write for the in-process agent call, matching the linked release regression. No live after-fix reproduction has been supplied.

Review metrics: 1 noteworthy metric.

  • Authorization identity: 1 identity-selection rule changed; write/admin tiers preserved. The patch changes which principal authorizes the internal RPC while retaining write for child start and explicit admin for cleanup.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #98614
Summary: This PR is the direct candidate fix for the bisected token-auth channel regression; older reports and PRs overlap but do not safely replace it.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🐚 platinum hermit
Result: blocked until real behavior proof from a real setup is added.

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

Rank-up moves:

  • [P1] Add redacted live token-auth channel sessions_spawn success proof.
  • Obtain explicit approval for the synthetic write-scoped authorization boundary.
  • Rebase onto current main and re-run exact-head review.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body provides focused unit or mock runner output and explicitly says no live affected channel was tested; add a redacted token-auth channel sessions_spawn transcript, terminal output, logs, or recording, update the PR body, and ask for @clawsweeper re-review if automatic review does not run.

Risk before merge

  • [P1] Merging intentionally replaces the originating channel or plugin request principal with a process-synthetic write-scoped operator principal for the child agent RPC; maintainers must confirm that sessions_spawn tool authorization is the intended trust boundary.
  • [P1] The PR has no redacted live token-auth channel or real sessions_spawn after-fix run, so the reported user path remains unproven despite green tests and CI.
  • [P1] The branch is behind current main; GitHub reports it mergeable, but the exact head should be refreshed and re-reviewed after any rebase.

Maintainer options:

  1. Confirm boundary and prove the real path (recommended)
    Approve the subagent-only write-scoped handoff, rebase the branch, and require a redacted token-auth channel sessions_spawn success before merge.
  2. Pause for delegated authorization
    Pause or close this implementation if channel or plugin caller identity must remain authoritative for internal subagent RPCs.

Next step before merge

  • [P1] The PR needs maintainer security-boundary approval, contributor live proof, and an exact-head refresh; there is no discrete mechanical code defect for an automated repair worker.

Maintainer decision needed

  • Question: Is successful sessions_spawn tool authorization sufficient to let its internal in-process agent RPC run as a synthetic operator with operator.write, rather than retaining the originating channel or plugin request principal?
  • Rationale: Source inspection proves the synthetic principal is limited to write scope, but repository evidence cannot determine whether tool authorization or caller identity is the intended permanent security boundary.
  • Likely owner: steipete — They co-developed and merged the original in-process dispatch behavior and are the strongest history-backed owner for the intended trust boundary.
  • Options:
    • Approve the write-scoped handoff (recommended): Allow synthetic operator.write at this subagent-only chokepoint, retain explicit admin only for cleanup, and require live regression proof before merge.
    • Require delegated caller identity: Pause this patch and design an explicit delegated capability that preserves the originating principal through the internal RPC.

Security
Needs attention: The implementation remains write-only, but replacing caller identity with synthetic operator identity requires explicit owner approval before merge.

Review details

Best possible solution:

Keep the write-only synthetic client at the subagent chokepoint and explicit admin scope for cleanup, but land only after the auth owner approves that trust handoff and a redacted affected-channel run proves the shipped regression is fixed.

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

Yes at source level: current main can inherit a channel or plugin client without operator.write for the in-process agent call, matching the linked release regression. No live after-fix reproduction has been supplied.

Is this the best way to solve the issue?

Yes technically: the patch is narrow, the synthetic default is write-only, and admin cleanup remains explicit. It is not merge-ready until maintainers approve the principal handoff and the contributor proves the real affected path.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 7fe004d85251.

Label changes

Label justifications:

  • P1: The linked shipped regression blocks channel-triggered multi-agent delegation for affected token-auth users.
  • merge-risk: 🚨 security-boundary: The diff substitutes a synthetic operator principal for the originating request principal at an authorization-sensitive internal RPC boundary.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body provides focused unit or mock runner output and explicitly says no live affected channel was tested; add a redacted token-auth channel sessions_spawn transcript, terminal output, logs, or recording, update the PR body, and ask for @clawsweeper re-review if automatic review does not run.
Evidence reviewed

PR surface:

Source +3, Tests +1. Total +4 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 6 3 +3
Tests 1 1 0 +1
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 7 3 +4

Security concerns:

  • [medium] Confirm the synthetic operator trust handoff — src/agents/subagent-spawn.ts:273
    The changed line makes every in-process child agent call use synthetic operator.write even when the originating channel or plugin client lacks that scope; this is a plausible internal capability boundary, but it must be an intentional owner-approved authorization contract.
    Confidence: 0.96

What I checked:

Likely related people:

  • lanzhi-lee: Authored the merged in-process subagent dispatch feature that created this caller-identity path. (role: introduced behavior; confidence: high; commits: 58bab0c2761e; files: src/agents/subagent-spawn.ts, src/gateway/server-plugins.ts)
  • steipete: Contributed the timeout and test follow-ups to the original in-process dispatch PR and merged the feature. (role: merger and adjacent contributor; confidence: high; commits: 6c00c17a4588, 58ef6cc9c429, 58bab0c2761e; files: src/agents/subagent-spawn.ts, src/gateway/server-plugins.ts, src/gateway/server-plugins.test.ts)
  • rvdlaar: Most recently carried the current versions of both the subagent chokepoint and synthetic-client dispatcher through a large agents refactor. (role: recent area contributor; confidence: medium; commits: fc507c70c5e3; files: src/agents/subagent-spawn.ts, src/gateway/server-plugins.ts)
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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-02T18:43:50.292Z sha 4a43bce :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 2, 2026
…bagent dispatch

When in-process subagent Gateway dispatch omitted forceSyntheticClient for
non-admin methods (e.g. "agent"), the call could inherit the caller's
channel-plugin client, which may not carry operator.write (openclaw#98614).

Always force the synthetic operator client for in-process dispatch so scope
resolution does not depend on the calling channel plugin's client scopes.

Closes openclaw#98614
@xiaobao-k8s
xiaobao-k8s force-pushed the fix/token-auth-operator-write-98614 branch from 4a43bce to cd202ae Compare July 10, 2026 02:54
@xiaobao-k8s

Copy link
Copy Markdown
Contributor Author

Rebased onto latest main (cd202ae) to resolve the merge conflict. No logic change — the fix remains: always force synthetic operator client for in-process dispatch.

Changes vs original PR:

  • Updated the comment block to align with main's existing resolveLeastPrivilegeOperatorScopesForMethod path
  • forceSyntheticClient is now unconditional (was conditional on scopes != null)
  • Test assertion added for the forceSyntheticClient seam

@clawsweeper re-review

Closes #98614

@clawsweeper

clawsweeper Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@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 Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS stale Marked as stale due to inactivity status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Regression]: sessions_spawn missing scope operator.write — introduced between v2026.6.1 and v2026.6.11

1 participant