fix(exec): distinguish one-shot from ask=always in approval prompt#97106
fix(exec): distinguish one-shot from ask=always in approval prompt#97106ZOOWH wants to merge 9 commits into
Conversation
When Allow Always is unavailable because a command is one-shot (e.g. shell redirection), show the correct reason instead of falsely claiming the effective policy requires approval every time. Closes openclaw#97069
|
Codex review: needs real behavior proof before merge. Reviewed June 30, 2026, 10:05 PM ET / 02:05 UTC. Summary PR surface: Source +36, Tests +56. Total +92 across 4 files. Reproducibility: yes. The linked report gives concrete redirected-command steps, and source inspection shows current main collapses ask=always and one-shot persistence into the same missing Allow Always decision while the PR head still loses the reason on several surfaces. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Carry a producer-owned Allow Always unavailable reason through approval request/detail/view models and render it consistently across reply, forwarder, Telegram native, reaction/manual fallback, foreground exec, Control UI, embedded reconstructed prompts, and gateway resolve errors. Do we have a high-confidence way to reproduce the issue? Yes. The linked report gives concrete redirected-command steps, and source inspection shows current main collapses ask=always and one-shot persistence into the same missing Allow Always decision while the PR head still loses the reason on several surfaces. Is this the best way to solve the issue? No. The shared helper is useful, but the best fix is to propagate the real unavailable reason from the producer through request/detail/view models instead of defaulting missing reason data back to policy copy. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 816038e97a5d. Label changesLabel justifications:
Evidence reviewedPR surface: Source +36, Tests +56. Total +92 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
|
- Fix forwarder path (exec-approval-forwarder.ts) same as reply path - Default to policy message when ask is unavailable (null/undefined) - Leave approval-reaction-runtime and bash-tools as-is (no ask info) Closes openclaw#97069
Mantis Telegram Desktop ProofSummary: Mantis captured native Telegram Desktop before/after GIFs showing the approval prompt reason change.
Motion-trimmed clips: |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…n through approval data Export a single source-of-truth function from exec-approvals.ts that all renderers use to show why Allow Always is unavailable. Supports explicit allowAlwaysPersistenceKind for paths that carry it, and infers from ask for paths that don't. Closes openclaw#97069
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Add production-shaped tests for getAllowAlwaysUnavailableReason through the reply path: explicit one-shot kind and ask=always policy override.
|
@clawsweeper re-review Addressed P1: added shared |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |




What Problem This Solves
When a command includes shell redirection (e.g.
openclaw --version 2>&1), Allow Always is excluded because the command is one-shot. But the approval prompt shows "The effective approval policy requires approval every time" — falsely blaming the policy when the real reason is the command itself.Root Cause
Two approval renderers (
exec-approval-reply.ts,exec-approval-forwarder.ts) checkif (!allowedDecisions.includes("allow-always"))and always output the same policy message, regardless of whether allow-always is excluded due toask=alwaysorkind=one-shot.Fix
Use the
askfield (already available in both renderers' params) to distinguish:ask=always→ policy message (unchanged)ask→ one-shot message (new)askabsent → policy message (safe default)Closes #97069
Change Type
Scope
Evidence
Real production function proof (
node --import tsx):Test coverage:
Security Impact