Skip to content

fix(tools): skip allowlist guard when tools are explicitly disabled#74139

Closed
SymbolStar wants to merge 1 commit into
openclaw:mainfrom
SymbolStar:fix/74019-llm-task-allowlist-guard
Closed

fix(tools): skip allowlist guard when tools are explicitly disabled#74139
SymbolStar wants to merge 1 commit into
openclaw:mainfrom
SymbolStar:fix/74019-llm-task-allowlist-guard

Conversation

@SymbolStar

Copy link
Copy Markdown
Contributor

Summary

When an embedded model run (e.g. llm-task invoked from a Lobster workflow) intentionally disables tools, the explicit tool allowlist guard from the parent session's tools.alsoAllow config should not fire.

Root Cause

buildEmptyExplicitToolAllowlistError in src/agents/tool-allowlist-guard.ts would see:

  • sources.length > 0 (from parent config's alsoAllow entries like lobster, llm-task)
  • callableToolNames.length === 0 (tools are intentionally disabled for the embedded run)

This combination triggered the error: "No callable tools remain after resolving explicit tool allowlist ... tools are disabled for this run".

Fix

Early-return null from the guard when disableTools === true, since disabling tools is an intentional choice that should not be treated as a configuration failure. Removed the now-unreachable disableTools branch from the error reason.

Fixes #74019

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS labels Apr 29, 2026
@greptile-apps

greptile-apps Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a false-positive error in buildEmptyExplicitToolAllowlistError that fired when an embedded run intentionally disabled tools while a parent session's alsoAllow config was populated. The fix is a clean early-return guard (disableTools === true → null) and removes the now-dead branch from the error-reason ternary. Tests are updated to assert null is returned instead of an error.

Confidence Score: 5/5

Safe to merge — the change is minimal, well-tested, and correct.

The fix is a two-line early return that precisely targets the described failure mode. All pre-existing test cases continue to pass, and the updated test correctly asserts the new null return. The dead disableTools branch removal from the ternary is consistent with the early return. No logic regressions identified.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(tools): skip allowlist guard when to..." | Re-trigger Greptile

@clawsweeper

clawsweeper Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR makes buildEmptyExplicitToolAllowlistError return null whenever disableTools is true and updates the guard test to expect no error for that disabled-tool case.

Reproducibility: yes. source-level. A direct guard call with inherited allowlist sources, zero callable tools, and disableTools: true reproduces the reported false positive; the same call shape with runtime toolsAllow demonstrates the PR regression against current main's test contract.

Next step before merge
The remaining repair is narrow and automatable: preserve the runtime conflict contract, add the disabled inherited-source case, and add the required changelog entry.

Security
Cleared: The diff does not touch CI, dependencies, lockfiles, secrets, install scripts, or publishing surfaces; the fail-closed policy regression is covered as a functional review finding.

Review findings

  • [P2] Preserve runtime allowlist conflicts — src/agents/tool-allowlist-guard.ts:23-24
  • [P3] Add the changelog entry — src/agents/tool-allowlist-guard.ts:23-24
Review details

Best possible solution:

Keep this PR open but repair it so disabled LLM-only runs ignore inherited allowlist sources while runtime toolsAllow plus disabled tools continues to error and stays covered by a test.

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

Yes, source-level. A direct guard call with inherited allowlist sources, zero callable tools, and disableTools: true reproduces the reported false positive; the same call shape with runtime toolsAllow demonstrates the PR regression against current main's test contract.

Is this the best way to solve the issue?

No. The fix direction is right, but returning null for every disabled-tool run is broader than the bug; the safer fix should distinguish inherited ambient allowlists from explicit runtime toolsAllow.

Full review comments:

  • [P2] Preserve runtime allowlist conflicts — src/agents/tool-allowlist-guard.ts:23-24
    Returning null before checking the allowlist source suppresses the existing runtime toolsAllow conflict case. A caller that passes toolsAllow while also disabling tools would now silently run with no tools instead of getting the fail-closed error covered by current main's test, so narrow the bypass to inherited config/profile allowlists or otherwise keep runtime toolsAllow plus disableTools erroring.
    Confidence: 0.9
  • [P3] Add the changelog entry — src/agents/tool-allowlist-guard.ts:23-24
    This is a user-facing bug fix for Lobster/llm-task disabled-tool runs, but the PR only changes the guard and its test. Add a CHANGELOG.md fix entry under the active version before merge.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.9

Acceptance criteria:

  • pnpm test src/agents/tool-allowlist-guard.test.ts
  • pnpm check:changed

What I checked:

Likely related people:

  • steipete: Commit history for src/agents/tool-allowlist-guard.ts shows 61ee67ae introduced the empty explicit allowlist guard, b97a6f28 later maintained the helper, and llm-task history also shows related plugin-runtime work. (role: introduced behavior and recent maintainer; confidence: high; commits: 61ee67aecc3f, b97a6f284904, 67a447c17530; files: src/agents/tool-allowlist-guard.ts, src/agents/tool-allowlist-guard.test.ts, extensions/llm-task/src/llm-task-tool.ts)
  • obviyus: Recent embedded-runner history includes 02d7ad48 for plugin-only tool allowlists, adjacent to the callable-tool filtering and allowlist resolution path involved here. (role: adjacent owner; confidence: medium; commits: 02d7ad482083; files: src/agents/pi-embedded-runner/run/attempt.ts)
  • pashpashpash: Current-main blame and GitHub history show 8f4eaa9c recently touched the guard, guard test, embedded runner, llm-task, and heartbeat files while working near disabled-tool heartbeat behavior. (role: recent maintainer; confidence: medium; commits: 8f4eaa9c00be; files: src/agents/tool-allowlist-guard.ts, src/agents/tool-allowlist-guard.test.ts, src/agents/pi-embedded-runner/run/attempt.ts)

Remaining risk / open question:

  • A broad disableTools bypass would make caller-level runtime toolsAllow plus disabled-tools contradictions silently proceed as no-tool runs.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 5ecd01ff94d6.

When an embedded model run (e.g. llm-task from a Lobster workflow)
intentionally disables tools, the explicit tool allowlist guard from the
parent session's alsoAllow config should not fire. Previously it would
error with 'No callable tools remain' because the allowlist sources
existed but no tools were callable (by design).

Return null early from buildEmptyExplicitToolAllowlistError when
disableTools is true, since disabling tools is an intentional choice
that should not be treated as a configuration failure.

Fixes openclaw#74019
@steipete

steipete commented May 3, 2026

Copy link
Copy Markdown
Contributor

Closing as superseded by #76686, which landed as 3491060 and closed #74019. The landed fix keeps the narrower source distinction: inherited config allowlists are ignored for intentional no-tool runs while runtime toolsAllow still fails closed.

@steipete steipete closed this May 3, 2026
@SymbolStar

Copy link
Copy Markdown
Contributor Author

Hi @steipete — friendly ping 🙏 CI is green now (rebased on latest main). Would appreciate a look when you get a chance!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Lobster workflow calling llm-task fails with “No callable tools remain” when tools.alsoAllow includes lobster/llm-task

2 participants