Hi,

Attached is a patch that implements the following:

=item --include-templates-dir=PATH

Include PATH when searching for templates in addition to the system templates
directory (or the one specified with --templates-dir). System templates will
match before those in PATH.


=item --include-policy-groups-dir=PATH

Include PATH when searching for policy groups in addition to the system
policy-groups directory (or the one specified with --policy-groups-dir). System
policy-groups will match before those in PATH.


It makes the following changes:
* utils/aa-easyprof:
  - update --show-template to handle --include-templates-dir
  - update --show-policy-group to handle --include-policy-groups-dir
* utils/aa-easyprof.pod
  - minor corrections for --show-template and --show-policy-group
  - add --include-templates-dir and --include-policy-groups-dir
* utils/apparmor/easyprof.py: implement these options according to
  man page
* utils/test/test-aa-easyprof.py:
  - implement tests to exercise the changed/added code
  - correct test_policygroups_list() and test_policygroups_show() which
    were copy and wasted

This option can be used to extend the available templates and policy groups
beyond what are in the system directories. This is being implemented in support
of Snappy for Ubuntu Core. The changes do not change aa-easyprof default
behavior. --include-templates-dir and --include-policy-groups-dir cannot be used
to override system templates and policy groups.

Signed-off-by: Jamie Strandboge <ja...@canonical.com>

-- 
Jamie Strandboge                 http://www.ubuntu.com/
Author: Jamie Strandboge <ja...@canonical.com>
Description: add --include-templates-dir and --include-policy-groups-dir
 options to easyprof to support framework policy on snappy
Forwarded: no

Index: apparmor-2.9.1/utils/aa-easyprof
===================================================================
--- apparmor-2.9.1.orig/utils/aa-easyprof
+++ apparmor-2.9.1/utils/aa-easyprof
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 # ------------------------------------------------------------------
 #
-#    Copyright (C) 2011-2013 Canonical Ltd.
+#    Copyright (C) 2011-2015 Canonical Ltd.
 #
 #    This program is free software; you can redistribute it and/or
 #    modify it under the terms of version 2 of the GNU General Public
@@ -68,16 +68,38 @@ if __name__ == "__main__":
             apparmor.easyprof.print_basefilenames(easyp.get_templates())
             sys.exit(0)
         elif options.template and options.show_template:
-            files = [os.path.join(easyp.dirs['templates'], options.template)]
-            apparmor.easyprof.print_files(files)
+            sys_t = os.path.join(easyp.dirs['templates'], options.template)
+            inc_t = None
+            if options.include_templates_dir:
+                inc_t = os.path.join(easyp.dirs['templates_include'],
+                                     options.template)
+
+            if os.path.exists(sys_t):
+                apparmor.easyprof.print_files([sys_t])
+            elif os.path.exists(inc_t):
+                apparmor.easyprof.print_files([inc_t])
+            else:
+                error("Could not find '%s'" % options.template)
             sys.exit(0)
         elif options.list_policy_groups:
             apparmor.easyprof.print_basefilenames(easyp.get_policy_groups())
             sys.exit(0)
         elif options.policy_groups and options.show_policy_group:
+            files = []
             for g in options.policy_groups.split(','):
-                files = [os.path.join(easyp.dirs['policygroups'], g)]
-                apparmor.easyprof.print_files(files)
+                sys_g = os.path.join(easyp.dirs['policygroups'], g)
+                inc_g = None
+                if options.include_policy_groups_dir:
+                    inc_g = os.path.join(easyp.dirs['policygroups_include'], g)
+
+                if os.path.exists(sys_g):
+                    files.append(sys_g)
+                elif os.path.exists(inc_g):
+                    files.append(inc_g)
+                else:
+                    warn("Could not find '%s'" % g)
+
+            apparmor.easyprof.print_files(files)
             sys.exit(0)
         elif binary == None and not options.profile_name and \
              not options.manifest:
