Skip to content

feat(adapter): support Endpoint implementation for Claude Code PreToolUse Hook#54

Merged
fohte merged 7 commits intomainfrom
fohte/impl-runok-init-hook-adapter
Feb 19, 2026
Merged

feat(adapter): support Endpoint implementation for Claude Code PreToolUse Hook#54
fohte merged 7 commits intomainfrom
fohte/impl-runok-init-hook-adapter

Conversation

@fohte
Copy link
Owner

@fohte fohte commented Feb 19, 2026

Why

  • Connect Claude Code PreToolUse Hook's stdin/stdout JSON protocol to the rule engine via the Endpoint trait

What

  • Add ClaudeCodeHookAdapter to translate between the Claude Code PreToolUse Hook JSON protocol and the Endpoint trait
    • Extract command only when tool_name == "Bash"; produce no output for other tools (outside runok's scope)
    • Rewrite command via updatedInput to runok exec --sandbox <preset> -- <cmd> on sandbox-enabled allow
    • Apply defaults.action and output hook response when no rule matches

Open with Devin

The Endpoint trait needed a concrete implementation to handle the
Claude Code PreToolUse Hook stdin/stdout protocol, translating between
hook JSON and the rule engine's Action types.

Implement ClaudeCodeHookAdapter with:
- extract_command: returns command only for tool_name == "Bash"
- handle_action: converts Action to HookOutput JSON (allow/deny/ask)
  with sandbox-aware command rewriting via updatedInput
- handle_no_match: applies defaults.action for Bash, outputs nothing
  for non-Bash tools
- handle_error: writes to stderr, exits with code 2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link

Summary of Changes

Hello @fohte, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request integrates the Claude Code PreToolUse Hook with the existing rule engine by implementing a new adapter. This adapter translates the hook's JSON protocol into a format compatible with the Endpoint trait, allowing the rule engine to process and respond to tool use requests. The primary impact is enabling the system to enforce policies and apply sandboxing to commands originating from Claude's code interpreter, enhancing security and control over executed actions.

Highlights

  • New Adapter for Claude Code PreToolUse Hook: Introduced ClaudeCodeHookAdapter to facilitate communication between the Claude Code PreToolUse Hook's stdin/stdout JSON protocol and the internal rule engine's Endpoint trait.
  • Conditional Command Extraction: Implemented logic to extract commands only when the tool_name is 'Bash', ensuring that other tools do not produce unexpected output.
  • Sandbox Command Rewriting: Added functionality to rewrite commands via updatedInput to runok exec --sandbox <preset> -- <cmd> when a sandbox-enabled 'allow' action is determined.
  • Default Action Handling: Configured the adapter to apply defaults.action and output the appropriate hook response when no specific rule matches the incoming request.
Changelog
  • src/adapter/hook_adapter.rs
    • Added ClaudeCodeHookAdapter struct and its associated methods.
    • Defined data structures (HookInput, BashToolInput, HookOutput, HookSpecificOutput, UpdatedInput) for JSON serialization/deserialization.
    • Implemented the Endpoint trait for ClaudeCodeHookAdapter, including extract_command, handle_action, handle_no_match, and handle_error.
    • Included comprehensive unit tests for all adapter functionalities, covering command extraction, action handling, no-match scenarios, and JSON (de)serialization.
  • src/adapter/mod.rs
    • Declared the new hook_adapter module as public.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

devin-ai-integration[bot]

This comment was marked as resolved.

gemini-code-assist[bot]

This comment was marked as resolved.

fohte and others added 2 commits February 20, 2026 00:08
…character bypass

Compound commands like `safe-cmd && dangerous-cmd` were passed
unquoted to `runok exec --sandbox`, causing the shell to interpret
`&&` before runok could enforce the sandbox. This meant the second
command would execute outside the sandbox.

Shell-quote the command with `shlex::try_quote` so the entire
compound command is passed as a single argument to `runok exec`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…put parsing

BashToolInput parsing via `serde_json::from_value(self.input.tool_input.clone())`
was repeated in three places: `build_action_output`, `build_no_match_output`,
and `extract_command`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

@codecov
Copy link

codecov bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 87.05036% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.27%. Comparing base (cb6dc15) to head (dd090aa).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/adapter/hook_adapter.rs 87.05% 18 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #54      +/-   ##
==========================================
- Coverage   90.33%   90.27%   -0.06%     
==========================================
  Files          20       21       +1     
  Lines        4315     4454     +139     
==========================================
+ Hits         3898     4021     +123     
- Misses        417      433      +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

fohte and others added 2 commits February 20, 2026 00:39
…d on quote failure

`wrap_with_sandbox` silently fell back to the raw unquoted command
when `shlex::try_quote` failed (on NUL bytes), which would bypass
sandbox protection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-hook-adapter

# Conflicts:
#	src/adapter/mod.rs
devin-ai-integration[bot]

This comment was marked as resolved.

fohte and others added 2 commits February 20, 2026 00:48
…th_sandbox

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Preset names come from user config files and could contain spaces or
special characters, so they need shell quoting just like the command
argument.
@fohte fohte merged commit 0c0eabf into main Feb 19, 2026
5 checks passed
@fohte fohte deleted the fohte/impl-runok-init-hook-adapter branch February 19, 2026 16:05
@fohte-bot fohte-bot bot mentioned this pull request Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant