openclaw - ✅(Solved) Fix [Bug]: toolsAllow cannot re-expose core tools in embedded cron runs [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#60841Fetched 2026-04-08 02:46:36
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

When an embedded run sets toolsAllow: ["exec"], the run still cannot access exec if an upstream config allowlist already filtered it out, such as tools.allow: ["group:openclaw"].

Root Cause

Observed evidence

  • Local config: ~/.openclaw/openclaw.json had tools.allow: ["group:openclaw"].
  • Session prompt reports for affected runs omitted exec, read, and write from systemPromptReport.tools.entries.
  • A regression test failed before the fix in src/agents/pi-tools-agent-config.test.ts when forceAllowTools: ["exec", "read", "write"] was ignored under group:openclaw.
  • A forwarding test failed before the fix in src/agents/pi-embedded-runner/run/attempt.memory-flush-forwarding.test.ts because runEmbeddedAttempt did not pass toolsAllow into createOpenClawCodingTools.

Fix Action

Fixed

PR fix notes

PR #60842: fix(agents): re-expose toolsAllow core tools in embedded runs

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: embedded runs only post-filtered toolsAllow after createOpenClawCodingTools, so restrictive config allowlists could remove exec/read/write before toolsAllow had any effect.
  • Why it matters: cron/isolated runs with toolsAllow: ["exec"] still lost exec under configs like tools.allow: ["group:openclaw"], breaking workflows that depended on explicit per-run tool exposure.
  • What changed: runEmbeddedAttempt now forwards toolsAllow into createOpenClawCodingTools, and the tool policy merge re-exposes explicitly requested core tools through restrictive config allowlists without overriding deny.
  • What did NOT change (scope boundary): this does not bypass explicit deny, sandbox/group/subagent tool policies, or provider/runtime capability gating.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #60841
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: runEmbeddedAttempt only did a final .filter() against toolsAllow, but createOpenClawCodingTools had already applied config-driven allowlists. Once the policy pipeline filtered a core tool out, the later post-filter could not re-add it.
  • Missing detection / guardrail: there was no regression test covering toolsAllow under a restrictive config allowlist such as group:openclaw.
  • Contributing context (if known): group:openclaw intentionally excludes exec, process, read, write, and edit, so the bug is deterministic under configs that rely on that group and then expect toolsAllow to re-expose a core tool for a specific run.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/pi-tools-agent-config.test.ts, src/agents/pi-embedded-runner/run/attempt.memory-flush-forwarding.test.ts
  • Scenario the test should lock in: restrictive config allowlists still permit explicitly requested core tools for that embedded run, while explicit deny continues to win.
  • Why this is the smallest reliable guardrail: one test pins the effective tool inventory after policy application, and the other pins the runEmbeddedAttempt -> createOpenClawCodingTools forwarding seam.
  • Existing test that already covers this (if any): None.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Embedded runs that set toolsAllow can now re-expose the requested core tools (exec, read, write, etc.) even when a restrictive config allowlist would otherwise hide them. Explicit deny still wins.

Diagram (if applicable)

Before:
[embedded run with toolsAllow=[exec]] -> [createOpenClawCodingTools applies config allowlist] -> [exec removed] -> [post-filter keeps missing set] -> [cron run still has no exec]

After:
[embedded run with toolsAllow=[exec]] -> [forceAllowTools merged into restrictive config allowlists] -> [exec survives policy pipeline unless denied] -> [post-filter selects exec] -> [cron run gets exec]

Security Impact (required)

  • New permissions/capabilities? Yes
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? Yes
  • Data access scope changed? Yes
  • If any Yes, explain risk + mitigation: The PR allows an embedded run to re-expose explicitly requested core tools through restrictive config allowlists. Mitigation: the re-exposure is limited to named core tools for that run, explicit deny still wins, and sandbox/group/subagent/provider/runtime restrictions still apply.

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local source checkout
  • Model/provider: policy regression is model-agnostic; forwarding seam verified with openai/gpt-5.4
  • Integration/channel (if any): embedded runner / cron-style tool exposure
  • Relevant config (redacted): tools.profile: "full", tools.allow: ["group:openclaw"]

Steps

  1. Configure a restrictive core-tool allowlist such as tools.allow: ["group:openclaw"].
  2. Run an embedded attempt with toolsAllow: ["exec"].
  3. Inspect the effective tool set.

Expected

  • The effective tool set contains exec for that run unless a stronger deny/runtime restriction blocks it.

Actual

  • Before this fix, exec was missing because it had already been filtered out before toolsAllow was applied.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: targeted regression tests for restrictive allowlist re-exposure and explicit-deny precedence; full attempt.memory-flush-forwarding test file; pnpm check; pnpm build.
  • Edge cases checked: allow-all semantics are preserved, explicit deny still blocks forced tools, and only known core tool ids are re-exposed.
  • What you did not verify: I did not run a live end-to-end cron job against a local gateway build from this branch.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No
  • If yes, exact upgrade steps:

Risks and Mitigations

  • Risk: a per-run toolsAllow request could unintentionally widen a restrictive config allowlist too broadly.
    • Mitigation: the merge only applies to explicitly requested known core tools, and allow-all / deny semantics are preserved.

Changed files

  • src/agents/pi-embedded-runner/run/attempt.memory-flush-forwarding.test.ts (modified, +39/-0)
  • src/agents/pi-embedded-runner/run/attempt.ts (modified, +1/-0)
  • src/agents/pi-tools-agent-config.test.ts (modified, +38/-1)
  • src/agents/pi-tools.ts (modified, +43/-16)
  • src/agents/tool-policy.ts (modified, +13/-0)
RAW_BUFFERClick to expand / collapse

Summary

When an embedded run sets toolsAllow: ["exec"], the run still cannot access exec if an upstream config allowlist already filtered it out, such as tools.allow: ["group:openclaw"].

Steps to reproduce

  1. Configure OpenClaw with tools.profile: "full" and tools.allow: ["group:openclaw"].
  2. Start an embedded/isolated run with toolsAllow: ["exec"].
  3. Observe the generated tool inventory and session transcript.

Expected behavior

toolsAllow should re-expose the explicitly requested core tool for that run, unless a stronger deny or runtime/provider restriction blocks it.

Actual behavior

The run receives a tool list without exec, read, or write, so cron/isolated sessions that explicitly request exec still fail before tool execution begins.

Observed evidence

  • Local config: ~/.openclaw/openclaw.json had tools.allow: ["group:openclaw"].
  • Session prompt reports for affected runs omitted exec, read, and write from systemPromptReport.tools.entries.
  • A regression test failed before the fix in src/agents/pi-tools-agent-config.test.ts when forceAllowTools: ["exec", "read", "write"] was ignored under group:openclaw.
  • A forwarding test failed before the fix in src/agents/pi-embedded-runner/run/attempt.memory-flush-forwarding.test.ts because runEmbeddedAttempt did not pass toolsAllow into createOpenClawCodingTools.

Impact and severity

  • Affected surface: embedded cron/isolated runs that depend on toolsAllow to request core tools.
  • Severity: high for those workflows, because the requested tool never becomes callable.
  • Frequency: deterministic under the reproduced config.
  • Consequence: cron jobs that expect exec fail even when safeBins and command policy are otherwise configured correctly.

Additional information

Root cause in code: runEmbeddedAttempt only post-filtered the tool array by toolsAllow, but createOpenClawCodingTools had already applied restrictive config allowlists, and the pipeline only filters downward, never re-adds tools.

extent analysis

TL;DR

Modify the runEmbeddedAttempt function to pre-filter or merge the toolsAllow list with the upstream config allowlist before passing it to createOpenClawCodingTools.

Guidance

  • Review the runEmbeddedAttempt function to ensure it correctly handles the toolsAllow parameter and merges it with the upstream config allowlist.
  • Verify that the createOpenClawCodingTools function is called with the updated tool list that includes the explicitly requested core tools.
  • Check the tools.profile configuration to ensure it is set to a value that allows the requested tools, such as "full".
  • Test the modified code with the provided regression test in src/agents/pi-tools-agent-config.test.ts to ensure the fix is correct.

Example

// Example of how to merge toolsAllow with upstream config allowlist
const mergedToolsAllow = [...upstreamConfigAllowlist, ...toolsAllow];
const codingTools = createOpenClawCodingTools(mergedToolsAllow);

Notes

The provided fix assumes that the runEmbeddedAttempt function has access to the upstream config allowlist. If this is not the case, additional modifications may be necessary to retrieve or pass the allowlist to the function.

Recommendation

Apply the workaround by modifying the runEmbeddedAttempt function to correctly handle the toolsAllow parameter and merge it with the upstream config allowlist. This will ensure that explicitly requested core tools are included in the tool list, even if they are filtered out by the upstream config allowlist.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

toolsAllow should re-expose the explicitly requested core tool for that run, unless a stronger deny or runtime/provider restriction blocks it.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING