Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,8 @@ def _open_guard(tool_name, args, session_id, turn_id):
cmd = str((args or {}).get("command") or "")
if not CARD_OPEN_RX.search(cmd) or PROBE_TITLE_RX.search(cmd):
return None
if _is_crew_turn(session_id, turn_id):
# A role process may open a card here too, as it may through crew_plan above and kanban_create.
if os.environ.get("HERMES_KANBAN_TASK") or _is_crew_turn(session_id, turn_id):
return None
return {"action": "block",
"message": "crew cards open only from the owner's /crew command. This session has no "
Expand Down
7 changes: 7 additions & 0 deletions tests/test_crew_tools_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ def test_a_terminal_card_open_is_still_refused_outside_a_crew_turn(self):
self.assertEqual("block", res["action"])
self.assertIn("crew_card.py open is refused", res["message"])

def test_a_terminal_card_open_with_a_kanban_task_is_allowed(self):
# The same rule as crew_plan and kanban_create: a role process may open a card.
os.environ["HERMES_KANBAN_TASK"] = "t_x"
cmd = 'sh "$HERMES_HOME/plugins/crew/scripts/crew-run.sh" crew_card.py open --title X'
with mock.patch.object(P, "_card_budget", lambda c: 0):
self.assertIsNone(self.guard("terminal", {"command": cmd}, role="worker"))

def test_verifier_cannot_plan_but_can_verdict(self):
os.environ["HERMES_KANBAN_TASK"] = "t_x"
with mock.patch.object(P, "_card_budget", lambda c: 0), mock.patch.object(P, "_verdict_fails", lambda c: 0):
Expand Down
Loading