Index: apparmor-2.9.1/utils/aa-easyprof.pod
===================================================================
--- apparmor-2.9.1.orig/utils/aa-easyprof.pod
+++ apparmor-2.9.1/utils/aa-easyprof.pod
@@ -97,7 +97,7 @@ the specified template uses this value.
 
 List available templates.
 
-=item --show-template=TEMPLATE
+=item --show-template
 
 Display template specified with --template.
 
@@ -105,18 +105,30 @@ Display template specified with --templa
 
 Use PATH instead of system templates directory.
 
+=item --include-templates-dir=PATH
+
+Include PATH when searching for templates in addition to the system templates
+directory (or the one specified with --templates-dir). System templates will
+match before those in PATH.
+
 =item --list-policy-groups
 
 List available policy groups.
 
 =item --show-policy-group
 
-Display policy groups specified with --policy.
+Display policy groups specified with --policy-groups.
 
 =item --policy-groups-dir=PATH
 
 Use PATH instead of system policy-groups directory.
 
+=item --include-policy-groups-dir=PATH
+
+Include PATH when searching for policy groups in addition to the system
+policy-groups directory (or the one specified with --policy-groups-dir). System
+policy-groups will match before those in PATH.
+
 =item --policy-version=VERSION
 
 Must be used with --policy-vendor and is used to specify the version of policy
Index: apparmor-2.9.1/utils/apparmor/easyprof.py
===================================================================
--- apparmor-2.9.1.orig/utils/apparmor/easyprof.py
+++ apparmor-2.9.1/utils/apparmor/easyprof.py
@@ -1,6 +1,6 @@
 # ------------------------------------------------------------------
 #
-#    Copyright (C) 2011-2013 Canonical Ltd.
+#    Copyright (C) 2011-2015 Canonical Ltd.
 #
 #    This program is free software; you can redistribute it and/or
 #    modify it under the terms of version 2 of the GNU General Public
@@ -312,15 +312,26 @@ class AppArmorEasyProfile:
 	    # the templates directory to the parent of the template so we don't
             # have to require --template-dir with absolute paths.
             self.dirs['templates'] = os.path.abspath(os.path.dirname(opt.template))
+
+        if opt.include_templates_dir and \
+           os.path.isdir(opt.include_templates_dir):
+            self.dirs['templates_include'] = os.path.abspath(opt.include_templates_dir)
+
         if opt.policy_groups_dir and os.path.isdir(opt.policy_groups_dir):
             self.dirs['policygroups'] = os.path.abspath(opt.policy_groups_dir)
 
+        if opt.include_policy_groups_dir and \
+           os.path.isdir(opt.include_policy_groups_dir):
+            self.dirs['policygroups_include'] = os.path.abspath(opt.include_policy_groups_dir)
 
         self.policy_version = None
         self.policy_vendor = None
         if (opt.policy_version and not opt.policy_vendor) or \
            (opt.policy_vendor and not opt.policy_version):
             raise AppArmorException("Must specify both policy version and vendor")
+
+        # If specified --policy-version and --policy-vendor, use
+        #  templates_dir/policy_vendor/policy_version
         if opt.policy_version and opt.policy_vendor:
             self.policy_vendor = opt.policy_vendor
             self.policy_version = str(opt.policy_version)
@@ -361,11 +372,22 @@ class AppArmorEasyProfile:
         for f in get_directory_contents(self.dirs['templates']):
             if os.path.isfile(f):
                 self.templates.append(f)
+
+        if 'templates_include' in self.dirs:
+            for f in get_directory_contents(self.dirs['templates_include']):
+                if os.path.isfile(f) and f not in self.templates:
+                    self.templates.append(f)
+
         self.policy_groups = []
         for f in get_directory_contents(self.dirs['policygroups']):
             if os.path.isfile(f):
                 self.policy_groups.append(f)
 
