Skip to content

Commit 415f0aa

Browse files
committed
Harden CybORG agent validation
1 parent 7fcc206 commit 415f0aa

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

codeclash/arenas/cyborg/cyborg.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ def validate_code(self, agent: Player) -> tuple[bool, str | None]:
6363
"assert hasattr(module, 'MyAgent'), 'MyAgent class not found'\n"
6464
"from CybORG.Agents import BaseAgent\n"
6565
"assert issubclass(module.MyAgent, BaseAgent), 'MyAgent must inherit from a CybORG BaseAgent class'\n"
66+
"def make_agent(agent_class, agent_name):\n"
67+
" try:\n"
68+
" return agent_class(name=agent_name)\n"
69+
" except TypeError:\n"
70+
" try:\n"
71+
" return agent_class(agent_name)\n"
72+
" except TypeError:\n"
73+
" try:\n"
74+
" return agent_class()\n"
75+
" except TypeError as final_error:\n"
76+
" raise TypeError(\n"
77+
" 'MyAgent could not be constructed with the CybORG runtime constructor fallbacks'\n"
78+
" ) from final_error\n"
79+
"make_agent(module.MyAgent, 'validation-agent')\n"
6680
"PY"
6781
)
6882
if import_check["returncode"] != 0:

tests/arenas/test_cyborg.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,67 @@ def test_import_failure(self, mock_player_factory):
6666
assert valid is False
6767
assert "Could not import" in error
6868

69+
def test_validation_instantiates_agent_with_runtime_fallbacks(self, mock_player_factory):
70+
arena = CybORGArena.__new__(CybORGArena)
71+
arena.submission = "cyborg_agent.py"
72+
player = mock_player_factory(
73+
name="Alice",
74+
files={"cyborg_agent.py": "from CybORG.Agents import RandomAgent\nclass MyAgent(RandomAgent):\n pass\n"},
75+
command_outputs={
76+
"test -f cyborg_agent.py && echo exists": {"output": "exists\n", "returncode": 0},
77+
"cat cyborg_agent.py": {
78+
"output": "from CybORG.Agents import RandomAgent\nclass MyAgent(RandomAgent):\n pass\n",
79+
"returncode": 0,
80+
},
81+
"python -m py_compile cyborg_agent.py": {"output": "", "returncode": 0},
82+
},
83+
)
84+
85+
valid, error = arena.validate_code(player)
86+
87+
import_command = player.environment._executed_commands[-1]
88+
assert valid is True
89+
assert error is None
90+
assert "make_agent(module.MyAgent, 'validation-agent')" in import_command
91+
92+
def test_validation_rejects_agent_constructor_failure(self, mock_player_factory):
93+
arena = CybORGArena.__new__(CybORGArena)
94+
arena.submission = "cyborg_agent.py"
95+
player = mock_player_factory(
96+
name="Alice",
97+
files={
98+
"cyborg_agent.py": (
99+
"from CybORG.Agents import RandomAgent\n"
100+
"class MyAgent(RandomAgent):\n"
101+
" def __init__(self, seed=None):\n"
102+
" super().__init__(seed=seed)\n"
103+
)
104+
},
105+
command_outputs={
106+
"test -f cyborg_agent.py && echo exists": {"output": "exists\n", "returncode": 0},
107+
"cat cyborg_agent.py": {
108+
"output": (
109+
"from CybORG.Agents import RandomAgent\n"
110+
"class MyAgent(RandomAgent):\n"
111+
" def __init__(self, seed=None):\n"
112+
" super().__init__(seed=seed)\n"
113+
),
114+
"returncode": 0,
115+
},
116+
"python -m py_compile cyborg_agent.py": {"output": "", "returncode": 0},
117+
"python - <<'PY'": {
118+
"output": "TypeError: RandomAgent.__init__() got an unexpected keyword argument 'seed'",
119+
"returncode": 1,
120+
},
121+
},
122+
)
123+
124+
valid, error = arena.validate_code(player)
125+
126+
assert valid is False
127+
assert "Could not import `MyAgent`" in error
128+
assert "unexpected keyword argument 'seed'" in error
129+
69130

70131
class TestCybORGResults:
71132
def test_parse_winner(self, tmp_log_dir):

0 commit comments

Comments
 (0)