Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1960 deserialize config #2043

Merged
merged 67 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
77804ca
Agent: Add from_dict method to AgentConfiguration
VakarisZ Jun 20, 2022
d8ac441
Agent: Fix configuration retrieval in _run_simulation
VakarisZ Jun 21, 2022
e83995d
UT: Add a new fixture for config object
VakarisZ Jun 21, 2022
6b406ef
Agent: Change configuration to object in control channel
VakarisZ Jun 21, 2022
ffe8c34
Agent: Change scanners to use the config object
VakarisZ Jun 21, 2022
095e49b
Agent: Use deserialized config in automated_master.py
VakarisZ Jun 22, 2022
9286e86
Agent: Use deserialized in exploiter.py and propagator.py
VakarisZ Jun 22, 2022
86ed174
Agent: Usa agent config object instead of dict in option_parsing.py
VakarisZ Jun 23, 2022
ab67853
Agent: Usa agent config object instead of dict automated_master.py
VakarisZ Jun 23, 2022
0f848eb
Agent: Usa agent config object instead of dict should_propagate
VakarisZ Jun 23, 2022
aff5423
Agent: Remove redundant call to control_channel.get_config()
mssalvatore Jun 23, 2022
bba7139
Agent: Add missing return type hint to _try_communicate_with_island()
mssalvatore Jun 23, 2022
6e951ed
UT: Remove supported_os from default_config.py
mssalvatore Jun 23, 2022
81d3300
Agent: Remove print() that was added by mistake
mssalvatore Jun 23, 2022
bff92ed
UT: Fix erroneously abbreviated fixture
mssalvatore Jun 23, 2022
5a95aef
Agent: Remove unnecessary parameter
mssalvatore Jun 23, 2022
afeca66
UT: Use AgentConfiguration in test_propagation.py
mssalvatore Jun 23, 2022
ad0f694
Agent: Decouple should_propagate() and AgentConfiguration
mssalvatore Jun 23, 2022
05f640d
Agent: Rename should_propagate -> maximum_depth_reached
mssalvatore Jun 23, 2022
6d156b8
Island: Return config timeouts in seconds
mssalvatore Jun 23, 2022
2ff2e5f
Agent: Fix running of payloads
ilija-lazoroski Jun 24, 2022
f9445a2
Agent: Use == to compare OperatingSystems enum
ilija-lazoroski Jun 24, 2022
d59dd81
Agent: Use OperatingSystems in CachingAgentRepository
ilija-lazoroski Jun 24, 2022
fb67586
Agent: Use OperatingSystems.value for urllib.parse.quote
ilija-lazoroski Jun 24, 2022
b605f16
Agent: Use == to compare OperatingSystems enum in Log4Shell
ilija-lazoroski Jun 24, 2022
e1d5d25
Agent: Use OperatingSystem.WINDOWS in Powershell
ilija-lazoroski Jun 24, 2022
ffd3464
Agent: Move enum to string conversion to _download_binary_from_island()
mssalvatore Jun 24, 2022
858eb23
Agent: Rename os -> operating_system in caching_agent_repository
mssalvatore Jun 24, 2022
2eb1691
Agent: Use operating_system.value in _download_binary_from_island()
mssalvatore Jun 24, 2022
a3db414
Common: Add a docstring to OperatingSystems
mssalvatore Jun 24, 2022
7b4daaa
Agent: Change IAgentRepository to ccept OperatingSystems
mssalvatore Jun 24, 2022
02cca3e
Agent: Remove unnecessary type hints from IAgentRepository doctring
mssalvatore Jun 24, 2022
7bba711
Agent: Revert scan/exploit thread numer change
mssalvatore Jun 24, 2022
e3cea20
UT: Move test_agent_configuration.py to configuration/
mssalvatore Jun 24, 2022
5c73971
Common: Rename _dict -> dict_
mssalvatore Jun 24, 2022
8605fd4
UT: Add a test for AgentConfiguration.from_dict()
mssalvatore Jun 24, 2022
1f9a056
Agent: Add AgentConfiguration.from_json()
mssalvatore Jun 24, 2022
28250da
Common: Add AgentConfiguration.to_json()
mssalvatore Jun 24, 2022
e4eee6a
UT: Use from_dict() and from_json() in tests
mssalvatore Jun 24, 2022
6a92726
Island: Use {from,to}_json() in FileAgentConfigurationRepository
mssalvatore Jun 24, 2022
a1baaae
Common: Use from_json() in build_default_agent_configuration()
mssalvatore Jun 24, 2022
07d1d9c
Island: Use {from,to}_json() in resources
mssalvatore Jun 24, 2022
4c47eae
Common: Encapsulate AgentConfigurationSchema
mssalvatore Jun 24, 2022
ea02bec
Common: Remove circular dependency in agent_configuration.py
mssalvatore Jun 24, 2022
fc9d854
Common: Add validation to AgentConfiguration construction
mssalvatore Jun 24, 2022
94524d1
Common: Add InvalidConfigurationError
mssalvatore Jun 24, 2022
dbd0d3e
Common: Encapsulate MarshmallowError
mssalvatore Jun 24, 2022
e2f365a
Common: Rename dict_ -> config_dict
mssalvatore Jun 24, 2022
334d2a7
Common: Rename from_dict() -> from_mapping()
mssalvatore Jun 24, 2022
8cb045d
Common: Fix incorrect type hints on AgentConfiguration.from_json()
mssalvatore Jun 24, 2022
568eb4f
Common: Add docstrings to static methods in AgentConfiguration
mssalvatore Jun 24, 2022
93ed7cf
Merge pull request #2041 from guardicore/agent-configuration-construc…
mssalvatore Jun 24, 2022
84fc78c
UT: Remove unused imports from conftest.py
mssalvatore Jun 24, 2022
b219ca0
UT: Fix line that was too long
mssalvatore Jun 24, 2022
33ec4f7
Agent: Log configuration when it's received from the Island
mssalvatore Jun 24, 2022
dc9b91d
Agent: Use Iterable instead of List in type hint
mssalvatore Jun 24, 2022
8886ebc
Agent: Remove unnecessary local variables
mssalvatore Jun 24, 2022
4f7d8be
Agent: Use PluginConfiguration in _run_payload()
mssalvatore Jun 24, 2022
503a0a8
Agent: Use Sequence instead of List for type hints
mssalvatore Jun 24, 2022
fefd2da
Agent: Use Mapping instead of Dict
mssalvatore Jun 24, 2022
4b7ab05
Agent: Fix typehints in _run_pbas of automated_master.py
VakarisZ Jun 27, 2022
7179f91
Agent: Fix typehints in clear_command_history.py
VakarisZ Jun 27, 2022
c080f03
Agent: Fix _filter_none_values to be a static method
VakarisZ Jun 27, 2022
232d6ba
Agent: Fix string formatting in http_tools.py
VakarisZ Jun 27, 2022
bf1d360
UT: Remove disused DEFAULT_CONFIG
mssalvatore Jun 27, 2022
90259c1
UT: Remove dependency on DEFAULT_AGENT_CONFIGURATION_JSON
mssalvatore Jun 27, 2022
e6d3854
Common: Remove DEFAULT_AGENT_CONFIGURATION_JSON
mssalvatore Jun 27, 2022
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
15 changes: 12 additions & 3 deletions monkey/common/configuration/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from .agent_configuration import (
AgentConfiguration,
AgentConfigurationSchema,
from .agent_configuration import AgentConfiguration, InvalidConfigurationError
from .agent_sub_configurations import (
CustomPBAConfiguration,
PluginConfiguration,
ScanTargetConfiguration,
ICMPScanConfiguration,
TCPScanConfiguration,
NetworkScanConfiguration,
ExploitationOptionsConfiguration,
ExploiterConfiguration,
ExploitationConfiguration,
PropagationConfiguration,
Comment on lines +2 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have both PluginConfiguration and ExploiterConfiguration dataclasses which have the same member variables (link to file with definitions)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! ExploiterConfiguration had supported_os in it, until that was removed by #2038. When supported_os was removed, everything that used ExploiterConfiguration should have been changed to PluginConfiguration. I'll add a task to #1960.

)
from .default_agent_configuration import (
DEFAULT_AGENT_CONFIGURATION_JSON,
Expand Down
71 changes: 65 additions & 6 deletions monkey/common/configuration/agent_configuration.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import List
from typing import Any, List, Mapping

from marshmallow import Schema, fields, post_load
from marshmallow import Schema, fields
from marshmallow.exceptions import MarshmallowError

from .agent_sub_configuration_schemas import (
CustomPBAConfigurationSchema,
Expand All @@ -15,6 +18,15 @@
)


class InvalidConfigurationError(Exception):
pass


INVALID_CONFIGURATION_ERROR_MESSAGE = (
"Cannot construct an AgentConfiguration object with the supplied, invalid data:"
)


@dataclass(frozen=True)
class AgentConfiguration:
keep_tunnel_open_time: float
Expand All @@ -24,6 +36,57 @@ class AgentConfiguration:
payloads: List[PluginConfiguration]
propagation: PropagationConfiguration

def __post_init__(self):
# This will raise an exception if the object is invalid. Calling this in __post__init()
# makes it impossible to construct an invalid object
try:
AgentConfigurationSchema().dump(self)
except Exception as err:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we expecting anything but MarshmallowError?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That I'm aware, it can raise MarshmallowError, TypeError, or ValueError. It may raise others as well, I'm not sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better question is, "Is there any case where AgentConfigurationSchema().dump() could raise an exception for any reason other than an invalid exception?" To my knowledge, there's not.

raise InvalidConfigurationError(f"{INVALID_CONFIGURATION_ERROR_MESSAGE}: {err}")

@staticmethod
def from_mapping(config_mapping: Mapping[str, Any]) -> AgentConfiguration:
"""
Construct an AgentConfiguration from a Mapping

:param config_mapping: A Mapping that represents an AgentConfiguration
:return: An AgentConfiguration
:raises: InvalidConfigurationError if the provided Mapping does not represent a valid
AgentConfiguration
"""

try:
config_dict = AgentConfigurationSchema().load(config_mapping)
return AgentConfiguration(**config_dict)
except MarshmallowError as err:
raise InvalidConfigurationError(f"{INVALID_CONFIGURATION_ERROR_MESSAGE}: {err}")

@staticmethod
def from_json(config_json: str) -> AgentConfiguration:
"""
Construct an AgentConfiguration from a JSON string

:param config_json: A JSON string that represents an AgentConfiguration
:return: An AgentConfiguration
:raises: InvalidConfigurationError if the provided JSON does not represent a valid
AgentConfiguration
"""
try:
config_dict = AgentConfigurationSchema().loads(config_json)
return AgentConfiguration(**config_dict)
except MarshmallowError as err:
raise InvalidConfigurationError(f"{INVALID_CONFIGURATION_ERROR_MESSAGE}: {err}")

@staticmethod
def to_json(config: AgentConfiguration) -> str:
"""
Serialize an AgentConfiguration to JSON

:param config: An AgentConfiguration
:return: A JSON string representing the AgentConfiguration
"""
return AgentConfigurationSchema().dumps(config)


class AgentConfigurationSchema(Schema):
keep_tunnel_open_time = fields.Float()
Expand All @@ -32,7 +95,3 @@ class AgentConfigurationSchema(Schema):
credential_collectors = fields.List(fields.Nested(PluginConfigurationSchema))
payloads = fields.List(fields.Nested(PluginConfigurationSchema))
propagation = fields.Nested(PropagationConfigurationSchema)

@post_load
def _make_agent_configuration(self, data, **kwargs):
return AgentConfiguration(**data)
5 changes: 2 additions & 3 deletions monkey/common/configuration/default_agent_configuration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from . import AgentConfiguration, AgentConfigurationSchema
from . import AgentConfiguration

DEFAULT_AGENT_CONFIGURATION_JSON = """{
"keep_tunnel_open_time": 30,
Expand Down Expand Up @@ -204,5 +204,4 @@


def build_default_agent_configuration() -> AgentConfiguration:
schema = AgentConfigurationSchema()
return schema.loads(DEFAULT_AGENT_CONFIGURATION_JSON)
return AgentConfiguration.from_json(DEFAULT_AGENT_CONFIGURATION_JSON)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably specify the defaults in the marshmallow schema. We'll do it with validation, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, #2004.

7 changes: 7 additions & 0 deletions monkey/common/operating_systems.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@


class OperatingSystems(Enum):
"""
An Enum representing all supported operating systems

This Enum represents all operating systems that Infection Monkey supports. The value of each
member is the member's name in all lower-case characters.
"""

LINUX = "linux"
WINDOWS = "windows"
2 changes: 2 additions & 0 deletions monkey/common/utils/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,7 @@ class DomainControllerNameFetchError(FailedExploitationError):
"""Raise on failed attempt to extract domain controller's name"""


# TODO: This has been replaced by common.configuration.InvalidConfigurationError. Use that error
# instead and remove this one.
Comment on lines +41 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's out of scope. Other components are still using the old ConfigService and other components that still use this error. The TODO is here because vulture can't tell which one is being used, so once everything is switched over to the new error, we don't want to forget to remove this one.

class InvalidConfigurationError(Exception):
"""Raise when configuration is invalid"""
13 changes: 9 additions & 4 deletions monkey/infection_monkey/exploit/caching_agent_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import requests

from common import OperatingSystems
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT

from . import IAgentRepository
Expand All @@ -22,18 +23,22 @@ def __init__(self, island_url: str, proxies: Mapping[str, str]):
self._proxies = proxies
self._lock = threading.Lock()

def get_agent_binary(self, os: str, architecture: str = None) -> io.BytesIO:
def get_agent_binary(
self, operating_system: OperatingSystems, architecture: str = None
) -> io.BytesIO:
# If multiple calls to get_agent_binary() are made simultaneously before the result of
# _download_binary_from_island() is cached, then multiple requests will be sent to the
# island. Add a mutex in front of the call to _download_agent_binary_from_island() so
# that only one request per OS will be sent to the island.
with self._lock:
return io.BytesIO(self._download_binary_from_island(os))
return io.BytesIO(self._download_binary_from_island(operating_system))

@lru_cache(maxsize=None)
def _download_binary_from_island(self, os: str) -> bytes:
def _download_binary_from_island(self, operating_system: OperatingSystems) -> bytes:
os_name = operating_system.value

response = requests.get( # noqa: DUO123
f"{self._island_url}/api/agent-binaries/{os}",
f"{self._island_url}/api/agent-binaries/{os_name}",
verify=False,
proxies=self._proxies,
timeout=MEDIUM_REQUEST_TIMEOUT,
Expand Down
11 changes: 7 additions & 4 deletions monkey/infection_monkey/exploit/i_agent_repository.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import abc
import io

from common import OperatingSystems

# TODO: The Island also has an IAgentRepository with a totally different interface. At the moment,
# the Island and Agent have different needs, but at some point we should unify these.

Expand All @@ -13,12 +15,13 @@ class IAgentRepository(metaclass=abc.ABCMeta):
"""

@abc.abstractmethod
def get_agent_binary(self, os: str, architecture: str = None) -> io.BytesIO:
def get_agent_binary(
self, operating_system: OperatingSystems, architecture: str = None
) -> io.BytesIO:
"""
Retrieve the appropriate agent binary from the repository.
:param str os: The name of the operating system on which the agent binary will run
:param str architecture: Reserved
:param operating_system: The name of the operating system on which the agent binary will run
:param architecture: Reserved
:return: A file-like object for the requested agent binary
:rtype: io.BytesIO
"""
pass
2 changes: 1 addition & 1 deletion monkey/infection_monkey/exploit/log4shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def _build_command(self, path: PurePath, http_path) -> str:
}

def _build_java_class(self, exploit_command: str) -> bytes:
if OperatingSystems.LINUX in self.host.os["type"]:
if OperatingSystems.LINUX == self.host.os["type"]:
return build_exploit_bytecode(exploit_command, LINUX_EXPLOIT_TEMPLATE_PATH)
else:
return build_exploit_bytecode(exploit_command, WINDOWS_EXPLOIT_TEMPLATE_PATH)
Expand Down
3 changes: 2 additions & 1 deletion monkey/infection_monkey/exploit/powershell.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path, PurePath
from typing import List, Optional

from common import OperatingSystems
from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.powershell_utils.auth_options import AuthOptions, get_auth_options
from infection_monkey.exploit.powershell_utils.credentials import (
Expand Down Expand Up @@ -162,7 +163,7 @@ def _copy_monkey_binary_to_victim(self, monkey_path_on_victim: PurePath):
temp_monkey_binary_filepath.unlink()

def _create_local_agent_file(self, binary_path):
agent_binary_bytes = self.agent_repository.get_agent_binary("windows")
agent_binary_bytes = self.agent_repository.get_agent_binary(OperatingSystems.WINDOWS)
with open(binary_path, "wb") as f:
f.write(agent_binary_bytes.getvalue())

Expand Down
2 changes: 1 addition & 1 deletion monkey/infection_monkey/exploit/tools/http_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ def create_locked_transfer(
httpd.start()
lock.acquire()
return (
"http://%s:%s/%s" % (local_ip, local_port, urllib.parse.quote(host.os["type"])),
"http://%s:%s/%s" % (local_ip, local_port, urllib.parse.quote(host.os["type"].value)),
httpd,
)
8 changes: 5 additions & 3 deletions monkey/infection_monkey/i_control_channel.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import abc

from common.configuration import AgentConfiguration


class IControlChannel(metaclass=abc.ABCMeta):
@abc.abstractmethod
Expand All @@ -11,10 +13,10 @@ def should_agent_stop(self) -> bool:
"""

@abc.abstractmethod
def get_config(self) -> dict:
def get_config(self) -> AgentConfiguration:
"""
:return: A dictionary containing Agent Configuration
:rtype: dict
:return: An AgentConfiguration object
:rtype: AgentConfiguration
"""
pass

Expand Down
53 changes: 29 additions & 24 deletions monkey/infection_monkey/master/automated_master.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import logging
import threading
import time
from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple
from typing import Any, Callable, Dict, Iterable, List, Optional

from common.configuration import PluginConfiguration
from common.utils import Timer
from infection_monkey.credential_store import ICredentialsStore
from infection_monkey.i_control_channel import IControlChannel, IslandCommunicationError
Expand All @@ -13,7 +14,7 @@
from infection_monkey.telemetry.credentials_telem import CredentialsTelem
from infection_monkey.telemetry.messengers.i_telemetry_messenger import ITelemetryMessenger
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
from infection_monkey.utils.propagation import should_propagate
from infection_monkey.utils.propagation import maximum_depth_reached
from infection_monkey.utils.threading import create_daemon_thread, interruptible_iter

from . import Exploiter, IPScanner, Propagator
Expand Down Expand Up @@ -111,7 +112,7 @@ def _wait_for_master_stop_condition(self):
time.sleep(CHECK_FOR_TERMINATE_INTERVAL_SEC)

@staticmethod
def _try_communicate_with_island(fn: Callable[[], Any], max_tries: int):
def _try_communicate_with_island(fn: Callable[[], Any], max_tries: int) -> Any:
shreyamalviya marked this conversation as resolved.
Show resolved Hide resolved
tries = 0
while tries < max_tries:
try:
Expand Down Expand Up @@ -141,7 +142,7 @@ def _run_simulation(self):
try:
config = AutomatedMaster._try_communicate_with_island(
self._control_channel.get_config, CHECK_FOR_CONFIG_COUNT
)["config"]
)
except IslandCommunicationError as e:
logger.error(f"An error occurred while fetching configuration: {e}")
return
Expand All @@ -150,15 +151,15 @@ def _run_simulation(self):
target=self._run_plugins,
name="CredentialCollectorThread",
args=(
config["credential_collectors"],
config.credential_collectors,
"credential collector",
self._collect_credentials,
),
)
pba_thread = create_daemon_thread(
target=self._run_pbas,
name="PBAThread",
args=(config["post_breach_actions"].items(), self._run_pba, config["custom_pbas"]),
args=(config.post_breach_actions, self._run_pba, config.custom_pbas),
)

credential_collector_thread.start()
Expand All @@ -173,52 +174,56 @@ def _run_simulation(self):
current_depth = self._current_depth if self._current_depth is not None else 0
logger.info(f"Current depth is {current_depth}")

if should_propagate(self._control_channel.get_config(), self._current_depth):
self._propagator.propagate(config["propagation"], current_depth, self._stop)
if maximum_depth_reached(config.propagation.maximum_depth, self._current_depth):
self._propagator.propagate(config.propagation, current_depth, self._stop)
else:
logger.info("Skipping propagation: maximum depth reached")

payload_thread = create_daemon_thread(
target=self._run_plugins,
name="PayloadThread",
args=(config["payloads"].items(), "payload", self._run_payload),
args=(config.payloads, "payload", self._run_payload),
)
payload_thread.start()
payload_thread.join()

pba_thread.join()

def _collect_credentials(self, collector: str):
credentials = self._puppet.run_credential_collector(collector, {})
def _collect_credentials(self, collector: PluginConfiguration):
credentials = self._puppet.run_credential_collector(collector.name, collector.options)

if credentials:
self._telemetry_messenger.send_telemetry(CredentialsTelem(credentials))
else:
logger.debug(f"No credentials were collected by {collector}")

def _run_pba(self, pba: Tuple[str, Dict]):
name = pba[0]
options = pba[1]

for pba_data in self._puppet.run_pba(name, options):
def _run_pba(self, pba: PluginConfiguration):
for pba_data in self._puppet.run_pba(pba.name, pba.options):
self._telemetry_messenger.send_telemetry(PostBreachTelem(pba_data))

def _run_payload(self, payload: Tuple[str, Dict]):
name = payload[0]
options = payload[1]

self._puppet.run_payload(name, options, self._stop)
def _run_payload(self, payload: PluginConfiguration):
self._puppet.run_payload(payload.name, payload.options, self._stop)

def _run_pbas(
self, plugins: Iterable[Any], callback: Callable[[Any], None], custom_pba_options: Mapping
self,
plugins: Iterable[PluginConfiguration],
callback: Callable[[Any], None],
custom_pba_options: Dict,
mssalvatore marked this conversation as resolved.
Show resolved Hide resolved
):
self._run_plugins(plugins, "post-breach action", callback)

if custom_pba_is_enabled(custom_pba_options):
self._run_plugins([("CustomPBA", custom_pba_options)], "post-breach action", callback)
self._run_plugins(
[PluginConfiguration(name="CustomPBA", options=custom_pba_options)],
"post-breach action",
callback,
)

def _run_plugins(
self, plugins: Iterable[Any], plugin_type: str, callback: Callable[[Any], None]
self,
plugins: Iterable[PluginConfiguration],
plugin_type: str,
callback: Callable[[Any], None],
):
logger.info(f"Running {plugin_type}s")
logger.debug(f"Found {len(plugins)} {plugin_type}(s) to run")
Expand Down
Loading