+        if 'policygroups_include' in self.dirs:
+            for f in get_directory_contents(self.dirs['policygroups_include']):
+                if os.path.isfile(f) and f not in self.policy_groups:
+                    self.policy_groups.append(f)
+
     def _get_defaults(self):
         '''Read in defaults from configuration'''
         if not os.path.exists(self.conffile):
@@ -411,13 +433,25 @@ class AppArmorEasyProfile:
         elif template.startswith('/') and not allow_abs_path:
             raise AppArmorException("Cannot use an absolute path template '%s'" % template)
 
+        # If have abs path, just use it
         if template.startswith('/'):
+            if not os.path.exists(template):
+                raise AppArmorException('%s does not exist' % (template))
             self.template = template
-        else:
-            self.template = os.path.join(self.dirs['templates'], template)
+            return
 
-        if not os.path.exists(self.template):
-            raise AppArmorException('%s does not exist' % (self.template))
+        # Find the template since we don't have an abs path
+        sys_t = os.path.join(self.dirs['templates'], template)
+        inc_t = None
+        if 'templates_include' in self.dirs:
+            inc_t = os.path.join(self.dirs['templates_include'], template)
+
+        if os.path.exists(sys_t):
+            self.template = sys_t
+        elif inc_t is not None and os.path.exists(inc_t):
+            self.template = inc_t
+        else:
+            raise AppArmorException('%s does not exist' % (template))
 
     def get_templates(self):
         '''Get list of all available templates by filename'''
@@ -427,7 +461,16 @@ class AppArmorEasyProfile:
         '''Get contents of specific policygroup'''
         p = policygroup
         if not p.startswith('/'):
-            p = os.path.join(self.dirs['policygroups'], p)
+            sys_p = os.path.join(self.dirs['policygroups'], p)
+            inc_p = None
+            if 'policygroups_include' in self.dirs:
+                inc_p = os.path.join(self.dirs['policygroups_include'], p)
+
+            if os.path.exists(sys_p):
+                p = sys_p
+            elif inc_p is not None and os.path.exists(inc_p):
+                p = inc_p
+
         if self.policy_groups == None or not p in self.policy_groups:
             raise AppArmorException("Policy group '%s' does not exist" % p)
         return open(p).read()
@@ -437,11 +480,25 @@ class AppArmorEasyProfile:
         self.policy_groups = []
         if policygroups != None:
             for p in policygroups.split(','):
-                if not p.startswith('/'):
-                    p = os.path.join(self.dirs['policygroups'], p)
-                if not os.path.exists(p):
+                # If have abs path, just use it
+                if p.startswith('/'):
+                    if not os.path.exists(p):
+                        raise AppArmorException('%s does not exist' % (p))
+                    self.policy_groups.append(p)
+                    continue
+
+                # Find the policy group since we don't have and abs path
+                sys_p = os.path.join(self.dirs['policygroups'], p)
+                inc_p = None
+                if 'policygroups_include' in self.dirs:
+                    inc_p = os.path.join(self.dirs['policygroups_include'], p)
+
+                if os.path.exists(sys_p):
+                    self.policy_groups.append(sys_p)
+                elif inc_p is not None and os.path.exists(inc_p):
+                    self.policy_groups.append(inc_p)
+                else:
                     raise AppArmorException('%s does not exist' % (p))
-                self.policy_groups.append(p)
 
     def get_policy_groups(self):
         '''Get list of all policy groups by filename'''
@@ -777,6 +834,10 @@ def add_parser_policy_args(parser):
                       dest="templates_dir",
                       help="Use non-default templates directory",
                       metavar="DIR")
+    parser.add_option("--include-templates-dir",
+                      dest="include_templates_dir",
+                      help="Also search DIR for templates",
+                      metavar="DIR")
     parser.add_option("-p", "--policy-groups",
                       action="callback",
                       callback=check_for_manifest_arg,
@@ -787,6 +848,10 @@ def add_parser_policy_args(parser):
                       dest="policy_groups_dir",
                       help="Use non-default policy-groups directory",
                       metavar="DIR")
