Hello,

this patch adds match() and _match() class methods to rule classes:
- _match() returns a regex match object for the given raw_rule
- match() converts the _match() result to True or False

The primary usage is to get an answer to the question "is this raw_rule
your job?". (For a moment, I thought about naming the function
*Rule.myjob() instead of *Rule.match() ;-)

My next patch will change aa.py to use *Rule.match() instead of directly
using RE_*, which will make the import list much shorter and hide 
another implementation detail inside the rule classes.

Also change _parse() to use _match() instead of the regex, and add some
tests for match() and _match().


Note: This patch depends on all my pending patches (well, except the
.bzrignore patch ;-)


[ 48-add-rule-match.diff ]

=== modified file utils/apparmor/rule/capability.py
--- utils/apparmor/rule/capability.py   2015-04-17 22:44:58.568224878 +0200
+++ utils/apparmor/rule/capability.py   2015-04-21 23:22:21.695364126 +0200
@@ -61,10 +61,14 @@
                     raise AppArmorBug('Passed empty capability to 
CapabilityRule: %s' % str(cap_list))
 
     @classmethod
+    def _match(cls, raw_rule):
+        return RE_PROFILE_CAP.search(raw_rule)
+
+    @classmethod
     def _parse(cls, raw_rule):
         '''parse raw_rule and return CapabilityRule'''
 
-        matches = RE_PROFILE_CAP.search(raw_rule)
+        matches = cls._match(raw_rule)
         if not matches:
             raise AppArmorException(_("Invalid capability rule '%s'") % 
raw_rule)
 
=== modified file utils/apparmor/rule/__init__.py
--- utils/apparmor/rule/__init__.py     2015-04-16 02:18:03.865500000 +0200
+++ utils/apparmor/rule/__init__.py     2015-04-21 23:24:53.741276189 +0200
@@ -26,6 +26,8 @@
     # type specific rules should inherit from this class.
     # Methods that subclasses need to implement:
     #   __init__
+    #   _match(cls, raw_rule) (as a class method)
+    #     - parses a raw rule and returns a regex match object
     #   _parse(cls, raw_rule) (as a class method)
     #     - parses a raw rule and returns an object of the Rule subclass
     #   get_clean(depth)
@@ -49,7 +51,25 @@
         self.raw_rule = None
 
     @classmethod
+    def match(cls, raw_rule):
+        '''return True if raw_rule matches the class (main) regex, False 
otherwise
+           Note: This function just provides an answer to "is this your job?".
+                 It does not guarantee that the rule is completely valid.'''
+
+        if cls._match(raw_rule):
+            return True
+        else:
+            return False
+
+    # @abstractmethod  FIXME - uncomment when python3 only
+    @classmethod
+    def _match(cls, raw_rule):
+        '''parse raw_rule and return regex match object'''
+        raise AppArmorBug("'%s' needs to implement _match(), but didn't" % 
(str(cls)))
+
+    @classmethod
     def parse(cls, raw_rule):
+        '''parse raw_rule and return a rule object'''
         rule = cls._parse(raw_rule)
         rule.raw_rule = raw_rule.strip()
         return rule
=== modified file utils/apparmor/rule/network.py
--- utils/apparmor/rule/network.py      2015-04-17 23:10:00.147204258 +0200
+++ utils/apparmor/rule/network.py      2015-04-21 23:22:12.494914387 +0200
@@ -98,10 +98,14 @@
             raise AppArmorBug('Passed unknown object to NetworkRule: %s' % 
str(type_or_protocol))
 
     @classmethod
+    def _match(cls, raw_rule):
+        return RE_PROFILE_NETWORK.search(raw_rule)
+
+    @classmethod
     def _parse(cls, raw_rule):
         '''parse raw_rule and return NetworkRule'''
 
-        matches = RE_PROFILE_NETWORK.search(raw_rule)
+        matches = cls._match(raw_rule)
         if not matches:
             raise AppArmorException(_("Invalid network rule '%s'") % raw_rule)
 
=== modified file utils/test/test-baserule.py
--- utils/test/test-baserule.py 2015-04-19 23:30:50.904564067 +0200
+++ utils/test/test-baserule.py 2015-04-21 23:21:41.578763715 +0200
@@ -22,6 +22,18 @@
         with self.assertRaises(AppArmorBug):
             BaseRule._parse('foo')
 
+    def test_abstract__parse_2(self):
+        with self.assertRaises(AppArmorBug):
+            BaseRule.parse('foo')
+
+    def test_abstract__match(self):
+        with self.assertRaises(AppArmorBug):
+            BaseRule._match('foo')
+
+    def test_abstract__match2(self):
+        with self.assertRaises(AppArmorBug):
+            BaseRule.match('foo')
+
     def test_is_equal_localvars(self):
         obj = BaseRule()
         with self.assertRaises(AppArmorBug):
=== modified file utils/test/test-capability.py
--- utils/test/test-capability.py       2015-04-19 23:30:50.904564067 +0200
+++ utils/test/test-capability.py       2015-04-21 23:11:15.155343906 +0200
@@ -30,6 +30,7 @@
 
         obj = CapabilityRule.parse(rawrule)
 
+        self.assertTrue(CapabilityRule.match(rawrule))
         self.assertEqual(rawrule.strip(), obj.raw_rule)
 
         self._compare_obj(obj, expected)
@@ -220,6 +221,7 @@
         with self.assertRaises(AppArmorException):
             obj = CapabilityRule(CapabilityRule.parse(rawrule))
 
+        self.assertFalse(CapabilityRule.match(rawrule))
         self.assertIsNone(obj, 'CapbilityRule handed back an object 
unexpectedly')
 
     def test_invalid_cap_missing_comma(self):
@@ -269,6 +271,7 @@
         clean = obj.get_clean()
         raw = obj.get_raw()
 
+        self.assertTrue(CapabilityRule.match(rawrule))
         self.assertEqual(cleanrule.strip(), clean, 'unexpected clean rule')
         self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule')
 
@@ -294,12 +297,15 @@
         self.maxDiff = None
 
     def _is_covered(self, obj, rule_to_test):
+        self.assertTrue(CapabilityRule.match(rule_to_test))
         return obj.is_covered(CapabilityRule.parse(rule_to_test))
 
     def _is_covered_exact(self, obj, rule_to_test):
+        self.assertTrue(CapabilityRule.match(rule_to_test))
         return obj.is_covered(CapabilityRule.parse(rule_to_test), True, True)
 
     def _is_equal(self, obj, rule_to_test, strict):
+        self.assertTrue(CapabilityRule.match(rule_to_test))
         return obj.is_equal(CapabilityRule.parse(rule_to_test), strict)
 
     def test_covered_single(self):
=== modified file utils/test/test-network.py
--- utils/test/test-network.py  2015-04-20 00:17:55.028303768 +0200
+++ utils/test/test-network.py  2015-04-21 23:04:14.672708712 +0200
@@ -49,6 +49,7 @@
     ]
 
     def _run_test(self, rawrule, expected):
+        self.assertTrue(NetworkRule.match(rawrule))
         obj = NetworkRule.parse(rawrule)
         self.assertEqual(rawrule.strip(), obj.raw_rule)
         self._compare_obj(obj, expected)
@@ -63,6 +64,7 @@
     ]
 
     def _run_test(self, rawrule, expected):
