fix(hosthooks): source delete operands from the raw command, not the redacted target - #692
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The host-hook delete guard (blast-radius preview + post-approval TOCTOU recheck, shipped in v0.18.7 for #649/#665) silently does not run when the delete's path is long enough to be redacted.
_delete_operandsreadaction.target, which is the post-redaction string.normalize._redact_valuereplaces any value carrying a 40+ character unbroken[A-Za-z0-9+/_-]run with<redacted>— and/is in that class, so any ordinary nested absolute path qualifies. The operand source then became<redacted>,_delete_operandsreturned(None, False), andresolve_auth_resultskipped both the preview and the recheck. Reproduced on v0.18.7:The proxy path never had this bug (
executor.pybuilds operands from the raw tool arguments viacommand_line_from_arguments). The host-hook port regressed the source.Fix
argumentsthroughresolve_auth/resolve_auth_result/_delete_operands; build the command with the samecommand_line_from_argumentsthe proxy uses, so the operand source is never the redacted string.tool_inputat all three live call sites:claude_code.py,codex.py,cursor.py.openclaw.pydoes not callresolve_auth_result(it delegates to OpenClaw's own approve flow), so it is untouched — tracked separately.raise-only: no decision that was denied before can now be allowed.
Verification
ruff check,ruff format --check,lint-imports: green. (command_line_from_argumentscomes from the sameengine.rules.commandsmodule already imported here, so no new import contract.)tests/unit/test_hosthook_delete_recheck.py+tests/unit/test_hosthook_claude_cursor_compat.py: 36 passed. New tests cover a 60-char redacted path with raw args (real operands recovered), the end-to-end challenge (preview computed, recheck runs), and the fail-closed no-args case (unknown effects, guard still runs).tests/unitsweep: one failure,test_benchmark_agentdojo_live— a local pyarrow/NumPy-2 ABI import error (_ARRAY_API not found), reproduces on the base commit and is unrelated to this change. GUI-prompter tests excluded locally (the separate nightly-red font-metric hang).