Skip to content

Commit

Permalink
Merge pull request #146 from CrowdStrike/black-formatting
Browse files Browse the repository at this point in the history
Formats codebase using black and bumps requirements
  • Loading branch information
ChristopherHammond13 authored Jul 8, 2024
2 parents 297ee5f + ca46961 commit ec1253f
Show file tree
Hide file tree
Showing 35 changed files with 1,131 additions and 1,080 deletions.
1 change: 1 addition & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[flake8]
max-line-length = 100
extend-ignore = E203
2 changes: 2 additions & 0 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ jobs:
- name: Lint package docstrings and comments with pydocstyle
if: success() || failure()
run: poetry run pydocstyle falcon_toolkit/
- name: Lint package with black
run: poetry run black -l 100 --check falcon_toolkit/
3 changes: 2 additions & 1 deletion falcon_toolkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
A CLI for CrowdStrike Falcon, made with love by the CrowdStrike Services Team.
"""

__all__ = [
'__version__',
"__version__",
]

from falcon_toolkit.common.meta import __version__
1 change: 1 addition & 0 deletions falcon_toolkit/common/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
hold a FalconPy authentication object. It will be possible to generate more of these backends for
other purposes, such as for authentication against alternative API gateways.
"""

from __future__ import annotations
from abc import (
abstractmethod,
Expand Down
1 change: 1 addition & 0 deletions falcon_toolkit/common/auth_backends/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This file configures the default authentication backends.
"""

from falcon_toolkit.common.auth_backends.public_mssp import PublicCloudFlightControlParentCIDBackend
from falcon_toolkit.common.auth_backends.public_single_cid import PublicCloudSingleCIDBackend

Expand Down
22 changes: 10 additions & 12 deletions falcon_toolkit/common/auth_backends/public_mssp.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This authentication backend can take public cloud API keys (US-1, US-2, EU-1), and will ask the
user which child CID to authenticate against.
"""

import os

from typing import Dict, Optional
Expand Down Expand Up @@ -93,10 +94,10 @@ def dump_config(self) -> Dict[str, object]:
keyring.
"""
config: Dict[str, object] = {}
config['client_id']: str = self.client_id
config['cloud_name']: str = self.cloud_name
config['ssl_verify']: bool = self.ssl_verify
config['proxy']: Dict[str, str] = self.proxy
config["client_id"]: str = self.client_id
config["cloud_name"]: str = self.cloud_name
config["ssl_verify"]: bool = self.ssl_verify
config["proxy"]: Dict[str, str] = self.proxy

return config

Expand All @@ -112,18 +113,15 @@ def authenticate(self) -> Client:
child_cids = parent_client.flight_control.get_child_cids()
chosen_cid_str = os.environ.get("FALCON_MSSP_CHILD_CID")
if chosen_cid_str and chosen_cid_str.lower() in child_cids:
chosen_cid = parent_client.flight_control.get_child_cid_data(
cids=[chosen_cid_str]
)[chosen_cid_str]
chosen_cid = parent_client.flight_control.get_child_cid_data(cids=[chosen_cid_str])[
chosen_cid_str
]
else:
child_cids_data = parent_client.flight_control.get_child_cid_data(cids=child_cids)
chosen_cid_str = choose_cid(
cids=child_cids_data,
prompt_text="MSSP Child CID Search"
)
chosen_cid_str = choose_cid(cids=child_cids_data, prompt_text="MSSP Child CID Search")
chosen_cid = child_cids_data[chosen_cid_str]

chosen_cid_name = chosen_cid['name']
chosen_cid_name = chosen_cid["name"]
print(f"Connecting to {chosen_cid_name}")

client = Client(
Expand Down
9 changes: 5 additions & 4 deletions falcon_toolkit/common/auth_backends/public_single_cid.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This authentication backend can take public cloud API keys (US-1, US-2, EU-1), and will return
an OAuth2 object suitable for authenticating with FalconPy.
"""

from typing import Dict, Optional

import keyring
Expand Down Expand Up @@ -81,10 +82,10 @@ def dump_config(self) -> Dict[str, object]:
keyring.
"""
config: Dict[str, object] = {}
config['client_id'] = self.client_id
config['cloud_name'] = self.cloud_name
config['ssl_verify'] = self.ssl_verify
config['proxy'] = self.proxy
config["client_id"] = self.client_id
config["cloud_name"] = self.cloud_name
config["ssl_verify"] = self.ssl_verify
config["proxy"] = self.proxy

return config

Expand Down
7 changes: 4 additions & 3 deletions falcon_toolkit/common/auth_backends/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- A cloud selection function to allow a user to choose a cloud via Prompt Toolkit
- Advanced options configuration for overriding cloud, TLS validation, etc.
"""

from typing import (
Dict,
List,
Expand Down Expand Up @@ -56,8 +57,8 @@ class AdvancedOptionsType(NamedTuple):
def advanced_options_wizard() -> AdvancedOptionsType:
"""Define advanced connection options and return an AdvancedOptionsType."""
advanced_options_input = fancy_input("Do you want to configure more options? [y/n]: ")
if advanced_options_input not in ('y', 'Y'):
return AdvancedOptionsType('auto', True, None)
if advanced_options_input not in ("y", "Y"):
return AdvancedOptionsType("auto", True, None)

cloud_name = cloud_choice()

Expand All @@ -76,7 +77,7 @@ def advanced_options_wizard() -> AdvancedOptionsType:
proxy_url_input = fancy_input("HTTPS proxy URL (leave blank if not needed): ", loop=False)

if proxy_url_input:
proxy_dict = {'https', proxy_url_input}
proxy_dict = {"https", proxy_url_input}

advanced_options_result = AdvancedOptionsType(cloud_name, ssl_verify, proxy_dict)
return advanced_options_result
27 changes: 15 additions & 12 deletions falcon_toolkit/common/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Falcon Toolkit: Common CLI Functions."""

import sys

from typing import List
Expand All @@ -13,39 +14,41 @@

def get_instance(ctx: click.Context):
"""Load a specified Falcon instance configuration ready for use."""
config: FalconToolkitConfig = ctx.obj['config']
profile_name: str = ctx.obj['profile_name']
config: FalconToolkitConfig = ctx.obj["config"]
profile_name: str = ctx.obj["profile_name"]

if profile_name in config.instances:
profile = config.instances[profile_name]
elif not profile_name and len(config.instances) == 1:
profile = list(config.instances.values())[0]
elif not config.instances:
click.echo(click.style("No profiles are configured. Please set one up first.", fg='red'))
click.echo(click.style("No profiles are configured. Please set one up first.", fg="red"))
sys.exit(1)
elif not profile_name:
click.echo(click.style(
"Multiple profiles are configured, so you must use the -p/--profile option "
"to choose a profile to execute this tool with.",
fg='red',
))
click.echo(
click.style(
"Multiple profiles are configured, so you must use the -p/--profile option "
"to choose a profile to execute this tool with.",
fg="red",
)
)
sys.exit(1)
else:
click.echo(click.style(f"The profile {profile_name} does not exist.", fg='red'))
click.echo(click.style(f"The profile {profile_name} does not exist.", fg="red"))
sys.exit(1)

return profile


def parse_cli_filters(filter_kv_strings: List[str], client: Client) -> FalconFilter:
"""Parse consecutive chains of -f filters into a FalconFilter object for later use."""
filters = client.FalconFilter(dialect='hosts')
filters = client.FalconFilter(dialect="hosts")
for filter_kv_string in filter_kv_strings:
if '=' not in filter_kv_string:
if "=" not in filter_kv_string:
raise ValueError("Filter key=value string is in the wrong format")
first_equals = filter_kv_string.index("=")
filter_key = filter_kv_string[0:first_equals]
filter_value = filter_kv_string[first_equals + 1:]
filter_value = filter_kv_string[first_equals + 1 :]
filters.create_new_filter_from_kv_string(filter_key, filter_value)

return filters
11 changes: 5 additions & 6 deletions falcon_toolkit/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
These configurations are stored in a wider config file stored within the configuration
path (usually ~/FalconToolkit/FalconToolkit.json).
"""

from __future__ import annotations
import importlib.util
import json
Expand Down Expand Up @@ -63,9 +64,7 @@ def load_config(self, config: Dict[str, object]):
break

if not matching_auth_backend:
raise ValueError(
f"Auth backend {auth_backend_name} is not loaded or does not exist"
)
raise ValueError(f"Auth backend {auth_backend_name} is not loaded or does not exist")

auth_backend_config = auth.get("backend_config")
if not auth_backend_config:
Expand All @@ -81,7 +80,7 @@ def dump_config(self):
"auth": {
"backend_name": self.auth_backend.simple_name,
"backend_config": self.auth_backend.dump_config(),
}
},
}


