RustImplementation #23
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
+28
-15
@@ -132,6 +132,7 @@ def buildPathsandPublishers(selected_policies: List[Policy], split):
|
|||||||
all_approved_hashes = pd.DataFrame()
|
all_approved_hashes = pd.DataFrame()
|
||||||
path1 = f"{working_dir}\\Approved\\{selected_policies[0].name}_approved_executions.csv"
|
path1 = f"{working_dir}\\Approved\\{selected_policies[0].name}_approved_executions.csv"
|
||||||
path2 = f"{working_dir}\\Approved\\{selected_policies[0].name}_needs_review_executions.csv"
|
path2 = f"{working_dir}\\Approved\\{selected_policies[0].name}_needs_review_executions.csv"
|
||||||
|
path_exclusion_constant = get_protected_value("PATH_EXCLUSION_CONST", cast_type= int)
|
||||||
|
|
||||||
if os.path.exists(path1):
|
if os.path.exists(path1):
|
||||||
df1 = pd.read_csv(path1)
|
df1 = pd.read_csv(path1)
|
||||||
@@ -154,29 +155,31 @@ def buildPathsandPublishers(selected_policies: List[Policy], split):
|
|||||||
else:
|
else:
|
||||||
logger.warning("Warning: 'filename' column not found in concatenated DataFrame.")
|
logger.warning("Warning: 'filename' column not found in concatenated DataFrame.")
|
||||||
|
|
||||||
if not all_approved_hashes.empty:
|
if not all_approved_hashes.empty and path_exclusion_constant:
|
||||||
|
|
||||||
primary_path_exclusions = calculatePath(
|
primary_path_exclusions = calculatePath(
|
||||||
all_approved_hashes,
|
all_approved_hashes, path_exclusion_constant,
|
||||||
split,
|
split,
|
||||||
)
|
)
|
||||||
remaining_hashes = all_approved_hashes[
|
remaining_hashes = all_approved_hashes[
|
||||||
~all_approved_hashes["sha256"].isin(primary_path_exclusions["sha256"])
|
~all_approved_hashes["sha256"].isin(primary_path_exclusions["sha256"])
|
||||||
]
|
]
|
||||||
secondary_path_exclusions = calculatePath(
|
secondary_path_exclusions = calculatePath(
|
||||||
remaining_hashes, split
|
remaining_hashes,(path_exclusion_constant - 1), split
|
||||||
)
|
)
|
||||||
remaining_hashes = remaining_hashes[
|
remaining_hashes = remaining_hashes[
|
||||||
~remaining_hashes["sha256"].isin(secondary_path_exclusions["sha256"])
|
~remaining_hashes["sha256"].isin(secondary_path_exclusions["sha256"])
|
||||||
]
|
]
|
||||||
dataframes = {
|
dataframes = {
|
||||||
|
"all_approved_hashes" : all_approved_hashes,
|
||||||
"primary_Paths": primary_path_exclusions,
|
"primary_Paths": primary_path_exclusions,
|
||||||
"secondary_Paths": secondary_path_exclusions,
|
"secondary_Paths": secondary_path_exclusions,
|
||||||
"hashes_to_add": remaining_hashes,
|
"hashes_not_approvable_by_path": remaining_hashes
|
||||||
}
|
}
|
||||||
logger.debug("Preparing to sort dataframes")
|
logger.debug("Preparing to sort dataframes")
|
||||||
for name, df in dataframes.items():
|
for name, df in dataframes.items():
|
||||||
logger.debug(f" DataFrame headers: {list(df.columns)}")
|
logger.debug(f" DataFrame headers: {list(df.columns)}")
|
||||||
if name == "hashes_to_add": df.sort_values(by="filename", inplace=True)
|
if "hashes" in name : df.sort_values(by="filename", inplace=True)
|
||||||
else: df.sort_values(by="longestcfp", inplace=True)
|
else: df.sort_values(by="longestcfp", inplace=True)
|
||||||
|
|
||||||
df.to_csv(f"{working_dir}\\Needs_Review\\Review_Second\\{selected_policies[0].name}_{name}.csv", index=False)
|
df.to_csv(f"{working_dir}\\Needs_Review\\Review_Second\\{selected_policies[0].name}_{name}.csv", index=False)
|
||||||
@@ -193,6 +196,8 @@ def buildPathsandPublishers(selected_policies: List[Policy], split):
|
|||||||
publist = publist[["publisher"]]
|
publist = publist[["publisher"]]
|
||||||
publist.sort_values(by="publisher", inplace=True)
|
publist.sort_values(by="publisher", inplace=True)
|
||||||
publist.to_csv(f"{working_dir}\\Needs_Review\\Review_Second\\{selected_policies[0].name}_publishers.csv", index=False)
|
publist.to_csv(f"{working_dir}\\Needs_Review\\Review_Second\\{selected_policies[0].name}_publishers.csv", index=False)
|
||||||
|
else:
|
||||||
|
logger.debug("Approved Hashes list appears empty")
|
||||||
|
|
||||||
def buildPreflights(selected_policies: List[Policy]):
|
def buildPreflights(selected_policies: List[Policy]):
|
||||||
working_dir = load_env("WORKING_DIR")
|
working_dir = load_env("WORKING_DIR")
|
||||||
@@ -202,17 +207,13 @@ def buildPreflights(selected_policies: List[Policy]):
|
|||||||
approved_hashes = pd.DataFrame()
|
approved_hashes = pd.DataFrame()
|
||||||
approved_publishers = pd.DataFrame()
|
approved_publishers = pd.DataFrame()
|
||||||
|
|
||||||
hash = f"{working_dir}\\Approved\\{selected_policies[0].name}_hashes_to_add.csv"
|
hash = f"{working_dir}\\Needs_Review\\Review_Second\\{selected_policies[0].name}_all_approved_hashes.csv"
|
||||||
path1 = f"{working_dir}\\Approved\\{selected_policies[0].name}_primary_Paths.csv"
|
path1 = f"{working_dir}\\Approved\\{selected_policies[0].name}_primary_Paths.csv"
|
||||||
path2 = f"{working_dir}\\Approved\\{selected_policies[0].name}_secondary_Paths.csv"
|
path2 = f"{working_dir}\\Approved\\{selected_policies[0].name}_secondary_Paths.csv"
|
||||||
publishers = f"{working_dir}\\Approved\\{selected_policies[0].name}_publishers.csv"
|
publishers = f"{working_dir}\\Approved\\{selected_policies[0].name}_publishers.csv"
|
||||||
|
|
||||||
if os.path.exists(hash):
|
|
||||||
approved_hashes = pd.read_csv(hash)
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.warning(f"File not found: {hash}")
|
|
||||||
|
|
||||||
|
#Read in and combine the two path generations
|
||||||
if os.path.exists(path1):
|
if os.path.exists(path1):
|
||||||
df1 = pd.read_csv(path1)
|
df1 = pd.read_csv(path1)
|
||||||
else:
|
else:
|
||||||
@@ -229,6 +230,19 @@ def buildPreflights(selected_policies: List[Policy]):
|
|||||||
else:
|
else:
|
||||||
approved_paths = pd.concat([df1, df2], ignore_index=True)
|
approved_paths = pd.concat([df1, df2], ignore_index=True)
|
||||||
|
|
||||||
|
approved_paths = approved_paths.drop_duplicates(subset="longestcfp", keep ="first")
|
||||||
|
|
||||||
|
#We create a list of hashes that are left over if we exclude the ones that are covered by the path exclusions.
|
||||||
|
if os.path.exists(hash):
|
||||||
|
hashes = pd.read_csv(hash)
|
||||||
|
approved_hashes = hashes[~hashes['filename'].isin(approved_paths['longestcfp'])]
|
||||||
|
|
||||||
|
approved_hashes = approved_hashes.drop_duplicates(subset="sha256", keep ="first")
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.warning(f"File not found: {hash}")
|
||||||
|
|
||||||
|
|
||||||
if os.path.exists(publishers):
|
if os.path.exists(publishers):
|
||||||
approved_publishers = pd.read_csv(publishers)
|
approved_publishers = pd.read_csv(publishers)
|
||||||
|
|
||||||
@@ -246,8 +260,7 @@ def buildPreflights(selected_policies: List[Policy]):
|
|||||||
df.to_csv(f"{working_dir}\\Preflight\\{selected_policies[0].name}_{name}.csv", index=False)
|
df.to_csv(f"{working_dir}\\Preflight\\{selected_policies[0].name}_{name}.csv", index=False)
|
||||||
formatHTML(df, f"{working_dir}\\Preflight\\HTML\\{selected_policies[0].name}_{name}.html")
|
formatHTML(df, f"{working_dir}\\Preflight\\HTML\\{selected_policies[0].name}_{name}.html")
|
||||||
|
|
||||||
def splitFilepathsGrouped(df, col="filename"):
|
def splitFilepathsGrouped(df, path_exclusion_constant, col="filename"):
|
||||||
path_exclusion_constant = get_protected_value("PATH_EXCLUSION_CONST", cast_type= int)
|
|
||||||
min_files_for_path = get_protected_value("MIN_FILES_FOR_PATH", cast_type= int)
|
min_files_for_path = get_protected_value("MIN_FILES_FOR_PATH", cast_type= int)
|
||||||
|
|
||||||
def clean_split(path):
|
def clean_split(path):
|
||||||
@@ -307,7 +320,7 @@ def splitFilepathsGrouped(df, col="filename"):
|
|||||||
|
|
||||||
return pd.DataFrame(new_rows).drop(columns=["group_key"])
|
return pd.DataFrame(new_rows).drop(columns=["group_key"])
|
||||||
|
|
||||||
def calculatePath(approved_hashes, split):
|
def calculatePath(approved_hashes, path_exclusion_constant, split):
|
||||||
if split:
|
if split:
|
||||||
dfs_by_policy = [group for _, group in approved_hashes.groupby("policy")]
|
dfs_by_policy = [group for _, group in approved_hashes.groupby("policy")]
|
||||||
else:
|
else:
|
||||||
@@ -319,7 +332,7 @@ def calculatePath(approved_hashes, split):
|
|||||||
processed_dfs = []
|
processed_dfs = []
|
||||||
|
|
||||||
for df in dfs_by_policy:
|
for df in dfs_by_policy:
|
||||||
haslcp = splitFilepathsGrouped(df, "filename")
|
haslcp = splitFilepathsGrouped(df, path_exclusion_constant, "filename")
|
||||||
haslcp = haslcp.drop_duplicates()
|
haslcp = haslcp.drop_duplicates()
|
||||||
|
|
||||||
forbidden = regulator(badpathparts, True)
|
forbidden = regulator(badpathparts, True)
|
||||||
|
|||||||
+19
-8
@@ -41,6 +41,7 @@ from utils.utils import (
|
|||||||
get_sanitized_input,
|
get_sanitized_input,
|
||||||
open_directory,
|
open_directory,
|
||||||
printEnforceChecklist,
|
printEnforceChecklist,
|
||||||
|
locked
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -99,7 +100,7 @@ def menu_main(api: AirlockAPIWrapper):
|
|||||||
else:
|
else:
|
||||||
print(colorText("Invalid choice. Please try again.", "red"))
|
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 = []
|
selected_policies = []
|
||||||
destination_policy = []
|
destination_policy = []
|
||||||
destination_allowlist = []
|
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.")
|
print("File not found. Please make sure it's saved correctly and try again.")
|
||||||
|
|
||||||
elif choice == "5":
|
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"
|
f"{working_dir}\\Approved\\{selected_policies[0].name}_primary_Paths.csv"
|
||||||
):
|
):
|
||||||
buildPreflights(selected_policies)
|
buildPreflights(selected_policies)
|
||||||
@@ -167,11 +168,13 @@ def menu_policy_enforce(api: AirlockAPIWrapper):
|
|||||||
for path, ext in unique_combinations.itertuples(index=False, name=None)
|
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"))
|
print(colorText("These publishers would added", "yellow"))
|
||||||
|
|
||||||
if os.path.exists(f"{working_dir}\\Preflight\\{selected_policies[0].name}_approved_publishers.csv"):
|
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:
|
if publishers.empty:
|
||||||
print(colorText("The publishers list is empty.", "red"))
|
print(colorText("The publishers list is empty.", "red"))
|
||||||
else:
|
else:
|
||||||
@@ -181,13 +184,14 @@ def menu_policy_enforce(api: AirlockAPIWrapper):
|
|||||||
.drop_duplicates()
|
.drop_duplicates()
|
||||||
.tolist()
|
.tolist()
|
||||||
)
|
)
|
||||||
print(processed_publishers)
|
for publisher in processed_publishers:
|
||||||
|
print(publisher)
|
||||||
|
|
||||||
print(colorText("These hashes would be added to:", "yellow"))
|
print(colorText("These hashes would be added to:", "yellow"))
|
||||||
print(destination_allowlist)
|
print(destination_allowlist)
|
||||||
|
|
||||||
processed_hashes = hashes["sha256"].unique().tolist()
|
processed_hashes = hashes["sha256"].unique().tolist()
|
||||||
print(processed_hashes)
|
print_three_wide(processed_hashes)
|
||||||
|
|
||||||
if processed_paths and processed_hashes:
|
if processed_paths and processed_hashes:
|
||||||
tested = True
|
tested = True
|
||||||
@@ -207,7 +211,6 @@ def menu_policy_enforce(api: AirlockAPIWrapper):
|
|||||||
for item in missing_items:
|
for item in missing_items:
|
||||||
logger.error(f" - {item}")
|
logger.error(f" - {item}")
|
||||||
|
|
||||||
|
|
||||||
elif choice == "7":
|
elif choice == "7":
|
||||||
areYouSure()
|
areYouSure()
|
||||||
confirmation = get_sanitized_input("Type 'I AGREE' to continue: ")
|
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)
|
api.policy_add_path_exclusions(destination_policy[0].groupid, processed_paths)
|
||||||
if processed_publishers:
|
if processed_publishers:
|
||||||
api.policy_add_publishers(destination_policy[0].groupid, processed_publishers)
|
api.policy_add_publishers(destination_policy[0].groupid, processed_publishers)
|
||||||
|
|
||||||
|
locked()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error("Confirmation block failed. Reasons:")
|
logger.error("Confirmation block failed. Reasons:")
|
||||||
if not tested:
|
if not tested:
|
||||||
@@ -237,7 +243,7 @@ def menu_policy_enforce(api: AirlockAPIWrapper):
|
|||||||
open_directory(working_dir)
|
open_directory(working_dir)
|
||||||
elif choice.upper() == "S":
|
elif choice.upper() == "S":
|
||||||
menu_settings()
|
menu_settings()
|
||||||
elif choice.upper == "B":
|
elif choice.upper() == "B":
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
@@ -314,3 +320,8 @@ def menu_settings():
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print("Invalid choice. Please try again.")
|
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))
|
||||||
+51
-31
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import logging.config
|
||||||
import logging.handlers
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
@@ -36,49 +37,69 @@ def get_base_directory() -> Path:
|
|||||||
else:
|
else:
|
||||||
return home / '.local' / 'share' / "AirlockTools"
|
return home / '.local' / 'share' / "AirlockTools"
|
||||||
|
|
||||||
|
|
||||||
def configure_logging(log_dir: Path, log_level: str = "DEBUG"):
|
def configure_logging(log_dir: Path, log_level: str = "DEBUG"):
|
||||||
log_file = log_dir / "airlocktools.log"
|
log_file = log_dir / "airlocktools.log"
|
||||||
logger = logging.getLogger()
|
|
||||||
|
|
||||||
# Always allow all messages to propagate to handlers
|
config = {
|
||||||
logger.setLevel(logging.DEBUG)
|
"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
|
# Add Windows Event Log handler if on Windows
|
||||||
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
|
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
try:
|
try:
|
||||||
event_handler = logging.handlers.NTEventLogHandler("AirlockTools")
|
config["handlers"]["eventlog"] = {
|
||||||
event_handler.setLevel(logging.CRITICAL)
|
"class": "logging.handlers.NTEventLogHandler",
|
||||||
event_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
|
"appname": "AirlockTools", # Event log source name
|
||||||
logger.addHandler(event_handler)
|
"level": "CRITICAL", # Only log critical errors
|
||||||
|
"formatter": "simple", # Use simple format
|
||||||
|
}
|
||||||
|
config["root"]["handlers"].append("eventlog")
|
||||||
except Exception as e:
|
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:
|
def get_system_config_path() -> Path:
|
||||||
base_path = Path(getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))))
|
base_path = Path(getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))))
|
||||||
return base_path.parent / "system_config.json"
|
return base_path.parent / "system_config.json"
|
||||||
|
|
||||||
|
|
||||||
def load_system_config() -> dict:
|
def load_system_config() -> dict:
|
||||||
try:
|
try:
|
||||||
config_path = get_system_config_path()
|
config_path = get_system_config_path()
|
||||||
@@ -180,4 +201,3 @@ def setup():
|
|||||||
logging.debug(f"Service URL set to: {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)
|
||||||
|
|
||||||
|
|||||||
+16
-25
@@ -184,20 +184,18 @@ def displayIntro():
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def printEnforceChecklist(selected_policies, destination_policy, destination_allowlist):
|
|
||||||
working_dir = load_env("WORKING_DIR")
|
|
||||||
|
|
||||||
def section_header(title):
|
def section_header(title):
|
||||||
print(colorText("\n --------------------------------------------------------------------", "cyan"))
|
print(colorText("\n --------------------------------------------------------------------", "cyan"))
|
||||||
print(colorText(f" ------------- {title} -------------", "cyan"))
|
print(colorText(f" ------------- {title} -------------", "cyan"))
|
||||||
print(colorText(" --------------------------------------------------------------------", "cyan"))
|
print(colorText(" --------------------------------------------------------------------", "cyan"))
|
||||||
|
|
||||||
|
def printEnforceChecklist(selected_policies, destination_policy, destination_allowlist):
|
||||||
|
working_dir = load_env("WORKING_DIR")
|
||||||
section_header("🛠️ 🔒 Prepare to Enforce Policy 🛠️ 🔒")
|
section_header("🛠️ 🔒 Prepare to Enforce Policy 🛠️ 🔒")
|
||||||
print(colorText("\nSequentially follow these steps to prepare a policy for enforcement:", "white"))
|
print(colorText("\nSequentially follow these steps to prepare a policy for enforcement:", "white"))
|
||||||
|
|
||||||
# Step 1: Originating Policies
|
# 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:
|
if not selected_policies:
|
||||||
print(colorText(" [✗] No policies have been chosen", "red"))
|
print(colorText(" [✗] No policies have been chosen", "red"))
|
||||||
else:
|
else:
|
||||||
@@ -206,7 +204,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
|
|||||||
print(colorText(f" [✓] {policy.name}", "green"))
|
print(colorText(f" [✓] {policy.name}", "green"))
|
||||||
|
|
||||||
# Step 2: Destination Policy and Allowlist
|
# 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:
|
if destination_policy:
|
||||||
print(colorText(f" [✓] {destination_policy[0].name} has been selected as the destination policy", "green"))
|
print(colorText(f" [✓] {destination_policy[0].name} has been selected as the destination policy", "green"))
|
||||||
else:
|
else:
|
||||||
@@ -218,7 +216,7 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
|
|||||||
print(colorText(" [✗] No allowlist has been chosen", "red"))
|
print(colorText(" [✗] No allowlist has been chosen", "red"))
|
||||||
|
|
||||||
# Step 3: Data Preparation
|
# 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:
|
if selected_policies:
|
||||||
policy_id = selected_policies[0].name
|
policy_id = selected_policies[0].name
|
||||||
review_path = f"{working_dir}\\Needs_Review\\Review_First\\{policy_id}_approved_executions.csv"
|
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
|
# Step 4: Manual Review
|
||||||
print(colorText("4. Manually review the files:", "cyan"))
|
print(colorText("4. Manually review the files:", "cyan"))
|
||||||
if selected_policies:
|
print(colorText(" Remove the rows containing hashes you do not approve of", "cyan"))
|
||||||
policy_id = selected_policies[0].name
|
print(colorText(f" When complete, save both csv files to {working_dir}\\data\\Approved and choose this option.", "cyan"))
|
||||||
print(colorText(f" 'prepare_policy\\needs_approved\\good_hashes.csv' and 'prepare_policy\\needs_approved\\{policy_id}_unknown_hashes.csv'\n", "cyan"))
|
print(colorText(" This will start the process to generate possible filepath approvals", "cyan"))
|
||||||
else:
|
|
||||||
print(colorText(" 'prepare_policy\\needs_approved\\good_hashes.csv' and 'prepare_policy\\needs_approved\\<policy>_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"))
|
|
||||||
|
|
||||||
if selected_policies:
|
if selected_policies:
|
||||||
policy_id = selected_policies[0].name
|
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"))
|
print(colorText(" [✗] No policies selected, cannot check reviewed hashes or path list", "red"))
|
||||||
|
|
||||||
# Step 5: Path Review
|
# 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(f"5. Manually review the files in {working_dir}\\Needs_Review\\Review_Second\\", "cyan"))
|
||||||
print(colorText(" Remove the rows containing path exclusions you do not approve of...", "cyan"))
|
print(colorText(" Remove the rows containing path exclusions or publishers you do not approve of.", "cyan"))
|
||||||
print(colorText(" When complete, save the csv file to the directory 'approved'", "cyan"))
|
print(colorText(f" When complete, save the files to {working_dir}\\data\\Approved", "cyan"))
|
||||||
print(colorText(" Do the same process with the list of publishers for the same directories", "cyan"))
|
print(colorText(" Choose this option when done to build your preflights", "cyan"))
|
||||||
print(colorText(" Preflight Lists will be generated", "cyan"))
|
|
||||||
|
|
||||||
if selected_policies:
|
if selected_policies:
|
||||||
policy_id = selected_policies[0].name
|
policy_id = selected_policies[0].name
|
||||||
@@ -267,12 +258,12 @@ def printEnforceChecklist(selected_policies, destination_policy, destination_all
|
|||||||
|
|
||||||
# Final Steps
|
# Final Steps
|
||||||
print(colorText("6. Test ------------------------------------------------------", "cyan"))
|
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("7. Liftoff ------------------------------------------------------", "cyan"))
|
||||||
print(colorText(" Apply path exclusions according to allowed and approved paths", "cyan"))
|
print(colorText(" Apply path exclusions and approved publishers to selected policy", "cyan"))
|
||||||
print(colorText(" Apply signed or attested hashes to Parent Allow List", "cyan"))
|
print(colorText(" Apply approved hashes to allowlist", "cyan"))
|
||||||
print(colorText(" Apply approved, but unsigned hashes to the Child Allow List", "cyan"))
|
|
||||||
|
|
||||||
# Utility Options
|
# Utility Options
|
||||||
print(colorText("R. Remove/Reset Generated data - will prompt to allow keeping execution history", "cyan"))
|
print(colorText("R. Remove/Reset Generated data - will prompt to allow keeping execution history", "cyan"))
|
||||||
|
|||||||
Reference in New Issue
Block a user