+    parser.add_option("--include-policy-groups-dir",
+                      dest="include_policy_groups_dir",
+                      help="Also search DIR for policy groups",
+                      metavar="DIR")
     parser.add_option("--policy-version",
                       action="callback",
                       callback=check_for_manifest_arg,
Index: apparmor-2.9.1/utils/test/test-aa-easyprof.py
===================================================================
--- apparmor-2.9.1.orig/utils/test/test-aa-easyprof.py
+++ apparmor-2.9.1/utils/test/test-aa-easyprof.py
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 # ------------------------------------------------------------------
 #
-#    Copyright (C) 2011-2013 Canonical Ltd.
+#    Copyright (C) 2011-2015 Canonical Ltd.
 #
 #    This program is free software; you can redistribute it and/or
 #    modify it under the terms of version 2 of the GNU General Public
@@ -112,7 +112,8 @@ class T(unittest.TestCase):
 
         # Copy everything into place
         for d in ['easyprof/policygroups', 'easyprof/templates']:
-            shutil.copytree(os.path.join(topdir, d), os.path.join(self.tmpdir, os.path.basename(d)))
+            shutil.copytree(os.path.join(topdir, d),
+                            os.path.join(self.tmpdir, os.path.basename(d)))
 
         # Create a test template
         self.test_template = "test-template"
@@ -167,6 +168,17 @@ TEMPLATES_DIR="%s/templates"
 
         (self.options, self.args) = easyprof.parse_args(self.full_args + [self.binary])
 
+        # Now create some differently prefixed files in the include-dir
+        self.test_include_dir = os.path.join(self.tmpdir, 'include-dir')
+        os.mkdir(self.test_include_dir)
+        os.mkdir(os.path.join(self.test_include_dir, "templates"))
+        os.mkdir(os.path.join(self.test_include_dir, "policygroups"))
+        for d in ['policygroups', 'templates']:
+            for f in easyprof.get_directory_contents(os.path.join(
+                                                     self.tmpdir, d)):
+                shutil.copy(f, os.path.join(self.test_include_dir, d,
+                                            "inc_%s" % os.path.basename(f)))
+
     def tearDown(self):
         '''Teardown for tests'''
         if os.path.exists(self.tmpdir):
@@ -505,6 +517,53 @@ POLICYGROUPS_DIR="%s/templates"
             self.assertTrue(os.path.exists(path), "Could not find '%s'" % path)
             open(path).read()
 
+    def test_templates_list_include(self):
+        '''Test templates (list with --include-templates-dir)'''
+        args = self.full_args
+        args.append('--list-templates')
+        (self.options, self.args) = easyprof.parse_args(args)
+
+        easyp = easyprof.AppArmorEasyProfile(None, self.options)
+        orig_templates = easyp.get_templates()
+
+        args = self.full_args
+        args.append('--list-templates')
+        args.append('--include-templates-dir=%s' %
+                    os.path.join(self.test_include_dir, 'templates'))
+        (self.options, self.args) = easyprof.parse_args(args)
+
+        easyp = easyprof.AppArmorEasyProfile(None, self.options)
+        inc_templates = easyp.get_templates()
+        self.assertTrue(len(inc_templates) == len(orig_templates) * 2,
+                        "templates missing: %s" % inc_templates)
+
+        for i in inc_templates:
+            self.assertTrue(os.path.exists(i), "Could not find '%s'" % i)
+
+    def test_templates_show_include(self):
+        '''Test templates (show with --include-templates-dir)'''
+        files = []
+        for f in glob.glob("%s/templates/*" % self.test_include_dir):
+            files.append(f)
+
+        for f in files:
+            args = self.full_args
+            args += ['--show-template',
+                     '--template', f,
+                     '--include-templates-dir=%s' %
+                     os.path.join(self.test_include_dir, 'templates')]
+            (self.options, self.args) = easyprof.parse_args(args)
+            easyp = easyprof.AppArmorEasyProfile(None, self.options)
+
+            path = os.path.join(easyp.dirs['templates_include'], f)
+            self.assertTrue(os.path.exists(path), "Could not find '%s'" % path)
+            open(path).read()
+
+            bn = os.path.basename(f)
+            # setup() copies everything in the include prefixed with inc_
+            self.assertTrue(bn.startswith('inc_'),
+                            "'%s' does not start with 'inc_'" % bn)
+
 #
 # Policygroups tests
 #
@@ -515,7 +574,7 @@ POLICYGROUPS_DIR="%s/templates"
         (self.options, self.args) = easyprof.parse_args(args)
 
         easyp = easyprof.AppArmorEasyProfile(None, self.options)
-        for i in easyp.get_templates():
+        for i in easyp.get_policy_groups():
             self.assertTrue(os.path.exists(i), "Could not find '%s'" % i)
 
     def test_policygroups_show(self):
@@ -526,7 +585,8 @@ POLICYGROUPS_DIR="%s/templates"
 
         for f in files:
             args = self.full_args
-            args += ['--show-template', '--template', f]
+            args += ['--show-policy-group',
+                     '--policy-groups', os.path.basename(f)]
             (self.options, self.args) = easyprof.parse_args(args)
             easyp = easyprof.AppArmorEasyProfile(None, self.options)
 
@@ -534,6 +594,53 @@ POLICYGROUPS_DIR="%s/templates"
             self.assertTrue(os.path.exists(path), "Could not find '%s'" % path)
             open(path).read()
 
+    def test_policygroups_list_include(self):
+        '''Test policygroups (list with --include-policy-groups-dir)'''
+        args = self.full_args
+        args.append('--list-policy-groups')
+        (self.options, self.args) = easyprof.parse_args(args)
+
+        easyp = easyprof.AppArmorEasyProfile(None, self.options)
+        orig_policy_groups = easyp.get_policy_groups()
+
+        args = self.full_args
+        args.append('--list-policy-groups')
+        args.append('--include-policy-groups-dir=%s' %
+                    os.path.join(self.test_include_dir, 'policygroups'))
+        (self.options, self.args) = easyprof.parse_args(args)
+
+        easyp = easyprof.AppArmorEasyProfile(None, self.options)
+        inc_policy_groups = easyp.get_policy_groups()
+        self.assertTrue(len(inc_policy_groups) == len(orig_policy_groups) * 2,
+                        "policy_groups missing: %s" % inc_policy_groups)
+
+        for i in inc_policy_groups:
+            self.assertTrue(os.path.exists(i), "Could not find '%s'" % i)
+
+    def test_policygroups_show_include(self):
+        '''Test policygroups (show with --include-policy-groups-dir)'''
+        files = []
+        for f in glob.glob("%s/policygroups/*" % self.test_include_dir):
+            files.append(f)
+
+        for f in files:
+            args = self.full_args
+            args += ['--show-policy-group',
+                     '--policy-groups', os.path.basename(f),
+                     '--include-policy-groups-dir=%s' %
+                     os.path.join(self.test_include_dir, 'policygroups')]
+            (self.options, self.args) = easyprof.parse_args(args)
+            easyp = easyprof.AppArmorEasyProfile(None, self.options)
+
+            path = os.path.join(easyp.dirs['policygroups_include'], f)
+            self.assertTrue(os.path.exists(path), "Could not find '%s'" % path)
+            open(path).read()
+
+            bn = os.path.basename(f)
+            # setup() copies everything in the include prefixed with inc_
+            self.assertTrue(bn.startswith('inc_'),
+                            "'%s' does not start with 'inc_'" % bn)
+
 #
 # Manifest file argument tests
 #

Attachment: signature.asc
Description: OpenPGP digital signature

-- 
AppArmor mailing list
AppArmor@lists.ubuntu.com
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to