Skip to content

Fix config rules not matching commands with global flags#137

Open
berk-karaal wants to merge 2 commits into
ldayton:mainfrom
berk-karaal:fix/config-match-global-flags
Open

Fix config rules not matching commands with global flags#137
berk-karaal wants to merge 2 commits into
ldayton:mainfrom
berk-karaal:fix/config-match-global-flags

Conversation

@berk-karaal

@berk-karaal berk-karaal commented Apr 5, 2026

Copy link
Copy Markdown

Summary

Fixes #136

Config rules like allow git commit fail to match commands with global flags such as git -C /path commit. This happens because the config matcher operates on raw tokens, where -C /path breaks the prefix match — even though Dippy displays the command as "git commit" when asking for permission (fixed in #17).

Approach: Two-Pass Config Matching

  • Step 1 (unchanged): Match raw tokens against config rules. This preserves explicit rules like deny git -C * commit.
  • Step 1.5 (new): If step 1 finds no match, strip global flags using handler-exported GLOBAL_FLAGS_WITH_ARG / GLOBAL_FLAGS_NO_ARG constants and re-match.

This ensures the config matcher recognizes the same command the user sees in the permission prompt.

Changes

  • src/dippy/cli/__init__.py: Added strip_global_flags() — reads global flag constants from handlers via getattr(), strips them from tokens, returns cleaned tokens or None if no change.
  • src/dippy/core/analyzer.py: Added step 1.5 between config matching and wrapper command handling. Extracted _config_match_decision() helper to deduplicate the match-to-decision conversion.

Test plan

  • Unit tests for strip_global_flags() covering git, docker, unknown commands, and edge cases (tests/test_strip_global_flags.py)
  • Integration tests via analyze() verifying end-to-end behavior including precedence of explicit flag rules (tests/test_analyzer_bugs.py::TestConfigGlobalFlagStripping)
  • Full test suite passes (10,922 tests)
  • just check passes

🤖 Generated with Claude Code

berk-karaal and others added 2 commits April 5, 2026 11:52
Config rules like "allow git commit" failed to match "git -C /path commit"
because _match_words() matched against raw tokens where global flags broke
the prefix match. Add a two-pass approach: step 1 matches raw tokens (preserving
explicit rules like "deny git -C * commit"), step 1.5 strips handler-recognized
global flags and re-matches if step 1 found nothing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ldayton

ldayton commented Jun 8, 2026

Copy link
Copy Markdown
Owner

The two-pass shape here is nice — matching raw tokens first means explicit rules like deny git -C * commit still win before the stripped fallback runs. The thing I want to work through before this lands is which flags strip_global_flags() removes.

It reuses each handler's full GLOBAL_FLAGS_WITH_ARG set, and those sets aren't all benign locators. For git that includes -c and --config-env; for docker, -H/--host and -c/--context. Those flags change what the command does or targets, not just where it runs. So after this change:

  • allow git commit also matches git -c core.sshCommand='…' commit (the -c payload runs a command)
  • allow docker ps matches docker -H tcp://other-host ps — which test_allow_docker_ps_with_H_flag currently asserts as desired

And because the description strips these flags too, the user never sees them in the prompt — so their allow git commit rule silently covers variants they didn't know about.

This bumps against the core philosophy in the security model — "approve what we know is safe; anything not explicitly safe requires approval." Matching on the stripped skeleton approves the command without ever examining the part that was removed. It's not only a malicious-injection concern either: docker -H tcp://prod ps or git --work-tree=/wrong commit are exactly the "ran it against the wrong thing" mistakes the model exists to catch.

I think the fix is to split the strippable set: flags that only relocate (-C, --git-dir, --work-tree) are safe to ignore for an allow decision, but behavior/target-changing flags (-c, --config-env, docker -H/--host/--context) shouldn't be transparently dropped. Could you curate strip_global_flags() to a known-safe subset rather than the handler's full set?

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.

Config rules don't match commands with global flags (e.g. git -C /path commit)

2 participants