Repository navigation
fix(chat): in-chat approval card can show a different command than Allow runs - #1499
Conversation
- Run command and message through ExecApprovalCommandDisplaySanitizer before the card renders them - Keep the approval request id unchanged - Tray test covers bidi, zero-width, and line-separator payloads Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed September 27, 2026, 3:11 PM ET / 19:11 UTC (Revision 14). ClawSweeper reviewWhat this changesThe branch sanitizes command text on native chat approval cards, limits unreviewable requests to Deny, checks pending approval state before sending a response, and adds fixture and UI coverage. Merge readiness✅ Ready for maintainer review Keep this PR open. Current main still offers Allow for approval text the user cannot fully review, while this branch adds a guard at the approval RPC boundary. The prior review’s fixture finding is addressed, and the current-head proof covers the previously missing stale-Allow case. Priority: P1 Review scores
Verification
How this fits togetherGateway approval events enter the Windows tray chat view as cards with command details and response buttons. A user’s response passes through the chat provider to the Gateway approval RPC, which can authorize command execution. flowchart LR
A[Gateway approval event] --> B[Chat event mapper]
B --> C[Sanitize displayed text]
C --> D{Fully reviewable?}
D -->|Yes| E[Allow and Deny card]
D -->|No| F[Deny only card]
E --> G[Pending approval check]
F --> G
G --> H[Gateway approval response]
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Technical reviewBest possible solution: Land the card eligibility and pending-response guard together, retaining the native UI and production WebSocket regression coverage. Do we have a high-confidence way to reproduce the issue? Yes, from source: current main places raw approval text on a card with Allow actions, and the branch’s tests exercise unsafe and stale cases. This read-only review did not execute the application. Is this the best way to solve the issue? Yes. Reusing the established sanitizer and checking the pending card at the existing RPC entrypoint is a focused repair; the production-client and native UI tests cover the relevant effects. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against cf3626aa5ed7. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (13 earlier review cycles; latest 8 shown)
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9a0183f-460a-4854-b545-89033a081f21
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9a0183f-460a-4854-b545-89033a081f21
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9a0183f-460a-4854-b545-89033a081f21
|
Global triage: NEEDS_HUMAN_TEST. Take confidence 65%; recommendation confidence 92%; effort small-to-medium; risk medium. Reviewed exact head Owner: maintainer proof scheduler. Run strict |
Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
c8a3785 keeps Deny as the only action when the command text is missing, and the card now says that no command was included so only Deny is available. Local filter Map_ApprovalRequestOffersOnlyDeny: 8 passed. Strict |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ba54a2d-477b-4b8e-994c-5fb3755d8b01
|
I now have strict BaseContainer support on this host. I am updating this original branch onto current |
|
Validated updated exact branch head Validation
The validation process used task-local @clawsweeper re-review |
|
🦞👀 Re-review progress:
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ba54a2d-477b-4b8e-994c-5fb3755d8b01
|
Current head Changed-path behavior proof
The fixture retains only safe test-owned approval IDs and the validated decision enum. It never executes a command. Validation
@clawsweeper re-review |
|
🦞👀 Re-review progress:
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ba54a2d-477b-4b8e-994c-5fb3755d8b01
|
Current head Final validation after that guard:
The production approval path remains the real @clawsweeper re-review |
|
🦞👀 Re-review progress:
|
|
The current-head Core/CLI failure is the same unrelated |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ba54a2d-477b-4b8e-994c-5fb3755d8b01
|
@clawsweeper re-review |
|
🦞👀 Re-review progress:
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9ba54a2d-477b-4b8e-994c-5fb3755d8b01
|
@clawsweeper re-review |
|
🦞👀 Re-review progress:
|
What Problem This Solves
The in-chat approval card could display text different from the command an Allow action resolved, especially when Gateway text contained concealed Unicode, secret-shaped content, truncation, oversized content, or a missing command.
User Impact
exec.approval.resolveI/O unless the matching pending card permits that exact decision.Why This Change Was Made
The existing display sanitizer already classified truncated, oversized, secret-redacted, and concealment-unsafe text. The chat mapper previously discarded those status flags and still offered Allow. The repair carries the sanitizer status into card actions and verifies the current pending card immediately before the existing approval RPC.
The original contributor commits remain on the original PR branch. The final follow-up adds deterministic native WinUI, production-provider, production-WebSocket, and Gateway-fixture proof.
Change Type
Scope
Required proof pools
windows-winui-interactive: PASS. The real isolated native chat view showed a reviewable card with Allow/Deny actions and a missing-command card with Deny only.windows-wsl-mxc: PASS. Strict non-skipping Gateway-to-node MXC validation completed 17/17.windows-wsl-gateway-e2e: Production approval I/O boundary verified against the repository loopback Gateway. The test uses the realOpenClawChatDataProvider,GatewayClientChatBridge, andOpenClawGatewayClientWebSocket request/response implementation. An installed external Gateway service was not required and no command was executed.Validation
Current head:
8e6fe7c953604e0e9f189b92bbfd2df822f55844./build.ps1: PASS.validate-mxc-e2e.ps1without-AllowSkip: 17/17 passed.Real behavior proof
Native chat UI
GatewayFixtureUiTests.ApprovalCardsGateAllowAndResolveThroughGatewaylaunches the freshly built app in a disposable profile and drives the actual native chat UI against the production WebSocket client and isolated loopback Gateway.echo fixture-safeapproval rendered Allow once, Always allow, and Deny once. Clicking Allow once sentexec.approval.resolvewith fixture-issued IDfixture-safe-approvaland decisionallow-once; the Gateway returnedok.only Deny is available, exposed no Allow actions, and clicking Deny once sent fixture-issued IDfixture-unreviewable-approvalwith decisiondeny; the Gateway returnedok. The active Deny-only state was captured by the fixture.Production provider and WebSocket boundary
RespondToPermissionAsync_StaleAllowStopsBeforeProductionWebSocketIoconnects a realOpenClawGatewayClientto the loopback Gateway, wraps it in the productionGatewayClientChatBridge, and uses the realOpenClawChatDataProvider.exec.approval.resolveWebSocket request is recorded for A.allow-onceand receivesok.This directly verifies rejection before final WebSocket I/O when approval state changes.
Fixture correlation safety
The synthetic Gateway:
ok;INVALID_PARAMS.Security Impact
Compatibility and Migration
Review Conversations