#!/usr/bin/env python import argparse import os import shutil import sys from pathlib import Path def prune_unused_profiles(dest_profile_folder: Path) -> None: for root, dirs, files in os.walk(dest_profile_folder): for name in files: target_binary = Path('/' + name.replace('.', '/')) if not target_binary.exists(): profile_path = os.path.join(root, name) print(f'Removing {profile_path}') os.remove(profile_path) for folder in dirs: fullpath = os.path.join(root, folder) if not os.listdir(fullpath): print(f'Removing empty directory {fullpath}') os.rmdir(fullpath) def install_profiles(source_folder: Path, dest_profile_folder: Path) -> None: for root, dirs, files in os.walk(source_folder): for name in files: target_binary = Path('/' + name.replace('.', '/')) print(f'Testing {target_binary}') if target_binary.exists(): print(f'Adding profile for {target_binary}') profile_path = os.path.join(root, name) shutil.copy2(profile_path, dest_profile_folder) parser = argparse.ArgumentParser( description='Install or prune apparmor profiles', usage='/sync-apparmor.py ~/playground/apparmor-profiles/ /etc/apparmor.d/local/', ) parser.add_argument( '--dry-run', '-d', action='store_true', help="Don't change files, only output what would be done") parser.add_argument( '--prune-destination', '-r', action='store_true', help="Check whether target binaries for profiles in dest exist. Delete profiles if not.") parser.add_argument( '--sync-source', '-s', action='store_true', help="Check whether target binaries for profiles in dest exist. Copy profiles from source if so.") parser.add_argument( 'source_folder', type=Path, help='Folder to copy AppArmor profiles from') parser.add_argument( 'dest', type=Path, help='Folder to copy AppArmor profiles to') args = parser.parse_args() if Path.home() == Path('/root'): print('$HOME is /root, maybe you forgot to use sudo -E?') if args.dry_run: shutil.copy2 = lambda *args: None os.remove = lambda *args: None os.rmdir = lambda *args: None none_defined = not(args.prune_destination and args.sync_source) if none_defined: prune_unused_profiles(args.dest) install_profiles(args.source_folder, args.dest) if args.prune_destination: prune_unused_profiles(args.dest) if args.sync_source: install_profiles(args.source_folder, args.dest)