diff --git a/tools/agent-guard/src/agent_guard/__init__.py b/tools/agent-guard/src/agent_guard/__init__.py index 3f28dfb18..6cb62e0aa 100644 --- a/tools/agent-guard/src/agent_guard/__init__.py +++ b/tools/agent-guard/src/agent_guard/__init__.py @@ -113,8 +113,8 @@ class Segment: """One simple command from a (possibly compound) shell line. ``argv`` has leading ``NAME=value`` env assignments stripped into ``env``; - ``raw`` is the original text of the segment (used for substring scans that - survive heredocs, e.g. the Co-Authored-By trailer). + ``raw`` is a reconstruction of this segment's own tokens only (used for + substring scans that survive heredocs, e.g. the Co-Authored-By trailer). """ def __init__(self, tokens: list[str], raw: str) -> None: @@ -164,12 +164,12 @@ def split_segments(command: str) -> list[Segment]: for tok in tokens: if tok in SHELL_OPERATORS: if current: - segments.append(Segment(current, command)) + segments.append(Segment(current, shlex.join(current))) current = [] else: current.append(tok) if current: - segments.append(Segment(current, command)) + segments.append(Segment(current, shlex.join(current))) return segments diff --git a/tools/agent-guard/tests/test_guards.py b/tools/agent-guard/tests/test_guards.py index cb864a7ec..9ac485ebb 100644 --- a/tools/agent-guard/tests/test_guards.py +++ b/tools/agent-guard/tests/test_guards.py @@ -218,6 +218,13 @@ def test_compound_command_guarded(): assert dispatch('cd /tmp && git commit -m "x\nCo-Authored-By: a"') is not None +def test_compound_command_other_segment_not_denied(): + # The phrase lives in an unrelated earlier segment, not in the commit's + # own message, so the commit segment must not inherit it. + command = 'echo "note: never add a Co-Authored-By: trailer" && git commit -m "clean fix"' + assert dispatch(command) is None + + def test_malformed_command_allows(): assert dispatch('gh pr comment 5 --body "oops') is None