mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 10:07:12 +00:00
Add match() and _match() class methods to rule classes
Add 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(). Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
parent
f340126ec1
commit
6dade51f92
@ -26,6 +26,8 @@ class BaseRule(object):
|
|||||||
# type specific rules should inherit from this class.
|
# type specific rules should inherit from this class.
|
||||||
# Methods that subclasses need to implement:
|
# Methods that subclasses need to implement:
|
||||||
# __init__
|
# __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)
|
# _parse(cls, raw_rule) (as a class method)
|
||||||
# - parses a raw rule and returns an object of the Rule subclass
|
# - parses a raw rule and returns an object of the Rule subclass
|
||||||
# get_clean(depth)
|
# get_clean(depth)
|
||||||
@ -48,8 +50,26 @@ class BaseRule(object):
|
|||||||
# Set only in the parse() class method
|
# Set only in the parse() class method
|
||||||
self.raw_rule = None
|
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
|
@classmethod
|
||||||
def parse(cls, raw_rule):
|
def parse(cls, raw_rule):
|
||||||
|
'''parse raw_rule and return a rule object'''
|
||||||
rule = cls._parse(raw_rule)
|
rule = cls._parse(raw_rule)
|
||||||
rule.raw_rule = raw_rule.strip()
|
rule.raw_rule = raw_rule.strip()
|
||||||
return rule
|
return rule
|
||||||
|
@ -60,11 +60,15 @@ class CapabilityRule(BaseRule):
|
|||||||
if len(cap.strip()) == 0:
|
if len(cap.strip()) == 0:
|
||||||
raise AppArmorBug('Passed empty capability to CapabilityRule: %s' % str(cap_list))
|
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
|
@classmethod
|
||||||
def _parse(cls, raw_rule):
|
def _parse(cls, raw_rule):
|
||||||
'''parse raw_rule and return CapabilityRule'''
|
'''parse raw_rule and return CapabilityRule'''
|
||||||
|
|
||||||
matches = RE_PROFILE_CAP.search(raw_rule)
|
matches = cls._match(raw_rule)
|
||||||
if not matches:
|
if not matches:
|
||||||
raise AppArmorException(_("Invalid capability rule '%s'") % raw_rule)
|
raise AppArmorException(_("Invalid capability rule '%s'") % raw_rule)
|
||||||
|
|
||||||
|
@ -97,11 +97,15 @@ class NetworkRule(BaseRule):
|
|||||||
else:
|
else:
|
||||||
raise AppArmorBug('Passed unknown object to NetworkRule: %s' % str(type_or_protocol))
|
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
|
@classmethod
|
||||||
def _parse(cls, raw_rule):
|
def _parse(cls, raw_rule):
|
||||||
'''parse raw_rule and return NetworkRule'''
|
'''parse raw_rule and return NetworkRule'''
|
||||||
|
|
||||||
matches = RE_PROFILE_NETWORK.search(raw_rule)
|
matches = cls._match(raw_rule)
|
||||||
if not matches:
|
if not matches:
|
||||||
raise AppArmorException(_("Invalid network rule '%s'") % raw_rule)
|
raise AppArmorException(_("Invalid network rule '%s'") % raw_rule)
|
||||||
|
|
||||||
|
@ -22,6 +22,18 @@ class TestBaserule(AATest):
|
|||||||
with self.assertRaises(AppArmorBug):
|
with self.assertRaises(AppArmorBug):
|
||||||
BaseRule._parse('foo')
|
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):
|
def test_is_equal_localvars(self):
|
||||||
obj = BaseRule()
|
obj = BaseRule()
|
||||||
with self.assertRaises(AppArmorBug):
|
with self.assertRaises(AppArmorBug):
|
||||||
|
@ -30,6 +30,7 @@ class CapabilityTest(unittest.TestCase):
|
|||||||
|
|
||||||
obj = CapabilityRule.parse(rawrule)
|
obj = CapabilityRule.parse(rawrule)
|
||||||
|
|
||||||
|
self.assertTrue(CapabilityRule.match(rawrule))
|
||||||
self.assertEqual(rawrule.strip(), obj.raw_rule)
|
self.assertEqual(rawrule.strip(), obj.raw_rule)
|
||||||
|
|
||||||
self._compare_obj(obj, expected)
|
self._compare_obj(obj, expected)
|
||||||
@ -220,6 +221,7 @@ class InvalidCapabilityTest(unittest.TestCase):
|
|||||||
with self.assertRaises(AppArmorException):
|
with self.assertRaises(AppArmorException):
|
||||||
obj = CapabilityRule(CapabilityRule.parse(rawrule))
|
obj = CapabilityRule(CapabilityRule.parse(rawrule))
|
||||||
|
|
||||||
|
self.assertFalse(CapabilityRule.match(rawrule))
|
||||||
self.assertIsNone(obj, 'CapbilityRule handed back an object unexpectedly')
|
self.assertIsNone(obj, 'CapbilityRule handed back an object unexpectedly')
|
||||||
|
|
||||||
def test_invalid_cap_missing_comma(self):
|
def test_invalid_cap_missing_comma(self):
|
||||||
@ -269,6 +271,7 @@ class WriteCapabilityTest(unittest.TestCase):
|
|||||||
clean = obj.get_clean()
|
clean = obj.get_clean()
|
||||||
raw = obj.get_raw()
|
raw = obj.get_raw()
|
||||||
|
|
||||||
|
self.assertTrue(CapabilityRule.match(rawrule))
|
||||||
self.assertEqual(cleanrule.strip(), clean, 'unexpected clean rule')
|
self.assertEqual(cleanrule.strip(), clean, 'unexpected clean rule')
|
||||||
self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule')
|
self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule')
|
||||||
|
|
||||||
@ -294,12 +297,15 @@ class CapabilityCoveredTest(unittest.TestCase):
|
|||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
|
|
||||||
def _is_covered(self, obj, rule_to_test):
|
def _is_covered(self, obj, rule_to_test):
|
||||||
|
self.assertTrue(CapabilityRule.match(rule_to_test))
|
||||||
return obj.is_covered(CapabilityRule.parse(rule_to_test))
|
return obj.is_covered(CapabilityRule.parse(rule_to_test))
|
||||||
|
|
||||||
def _is_covered_exact(self, obj, 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)
|
return obj.is_covered(CapabilityRule.parse(rule_to_test), True, True)
|
||||||
|
|
||||||
def _is_equal(self, obj, rule_to_test, strict):
|
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)
|
return obj.is_equal(CapabilityRule.parse(rule_to_test), strict)
|
||||||
|
|
||||||
def test_covered_single(self):
|
def test_covered_single(self):
|
||||||
|
@ -49,6 +49,7 @@ class NetworkTestParse(NetworkTest):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def _run_test(self, rawrule, expected):
|
def _run_test(self, rawrule, expected):
|
||||||
|
self.assertTrue(NetworkRule.match(rawrule))
|
||||||
obj = NetworkRule.parse(rawrule)
|
obj = NetworkRule.parse(rawrule)
|
||||||
self.assertEqual(rawrule.strip(), obj.raw_rule)
|
self.assertEqual(rawrule.strip(), obj.raw_rule)
|
||||||
self._compare_obj(obj, expected)
|
self._compare_obj(obj, expected)
|
||||||
@ -63,6 +64,7 @@ class NetworkTestParseInvalid(NetworkTest):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def _run_test(self, rawrule, expected):
|
def _run_test(self, rawrule, expected):
|
||||||
|
self.assertTrue(NetworkRule.match(rawrule)) # the above invalid rules still match the main regex!
|
||||||
with self.assertRaises(expected):
|
with self.assertRaises(expected):
|
||||||
NetworkRule.parse(rawrule)
|
NetworkRule.parse(rawrule)
|
||||||
|
|
||||||
@ -152,6 +154,7 @@ class InvalidNetworkInit(AATest):
|
|||||||
class InvalidNetworkTest(AATest):
|
class InvalidNetworkTest(AATest):
|
||||||
def _check_invalid_rawrule(self, rawrule):
|
def _check_invalid_rawrule(self, rawrule):
|
||||||
obj = None
|
obj = None
|
||||||
|
self.assertFalse(NetworkRule.match(rawrule))
|
||||||
with self.assertRaises(AppArmorException):
|
with self.assertRaises(AppArmorException):
|
||||||
obj = NetworkRule(NetworkRule.parse(rawrule))
|
obj = NetworkRule(NetworkRule.parse(rawrule))
|
||||||
|
|
||||||
@ -180,6 +183,7 @@ class InvalidNetworkTest(AATest):
|
|||||||
|
|
||||||
class WriteNetworkTestAATest(AATest):
|
class WriteNetworkTestAATest(AATest):
|
||||||
def _run_test(self, rawrule, expected):
|
def _run_test(self, rawrule, expected):
|
||||||
|
self.assertTrue(NetworkRule.match(rawrule))
|
||||||
obj = NetworkRule.parse(rawrule)
|
obj = NetworkRule.parse(rawrule)
|
||||||
clean = obj.get_clean()
|
clean = obj.get_clean()
|
||||||
raw = obj.get_raw()
|
raw = obj.get_raw()
|
||||||
@ -210,6 +214,8 @@ class NetworkCoveredTest(AATest):
|
|||||||
obj = NetworkRule.parse(self.rule)
|
obj = NetworkRule.parse(self.rule)
|
||||||
check_obj = NetworkRule.parse(param)
|
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), 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])
|
self.assertEqual(obj.is_equal(check_obj, True), expected[1], 'Mismatch in is_equal/strict, expected %s' % expected[1])
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user