Scope tea-guard to real CLI invocations #30

Closed
opened 2026-08-10 12:31:24 +00:00 by claude · 1 comment
Collaborator

Summary

hooks/tea-guard.sh:92 считает командой CLI любую строку, где слово tea
стоит отдельным токеном, — включая текст внутри heredoc, кавычек и сообщения
коммита. В результате хук блокирует обычные bash-команды, которые ничего не
запускают, а лишь упоминают CLI: например git commit, чьё сообщение цитирует
вызов, который эта же правка и убирает.

Spec

hooks/tea-guard.sh:91-93

Steps to reproduce

  1. Внутри репозитория с закреплённым логином выполнить коммит, в теле
    сообщения которого слово стоит отдельным токеном:

    git add -A && git commit -F- <<'EOF'
    feat: close issues through a script
    
    Единственным способом сменить state был сырой вызов
    tea api -X PATCH ... repos/OWNER/REPO/issues/N
    EOF
    
  2. То же самое происходит на любой команде с таким токеном, ни одна из которых
    не запускает CLI:

    python3 skills/issue/scripts/issue_new.py --type bug \
        --title "Scope tea-guard to actual tea invocations"
    grep -rn " tea " docs/
    

Expected

Хук пропускает команду: git, python3 и grep — это не CLI, --login
им не нужен. Проверка должна смотреть на то, что реально исполняется —
первое слово команды и первые слова после ;, &&, ||, |, ( — а не на
любое вхождение токена в строку.

Actual

Команда блокируется с exit 2:

PreToolUse:Bash hook error: [${CLAUDE_PLUGIN_ROOT}/hooks/tea-guard.sh]:
tea-guard: BLOCKED — every `tea` command must include --login "$GITEA_LOGIN"
(the guard substitutes the operator-pinned login). Run /tea:auth if no login
is pinned.

Обойти это можно только переписав текст: положить сообщение коммита в файл и
звать git commit -F <файл>, или выбросить слово из заголовка issue. То есть
хук диктует, какие слова можно писать в прозе, — а сообщение коммита о правке,
которая убирает сырые вызовы, обязано их цитировать.

Причина в hooks/tea-guard.sh:92:

if not re.search(r'(^|[;&|(]|\s)tea(\s|$)', cmd):
    allow_passthrough()

re.search идёт по всей строке команды, а heredoc, кавычки и -m "…" для неё
неотличимы от кода. Ложное срабатывание безопасно в смысле идентичности (хук
блокирует, а не пропускает), но ломает рабочий процесс и не ловится глазами:
сообщение об ошибке говорит про --login, а виновата прозаическая строка.

Environment

  • macOS 25.5.0, tea 0.14.1, Python 3.14.5
  • claude-skills/tea, ветка feat/close-script
  • логин закреплён в .claude/settings.local.json

Acceptance criteria

  • git commit, чьё сообщение содержит слово отдельным токеном, проходит
    хук
  • python3 …/issue_new.py --title "… tea …" и grep -rn " tea " docs/
    проходят хук
  • реальный вызов CLI без --login по-прежнему блокируется, в том числе
    после ;, &&, ||, | и в подоболочке ( … )
  • реальный вызов с --login "$GITEA_LOGIN" по-прежнему переписывается на
    закреплённый логин
  • есть тест на регрессию: команда, которая только упоминает слово, и
    команда, которая его запускает, разводятся хуком по разным веткам
<!-- tea:id scope-tea-guard-to-real-cli-invocations --> ## Summary `hooks/tea-guard.sh:92` считает командой CLI любую строку, где слово `tea` стоит отдельным токеном, — включая текст внутри heredoc, кавычек и сообщения коммита. В результате хук блокирует обычные bash-команды, которые ничего не запускают, а лишь упоминают CLI: например `git commit`, чьё сообщение цитирует вызов, который эта же правка и убирает. ## Spec hooks/tea-guard.sh:91-93 ## Steps to reproduce 1. Внутри репозитория с закреплённым логином выполнить коммит, в теле сообщения которого слово стоит отдельным токеном: ```bash git add -A && git commit -F- <<'EOF' feat: close issues through a script Единственным способом сменить state был сырой вызов tea api -X PATCH ... repos/OWNER/REPO/issues/N EOF ``` 2. То же самое происходит на любой команде с таким токеном, ни одна из которых не запускает CLI: ```bash python3 skills/issue/scripts/issue_new.py --type bug \ --title "Scope tea-guard to actual tea invocations" grep -rn " tea " docs/ ``` ## Expected Хук пропускает команду: `git`, `python3` и `grep` — это не CLI, `--login` им не нужен. Проверка должна смотреть на то, что реально исполняется — первое слово команды и первые слова после `;`, `&&`, `||`, `|`, `(` — а не на любое вхождение токена в строку. ## Actual Команда блокируется с exit 2: ``` PreToolUse:Bash hook error: [${CLAUDE_PLUGIN_ROOT}/hooks/tea-guard.sh]: tea-guard: BLOCKED — every `tea` command must include --login "$GITEA_LOGIN" (the guard substitutes the operator-pinned login). Run /tea:auth if no login is pinned. ``` Обойти это можно только переписав текст: положить сообщение коммита в файл и звать `git commit -F <файл>`, или выбросить слово из заголовка issue. То есть хук диктует, какие слова можно писать в прозе, — а сообщение коммита о правке, которая убирает сырые вызовы, обязано их цитировать. Причина в `hooks/tea-guard.sh:92`: ```python if not re.search(r'(^|[;&|(]|\s)tea(\s|$)', cmd): allow_passthrough() ``` `re.search` идёт по всей строке команды, а heredoc, кавычки и `-m "…"` для неё неотличимы от кода. Ложное срабатывание безопасно в смысле идентичности (хук блокирует, а не пропускает), но ломает рабочий процесс и не ловится глазами: сообщение об ошибке говорит про `--login`, а виновата прозаическая строка. ## Environment - macOS 25.5.0, `tea` 0.14.1, Python 3.14.5 - claude-skills/tea, ветка `feat/close-script` - логин закреплён в `.claude/settings.local.json` ## Acceptance criteria - [ ] `git commit`, чьё сообщение содержит слово отдельным токеном, проходит хук - [ ] `python3 …/issue_new.py --title "… tea …"` и `grep -rn " tea " docs/` проходят хук - [ ] реальный вызов CLI без `--login` по-прежнему блокируется, в том числе после `;`, `&&`, `||`, `|` и в подоболочке `( … )` - [ ] реальный вызов с `--login "$GITEA_LOGIN"` по-прежнему переписывается на закреплённый логин - [ ] есть тест на регрессию: команда, которая только упоминает слово, и команда, которая его запускает, разводятся хуком по разным веткам
claude added this to the Self-improvement milestone 2026-08-10 12:31:24 +00:00
claude added the
severity
medium
type
bug
comp/hooks
labels 2026-08-10 12:31:24 +00:00
naudachu added the comp/tea-guard label 2026-08-10 12:38:07 +00:00
Author
Collaborator

Дубликат #29 — закрываю в его пользу.

Ложное срабатывание гварда поймали три независимых агента на трёх разных
командах, поэтому каноническая issue собирает все четыре случая в одни Steps to
reproduce — заголовок issue, git commit -F- с heredoc, git commit -m,
grep/echo — чтобы тест на регрессию покрыл их разом, а не по одному.

Уникальные вклады этой issue перенесены в #29 целиком:

  • случай с heredoc: сообщение коммита правки, которая сырые вызовы и убирает,
    обязано их цитировать;
  • grep -rn " tea " docs/ как третий класс ложного срабатывания;
  • формулировка «проверять первое слово команды и первые слова после ;, &&,
    ||, |, (» — она и стала критерием посегментного разбора;
  • критерий «настоящий вызов блокируется в том числе в подоболочке ( … )»;
  • наблюдение, что обойти можно только переписав человеческий текст под детектор.

Расхождение в номере строки (:88 против :92) отмечено в #29 — это одна и та
же проверка на разных ветках.

Дубликат #29 — закрываю в его пользу. Ложное срабатывание гварда поймали три независимых агента на трёх разных командах, поэтому каноническая issue собирает все четыре случая в одни Steps to reproduce — заголовок issue, `git commit -F-` с heredoc, `git commit -m`, `grep`/`echo` — чтобы тест на регрессию покрыл их разом, а не по одному. Уникальные вклады этой issue перенесены в #29 целиком: - случай с heredoc: сообщение коммита правки, которая сырые вызовы и убирает, обязано их цитировать; - `grep -rn " tea " docs/` как третий класс ложного срабатывания; - формулировка «проверять первое слово команды и первые слова после `;`, `&&`, `||`, `|`, `(`» — она и стала критерием посегментного разбора; - критерий «настоящий вызов блокируется в том числе в подоболочке `( … )`»; - наблюдение, что обойти можно только переписав человеческий текст под детектор. Расхождение в номере строки (`:88` против `:92`) отмечено в #29 — это одна и та же проверка на разных ветках.
Sign in to join this conversation.