Skip to content

feat(core): implement native support for blocking hook execution via policy files#20430

Open
h30s wants to merge 2 commits intogoogle-gemini:mainfrom
h30s:feat/hook-policy-support
Open

feat(core): implement native support for blocking hook execution via policy files#20430
h30s wants to merge 2 commits intogoogle-gemini:mainfrom
h30s:feat/hook-policy-support

Conversation

@h30s
Copy link
Contributor

@h30s h30s commented Feb 26, 2026

Summary

Implemented native support for blocking the execution of hooks using policy files (.toml). Previously, hooks were unintentionally subjected to policy checks by routing their execution through the message bus as run_shell_command tools. This PR introduces explicit [[hook_rule]] configurations in policy files to enforce whether a hook is allowed or denied without relying on the message bus.

Details

  • Introduced HookRule to PolicyEngineConfig.
  • Added HookRuleSchema in toml-loader.ts to parse [[hook_rule]] items from .toml files.
  • Added checkHook to PolicyEngine prioritizing matching rules for eventName, hookName, and commandPattern.
  • Modified HookEventHandler's executeHooks to filter out denied hooks and appropriately log decisions without invoking hookRunner.
  • ASK_USER decisions uniformly downgraded to DENY due to headless hook invocation.

Related Issues

Fixes: #17406

How to Validate

  1. Define a [[hook_rule]] in ~/.gemini/policies/project.toml with decision = "deny" for eventName = "BeforeTool".
  2. Trigger a hook and verify standard output logs its blockage properly.
  3. Test suite can be validated with npm run test -- -w @google/gemini-cli-core.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@h30s h30s requested a review from a team as a code owner February 26, 2026 12:48
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @h30s, 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 significantly enhances the security and control mechanisms within the system by introducing explicit policy enforcement for hooks. Instead of relying on an indirect message bus route for policy checks, a dedicated [[hook_rule]] structure in TOML files now allows for granular control over hook execution. This change provides a more direct and robust way to manage which hooks are permitted to run, improving overall system integrity and predictability.

Highlights

  • Native Hook Policy Support: Implemented native support for blocking the execution of hooks using policy files (.toml), moving away from indirect policy checks via the message bus.
  • New Policy Configuration: Introduced [[hook_rule]] configurations in policy files, allowing explicit definition of rules for allowing or denying hooks based on eventName, hookName, and commandPattern.
  • Policy Engine Integration: The PolicyEngine now includes a checkHook method to evaluate hook configurations against defined hook_rule policies.
  • Hook Execution Filtering: The HookEventHandler has been modified to filter out hooks that are denied by policy, logging the decision without invoking the hook runner.
  • Headless Hook Decision Handling: Any ASK_USER policy decisions for hooks are uniformly downgraded to DENY due to the headless nature of hook invocation.
Changelog
  • packages/core/src/hooks/hookEventHandler.test.ts
    • Updated tests to mock the getPolicyEngine and its checkHook method for policy evaluation.
  • packages/core/src/hooks/hookEventHandler.ts
    • Imported HookOutput and PolicyDecision types to support policy integration.
    • Added logic to filter hookConfigs based on decisions from the PolicyEngine's checkHook method.
    • Modified hook event emission to account for hooks denied by policy, ensuring proper logging and aggregation of results.
  • packages/core/src/hooks/hookSystem.test.ts
    • Updated mock configuration for integration tests to include getPolicyEngine.
  • packages/core/src/hooks/runtimeHooks.test.ts
    • Modified runtime hook tests to include mocking for getPolicyEngine.
  • packages/core/src/policy/config.test.ts
    • Updated policy configuration tests to include hookRules in the mock policy loading result.
  • packages/core/src/policy/config.ts
    • Imported the HookRule type.
    • Added hookRules to the PolicyEngineConfig creation process.
    • Initialized hookRules from the TOML loading result.
  • packages/core/src/policy/policy-engine.test.ts
    • Added a new test suite for the checkHook method, covering various scenarios for matching hook rules by eventName, hookName, and commandPattern.
    • Included tests for default decision fallback and the conversion of ASK_USER decisions to DENY for headless hooks.
  • packages/core/src/policy/policy-engine.ts
    • Imported the HookRule type.
    • Added a hookRules private property to the PolicyEngine class.
    • Initialized hookRules in the constructor, sorting them by priority.
    • Implemented the asynchronous checkHook method to evaluate a given hook configuration against the configured hookRules, applying priority and converting ASK_USER to DENY.
  • packages/core/src/policy/toml-loader.test.ts
    • Added tests for parsing [[hook_rule]] configurations from TOML files, including hookName, eventName, commandPrefix, commandRegex, decision, priority, and deny_message.
  • packages/core/src/policy/toml-loader.ts
    • Imported HookRule type and escapeRegex utility.
    • Defined HookRuleSchema for validating [[hook_rule]] entries in TOML files.
    • Added hook_rule to the PolicyFileSchema to allow parsing of hook policy sections.
    • Updated PolicyLoadResult interface to include hookRules.
    • Implemented logic within loadPoliciesFromToml to parse, validate, and transform [[hook_rule]] entries, converting commandPrefix and commandRegex into RegExp objects.
  • packages/core/src/policy/types.ts
    • Defined the HookRule interface, specifying properties such as hookName, eventName, commandPattern, decision, priority, source, and denyMessage.
    • Added an optional hookRules property to the PolicyEngineConfig interface.
