From f8302e15c190d104b51ce2247dbdfb62b1a01fd3 Mon Sep 17 00:00:00 2001 From: Zarithas Date: Wed, 22 Oct 2025 17:24:39 -0400 Subject: [PATCH] Fixed several logic issues / generation of secondary paths. Cleaned up Policy Prep text to be accurate to current functionality. Fixed issue with going back from policy prep menu. Switched to logging.dict from standard logging config. --- IRT_icon_32-512.ico | Bin 0 -> 21181 bytes flows/prepPolicy.py | 43 +++++++++++++++-------- icon.ico | Bin 30903 -> 0 bytes utils/menus.py | 27 +++++++++----- utils/setup.py | 84 +++++++++++++++++++++++++++----------------- utils/utils.py | 45 ++++++++++-------------- 6 files changed, 117 insertions(+), 82 deletions(-) create mode 100644 IRT_icon_32-512.ico delete mode 100644 icon.ico diff --git a/IRT_icon_32-512.ico b/IRT_icon_32-512.ico new file mode 100644 index 0000000000000000000000000000000000000000..103b72ef73c7c58a81ad42b075aad1a626c2402f GIT binary patch literal 21181 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 v2p~cYUO!I+A-Hx9S-jwA;Ljm+IG!f_)x>}@ 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 diff --git a/utils/menus.py b/utils/menus.py index 404dfbb..0794d8e 100644 --- a/utils/menus.py +++ b/utils/menus.py @@ -41,6 +41,7 @@ from utils.utils import ( get_sanitized_input, open_directory, printEnforceChecklist, + locked ) logger = logging.getLogger(__name__) @@ -99,7 +100,7 @@ def menu_main(api: AirlockAPIWrapper): else: print(colorText("Invalid choice. Please try again.", "red")) -def menu_policy_enforce(api: AirlockAPIWrapper): +def menu_policy_enforce(api: AirlockAPIWrapper): #TODO Need to clean up 6 and 7 into functions selected_policies = [] destination_policy = [] destination_allowlist = [] @@ -139,7 +140,7 @@ def menu_policy_enforce(api: AirlockAPIWrapper): print("File not found. Please make sure it's saved correctly and try again.") elif choice == "5": - if os.path.exists(f"{working_dir}\\Approved\\{selected_policies[0].name}_hashes_to_add.csv") and os.path.exists( + if os.path.exists(f"{working_dir}\\Approved\\{selected_policies[0].name}_approved_executions.csv") and os.path.exists( f"{working_dir}\\Approved\\{selected_policies[0].name}_primary_Paths.csv" ): buildPreflights(selected_policies) @@ -167,11 +168,13 @@ def menu_policy_enforce(api: AirlockAPIWrapper): for path, ext in unique_combinations.itertuples(index=False, name=None) ] - print(processed_paths) + for path in processed_paths: + print(path) + print(colorText("These publishers would added", "yellow")) if os.path.exists(f"{working_dir}\\Preflight\\{selected_policies[0].name}_approved_publishers.csv"): - publishers = pd.read_csv(f"{working_dir}\\Preflight\\{selected_policies[0].name}_approved_hashes.csv") + publishers = pd.read_csv(f"{working_dir}\\Preflight\\{selected_policies[0].name}_approved_publishers.csv") if publishers.empty: print(colorText("The publishers list is empty.", "red")) else: @@ -181,13 +184,14 @@ def menu_policy_enforce(api: AirlockAPIWrapper): .drop_duplicates() .tolist() ) - print(processed_publishers) + for publisher in processed_publishers: + print(publisher) print(colorText("These hashes would be added to:", "yellow")) print(destination_allowlist) processed_hashes = hashes["sha256"].unique().tolist() - print(processed_hashes) + print_three_wide(processed_hashes) if processed_paths and processed_hashes: tested = True @@ -207,7 +211,6 @@ def menu_policy_enforce(api: AirlockAPIWrapper): for item in missing_items: logger.error(f" - {item}") - elif choice == "7": areYouSure() confirmation = get_sanitized_input("Type 'I AGREE' to continue: ") @@ -222,6 +225,9 @@ def menu_policy_enforce(api: AirlockAPIWrapper): api.policy_add_path_exclusions(destination_policy[0].groupid, processed_paths) if processed_publishers: api.policy_add_publishers(destination_policy[0].groupid, processed_publishers) + + locked() + else: logger.error("Confirmation block failed. Reasons:") if not tested: @@ -237,7 +243,7 @@ def menu_policy_enforce(api: AirlockAPIWrapper): open_directory(working_dir) elif choice.upper() == "S": menu_settings() - elif choice.upper == "B": + elif choice.upper() == "B": break @@ -314,3 +320,8 @@ def menu_settings(): break else: print("Invalid choice. Please try again.") + +def print_three_wide(items): + for i in range(0, len(items), 3): + row = items[i:i+3] + print(" | ".join(row)) \ No newline at end of file diff --git a/utils/setup.py b/utils/setup.py index a530926..e12bef5 100644 --- a/utils/setup.py +++ b/utils/setup.py @@ -15,6 +15,7 @@ import json import logging +import logging.config import logging.handlers import os import platform @@ -36,49 +37,69 @@ def get_base_directory() -> Path: else: return home / '.local' / 'share' / "AirlockTools" + def configure_logging(log_dir: Path, log_level: str = "DEBUG"): log_file = log_dir / "airlocktools.log" - logger = logging.getLogger() - # Always allow all messages to propagate to handlers - logger.setLevel(logging.DEBUG) + config = { + "version": 1, # Required key for dictConfig format version + "disable_existing_loggers": False, # Keeps existing loggers active + "formatters": { + "detailed": { + "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s" + # Includes timestamp, logger name, level, and message + }, + "simple": { + "format": "%(levelname)s - %(message)s" + # Minimal format for console output + }, + }, + "handlers": { + "file": { + "class": "logging.handlers.TimedRotatingFileHandler", + "filename": str(log_file), + "when": "midnight", # Rotate logs at midnight + "interval": 1, # Every 1 day + "backupCount": 7, # Keep 7 days of logs + "encoding": "utf-8", # Ensure UTF-8 encoding + "level": "DEBUG", # Always log DEBUG and above + "formatter": "detailed", # Use detailed format + }, + "console": { + "class": "logging.StreamHandler", + "level": log_level.upper(), # Configurable log level + "formatter": "simple", # Use simple format + }, + }, + "root": { + "level": "DEBUG", # Root logger level + "handlers": ["file", "console"], # Attach both handlers + }, + } - # Remove existing handlers - for handler in logger.handlers[:]: - logger.removeHandler(handler) - - # File handler always logs DEBUG and above - file_handler = logging.handlers.RotatingFileHandler( - log_file, maxBytes=5_000_000, backupCount=5, encoding='utf-8' - ) - file_handler.setLevel(logging.DEBUG) - file_handler.setFormatter(logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s' - )) - logger.addHandler(file_handler) - - # Console handler respects the configured log level - console_handler = logging.StreamHandler() - console_handler.setLevel(getattr(logging, log_level.upper(), logging.INFO)) - console_handler.setFormatter(logging.Formatter('%(levelname)s - %(message)s')) - logger.addHandler(console_handler) - - # Optional Windows Event Log handler + # Add Windows Event Log handler if on Windows if platform.system() == "Windows": try: - event_handler = logging.handlers.NTEventLogHandler("AirlockTools") - event_handler.setLevel(logging.CRITICAL) - event_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) - logger.addHandler(event_handler) + config["handlers"]["eventlog"] = { + "class": "logging.handlers.NTEventLogHandler", + "appname": "AirlockTools", # Event log source name + "level": "CRITICAL", # Only log critical errors + "formatter": "simple", # Use simple format + } + config["root"]["handlers"].append("eventlog") except Exception as e: - logger.warning(f"Could not attach Windows Event Log handler: {e}") + logging.warning(f"Could not attach Windows Event Log handler: {e}") + + # Apply the logging configuration + logging.config.dictConfig(config) + logging.getLogger().debug("✅ Logging configured.") - logger.debug("✅ Logging configured.") def get_system_config_path() -> Path: base_path = Path(getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))) return base_path.parent / "system_config.json" + def load_system_config() -> dict: try: config_path = get_system_config_path() @@ -179,5 +200,4 @@ def setup(): os.environ["URL"] = url logging.debug(f"Service URL set to: {url}") - write_config_to_env(merged_config, env_path) - + write_config_to_env(merged_config, env_path) \ No newline at end of file diff --git a/utils/utils.py b/utils/utils.py index fdb1d66..2f48ff3 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -184,20 +184,18 @@ def displayIntro(): ) ) +def section_header(title): + print(colorText("\n --------------------------------------------------------------------", "cyan")) + print(colorText(f" ------------- {title} -------------", "cyan")) + print(colorText(" --------------------------------------------------------------------", "cyan")) def printEnforceChecklist(selected_policies, destination_policy, destination_allowlist): working_dir = load_env("WORKING_DIR") - - def section_header(title): - print(colorText("\n --------------------------------------------------------------------", "cyan")) - print(colorText(f" ------------- {title} -------------", "cyan")) - print(colorText(" --------------------------------------------------------------------", "cyan")) - section_header("🛠️ 🔒 Prepare to Enforce Policy 🛠️ 🔒") print(colorText("\nSequentially follow these steps to prepare a policy for enforcement:", "white")) # Step 1: Originating Policies - print(colorText("\n1. Choose which originating policy or policies to move to enforcement", "cyan")) + print(colorText("\n1. Choose which policy or policies to gather execution info from", "cyan")) if not selected_policies: print(colorText(" [✗] No policies have been chosen", "red")) else: @@ -206,7 +204,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all print(colorText(f" [✓] {policy.name}", "green")) # Step 2: Destination Policy and Allowlist - print(colorText("2. Choose the destination policy and allowlist", "cyan")) + print(colorText("2. Choose the destination policy and associated allowlist", "cyan")) if destination_policy: print(colorText(f" [✓] {destination_policy[0].name} has been selected as the destination policy", "green")) else: @@ -218,7 +216,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all print(colorText(" [✗] No allowlist has been chosen", "red")) # Step 3: Data Preparation - print(colorText("3. Pull and stage event history, combine the histories, add hash info, then categorize the hashes", "cyan")) + print(colorText(f"3. Select to begin pulling execution history. The executions will be sorted and placed in {working_dir}\\data\\Needs_Review", "cyan")) if selected_policies: policy_id = selected_policies[0].name review_path = f"{working_dir}\\Needs_Review\\Review_First\\{policy_id}_approved_executions.csv" @@ -228,15 +226,9 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all # Step 4: Manual Review print(colorText("4. Manually review the files:", "cyan")) - if selected_policies: - policy_id = selected_policies[0].name - print(colorText(f" 'prepare_policy\\needs_approved\\good_hashes.csv' and 'prepare_policy\\needs_approved\\{policy_id}_unknown_hashes.csv'\n", "cyan")) - else: - print(colorText(" 'prepare_policy\\needs_approved\\good_hashes.csv' and 'prepare_policy\\needs_approved\\_unknown_hashes.csv'\n", "cyan")) - - print(colorText(" Remove the rows containing hashes you do not approve of...", "cyan")) - print(colorText(" When complete, save both csv files to the directory 'approved' and choose this option.", "cyan")) - print(colorText(" This will combine these approved hashes with the automatically approved hashes and generate a list of paths to be reviewed", "cyan")) + print(colorText(" Remove the rows containing hashes you do not approve of", "cyan")) + print(colorText(f" When complete, save both csv files to {working_dir}\\data\\Approved and choose this option.", "cyan")) + print(colorText(" This will start the process to generate possible filepath approvals", "cyan")) if selected_policies: policy_id = selected_policies[0].name @@ -248,11 +240,10 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all print(colorText(" [✗] No policies selected, cannot check reviewed hashes or path list", "red")) # Step 5: Path Review - print(colorText("5. Manually review the files \n 'prepare_policy\\needs_approved\\primary_Paths.csv'\n 'prepare_policy\\needs_approved\\secondary_Paths.csv'", "cyan")) - print(colorText(" Remove the rows containing path exclusions you do not approve of...", "cyan")) - print(colorText(" When complete, save the csv file to the directory 'approved'", "cyan")) - print(colorText(" Do the same process with the list of publishers for the same directories", "cyan")) - print(colorText(" Preflight Lists will be generated", "cyan")) + print(colorText(f"5. Manually review the files in {working_dir}\\Needs_Review\\Review_Second\\", "cyan")) + print(colorText(" Remove the rows containing path exclusions or publishers you do not approve of.", "cyan")) + print(colorText(f" When complete, save the files to {working_dir}\\data\\Approved", "cyan")) + print(colorText(" Choose this option when done to build your preflights", "cyan")) if selected_policies: policy_id = selected_policies[0].name @@ -267,12 +258,12 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all # Final Steps print(colorText("6. Test ------------------------------------------------------", "cyan")) - print(colorText(" Print rather than apply selected data.", "cyan")) + print(colorText(" Prints to console the changes that would be made, must be done to proceed. ", "cyan")) print(colorText("7. Liftoff ------------------------------------------------------", "cyan")) - print(colorText(" Apply path exclusions according to allowed and approved paths", "cyan")) - print(colorText(" Apply signed or attested hashes to Parent Allow List", "cyan")) - print(colorText(" Apply approved, but unsigned hashes to the Child Allow List", "cyan")) + print(colorText(" Apply path exclusions and approved publishers to selected policy", "cyan")) + print(colorText(" Apply approved hashes to allowlist", "cyan")) + # Utility Options print(colorText("R. Remove/Reset Generated data - will prompt to allow keeping execution history", "cyan"))