[apparmor] [utils] proposed redesign for mergeprof

Kshitij Gupta kgupta8592 at gmail.com
Thu Sep 4 18:49:12 UTC 2014


Hello,

Version -1:

Changes to facilitate 2-way merge (maybe also 3-way) of multiple
profiles as discussed on IRC ( which someone had to summarize for ml
;-))

The proposal:
- moves reset method to reset_aa function
- modifies message displayed to user
- allows processing of multiple files in 2-way merge
- disables 3-way merge till new syntax has been decided

The changes reflect the approach of providing arbitrary number of
files using wildcards or explicitly. This makes it necessary to define
a way to distinguish the files for base and other case to be used in
3-way merge.
@cboltz Any ideas are welcome!

The changes map the profiles in the given files to their respective
files in the local directory specified using -d. Then the merges take
place profile-wise. There are some cases with this approach with
multiple profiles in a file where unnecessary questions are asked not
relevant to the other profile.

=== modified file 'utils/aa-mergeprof'
--- utils/aa-mergeprof    2014-09-03 23:49:47 +0000
+++ utils/aa-mergeprof    2014-09-04 18:33:34 +0000
@@ -26,19 +26,19 @@
 from apparmor.translations import init_translation
 _ = init_translation()

-parser = argparse.ArgumentParser(description=_('Perform a 2-way or
3-way merge on the given profiles'),
+parser = argparse.ArgumentParser(description=_('Perform a 2-way or
3-way merge on the given profiles'),
     epilog='WARNING: the arguments will change in a future version!')
-parser.add_argument('mine', type=str, help=_('your profile'))
-parser.add_argument('base', type=str, help=_('base profile'))
-parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
+parser.add_argument('files', nargs='+', type=str, help=_('base profile'))
+#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
 parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
 #parser.add_argument('-a', '--auto', action='store_true',
help=_('Automatically merge profiles, exits incase of *x conflicts'))
 args = parser.parse_args()

+args.other = None
 # 2-way merge or 3-way merge based on number of params
-merge_mode = 2 if args.other == None else 3
+merge_mode = 2 #if args.other == None else 3

-profiles = [args.mine, args.base, args.other]
+profiles = [args.files, [args.other]]

 profiledir = args.dir
 if profiledir:
@@ -46,9 +46,78 @@
     if not os.path.isdir(apparmor.aa.profile_dir):
         raise apparmor.AppArmorException(_("%s is not a directory.")
%profiledir)

+def reset_aa():
+    apparmor.aa.aa = apparmor.aa.hasher()
+    apparmor.aa.filelist = apparmor.aa.hasher()
+    apparmor.aa.include = dict()
+    apparmor.aa.existing_profiles = apparmor.aa.hasher()
+    apparmor.aa.original_aa = apparmor.aa.hasher()
+
+def find_profiles_from_files(files):
+    profile_to_filename = dict()
+    for file_name in files:
+        apparmor.aa.read_profile(file_name, True)
+        for profile_name in apparmor.aa.filelist[file_name]['profiles'].keys():
+            profile_to_filename[profile_name] = file_name
+        reset_aa()
+
+    return profile_to_filename
+
+def find_files_from_profiles(profiles):
+    profile_to_filename = dict()
+    apparmor.aa.read_profiles()
+
+    for profile_name in profiles:
+        profile_to_filename[profile_name] =
apparmor.aa.get_profile_filename(profile_name)
+
+    reset_aa()
+
+    return profile_to_filename

 def main():
-    mergeprofiles = Merge(profiles)
+    profiles_to_merge = set()
+
+    base_files, other_files = profiles
+
+    base_profile_to_file = find_profiles_from_files(base_files)
+
+    profiles_to_merge =
profiles_to_merge.union(set(base_profile_to_file.keys()))
+
+    other_profile_to_file = dict()
+
+    if merge_mode == 3:
+        other_profile_to_file = find_profiles_from_files(other_files)
+        profiles_to_merge.add(other_profile_to_file.keys())
+
+    user_profile_to_file = find_files_from_profiles(profiles_to_merge)
+
+    print(base_files,"\n",other_files)
+    print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
+    print(profiles_to_merge)
+
+    for profile_name in profiles_to_merge:
+        user_file = user_profile_to_file[profile_name]
+        base_file = base_profile_to_file.get(profile_name, None)
+        other_file =  None
+
+        if merge_mode == 3:
+            other_file = other_profile_to_file.get(profile_name, None)
+
+        if base_file == None:
+            if other_file == None:
+                continue
+
+            act([user_file, other_file, None], 2, profile_name)
+        else:
+            if other_file == None:
+                act([user_file, base_file, None], 2, profile_name)
+            else:
+                act([user_file, base_file, other_file], 3, profile_name)
+
+        reset_aa()
+
+def act(files, merge_mode, merging_profile):
+    mergeprofiles = Merge(files)
     #Get rid of common/superfluous stuff
     mergeprofiles.clear_common()

@@ -62,10 +131,10 @@
         mergeprofiles.ask_the_questions('base')

         q = apparmor.aa.hasher()
-        q['title'] = 'Changed Local Profiles'
+        q['title'] = _('Changes for Local Profile: %s')%(merging_profile)
         q['headers'] = []
-        q['explanation'] = _('The following local profiles were
changed. Would you like to save them?')
-        q['functions'] = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT']
+        q['explanation'] = _('Would you like to save them?')
+        q['functions'] = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES',
'CMD_ABORT', 'CMD_IGNORE_ENTRY']
         q['default'] = 'CMD_VIEW_CHANGES'
         q['options'] = []
         q['selected'] = 0
@@ -84,6 +153,8 @@
                 #oldprofile =
apparmor.serialize_profile(apparmor.original_aa[program], program, '')
                 newprofile =
apparmor.aa.serialize_profile(mergeprofiles.user.aa[program], program,
'')

apparmor.aa.display_changes_with_comments(mergeprofiles.user.filename,
newprofile)
+            elif ans == 'CMD_IGNORE_ENTRY':
+                break


 class Merge(object):
@@ -94,25 +165,18 @@
         apparmor.aa.read_profile(base, True)
         self.base = cleanprofile.Prof(base)

-        self.reset()
+        reset_aa()

         #Read and parse other profile and save profile data, include
data from it and reset them
         if merge_mode == 3:
             apparmor.aa.read_profile(other, True)
             self.other = cleanprofile.Prof(other)
-            self.reset()
+            reset_aa()

         #Read and parse user profile
         apparmor.aa.read_profile(user, True)
         self.user = cleanprofile.Prof(user)

-    def reset(self):
-        apparmor.aa.aa = apparmor.aa.hasher()
-        apparmor.aa.filelist = apparmor.aa.hasher()
-        apparmor.aa.include = dict()
-        apparmor.aa.existing_profiles = apparmor.aa.hasher()
-        apparmor.aa.original_aa = apparmor.aa.hasher()
-
     def clear_common(self):
         deleted = 0



Regards,
Kshitij Gupta



More information about the AppArmor mailing list