Activity
  • The pull request introduces a new feature to implement native support for blocking hook execution via policy files.
  • The author has provided a comprehensive summary of the changes and details of the implementation.
  • Instructions for validating the changes, including defining a [[hook_rule]] and triggering a hook, have been provided.
  • The author has confirmed that relevant documentation and README have been updated.
  • The author has confirmed that tests have been added/updated.
  • The author has validated the changes on Linux using npm run.
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.

@gemini-cli gemini-cli bot added priority/p3 Backlog - a good idea but not currently a priority. area/core Issues related to User Interface, OS Support, Core Functionality area/enterprise Issues related to Telemetry, Policy, Quota / Licensing labels Feb 26, 2026
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces native support for blocking hook execution via policy files, enhancing security and control. While the implementation in HookEventHandler and PolicyEngine is generally robust, correctly handling denied hooks, updating UI state, and following a 'fail-secure' principle, a critical logic flaw was identified. Specifically, the checkHook method in PolicyEngine incorrectly matches rules with a commandPattern to hooks lacking a command property (e.g., runtime hooks), which could lead to unintended authorization decisions. Furthermore, a high-severity issue exists in toml-loader.ts where the argsPattern for hook rules is inconsistent with tool rules, potentially causing user confusion.

Comment on lines 812 to 816
if (rule.commandPattern && hookConfig.command) {
if (!rule.commandPattern.test(hookConfig.command)) {
continue;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

The checkHook method contains a logic flaw in how it matches rules with a commandPattern. If a rule specifies a commandPattern, but the hook being checked does not have a command property (which is the case for RuntimeHook types), the matching logic skips the pattern check and incorrectly considers the rule a match. This happens because the condition if (rule.commandPattern && hookConfig.command) evaluates to false when hookConfig.command is missing, bypassing the continue statement that would otherwise signal a non-match.

This flaw can lead to unintended authorization decisions. For example, a rule intended to allow only specific shell commands (e.g., [[hook_rule]] commandPrefix = "git" decision = "allow") would unintentionally allow ALL runtime hooks for the same event, as they lack a command property. Conversely, a restrictive rule could block more than intended.

To fix this, ensure that if a rule specifies a commandPattern, it only matches hooks that have a command property and where that property matches the pattern.

Suggested change
if (rule.commandPattern && hookConfig.command) {
if (!rule.commandPattern.test(hookConfig.command)) {
continue;
}
}
if (rule.commandPattern) {
if (!hookConfig.command || !rule.commandPattern.test(hookConfig.command)) {
continue;
}
}

Comment on lines 61 to 63
commandPrefix: z.union([z.string(), z.array(z.string())]).optional(),
commandRegex: z.string().optional(),
argsPattern: z.string().optional(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The use of commandRegex and argsPattern here is confusing and inconsistent with how argsPattern is used for tool rules ([[rule]]). For tool rules, argsPattern matches against the JSON-stringified arguments. For hook rules, both commandRegex and argsPattern are being used to match against the hook's command string, as the checkHook method in PolicyEngine does not have access to hook arguments.

This creates an inconsistent and misleading API for users writing policy files. They might expect argsPattern to match against the hook's input payload, which is not the case.

To improve clarity and consistency, I recommend consolidating these fields. A good approach would be to:

  1. Deprecate commandRegex and argsPattern for [[hook_rule]].
  2. Introduce a single, clearly named field like commandPattern for regex matching against the hook's command string.

This would make the policy file schema for hooks less ambiguous.

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

Labels

area/core Issues related to User Interface, OS Support, Core Functionality area/enterprise Issues related to Telemetry, Policy, Quota / Licensing priority/p3 Backlog - a good idea but not currently a priority.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hook support in Policy files

1 participant