diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d02fa121..959cdb04 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1 +1,3 @@ ff87bcaf1741e8ecf15cb8d401438592dfef3ba7 # Mass reformat with adoption of ruff +9d96a56b763ece491a07441dbe26176777a1964c # Add I rules to ruff +4eefa15b8afbb387b9fa5338dc45759e1915ef56 # Add E, W, and RUF diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 81e6bac0..7bd9a339 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,7 +8,7 @@ repos: - id: detect-private-key - id: forbid-submodules - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.2 + rev: v0.12.5 hooks: - id: ruff args: [ --fix ] diff --git a/contentctl/actions/deploy_acs.py b/contentctl/actions/deploy_acs.py index b38e1273..5826da0b 100644 --- a/contentctl/actions/deploy_acs.py +++ b/contentctl/actions/deploy_acs.py @@ -1,7 +1,9 @@ -from contentctl.objects.config import deploy_acs, StackType -from requests import post import pprint +from requests import post + +from contentctl.objects.config import StackType, deploy_acs + class Deploy: def execute(self, config: deploy_acs, appinspect_token: str) -> None: @@ -33,7 +35,7 @@ def execute(self, config: deploy_acs, appinspect_token: str) -> None: raise Exception(f"Unsupported stack type: '{config.stack_type}'") except Exception as e: raise Exception( - f"Error installing to stack '{config.splunk_cloud_stack}' (stack_type='{config.stack_type}') via ACS:\n{str(e)}" + f"Error installing to stack '{config.splunk_cloud_stack}' (stack_type='{config.stack_type}') via ACS:\n{e!s}" ) try: diff --git a/contentctl/actions/detection_testing/DetectionTestingManager.py b/contentctl/actions/detection_testing/DetectionTestingManager.py index ae0df1e3..c7370a44 100644 --- a/contentctl/actions/detection_testing/DetectionTestingManager.py +++ b/contentctl/actions/detection_testing/DetectionTestingManager.py @@ -162,10 +162,10 @@ def sigint_handler(signum, frame): print() print(f"[{error_type}]:") for error in errors[error_type]: - print(f"\t❌ {str(error)}") + print(f"\t❌ {error!s}") if isinstance(error, ExceptionGroup): for suberror in error.exceptions: # type: ignore - print(f"\t\t❌ {str(suberror)}") # type: ignore + print(f"\t\t❌ {suberror!s}") # type: ignore print() return self.output_dto @@ -208,7 +208,7 @@ def create_DetectionTestingInfrastructureObjects(self): except Exception as e: raise Exception( "Failed to pull docker container image " - f"[{self.input_dto.config.container_settings.full_image_path}]: {str(e)}" + f"[{self.input_dto.config.container_settings.full_image_path}]: {e!s}" ) already_staged_container_files = False diff --git a/contentctl/actions/detection_testing/GitService.py b/contentctl/actions/detection_testing/GitService.py index 159e00bb..5beb916d 100644 --- a/contentctl/actions/detection_testing/GitService.py +++ b/contentctl/actions/detection_testing/GitService.py @@ -99,7 +99,7 @@ def getChanges(self, target_branch: str) -> List[Detection]: updated_detections.add(detectionObject) else: raise Exception( - f"Error getting detection object for file {str(decoded_path)}" + f"Error getting detection object for file {decoded_path!s}" ) elif ( @@ -111,7 +111,7 @@ def getChanges(self, target_branch: str) -> List[Detection]: updated_macros.add(macroObject) else: raise Exception( - f"Error getting macro object for file {str(decoded_path)}" + f"Error getting macro object for file {decoded_path!s}" ) elif ( @@ -125,7 +125,7 @@ def getChanges(self, target_branch: str) -> List[Detection]: updated_datasources.add(datasourceObject) else: raise Exception( - f"Error getting data source object for file {str(decoded_path)}" + f"Error getting data source object for file {decoded_path!s}" ) elif decoded_path.is_relative_to(self.config.path / "lookups"): @@ -172,7 +172,7 @@ def getChanges(self, target_branch: str) -> List[Detection]: else: raise Exception( - f"Detected a changed file in the lookups/ directory '{str(decoded_path)}'.\n" + f"Detected a changed file in the lookups/ directory '{decoded_path!s}'.\n" "Only files ending in .csv, .yml, or .mlmodel are supported in this " "directory. This file must be removed from the lookups/ directory." ) diff --git a/contentctl/actions/detection_testing/generate_detection_coverage_badge.py b/contentctl/actions/detection_testing/generate_detection_coverage_badge.py index 749a6b75..77c90eb9 100644 --- a/contentctl/actions/detection_testing/generate_detection_coverage_badge.py +++ b/contentctl/actions/detection_testing/generate_detection_coverage_badge.py @@ -47,13 +47,13 @@ try: results = parser.parse_args() except Exception as e: - print(f"Error parsing arguments: {str(e)}") + print(f"Error parsing arguments: {e!s}") exit(1) try: summary_info = json.loads(results.input_summary_file.read()) except Exception as e: - print(f"Error loading {results.input_summary_file.name} JSON file: {str(e)}") + print(f"Error loading {results.input_summary_file.name} JSON file: {e!s}") sys.exit(1) if "summary" not in summary_info: @@ -75,7 +75,7 @@ RAW_BADGE_SVG.format(results.badge_string, "{:2.1f}%".format(pass_percent)) ) except Exception as e: - print(f"Error generating badge: {str(e)}") + print(f"Error generating badge: {e!s}") sys.exit(1) diff --git a/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py b/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py index 30e91e97..e3ce2ac7 100644 --- a/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +++ b/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py @@ -197,7 +197,7 @@ def setup(self): self.check_for_teardown() except Exception as e: - msg = f"[{self.get_name()}]: {str(e)}" + msg = f"[{self.get_name()}]: {e!s}" self.finish() if isinstance(e, ExceptionGroup): raise ExceptionGroup(msg, e.exceptions) from e # type: ignore @@ -310,7 +310,7 @@ def configure_hec(self): return except Exception as e: - raise (Exception(f"Failure creating HEC Endpoint: {str(e)}")) + raise (Exception(f"Failure creating HEC Endpoint: {e!s}")) def get_all_indexes(self) -> None: """ @@ -327,7 +327,7 @@ def get_all_indexes(self) -> None: # Retrieve all available indexes on the splunk instance self.all_indexes_on_server = indexes except Exception as e: - raise (Exception(f"Failure getting indexes: {str(e)}")) + raise (Exception(f"Failure getting indexes: {e!s}")) def get_conn(self) -> client.Service: try: @@ -382,7 +382,7 @@ def connect_to_api(self, sleep_seconds: int = 5): pass except Exception as e: self.pbar.write( - f"Error getting API connection (not quitting) '{type(e).__name__}': {str(e)}" + f"Error getting API connection (not quitting) '{type(e).__name__}': {e!s}" ) for _ in range(sleep_seconds): @@ -402,7 +402,7 @@ def create_replay_index(self): pass else: raise Exception( - f"Error creating index {self.sync_obj.replay_index} - {str(e)}" + f"Error creating index {self.sync_obj.replay_index} - {e!s}" ) def configure_imported_roles( @@ -426,7 +426,7 @@ def configure_imported_roles( ) return except Exception as e: - msg = f"Error configuring roles: {str(e)}" + msg = f"Error configuring roles: {e!s}" self.pbar.write(msg) raise Exception(msg) from e @@ -436,7 +436,7 @@ def configure_delete_indexes(self): self.get_conn().post(endpoint, value=";".join(self.all_indexes_on_server)) except Exception as e: self.pbar.write( - f"Error configuring deleteIndexesAllowed with '{self.all_indexes_on_server}': [{str(e)}]" + f"Error configuring deleteIndexesAllowed with '{self.all_indexes_on_server}': [{e!s}]" ) def wait_for_conf_file(self, app_name: str, conf_file_name: str): @@ -474,12 +474,12 @@ def configure_conf_file_datamodels(self, APP_NAME: str = "Splunk_SA_CIM"): parser.read(custom_acceleration_datamodels) if len(parser.keys()) > 1: self.pbar.write( - f"Read {len(parser) - 1} custom datamodels from {str(custom_acceleration_datamodels)}!" + f"Read {len(parser) - 1} custom datamodels from {custom_acceleration_datamodels!s}!" ) if not cim_acceleration_datamodels.is_file(): self.pbar.write( - f"******************************\nDATAMODEL ACCELERATION FILE {str(cim_acceleration_datamodels)} NOT " + f"******************************\nDATAMODEL ACCELERATION FILE {cim_acceleration_datamodels!s} NOT " "FOUND. CIM DATAMODELS NOT ACCELERATED\n******************************\n" ) else: @@ -499,7 +499,7 @@ def configure_conf_file_datamodels(self, APP_NAME: str = "Splunk_SA_CIM"): except Exception as e: self.pbar.write( - f"Error creating the conf Datamodel {datamodel_name} key/value {name}/{value}: {str(e)}" + f"Error creating the conf Datamodel {datamodel_name} key/value {name}/{value}: {e!s}" ) def execute(self): @@ -528,9 +528,7 @@ def execute(self): self.finish() return except Exception as e: - self.pbar.write( - f"Error testing detection: {type(e).__name__}: {str(e)}" - ) + self.pbar.write(f"Error testing detection: {type(e).__name__}: {e!s}") raise e finally: self.sync_obj.outputQueue.append(detection) @@ -1365,7 +1363,7 @@ def delete_attack_data(self, attack_data_files: list[TestAttackData]): except Exception as e: raise ( Exception( - f"Trouble deleting data using the search {splunk_search}: {str(e)}" + f"Trouble deleting data using the search {splunk_search}: {e!s}" ) ) @@ -1440,7 +1438,7 @@ def replay_attack_data_file( except Exception as e: raise ( Exception( - f"Could not download attack data file [{attack_data_file.data}]:{str(e)}" + f"Could not download attack data file [{attack_data_file.data}]:{e!s}" ) ) @@ -1514,7 +1512,7 @@ def hec_raw_replay( except Exception as e: raise ( Exception( - f"There was an exception sending attack_data to HEC: {str(e)}" + f"There was an exception sending attack_data to HEC: {e!s}" ) ) @@ -1558,7 +1556,7 @@ def hec_raw_replay( ) ) except Exception as e: - raise (Exception(f"There was an exception in the post: {str(e)}")) + raise (Exception(f"There was an exception in the post: {e!s}")) def status(self): pass diff --git a/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py b/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py index ceced0eb..d0a3318f 100644 --- a/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +++ b/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py @@ -1,11 +1,12 @@ +import docker +import docker.models.containers +import docker.models.resource +import docker.types + from contentctl.actions.detection_testing.infrastructures.DetectionTestingInfrastructure import ( DetectionTestingInfrastructure, ) from contentctl.objects.config import test -import docker.models.resource -import docker.models.containers -import docker -import docker.types class DetectionTestingInfrastructureContainer(DetectionTestingInfrastructure): @@ -34,7 +35,7 @@ def finish(self): self.removeContainer() pass except Exception as e: - raise (Exception(f"Error removing container: {str(e)}")) + raise (Exception(f"Error removing container: {e!s}")) super().finish() def get_name(self) -> str: @@ -46,7 +47,7 @@ def get_docker_client(self): return c except Exception as e: - raise (Exception(f"Failed to get docker client: {str(e)}")) + raise (Exception(f"Failed to get docker client: {e!s}")) def check_for_teardown(self): try: @@ -56,7 +57,7 @@ def check_for_teardown(self): except Exception as e: if self.sync_obj.terminate is not True: self.pbar.write( - f"Error: could not get container [{self.get_name()}]: {str(e)}" + f"Error: could not get container [{self.get_name()}]: {e!s}" ) self.sync_obj.terminate = True else: @@ -175,6 +176,6 @@ def removeContainer(self, removeVolumes: bool = True, forceRemove: bool = True): except Exception as e: raise ( Exception( - f"Could not remove Docker Container [{self.get_name()}]: {str(e)}" + f"Could not remove Docker Container [{self.get_name()}]: {e!s}" ) ) diff --git a/contentctl/actions/detection_testing/progress_bar.py b/contentctl/actions/detection_testing/progress_bar.py index 183497d4..b66685a0 100644 --- a/contentctl/actions/detection_testing/progress_bar.py +++ b/contentctl/actions/detection_testing/progress_bar.py @@ -1,7 +1,8 @@ +import datetime import time from enum import StrEnum + from tqdm import tqdm -import datetime class TestReportingType(StrEnum): diff --git a/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py b/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py index 2246783f..2b9cc559 100644 --- a/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py +++ b/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py @@ -1,10 +1,11 @@ +import time + +import tqdm + from contentctl.actions.detection_testing.views.DetectionTestingView import ( DetectionTestingView, ) -import time -import tqdm - class DetectionTestingViewCLI(DetectionTestingView, arbitrary_types_allowed=True): pbar: tqdm.tqdm = None diff --git a/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py b/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py index 40f5be9e..89022657 100644 --- a/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +++ b/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py @@ -1,8 +1,10 @@ +import pathlib + +import yaml + from contentctl.actions.detection_testing.views.DetectionTestingView import ( DetectionTestingView, ) -import pathlib -import yaml OUTPUT_FOLDER = "test_results" OUTPUT_FILENAME = "summary.yml" diff --git a/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py b/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py index d7cf73fa..ac7f8e28 100644 --- a/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py +++ b/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py @@ -1,9 +1,9 @@ +import webbrowser from threading import Thread +from wsgiref.simple_server import WSGIRequestHandler, make_server -from bottle import template, Bottle, ServerAdapter -from wsgiref.simple_server import make_server, WSGIRequestHandler import jinja2 -import webbrowser +from bottle import Bottle, ServerAdapter, template from pydantic import ConfigDict from contentctl.actions.detection_testing.views.DetectionTestingView import ( @@ -39,8 +39,8 @@ {% for containerName, data in currentTestingQueue.items() %} {{ containerName }} - {{ data["name"] }} - {{ data["search"] }} + {{ data["name"] }} + {{ data["search"] }} {% endfor %} @@ -69,7 +69,7 @@ {% else %} False {% endif %} - + {% endfor %} {% endfor %} @@ -118,7 +118,7 @@ def setup(self): try: webbrowser.open(f"http://{self.server.host}:{DEFAULT_WEB_UI_PORT}") except Exception as e: - print(f"Could not open webbrowser for status page: {str(e)}") + print(f"Could not open webbrowser for status page: {e!s}") def stop(self): if self.server.server is None: diff --git a/contentctl/actions/doc_gen.py b/contentctl/actions/doc_gen.py index c9d89896..d151ab81 100644 --- a/contentctl/actions/doc_gen.py +++ b/contentctl/actions/doc_gen.py @@ -1,8 +1,7 @@ import os - from dataclasses import dataclass -from contentctl.input.director import DirectorInputDto, Director, DirectorOutputDto +from contentctl.input.director import Director, DirectorInputDto, DirectorOutputDto from contentctl.output.doc_md_output import DocMdOutput diff --git a/contentctl/actions/release_notes.py b/contentctl/actions/release_notes.py index decf8c54..ce18301a 100644 --- a/contentctl/actions/release_notes.py +++ b/contentctl/actions/release_notes.py @@ -155,7 +155,7 @@ def create_notes( except yaml.YAMLError as exc: raise Exception( - f"Error parsing YAML file for release_notes {file_path}: {str(exc)}" + f"Error parsing YAML file for release_notes {file_path}: {exc!s}" ) else: warnings.append( diff --git a/contentctl/actions/reporting.py b/contentctl/actions/reporting.py index 70e1cd33..8a37d660 100644 --- a/contentctl/actions/reporting.py +++ b/contentctl/actions/reporting.py @@ -1,9 +1,9 @@ from dataclasses import dataclass from contentctl.input.director import DirectorOutputDto -from contentctl.output.svg_output import SvgOutput -from contentctl.output.attack_nav_output import AttackNavOutput from contentctl.objects.config import report +from contentctl.output.attack_nav_output import AttackNavOutput +from contentctl.output.svg_output import SvgOutput @dataclass(frozen=True) @@ -24,7 +24,7 @@ def execute(self, input_dto: ReportingInputDto) -> None: ) else: raise Exception( - f"Error writing reporting : '{input_dto.config.getReportingPath()}': {str(e)}" + f"Error writing reporting : '{input_dto.config.getReportingPath()}': {e!s}" ) print("Creating GitHub Badges...") diff --git a/contentctl/actions/test.py b/contentctl/actions/test.py index 90ac3951..c751af7f 100644 --- a/contentctl/actions/test.py +++ b/contentctl/actions/test.py @@ -18,9 +18,8 @@ from contentctl.actions.detection_testing.views.DetectionTestingViewWeb import ( DetectionTestingViewWeb, ) -from contentctl.objects.config import Changes, Selected +from contentctl.objects.config import Changes, Selected, test_servers from contentctl.objects.config import test as test_ -from contentctl.objects.config import test_servers from contentctl.objects.detection import Detection from contentctl.objects.integration_test import IntegrationTest @@ -151,5 +150,5 @@ def execute(self, input_dto: TestInputDto) -> bool: return summary.get("success", False) except Exception as e: - print(f"Error determining if whole test was successful: {str(e)}") + print(f"Error determining if whole test was successful: {e!s}") return False diff --git a/contentctl/actions/validate.py b/contentctl/actions/validate.py index 5dc34f16..2ff41bc0 100644 --- a/contentctl/actions/validate.py +++ b/contentctl/actions/validate.py @@ -118,7 +118,7 @@ def validate_latest_TA_information(self, data_sources: list[DataSource]) -> None ) except Exception as e: errors.append( - f"Error processing checking version of TA {supported_TA.name}: {str(e)}" + f"Error processing checking version of TA {supported_TA.name}: {e!s}" ) if len(errors) > 0: diff --git a/contentctl/api.py b/contentctl/api.py index 037ac5ce..d1163349 100644 --- a/contentctl/api.py +++ b/contentctl/api.py @@ -1,9 +1,10 @@ from pathlib import Path -from typing import Any, Union, Type +from typing import Any, Type, Union + +from contentctl.input.director import DirectorOutputDto from contentctl.input.yml_reader import YmlReader -from contentctl.objects.config import test_common, test, test_servers +from contentctl.objects.config import test, test_common, test_servers from contentctl.objects.security_content_object import SecurityContentObject -from contentctl.input.director import DirectorOutputDto def config_from_file( @@ -36,7 +37,7 @@ def config_from_file( except Exception as e: raise Exception( - f"Failed to load contentctl configuration from file '{path}': {str(e)}" + f"Failed to load contentctl configuration from file '{path}': {e!s}" ) # Apply settings that have been overridden from the ones in the file @@ -45,7 +46,7 @@ def config_from_file( except Exception as e: raise Exception( f"Failed updating dictionary of values read from file '{path}'" - f" with the dictionary of arguments passed: {str(e)}" + f" with the dictionary of arguments passed: {e!s}" ) # The function below will throw its own descriptive exception if it fails @@ -78,7 +79,7 @@ def config_from_dict( try: test_object = configType.model_validate(config) except Exception as e: - raise Exception(f"Failed to load contentctl configuration from dict:\n{str(e)}") + raise Exception(f"Failed to load contentctl configuration from dict:\n{e!s}") return test_object diff --git a/contentctl/contentctl.py b/contentctl/contentctl.py index c0f37d9a..573c7ba0 100644 --- a/contentctl/contentctl.py +++ b/contentctl/contentctl.py @@ -206,7 +206,7 @@ def main(): config_obj = YmlReader().load_file(configFile, add_fields=False) t = test.model_validate(config_obj) except Exception as e: - print(f"Error validating 'contentctl.yml':\n{str(e)}") + print(f"Error validating 'contentctl.yml':\n{e!s}") sys.exit(1) # For ease of generating the constructor, we want to allow construction diff --git a/contentctl/enrichments/attack_enrichment.py b/contentctl/enrichments/attack_enrichment.py index 33729f72..da7dfafa 100644 --- a/contentctl/enrichments/attack_enrichment.py +++ b/contentctl/enrichments/attack_enrichment.py @@ -183,7 +183,7 @@ def get_attack_lookup( ) except Exception as err: - raise Exception(f"Error getting MITRE Enrichment: {str(err)}") + raise Exception(f"Error getting MITRE Enrichment: {err!s}") print("Done!") return attack_lookup diff --git a/contentctl/enrichments/cve_enrichment.py b/contentctl/enrichments/cve_enrichment.py index 75ffbd5a..424fff06 100644 --- a/contentctl/enrichments/cve_enrichment.py +++ b/contentctl/enrichments/cve_enrichment.py @@ -1,8 +1,11 @@ from __future__ import annotations -from pycvesearch import CVESearch -from typing import Annotated, Union, TYPE_CHECKING -from pydantic import ConfigDict, BaseModel, Field, computed_field + from decimal import Decimal +from typing import TYPE_CHECKING, Annotated, Union + +from pycvesearch import CVESearch +from pydantic import BaseModel, ConfigDict, Field, computed_field + from contentctl.objects.annotated_types import CVE_TYPE if TYPE_CHECKING: @@ -46,7 +49,7 @@ def getCveEnrichment( return CveEnrichment(use_enrichment=True, cve_api_obj=cve_api_obj) except Exception as e: raise Exception( - f"Error setting CVE_SEARCH API to: {CVESSEARCH_API_URL}: {str(e)}" + f"Error setting CVE_SEARCH API to: {CVESSEARCH_API_URL}: {e!s}" ) return CveEnrichment(use_enrichment=False, cve_api_obj=None) @@ -57,14 +60,14 @@ def enrich_cve( if not self.use_enrichment: return CveEnrichmentObj( id=cve_id, - cvss=Decimal(5.0), + cvss=Decimal("5.0"), summary="SUMMARY NOT AVAILABLE! ONLY THE LINK WILL BE USED AT THIS TIME", ) else: print("WARNING - Dynamic enrichment not supported at this time.") return CveEnrichmentObj( id=cve_id, - cvss=Decimal(5.0), + cvss=Decimal("5.0"), summary="SUMMARY NOT AVAILABLE! ONLY THE LINK WILL BE USED AT THIS TIME", ) # Depending on needs, we may add dynamic enrichment functionality back to the tool diff --git a/contentctl/enrichments/splunk_app_enrichment.py b/contentctl/enrichments/splunk_app_enrichment.py index 00d7c1be..9c30e2b9 100644 --- a/contentctl/enrichments/splunk_app_enrichment.py +++ b/contentctl/enrichments/splunk_app_enrichment.py @@ -1,8 +1,9 @@ -import requests -import xmltodict import functools -import shelve import os +import shelve + +import requests +import xmltodict SPLUNKBASE_API_URL = "https://apps.splunk.com/api/apps/entriesbyid/" @@ -75,7 +76,7 @@ def enrich_splunk_app( splunk_app_enriched["url"] = "" except Exception as e: print( - f"There was an unknown error enriching the Splunk TA [{splunk_ta}]: {str(e)}" + f"There was an unknown error enriching the Splunk TA [{splunk_ta}]: {e!s}" ) splunk_app_enriched["name"] = splunk_ta splunk_app_enriched["url"] = "" diff --git a/contentctl/helper/link_validator.py b/contentctl/helper/link_validator.py index 181642ec..9f036e81 100644 --- a/contentctl/helper/link_validator.py +++ b/contentctl/helper/link_validator.py @@ -1,13 +1,13 @@ -from pydantic import BaseModel, model_validator -from typing import Union, Callable, Any -import requests -import urllib3 -import urllib3.exceptions -import time import abc - import os import shelve +import time +from typing import Any, Callable, Union + +import requests +import urllib3 +import urllib3.exceptions +from pydantic import BaseModel, model_validator DEFAULT_USER_AGENT_STRING = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36" ALLOWED_HTTP_CODES = [200] diff --git a/contentctl/helper/splunk_app.py b/contentctl/helper/splunk_app.py index 34920e54..6e0d877f 100644 --- a/contentctl/helper/splunk_app.py +++ b/contentctl/helper/splunk_app.py @@ -1,7 +1,7 @@ import json -from typing import Optional, Collection -from pathlib import Path import xml.etree.ElementTree as ET +from pathlib import Path +from typing import Collection, Optional from urllib.parse import urlencode import requests @@ -139,7 +139,7 @@ def get_app_info_by_uid(self) -> dict: response.raise_for_status() except requests.exceptions.RequestException as e: raise SplunkBaseError( - f"Error fetching app info for app_uid {self.app_uid}: {str(e)}" + f"Error fetching app info for app_uid {self.app_uid}: {e!s}" ) # parse JSON and set cache @@ -191,7 +191,7 @@ def set_app_uid(self) -> None: response.raise_for_status() except requests.exceptions.RequestException as e: raise SplunkBaseError( - f"Error fetching app_uid for app_name_id '{self.app_name_id}': {str(e)}" + f"Error fetching app_uid for app_name_id '{self.app_name_id}': {e!s}" ) # Extract the app_uid from the redirect path @@ -233,7 +233,7 @@ def __fetch_url_latest_version_info(self) -> str: response.raise_for_status() except requests.exceptions.RequestException as e: raise SplunkBaseError( - f"Error fetching app entries for app_name_id '{self.app_name_id}': {str(e)}" + f"Error fetching app entries for app_name_id '{self.app_name_id}': {e!s}" ) # parse xml @@ -269,7 +269,7 @@ def __fetch_url_latest_version_download(self, info_url: str) -> str: response.raise_for_status() except requests.exceptions.RequestException as e: raise SplunkBaseError( - f"Error fetching download info for app_name_id '{self.app_name_id}': {str(e)}" + f"Error fetching download info for app_name_id '{self.app_name_id}': {e!s}" ) # parse XML and extract download URL diff --git a/contentctl/helper/utils.py b/contentctl/helper/utils.py index 78b44226..b11613ac 100644 --- a/contentctl/helper/utils.py +++ b/contentctl/helper/utils.py @@ -60,7 +60,7 @@ def get_security_content_files_from_directory( if not path.exists() or not path.is_dir(): raise Exception( - f"Unable to get security_content files, required directory '{str(path)}' does not exist or is not a directory" + f"Unable to get security_content files, required directory '{path!s}' does not exist or is not a directory" ) allowedFiles: list[pathlib.Path] = [] @@ -275,7 +275,7 @@ def verify_file_exists( # This is a file and we know it exists return None except Exception as e: - print(f"Could not copy local file {file_path} the file because {str(e)}") + print(f"Could not copy local file {file_path} the file because {e!s}") # Try to make a head request to verify existence of the file try: @@ -285,7 +285,7 @@ def verify_file_exists( if req.status_code > 400: raise (Exception(f"Return code={req.status_code}")) except Exception as e: - raise (Exception(f"HTTP Resolution Failed: {str(e)}")) + raise (Exception(f"HTTP Resolution Failed: {e!s}")) @staticmethod def copy_local_file( @@ -326,7 +326,7 @@ def copy_local_file( except Exception as e: raise ( Exception( - f"Error: Could not copy local file [{sourcePath}] to [{destPath}]: [{str(e)}]" + f"Error: Could not copy local file [{sourcePath}] to [{destPath}]: [{e!s}]" ) ) if verbose_print: @@ -417,26 +417,26 @@ def download_file_from_http( except requests.exceptions.ConnectionError as e: raise ( Exception( - f"Error: Could not download file [{file_path}] to [{destinationPath}] (Unable to connect to server. Are you sure the server exists and you have connectivity to it?): [{str(e)}]" + f"Error: Could not download file [{file_path}] to [{destinationPath}] (Unable to connect to server. Are you sure the server exists and you have connectivity to it?): [{e!s}]" ) ) except requests.exceptions.HTTPError as e: raise ( Exception( - f"Error: Could not download file [{file_path}] to [{destinationPath}] (The file was probably not found on the server): [{str(e)}]" + f"Error: Could not download file [{file_path}] to [{destinationPath}] (The file was probably not found on the server): [{e!s}]" ) ) except requests.exceptions.Timeout as e: raise ( Exception( - f"Error: Could not download file [{file_path}] to [{destinationPath}] (Timeout getting file): [{str(e)}]" + f"Error: Could not download file [{file_path}] to [{destinationPath}] (Timeout getting file): [{e!s}]" ) ) except Exception as e: raise ( Exception( - f"Error: Could not download file [{file_path}] to [{destinationPath}] (Unknown Reason): [{str(e)}]" + f"Error: Could not download file [{file_path}] to [{destinationPath}] (Unknown Reason): [{e!s}]" ) ) finally: diff --git a/contentctl/input/director.py b/contentctl/input/director.py index 5b8a42d7..c6e6b462 100644 --- a/contentctl/input/director.py +++ b/contentctl/input/director.py @@ -316,7 +316,7 @@ def createSecurityContent( print(f"{Colors.BOLD}{Colors.BRIGHT_MAGENTA}╚{'═' * 60}╝{Colors.END}\n") print( - f"{Colors.BOLD}{Colors.GREEN}{Colors.SPARKLE} Validation Completed{Colors.END} – Issues detected in {Colors.RED}{Colors.BOLD}{len(validation_errors)}{Colors.END} files.\n" + f"{Colors.BOLD}{Colors.GREEN}{Colors.SPARKLE} Validation Completed{Colors.END} - Issues detected in {Colors.RED}{Colors.BOLD}{len(validation_errors)}{Colors.END} files.\n" ) for index, entry in enumerate(validation_errors, 1): @@ -372,7 +372,7 @@ def createSecurityContent( f" {Colors.RED}{Colors.ERROR} {error_msg}{Colors.END}" ) else: - print(f" {Colors.RED}{Colors.ERROR} {str(error)}{Colors.END}") + print(f" {Colors.RED}{Colors.ERROR} {error!s}{Colors.END}") print("") # Clean footer with next steps diff --git a/contentctl/input/new_content_questions.py b/contentctl/input/new_content_questions.py index a7ce0e56..35621ae1 100644 --- a/contentctl/input/new_content_questions.py +++ b/contentctl/input/new_content_questions.py @@ -1,4 +1,5 @@ from typing import Any + from contentctl.objects.enums import DataSource diff --git a/contentctl/input/yml_reader.py b/contentctl/input/yml_reader.py index 84418563..3a7fa07a 100644 --- a/contentctl/input/yml_reader.py +++ b/contentctl/input/yml_reader.py @@ -16,7 +16,7 @@ def load_file( file_handler = open(file_path, "r", encoding="utf-8") except OSError as exc: print( - f"\nThere was an unrecoverable error when opening the file '{file_path}' - we will exit immediately:\n{str(exc)}" + f"\nThere was an unrecoverable error when opening the file '{file_path}' - we will exit immediately:\n{exc!s}" ) sys.exit(1) @@ -57,7 +57,7 @@ def load_file( ) except yaml.YAMLError as exc: print( - f"\nThere was an unrecoverable YML Parsing error when reading or parsing the file '{file_path}' - we will exit immediately:\n{str(exc)}" + f"\nThere was an unrecoverable YML Parsing error when reading or parsing the file '{file_path}' - we will exit immediately:\n{exc!s}" ) sys.exit(1) diff --git a/contentctl/objects/abstract_security_content_objects/detection_abstract.py b/contentctl/objects/abstract_security_content_objects/detection_abstract.py index 81e8f737..d0c2e785 100644 --- a/contentctl/objects/abstract_security_content_objects/detection_abstract.py +++ b/contentctl/objects/abstract_security_content_objects/detection_abstract.py @@ -463,7 +463,7 @@ def risk(self) -> list[dict[str, Any]]: ) """ action.risk.param._risk - of the conf file only contains a list of dicts. We do not eant to + of the conf file only contains a list of dicts. We do not eant to include the message here, so we do not return it. """ rba_dict = self.rba.model_dump() diff --git a/contentctl/objects/alert_action.py b/contentctl/objects/alert_action.py index c50e9bdb..d90f01e7 100644 --- a/contentctl/objects/alert_action.py +++ b/contentctl/objects/alert_action.py @@ -1,12 +1,14 @@ from __future__ import annotations -from pydantic import BaseModel, model_serializer, ConfigDict + from typing import Optional +from pydantic import BaseModel, ConfigDict, model_serializer + from contentctl.objects.deployment_email import DeploymentEmail from contentctl.objects.deployment_notable import DeploymentNotable +from contentctl.objects.deployment_phantom import DeploymentPhantom from contentctl.objects.deployment_rba import DeploymentRBA from contentctl.objects.deployment_slack import DeploymentSlack -from contentctl.objects.deployment_phantom import DeploymentPhantom class AlertAction(BaseModel): diff --git a/contentctl/objects/atomic.py b/contentctl/objects/atomic.py index 49ac443b..5c518942 100644 --- a/contentctl/objects/atomic.py +++ b/contentctl/objects/atomic.py @@ -1,16 +1,19 @@ from __future__ import annotations + from typing import TYPE_CHECKING if TYPE_CHECKING: from contentctl.objects.config import validate -from contentctl.input.yml_reader import YmlReader -from pydantic import BaseModel, model_validator, ConfigDict, FilePath, UUID4 import dataclasses -from typing import List, Optional, Dict, Union, Self import pathlib -from enum import StrEnum, auto import uuid +from enum import StrEnum, auto +from typing import Dict, List, Optional, Self, Union + +from pydantic import UUID4, BaseModel, ConfigDict, FilePath, model_validator + +from contentctl.input.yml_reader import YmlReader class SupportedPlatform(StrEnum): @@ -125,7 +128,7 @@ def parseArtRepo(cls, repo_path: pathlib.Path) -> dict[uuid.UUID, AtomicTest]: try: atomic_files.append(cls.constructAtomicFile(obj_path)) except Exception as e: - error_messages.append(f"File [{obj_path}]\n{str(e)}") + error_messages.append(f"File [{obj_path}]\n{e!s}") if len(error_messages) > 0: exceptions_string = "\n\n".join(error_messages) diff --git a/contentctl/objects/base_test.py b/contentctl/objects/base_test.py index 4505b4d3..5cd174b8 100644 --- a/contentctl/objects/base_test.py +++ b/contentctl/objects/base_test.py @@ -1,6 +1,6 @@ +from abc import ABC, abstractmethod from enum import StrEnum from typing import Union -from abc import ABC, abstractmethod from pydantic import BaseModel, ConfigDict diff --git a/contentctl/objects/base_test_result.py b/contentctl/objects/base_test_result.py index c528969a..8ddd003c 100644 --- a/contentctl/objects/base_test_result.py +++ b/contentctl/objects/base_test_result.py @@ -1,7 +1,7 @@ -from typing import Union, Any from enum import StrEnum +from typing import Any, Union -from pydantic import ConfigDict, BaseModel +from pydantic import BaseModel, ConfigDict from splunklib.data import Record # type: ignore from contentctl.helper.utils import Utils diff --git a/contentctl/objects/baseline_tags.py b/contentctl/objects/baseline_tags.py index c8911cc9..54a4c2ac 100644 --- a/contentctl/objects/baseline_tags.py +++ b/contentctl/objects/baseline_tags.py @@ -1,18 +1,19 @@ from __future__ import annotations + +from typing import Any, List, Union + from pydantic import ( BaseModel, + ConfigDict, Field, - field_validator, ValidationInfo, + field_validator, model_serializer, - ConfigDict, ) -from typing import List, Any, Union -from contentctl.objects.story import Story from contentctl.objects.detection import Detection -from contentctl.objects.enums import SecurityContentProductName -from contentctl.objects.enums import SecurityDomain +from contentctl.objects.enums import SecurityContentProductName, SecurityDomain +from contentctl.objects.story import Story class BaselineTags(BaseModel): diff --git a/contentctl/objects/config.py b/contentctl/objects/config.py index bffa66d6..6d785cb0 100644 --- a/contentctl/objects/config.py +++ b/contentctl/objects/config.py @@ -200,7 +200,7 @@ def validate_version(cls, v, values): raise ( ValueError( "The specified version does not follow the semantic versioning spec " - f"(https://semver.org/). {str(e)}" + f"(https://semver.org/). {e!s}" ) ) return v @@ -1094,7 +1094,7 @@ def dumpCICDPlanAndQuit(self, githash: str, detections: List[Detection]): f"Successfully wrote a test plan for [{len(self.mode.files)} detections] using [{len(self.apps)} apps] to [{output_file}]" ) except Exception as e: - raise Exception(f"Error writing test plan file [{output_file}]: {str(e)}") + raise Exception(f"Error writing test plan file [{output_file}]: {e!s}") def getLocalAppDir(self) -> pathlib.Path: # docker really wants absolute paths @@ -1189,7 +1189,7 @@ def getContainerInfrastructureObjects(self) -> Self: return self except Exception as e: - raise ValueError(f"Error constructing container test_instances: {str(e)}") + raise ValueError(f"Error constructing container test_instances: {e!s}") @model_validator(mode="after") def ensureAppsAreGood(self) -> Self: @@ -1213,7 +1213,7 @@ def ensureAppsAreGood(self) -> Self: stage_file=False, include_custom_app=False ) except Exception as e: - raise Exception(f"Error validating test apps: {str(e)}") + raise Exception(f"Error validating test apps: {e!s}") return self def getContainerEnvironmentString( @@ -1363,7 +1363,7 @@ def releaseNotesFilename(self, filename: str) -> pathlib.Path: p.mkdir(exist_ok=True, parents=True) except Exception as e: raise Exception( - f"Error making the directory '{p}' to hold release_notes: {str(e)}" + f"Error making the directory '{p}' to hold release_notes: {e!s}" ) return p / filename diff --git a/contentctl/objects/dashboard.py b/contentctl/objects/dashboard.py index 4c2d05b8..f05a2d23 100644 --- a/contentctl/objects/dashboard.py +++ b/contentctl/objects/dashboard.py @@ -79,7 +79,7 @@ def validate_fields_from_json(cls, data: Any) -> Any: try: json_obj: dict[str, Any] = json.load(jsonFilePointer) except Exception as e: - raise ValueError(f"Unable to load data from {json_file_path}: {str(e)}") + raise ValueError(f"Unable to load data from {json_file_path}: {e!s}") name_from_file = data.get("name", None) name_from_json = json_obj.get("title", None) diff --git a/contentctl/objects/deployment_email.py b/contentctl/objects/deployment_email.py index a4f829f0..92e00c74 100644 --- a/contentctl/objects/deployment_email.py +++ b/contentctl/objects/deployment_email.py @@ -1,4 +1,5 @@ from __future__ import annotations + from pydantic import BaseModel, ConfigDict diff --git a/contentctl/objects/deployment_notable.py b/contentctl/objects/deployment_notable.py index 8ac77568..ea0037bc 100644 --- a/contentctl/objects/deployment_notable.py +++ b/contentctl/objects/deployment_notable.py @@ -1,7 +1,9 @@ from __future__ import annotations -from pydantic import BaseModel, ConfigDict + from typing import List +from pydantic import BaseModel, ConfigDict + class DeploymentNotable(BaseModel): model_config = ConfigDict(extra="forbid") diff --git a/contentctl/objects/deployment_phantom.py b/contentctl/objects/deployment_phantom.py index 8bd96516..bc8e58c2 100644 --- a/contentctl/objects/deployment_phantom.py +++ b/contentctl/objects/deployment_phantom.py @@ -1,4 +1,5 @@ from __future__ import annotations + from pydantic import BaseModel, ConfigDict diff --git a/contentctl/objects/deployment_rba.py b/contentctl/objects/deployment_rba.py index 53df26f4..3fc4394f 100644 --- a/contentctl/objects/deployment_rba.py +++ b/contentctl/objects/deployment_rba.py @@ -1,4 +1,5 @@ from __future__ import annotations + from pydantic import BaseModel, ConfigDict diff --git a/contentctl/objects/deployment_scheduling.py b/contentctl/objects/deployment_scheduling.py index 177fbb30..4783c89e 100644 --- a/contentctl/objects/deployment_scheduling.py +++ b/contentctl/objects/deployment_scheduling.py @@ -1,4 +1,5 @@ from __future__ import annotations + from pydantic import BaseModel, ConfigDict diff --git a/contentctl/objects/deployment_slack.py b/contentctl/objects/deployment_slack.py index 63f99767..e6224c6e 100644 --- a/contentctl/objects/deployment_slack.py +++ b/contentctl/objects/deployment_slack.py @@ -1,4 +1,5 @@ from __future__ import annotations + from pydantic import BaseModel, ConfigDict diff --git a/contentctl/objects/detection_stanza.py b/contentctl/objects/detection_stanza.py index 8d4b545d..6ddfee98 100644 --- a/contentctl/objects/detection_stanza.py +++ b/contentctl/objects/detection_stanza.py @@ -1,6 +1,6 @@ -from typing import ClassVar import hashlib from functools import cached_property +from typing import ClassVar from pydantic import BaseModel, Field, computed_field diff --git a/contentctl/objects/integration_test.py b/contentctl/objects/integration_test.py index c1078e89..63cc8f09 100644 --- a/contentctl/objects/integration_test.py +++ b/contentctl/objects/integration_test.py @@ -1,9 +1,9 @@ from pydantic import Field from contentctl.objects.base_test import BaseTest, TestType -from contentctl.objects.unit_test import UnitTest -from contentctl.objects.integration_test_result import IntegrationTestResult from contentctl.objects.base_test_result import TestResultStatus +from contentctl.objects.integration_test_result import IntegrationTestResult +from contentctl.objects.unit_test import UnitTest class IntegrationTest(BaseTest): diff --git a/contentctl/objects/investigation_tags.py b/contentctl/objects/investigation_tags.py index a8ff6307..02847a33 100644 --- a/contentctl/objects/investigation_tags.py +++ b/contentctl/objects/investigation_tags.py @@ -1,18 +1,21 @@ from __future__ import annotations + from typing import List + from pydantic import ( BaseModel, + ConfigDict, Field, - field_validator, ValidationInfo, + field_validator, model_serializer, - ConfigDict, ) -from contentctl.objects.story import Story + from contentctl.objects.enums import ( SecurityContentInvestigationProductName, SecurityDomain, ) +from contentctl.objects.story import Story class InvestigationTags(BaseModel): diff --git a/contentctl/objects/manual_test.py b/contentctl/objects/manual_test.py index d77f21fe..04c2580b 100644 --- a/contentctl/objects/manual_test.py +++ b/contentctl/objects/manual_test.py @@ -2,10 +2,10 @@ from pydantic import Field -from contentctl.objects.test_attack_data import TestAttackData -from contentctl.objects.manual_test_result import ManualTestResult from contentctl.objects.base_test import BaseTest, TestType from contentctl.objects.base_test_result import TestResultStatus +from contentctl.objects.manual_test_result import ManualTestResult +from contentctl.objects.test_attack_data import TestAttackData class ManualTest(BaseTest): diff --git a/contentctl/objects/playbook_tags.py b/contentctl/objects/playbook_tags.py index 3068e6df..6924098a 100644 --- a/contentctl/objects/playbook_tags.py +++ b/contentctl/objects/playbook_tags.py @@ -1,7 +1,10 @@ from __future__ import annotations -from typing import Optional, List -from pydantic import BaseModel, Field, ConfigDict + import enum +from typing import List, Optional + +from pydantic import BaseModel, ConfigDict, Field + from contentctl.objects.detection import Detection diff --git a/contentctl/objects/risk_analysis_action.py b/contentctl/objects/risk_analysis_action.py index aa0d2c89..e04abcec 100644 --- a/contentctl/objects/risk_analysis_action.py +++ b/contentctl/objects/risk_analysis_action.py @@ -1,5 +1,5 @@ -from typing import Any import json +from typing import Any from pydantic import BaseModel, field_validator diff --git a/contentctl/objects/savedsearches_conf.py b/contentctl/objects/savedsearches_conf.py index 582ec5d9..79fcec28 100644 --- a/contentctl/objects/savedsearches_conf.py +++ b/contentctl/objects/savedsearches_conf.py @@ -1,8 +1,8 @@ -from pathlib import Path -from typing import Any, ClassVar import re -import tempfile import tarfile +import tempfile +from pathlib import Path +from typing import Any, ClassVar from pydantic import BaseModel, Field, PrivateAttr diff --git a/contentctl/objects/story_tags.py b/contentctl/objects/story_tags.py index 1abf30f3..6af77346 100644 --- a/contentctl/objects/story_tags.py +++ b/contentctl/objects/story_tags.py @@ -45,7 +45,7 @@ class StoryTags(BaseModel): def getCategory_conf(self) -> str: # if len(self.category) > 1: # print("Story with more than 1 category. We can only have 1 category, fix it!") - return list(self.category)[0] + return next(iter(self.category)) @model_serializer def serialize_model(self): diff --git a/contentctl/objects/test_group.py b/contentctl/objects/test_group.py index cd651f54..28b67b07 100644 --- a/contentctl/objects/test_group.py +++ b/contentctl/objects/test_group.py @@ -1,9 +1,9 @@ from pydantic import BaseModel -from contentctl.objects.unit_test import UnitTest +from contentctl.objects.base_test_result import TestResultStatus from contentctl.objects.integration_test import IntegrationTest from contentctl.objects.test_attack_data import TestAttackData -from contentctl.objects.base_test_result import TestResultStatus +from contentctl.objects.unit_test import UnitTest class TestGroup(BaseModel): diff --git a/contentctl/objects/throttling.py b/contentctl/objects/throttling.py index de6f9cd9..da7137d3 100644 --- a/contentctl/objects/throttling.py +++ b/contentctl/objects/throttling.py @@ -1,6 +1,7 @@ -from pydantic import BaseModel, Field, field_validator from typing import Annotated +from pydantic import BaseModel, Field, field_validator + # Alert Suppression/Throttling settings have been taken from # https://docs.splunk.com/Documentation/Splunk/9.2.2/Admin/Savedsearchesconf diff --git a/contentctl/objects/unit_test.py b/contentctl/objects/unit_test.py index 1bfc6308..d84a0de6 100644 --- a/contentctl/objects/unit_test.py +++ b/contentctl/objects/unit_test.py @@ -2,10 +2,10 @@ from pydantic import Field -from contentctl.objects.test_attack_data import TestAttackData -from contentctl.objects.unit_test_result import UnitTestResult from contentctl.objects.base_test import BaseTest, TestType from contentctl.objects.base_test_result import TestResultStatus +from contentctl.objects.test_attack_data import TestAttackData +from contentctl.objects.unit_test_result import UnitTestResult class UnitTest(BaseTest): diff --git a/contentctl/objects/unit_test_baseline.py b/contentctl/objects/unit_test_baseline.py index ca7e2a3e..d4b5ed2a 100644 --- a/contentctl/objects/unit_test_baseline.py +++ b/contentctl/objects/unit_test_baseline.py @@ -1,6 +1,7 @@ -from pydantic import BaseModel, ConfigDict from typing import Union +from pydantic import BaseModel, ConfigDict + class UnitTestBaseline(BaseModel): model_config = ConfigDict(extra="forbid") diff --git a/contentctl/objects/unit_test_result.py b/contentctl/objects/unit_test_result.py index 56aa863a..c8b62834 100644 --- a/contentctl/objects/unit_test_result.py +++ b/contentctl/objects/unit_test_result.py @@ -1,7 +1,9 @@ from __future__ import annotations -from typing import Union, TYPE_CHECKING +from typing import TYPE_CHECKING, Union + from splunklib.data import Record + from contentctl.objects.base_test_result import BaseTestResult, TestResultStatus if TYPE_CHECKING: @@ -70,7 +72,7 @@ def set_job_content( elif content is None: self.status = TestResultStatus.ERROR if self.exception is not None: - self.message = f"EXCEPTION: {str(self.exception)}" + self.message = f"EXCEPTION: {self.exception!s}" else: self.message = "ERROR with no more specific message available." self.sid_link = NO_SID diff --git a/contentctl/output/conf_output.py b/contentctl/output/conf_output.py index b90d0121..df8c0d8a 100644 --- a/contentctl/output/conf_output.py +++ b/contentctl/output/conf_output.py @@ -270,7 +270,7 @@ def packageAppSlim(self) -> None: output_dir=pathlib.Path(self.config.getBuildDir()), ) except SystemExit as e: - raise Exception(f"Error building package with slim: {str(e)}") + raise Exception(f"Error building package with slim: {e!s}") except Exception as e: print( @@ -278,7 +278,7 @@ def packageAppSlim(self) -> None: "Packaging app with tar instead. This should still work, but appinspect may catch " "errors that otherwise would have been flagged by slim." ) - raise Exception(f"slim (splunk packaging toolkit) not installed: {str(e)}") + raise Exception(f"slim (splunk packaging toolkit) not installed: {e!s}") def packageApp(self, method: Callable[[ConfOutput], None] = packageAppTar) -> None: return method(self) diff --git a/contentctl/output/conf_writer.py b/contentctl/output/conf_writer.py index bcfb6d19..9b366e5a 100644 --- a/contentctl/output/conf_writer.py +++ b/contentctl/output/conf_writer.py @@ -339,7 +339,7 @@ def writeConfFile( f"Name:{obj.name if not isinstance(obj, CustomApp) else obj.title}\n" f"Type {type(obj)}: \n" f"Output File: {app_output_path}\n" - f"Error: {str(e)}\n" + f"Error: {e!s}\n" ) output_path.parent.mkdir(parents=True, exist_ok=True) @@ -376,7 +376,7 @@ def validateConfFile(path: pathlib.Path): try: _ = configparser.RawConfigParser().read(path) except Exception as e: - raise Exception(f"Failed to validate .conf file {str(path)}: {str(e)}") + raise Exception(f"Failed to validate .conf file {path!s}: {e!s}") @staticmethod def validateXmlFile(path: pathlib.Path): @@ -390,7 +390,7 @@ def validateXmlFile(path: pathlib.Path): with open(path, "r") as xmlFile: _ = ET.fromstring(xmlFile.read()) except Exception as e: - raise Exception(f"Failed to validate .xml file {str(path)}: {str(e)}") + raise Exception(f"Failed to validate .xml file {path!s}: {e!s}") @staticmethod def validateManifestFile(path: pathlib.Path): @@ -405,9 +405,9 @@ def validateManifestFile(path: pathlib.Path): _ = json.load(manifestFile) except Exception as e: raise Exception( - f"Failed to validate .manifest file {str(path)} (Note that .manifest files should contain only valid JSON-formatted data): {str(e)}" + f"Failed to validate .manifest file {path!s} (Note that .manifest files should contain only valid JSON-formatted data): {e!s}" ) except Exception as e: raise Exception( - f"Failed to validate .manifest file {str(path)} (Note that .manifest files should contain only valid JSON-formatted data): {str(e)}" + f"Failed to validate .manifest file {path!s} (Note that .manifest files should contain only valid JSON-formatted data): {e!s}" ) diff --git a/contentctl/output/doc_md_output.py b/contentctl/output/doc_md_output.py index 9d128742..26c732b6 100644 --- a/contentctl/output/doc_md_output.py +++ b/contentctl/output/doc_md_output.py @@ -1,6 +1,5 @@ import os import sys - from pathlib import Path from contentctl.output.jinja_writer import JinjaWriter diff --git a/contentctl/output/jinja_writer.py b/contentctl/output/jinja_writer.py index 0cd0a45a..6a626743 100644 --- a/contentctl/output/jinja_writer.py +++ b/contentctl/output/jinja_writer.py @@ -1,5 +1,6 @@ import os from typing import Any + from jinja2 import Environment, FileSystemLoader diff --git a/contentctl/output/json_writer.py b/contentctl/output/json_writer.py index c17ac787..f823494a 100644 --- a/contentctl/output/json_writer.py +++ b/contentctl/output/json_writer.py @@ -27,5 +27,5 @@ def writeJsonObject( except Exception as e: raise Exception( - f"Error serializing object to Json File '{file_path}': {str(e)}" + f"Error serializing object to Json File '{file_path}': {e!s}" ) diff --git a/contentctl/output/yml_writer.py b/contentctl/output/yml_writer.py index a7d0381a..3c84e7cc 100644 --- a/contentctl/output/yml_writer.py +++ b/contentctl/output/yml_writer.py @@ -1,6 +1,7 @@ -import yaml +from enum import IntEnum, StrEnum from typing import Any -from enum import StrEnum, IntEnum + +import yaml # Set the following so that we can write StrEnum and IntEnum # to files. Otherwise, we will get the following errors when trying diff --git a/pyproject.toml b/pyproject.toml index ca1726d8..46d940d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ tqdm = "^4.66.5" pygit2 = "^1.15.1" #We are pinned to this version of tyro because 0.9.23 and above #have an issue when parsing an extremely large number of files -#(in our testing great than 130) when using the mode:selected +#(in our testing great than 130) when using the mode:selected #--mode.files command. tyro = "^0.9.2,<0.9.23" gitpython = "^3.1.43" @@ -38,7 +38,7 @@ setuptools = ">=69.5.1,<81.0.0" rich = "^14.0.0" [tool.poetry.group.dev.dependencies] -ruff = "^0.11.2" +ruff = "^0.12.5" [build-system] requires = ["poetry-core>=1.0.0"] @@ -47,32 +47,32 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] # Exclude a variety of commonly ignored directories. exclude = [ - ".bzr", - ".direnv", - ".eggs", - ".git", - ".git-rewrite", - ".hg", - ".ipynb_checkpoints", - ".mypy_cache", - ".nox", - ".pants.d", - ".pyenv", - ".pytest_cache", - ".pytype", - ".ruff_cache", - ".svn", - ".tox", - ".venv", - ".vscode", - "__pypackages__", - "_build", - "buck-out", - "build", - "dist", - "node_modules", - "site-packages", - "venv", + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", ] # Same as Black. @@ -85,8 +85,8 @@ target-version = "py311" # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or # McCabe complexity (`C901`) by default. -select = ["E4", "E7", "E9", "F"] -ignore = [] +select = ["E", "W", "F", "I", "RUF"] +ignore = ["E501", "RUF012"] # Allow fix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"]