+        self.assertTrue(NetworkRule.match(rawrule))  # the above invalid rules 
still match the main regex!
         with self.assertRaises(expected):
             NetworkRule.parse(rawrule)
 
@@ -152,6 +154,7 @@
 class InvalidNetworkTest(AATest):
     def _check_invalid_rawrule(self, rawrule):
         obj = None
+        self.assertFalse(NetworkRule.match(rawrule))
         with self.assertRaises(AppArmorException):
             obj = NetworkRule(NetworkRule.parse(rawrule))
 
@@ -180,6 +183,7 @@
 
 class WriteNetworkTestAATest(AATest):
     def _run_test(self, rawrule, expected):
+        self.assertTrue(NetworkRule.match(rawrule))
         obj = NetworkRule.parse(rawrule)
         clean = obj.get_clean()
         raw = obj.get_raw()
@@ -210,6 +214,8 @@
         obj = NetworkRule.parse(self.rule)
         check_obj = NetworkRule.parse(param)
 
+        self.assertTrue(NetworkRule.match(param))
+
         self.assertEqual(obj.is_equal(check_obj), expected[0], 'Mismatch in 
is_equal, expected %s' % expected[0])
         self.assertEqual(obj.is_equal(check_obj, True), expected[1], 'Mismatch 
in is_equal/strict, expected %s' % expected[1])
 




Regards,

Christian Boltz
-- 
> Und nun rate mal, warum ausgerechnet v.a. Vielschreiber mutt
> verwenden. Sicher nicht, weil KMail besser waere.
Weil eine Handvoll muttschisten die alle dazu gezwungen hat? ;)
[> David Haller und Manfred Misch in suse-linux]


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

Reply via email to