from__future__importannotationsfromnetforge_rl.docker_bridge.docker_hypervisorimportDockerHypervisorfromnetforge_rl.docker_bridge.mock_hypervisorimportMockHypervisorimportloggingfromtypingimportLiteralfromnetforge_rl.docker_bridge.hypervisor_baseimportBaseHypervisor,HypervisorResultlogger=logging.getLogger(__name__)_REWARD_DELTA:dict[str,float]={'success':+5.0,'failure_clean':-10.0,'failure_noisy':-20.0,'failure_error':-25.0,}_NOISY_LATENCY_THRESHOLD_MS=5000.0# Longer than this = "noisy" failure
[docs]classDockerBridge:"""Bridge connecting actions to the hypervisor backend."""def__init__(self,mode:Literal['sim','real']='sim')->None:self.mode=modeself._driver:BaseHypervisor=self._init_driver(mode)
[docs]defdispatch(self,action_name:str,target_ip:str,target_os:str,)->HypervisorResult:"""Execute payload; auto-fallback to mock if real driver is down."""result=self._driver.dispatch(action_name,target_ip,target_os)logger.debug('DockerBridge: %s',result)returnresult
[docs]defreward_delta(self,result:HypervisorResult)->float:"""Map a HypervisorResult to an immediate scalar reward delta."""ifresult.success:return_REWARD_DELTA['success']elifresult.return_code==2:# Container/infrastructure errorreturn_REWARD_DELTA['failure_error']elifresult.latency_ms>=_NOISY_LATENCY_THRESHOLD_MS:return_REWARD_DELTA['failure_noisy']else:return_REWARD_DELTA['failure_clean']
[docs]defteardown_all(self)->None:"""Destroy all active containers/sessions — call at episode end."""self._driver.teardown_all()
[docs]defreseed(self,seed:int|None)->None:"""Reseed the driver RNG so exploit outcomes are reproducible per episode."""self._driver.reseed(seed)
defis_available(self)->bool:returnself._driver.is_available()def_init_driver(self,mode:str)->BaseHypervisor:ifmode=='real':driver=DockerHypervisor()ifnotdriver.is_available():logger.warning('DockerBridge: real mode requested but Docker unavailable. ''Falling back to mock hypervisor.')returnMockHypervisor()returndriver# Default: sim / mockreturnMockHypervisor()