Bug Report
title: [Bug]: Socket attribute typo in BaseAgent.init causes silent broken-socket state
labels: bug
assignees: ondrej-lukas
Bug Description
In netsecgame/agents/base_agent.py, the __init__ method contains a critical typo in its socket error handler. When socket.connect() raises a socket.error, the code sets:
self.sock = None # <-- WRONG attribute name
instead of:
self._socket = None # <-- correct attribute name used everywhere else
Because self.sock is a completely different (newly created) attribute, self._socket is never reset to None. It continues to hold the socket object that failed to connect. Every subsequent method (communicate, make_step, register, request_game_reset, terminate_connection, __del__) guards its socket usage with if self._socket:, which will evaluate to True even on a broken connection, silently attempting I/O on an unusable socket.
Impact:
- An agent that failed to connect appears fully initialized — the caller has no way to detect the failure.
- All subsequent
communicate() / make_step() calls operate on a broken socket, causing unpredictable behavior: hangs waiting for data, BrokenPipeError, corrupted game state, or silent data loss — depending on OS-level socket behavior.
- The intended fallback (
self._socket = None) to trigger safe-guards never fires.
- The ghost
self.sock attribute pollutes the object namespace with a confusing, unused None value.
Affected file: netsecgame/agents/base_agent.py, line 25
Steps to Reproduce
- Instantiate
BaseAgent (or any subclass) with an unreachable host/port:
agent = BaseAgent("192.0.2.1", 9999, AgentRole.Attacker) # port not open
- Observe that no exception is raised and the agent object is returned.
- Call
agent.make_step(some_action) or agent.register().
- The call blocks or raises an unexpected low-level socket error rather than failing cleanly.
Expected Behavior
When the socket fails to connect, self._socket should be set to None. All subsequent method calls should then short-circuit cleanly (the if self._socket: guards would correctly prevent any I/O). Callers should be able to detect the failed state, e.g., by checking agent.socket is None.
Fix
# netsecgame/agents/base_agent.py (__init__)
except socket.error as e:
self._logger.error(f"Socket error: {e}")
- self.sock = None # BUG: wrong attribute name
+ self._socket = None # FIX: matches the actual attribute
Version
See VERSION file in repository root.
Installation / Deployment Method
Running locally from source
Bug Report
title: [Bug]: Socket attribute typo in BaseAgent.init causes silent broken-socket state
labels: bug
assignees: ondrej-lukas
Bug Description
In
netsecgame/agents/base_agent.py, the__init__method contains a critical typo in its socket error handler. Whensocket.connect()raises asocket.error, the code sets:instead of:
Because
self.sockis a completely different (newly created) attribute,self._socketis never reset toNone. It continues to hold the socket object that failed to connect. Every subsequent method (communicate,make_step,register,request_game_reset,terminate_connection,__del__) guards its socket usage withif self._socket:, which will evaluate toTrueeven on a broken connection, silently attempting I/O on an unusable socket.Impact:
communicate()/make_step()calls operate on a broken socket, causing unpredictable behavior: hangs waiting for data,BrokenPipeError, corrupted game state, or silent data loss — depending on OS-level socket behavior.self._socket = None) to trigger safe-guards never fires.self.sockattribute pollutes the object namespace with a confusing, unusedNonevalue.Affected file:
netsecgame/agents/base_agent.py, line 25Steps to Reproduce
BaseAgent(or any subclass) with an unreachable host/port:agent.make_step(some_action)oragent.register().Expected Behavior
When the socket fails to connect,
self._socketshould be set toNone. All subsequent method calls should then short-circuit cleanly (theif self._socket:guards would correctly prevent any I/O). Callers should be able to detect the failed state, e.g., by checkingagent.socket is None.Fix
Version
See
VERSIONfile in repository root.Installation / Deployment Method
Running locally from source