Expand Down Expand Up @@ -113,7 +112,7 @@ def __init__(self, config_path: str):
"""Load a Falcon Toolkit configuration file from disk."""
self.config_file_path = os.path.join(config_path, CONFIG_FILENAME)
if os.path.exists(self.config_file_path):
with open(self.config_file_path, 'rb') as config_file_handle:
with open(self.config_file_path, "rb") as config_file_handle:
config_data = json.load(config_file_handle)
else:
config_data = {}
Expand All @@ -139,7 +138,7 @@ def write_config(self):
"auth_backends": self.additional_auth_backend_paths,
"instances": [x.dump_config() for x in list(self.instances.values())],
}
with open(self.config_file_path, 'w', encoding='utf8') as config_file_handle:
with open(self.config_file_path, "w", encoding="utf8") as config_file_handle:
json.dump(config_data, config_file_handle, sort_keys=True, indent=4)

def add_instance(self):
Expand Down
11 changes: 6 additions & 5 deletions falcon_toolkit/common/console_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
This file contains tools to help with displaying data on the console in a user-friendly,
colourful and/or helpful way.
"""

import platform


ESC = '\033'
OSC = ESC + ']'
ST = ESC + '\\'
ESC = "\033"
OSC = ESC + "]"
ST = ESC + "\\"


def build_hyperlink(target: str, text: str, link_id: str = None):
Expand All @@ -17,7 +18,7 @@ def build_hyperlink(target: str, text: str, link_id: str = None):
id_str = "id=" + link_id
else:
id_str = ""
return f'{OSC}8;{id_str};{target}{ST}{text}{OSC}8;;{ST}'
return f"{OSC}8;{id_str};{target}{ST}{text}{OSC}8;;{ST}"


def build_file_hyperlink(file_path: str, text: str, link_id: str = None):
Expand All @@ -27,7 +28,7 @@ def build_file_hyperlink(file_path: str, text: str, link_id: str = None):
else:
hostname = platform.node()

if file_path.startswith('/'):
if file_path.startswith("/"):
file_path = file_path[1:]

uri_file_path = f"file://{hostname}/{file_path}"
Expand Down
5 changes: 3 additions & 2 deletions falcon_toolkit/common/constants.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Falcon Toolkit: Common Constants."""

