refactor(env): inject hook-handler env via capability traits#458
Open
akesling wants to merge 11 commits into
Open
refactor(env): inject hook-handler env via capability traits#458akesling wants to merge 11 commits into
akesling wants to merge 11 commits into
Conversation
858263c to
f149616
Compare
Plan for migrating handle_session_start, the PreToolUse path, and the PostToolUse path off direct env access (filesystem, sandbox probe, session bookkeeping) onto three capability traits — PolicyStore, SessionRecorder, SandboxProbe — bundled in an Env<'a> struct. Tests substitute an in-memory Env; production constructs Env::prod() at the hook command dispatcher. A clippy.toml at the repo root locks in the boundary by denying direct calls to every wrapped function outside of clash/src/env.rs (the only adapter module). Replaces the earlier single-handler `SessionStartEnv` design with one shared trait vocabulary across all three hook entry points, plus enforcement to keep new handlers from drifting back to direct calls.
f149616 to
1bf36c3
Compare
Repo-root clippy.toml lists every function wrapped by clash::env so that
new handler code can't accidentally bypass the trait layer. env.rs is
the lone module exempt (top-level `#![allow(clippy::disallowed_methods)]`).
Two legitimate-bypass categories are explicitly annotated:
- CLI commands (doctor, session, trace, sandbox_cmd, shell_cmd) that
are not on the hook handler path and have no testability target;
each callsite carries a single-line `#[allow]` plus rationale.
- In-module tests in audit/trace/session_policy that exercise the
very functions the module defines; each module carries a
`#![cfg_attr(test, allow(clippy::disallowed_methods))]` at the top.
Also migrates the Stop hook subcommand to route trace::sync_trace
through Env::prod for consistency with the other three hook arms.
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.
Summary
Routes the four hook entry points (
handle_session_start,PreToolUse,PostToolUse,Stop) through a smallEnvstruct that bundles three capability traits:PolicyStore,SessionRecorder,SandboxProbe. Production wiresEnv::prod()from zero-sized static impls that delegate to the existing free functions; tests construct a hermeticTestEnvwhose session writes land in aTempDirand whose sandbox probe returns cannedFull. The exact samehandle_*code runs in tests as in production — only the env differs.A repo-root
clippy.tomldenies direct calls to every wrapped function so the abstraction doesn't decay.clash/src/env.rsis the lone module exempt (top-level#![allow(clippy::disallowed_methods)]); CLI commands that legitimately bypassEnv(e.g.clash doctor --sandbox) annotate their callsite with a per-site allow + rationale.Commits
Test plan
cargo test --package clash --lib— 392 tests passingcargo clippy --package clash --all-targets— zerodisallowed_methodsviolationshandlers::tests::test_session_start_reports_*— all three pass against the samehandle_session_startproduction runs, viaTestEnv, on a machine with a legacy~/.clash/policy.json(previously panicked)TestEnv::newwrites confined to aTempDir(asserted inenv::tests::test_env_is_hermetic)Out of scope (explicit non-goals)
handle_permission_requestmigration — needs aNotifiertrait for desktop + Zulip; no current test asks for it.Clock,Random,Stdio,HttpClient,Subprocessports — no tests assert on these.clash-core/clash-adapters/clash-bin) — the lint guardrail gives most of the same enforcement without the disruption.Plan document
The implementation follows
docs/superpowers/plans/2026-05-13-hook-handler-env-injection.md, which is committed in this PR as the first commit for traceability.