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
35 changes: 6 additions & 29 deletions shared/egg_restrictions/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,13 @@
import posixpath
from dataclasses import dataclass, field

# Re-export the canonical AgentRole StrEnum from egg_contracts so the
# gateway sees a single source of truth — adding a role in egg_contracts
# is now automatically visible here, removing the silent-drift failure
# mode from #2066.
from egg_contracts.agent_roles import AgentRole

class AgentRole:
"""Agent role identifiers.

Note: Mirrors egg_contracts.agent_roles.AgentRole to avoid import
complexity in the gateway module. Values must be kept in sync.
"""

CODER = "coder"
TESTER = "tester"
DOCUMENTER = "documenter"
# Analysis roles
ARCHITECT = "architect"
TASK_PLANNER = "task_planner"
RISK_ANALYST = "risk_analyst"
REFINER = "refiner"
# Review roles
REVIEWER_CODE = "reviewer_code"
REVIEWER_CONTRACT = "reviewer_contract"
REVIEWER_AGENT_DESIGN = "reviewer_agent_design"
REVIEWER_REFINE = "reviewer_refine"
REVIEWER_PLAN = "reviewer_plan"
REVIEWER_SECURITY = "reviewer_security"
REVIEWER_CONCURRENCY = "reviewer_concurrency"
# Utility roles
AUTOFIXER = "autofixer"
CONFLICT_RESOLVER = "conflict_resolver"
# Interface roles
OVERSEER = "overseer"
INSPECTOR = "inspector"
__all__ = ["AGENT_PATTERNS", "AgentFilePattern", "AgentRole"]


@dataclass
Expand Down
2 changes: 1 addition & 1 deletion shared/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "egg-shared"
version = "0.1.0"
description = "Shared modules for egg (enrichment, logging, notifications, etc.)"
requires-python = ">=3.11"
dependencies = ["pyyaml>=6.0", "anthropic>=0.50,<1.0", "httpx>=0.25.0", "markdownify>=0.13.1"]
dependencies = ["pyyaml>=6.0", "anthropic>=0.50,<1.0", "httpx>=0.25.0", "markdownify>=0.13.1", "egg-contracts"]

[build-system]
requires = ["setuptools>=61.0"]
Expand Down
38 changes: 9 additions & 29 deletions tests/gateway/test_agent_restrictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,39 +25,19 @@


class TestAgentRoleConsistency:
"""Verify gateway AgentRole matches shared library AgentRole."""
"""Tripwire: gateway AgentRole must be the canonical egg_contracts enum.

def test_role_values_match_shared_library(self):
"""Gateway AgentRole values must match egg_contracts.agent_roles.AgentRole.

This test prevents subtle bugs from enum value drift between the two modules.
"""
from egg_contracts.agent_roles import AgentRole as SharedAgentRole
Issue #2066: replaced the per-package AgentRole duplicate with a
re-export so a new role added in egg_contracts is automatically
visible to the gateway. The identity assertion below catches anyone
re-introducing a parallel class or enum in egg_restrictions or the
gateway.
"""

# Verify all shared library roles exist in gateway with same values
for shared_role in SharedAgentRole:
assert hasattr(AgentRole, shared_role.name), (
f"Gateway AgentRole missing role: {shared_role.name}"
)
gateway_value = getattr(AgentRole, shared_role.name)
assert gateway_value == shared_role.value, (
f"Role value mismatch for {shared_role.name}: "
f"gateway={gateway_value}, shared={shared_role.value}"
)

def test_all_gateway_roles_in_shared_library(self):
"""All gateway roles must exist in the shared library."""
def test_gateway_agent_role_is_canonical(self):
from egg_contracts.agent_roles import AgentRole as SharedAgentRole

gateway_roles = {
AgentRole.CODER,
AgentRole.TESTER,
AgentRole.DOCUMENTER,
}
shared_values = {r.value for r in SharedAgentRole}

for role in gateway_roles:
assert role in shared_values, f"Gateway role '{role}' not found in shared library"
assert AgentRole is SharedAgentRole


class TestPathTraversalPrevention:
Expand Down
24 changes: 10 additions & 14 deletions tests/shared/egg_contracts/test_agent_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,23 +741,19 @@ def test_all_canonical_roles_in_types(self):


class TestRoleSyncWithGateway:
"""Verify gateway/agent_restrictions.py AgentRole stays in sync."""
"""Tripwire: the gateway must use the canonical AgentRole enum.

def test_all_canonical_roles_in_gateway(self):
"""Every canonical AgentRole should have a constant in gateway AgentRole."""
Issue #2066: gateway/agent_restrictions.py and
egg_restrictions.patterns now re-export this enum rather than
redefining it, eliminating the silent-drift failure mode that
PR #2061 surfaced. The identity check fails if anyone re-adds
a parallel class or enum in either module.
"""

def test_gateway_agent_role_is_canonical(self):
from agent_restrictions import AgentRole as GatewayAgentRole

canonical_values = {r.value for r in AgentRole}
# Gateway AgentRole is a plain class with string constants
gateway_values = {
v
for k, v in vars(GatewayAgentRole).items()
if not k.startswith("_") and isinstance(v, str)
}
missing = canonical_values - gateway_values
assert not missing, (
f"gateway/agent_restrictions.py AgentRole is missing constants: {missing}"
)
assert GatewayAgentRole is AgentRole


# ---------------------------------------------------------------------------
Expand Down
Loading