import os

import platformdirs
Expand All @@ -16,6 +17,6 @@

# Logging
LOG_CONSOLE_FORMATTER = "%(message)s"
LOG_FILE_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S%z'
LOG_FILE_OUTPUT_FORMAT = '%(asctime)s %(name)-24s %(levelname)-8s %(message)s'
LOG_FILE_DATE_FORMAT = "%Y-%m-%dT%H:%M:%S%z"
LOG_FILE_OUTPUT_FORMAT = "%(asctime)s %(name)-24s %(levelname)-8s %(message)s"
LOG_SUB_DIR = "logs"
9 changes: 5 additions & 4 deletions falcon_toolkit/common/logging_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
capture logs from both the toolkit itself, as well as Caracara behind the scenes.
All logs are compressed using gzip to keep file sizes down.
"""

import datetime
import gzip
import logging
Expand Down Expand Up @@ -48,7 +49,7 @@ def configure_logger(
# Gzip compress the main log file on the fly via a memory stream.
# This is required to avoid the gzip file from being corrupted if the
# the script ends prematurely (e.g, it crashes).
log_output_file = gzip.open(log_filepath, mode='wt', encoding='utf-8')
log_output_file = gzip.open(log_filepath, mode="wt", encoding="utf-8")
stream_handler = logging.StreamHandler(log_output_file)
memory_handler = logging.handlers.MemoryHandler(
capacity=1024,
Expand All @@ -60,22 +61,22 @@ def configure_logger(
datefmt=LOG_FILE_DATE_FORMAT,
format=LOG_FILE_OUTPUT_FORMAT,
handlers=[memory_handler],
encoding='utf-8',
encoding="utf-8",
)
else:
logging.basicConfig(
level=log_level,
format=LOG_FILE_OUTPUT_FORMAT,
datefmt=LOG_FILE_DATE_FORMAT,
filename=log_filepath,
filemode='wt',
filemode="wt",
)

console = logging.StreamHandler()
console.setLevel(level=log_level)
console_formatter = logging.Formatter(LOG_CONSOLE_FORMATTER)
console.setFormatter(console_formatter)
logging.getLogger('').addHandler(console)
logging.getLogger("").addHandler(console)

logging.debug("Logger configured")
return log_filepath_base
4 changes: 1 addition & 3 deletions falcon_toolkit/common/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,4 @@
import pkg_resources

# Derive the version via pkg_resources, which is populated based on the version in pyproject.toml
__version__ = pkg_resources.get_distribution(
__name__.split(".", maxsplit=1)[0]
).version
__version__ = pkg_resources.get_distribution(__name__.split(".", maxsplit=1)[0]).version
4 changes: 1 addition & 3 deletions falcon_toolkit/common/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ def __getitem__(self, key):

def __setitem__(self, key, value):
"""Assign a key to a value in the namespace."""
self.__init__(
** {key: value}
)
self.__init__(**{key: value})

def __delitem__(self, key):
"""Delete an item from the namespace."""
Expand Down
8 changes: 4 additions & 4 deletions falcon_toolkit/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This file is a catch-all for small code snippets that can be shared across the various sub-modules
of the application.
"""

import os

from typing import Dict, Iterable
Expand All @@ -21,8 +22,7 @@
def fancy_input(prompt_text: str, loop: bool = True):
"""Request user input (with colour). Optionally loop until the input is not blank."""
inputted = False
colour_prompt = Style.BRIGHT + Fore.BLUE + \
prompt_text + Fore.RESET + Style.RESET_ALL
colour_prompt = Style.BRIGHT + Fore.BLUE + prompt_text + Fore.RESET + Style.RESET_ALL

while not inputted:
data = input(colour_prompt)
Expand Down Expand Up @@ -62,11 +62,11 @@ def filename_safe_string(unsafe_string: str) -> str:
This function is heavily inspired by https://stackoverflow.com/a/7406369.
"""
safe_string = "".join(
[c for c in unsafe_string if c.isalpha() or c.isdigit() or c == ' ']
[c for c in unsafe_string if c.isalpha() or c.isdigit() or c == " "]
).rstrip()

# Replace spaces with underscores to match the general format of the log filename
clean_string = safe_string.replace(' ', '_')
clean_string = safe_string.replace(" ", "_")

return clean_string

Expand Down
Loading

0 comments on commit ec1253f

Please sign in to comment.