Skip to content

Commit

Permalink
update?
Browse files Browse the repository at this point in the history
  • Loading branch information
badra001 committed Jan 2, 2026
1 parent 233faaa commit 2648afe
Showing 1 changed file with 37 additions and 12 deletions.
49 changes: 37 additions & 12 deletions local-app/python-tools/cross-organization/audit_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import glob

# --- VERSIONING ---
__version__ = "1.1.0"
__version__ = "1.1.2"

def get_nested(data, key_path):
keys = key_path.split('.')
Expand All @@ -20,12 +20,34 @@ def get_nested(data, key_path):
return None
return data

def str_to_bool(val):
"""Converts common truthy/falsy strings to actual Booleans."""
if isinstance(val, bool):
return val
normalized = str(val).lower()
if normalized in ('true', 'yes', 't', 'y', '1', 'on'):
return True
if normalized in ('false', 'no', 'f', 'n', '0', 'off'):
return False
return val

def check_condition(item, field, operator, value):
actual_value = get_nested(item, field)

if actual_value is None:
return operator == "!="

# TYPE-AWARE CONVERSION:
# If the filter value looks like a boolean, convert BOTH to booleans for comparison
target_value = str_to_bool(value)
if isinstance(target_value, bool):
compare_value = str_to_bool(actual_value)
if operator == "==": return compare_value == target_value
if operator == "!=": return compare_value != target_value
return False # Regex doesn't apply to pure booleans

# Standard string comparison for everything else
str_actual = str(actual_value)

if operator == "==":
return str_actual == value
elif operator == "!=":
Expand All @@ -38,19 +60,20 @@ def check_condition(item, field, operator, value):
return False

def parse_filter_string(f_str):
# Regex split that handles operators
match = re.split(r'(==|!=|~)', f_str)
return match if len(match) == 3 else None

def main():
parser = argparse.ArgumentParser(description=f"Advanced Audit Filter v{__version__}")
parser = argparse.ArgumentParser(description=f"Boolean-Aware Audit Filter v{__version__}")
parser.add_argument("--input", help="JSON file to filter")
parser.add_argument("--and", action="append", dest="and_filters", help="Must match ALL of these (AND logic)")
parser.add_argument("--or", action="append", dest="or_filters", help="Must match AT LEAST ONE of these (OR logic)")
parser.add_argument("--and", action="append", dest="and_filters", help="Match ALL")
parser.add_argument("--or", action="append", dest="or_filters", help="Match ANY")
parser.add_argument("--csv", help="Output to CSV")
parser.add_argument("--json", action="store_true", help="Output to JSON")
args = parser.parse_args()

# Resolve input
# Resolve latest input file automatically
input_file = args.input or max(glob.glob("audit_results.*.json"), key=os.path.getctime, default=None)
if not input_file:
print("Error: No input file found."); sys.exit(1)
Expand All @@ -63,25 +86,27 @@ def main():

filtered_results = []
for record in data:
# Evaluate AND group (All must be True)
# Implicitly true if no filters provided
and_passed = all(check_condition(record, f[0], f[1], f[2]) for f in and_list)

# Evaluate OR group (At least one must be True, or group is empty)
or_passed = any(check_condition(record, f[0], f[1], f[2]) for f in or_list) if or_list else True

if and_passed and or_passed:
filtered_results.append(record)

# Output handling...
if not filtered_results:
print("No matches found.")
return

if args.json:
print(json.dumps(filtered_results, indent=2))
elif args.csv:
# (Standard CSV export logic here)
print(f"Saved to {args.csv}")
# Simple flattening for baseline CSV
with open(args.csv, 'w', newline='') as f:
headers = ["org_id", "account_id", "alias", "ou_path"]
writer = csv.DictWriter(f, fieldnames=headers, extrasaction='ignore')
writer.writeheader()
writer.writerows(filtered_results)
print(f"Results saved to {args.csv}")
else:
for r in filtered_results:
print(f"{r.get('account_id')} | {r.get('alias','N/A'):<20} | {r.get('ou_path')}")
Expand Down

0 comments on commit 2648afe

Please sign in to comment.