diff --git a/sediff b/sediff
index cf5e04c..c9ced6b 100755
--- a/sediff
+++ b/sediff
@@ -148,6 +148,29 @@ try:
print(" - {0}".format(p))
print()
+ if all_differences or args.bool_:
+ if diff.added_booleans or diff.removed_booleans or \
+ diff.modified_booleans or args.bool_:
+ print("Booleans ({0} Added, {1} Removed, {2} Modified)".format(
+ len(diff.added_booleans), len(diff.removed_booleans),
+ len(diff.modified_booleans)))
+ if diff.added_booleans and not args.stats:
+ print(" Added Booleans: {0}".format(len(diff.added_booleans)))
+ for a in sorted(diff.added_booleans):
+ print(" + {0}".format(a))
+ if diff.removed_booleans and not args.stats:
+ print(" Removed Booleans: {0}".format(len(diff.removed_booleans)))
+ for a in sorted(diff.removed_booleans):
+ print(" - {0}".format(a))
+ if diff.modified_booleans and not args.stats:
+ print(" Modified Booleans: {0}".format(len(diff.modified_booleans)))
+ for name, mod in sorted(diff.modified_booleans.items()):
+ print(" * {0} (Modified default state)".format(name))
+ print(" + {0}".format(mod.added_state))
+ print(" - {0}".format(mod.removed_state))
+
+ print()
+
if all_differences or args.role:
if diff.added_roles or diff.removed_roles or diff.modified_roles or args.role:
print("Roles ({0} Added, {1} Removed, {2} Modified)".format(len(diff.added_roles),
diff --git a/setools/diff/__init__.py b/setools/diff/__init__.py
index 3171f9e..703ac43 100644
--- a/setools/diff/__init__.py
+++ b/setools/diff/__init__.py
@@ -16,6 +16,7 @@
# License along with SETools. If not, see
# .
#
+from .bool import BooleansDifference
from .commons import CommonDifference
from .mlsrules import MLSRulesDifference
from .objclass import ObjClassDifference
@@ -29,7 +30,8 @@ from .users import UsersDifference
__all__ = ['PolicyDifference']
-class PolicyDifference(CommonDifference,
+class PolicyDifference(BooleansDifference,
+ CommonDifference,
MLSRulesDifference,
ObjClassDifference,
RBACRulesDifference,
diff --git a/setools/diff/bool.py b/setools/diff/bool.py
new file mode 100644
index 0000000..212a715
--- /dev/null
+++ b/setools/diff/bool.py
@@ -0,0 +1,64 @@
+# Copyright 2016, Tresys Technology, LLC
+#
+# This file is part of SETools.
+#
+# SETools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as
+# published by the Free Software Foundation, either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# SETools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with SETools. If not, see
+# .
+#
+from collections import namedtuple
+
+from .descriptors import DiffResultDescriptor
+from .difference import Difference, SymbolWrapper
+
+
+modified_bool_record = namedtuple("modified_boolean", ["added_state", "removed_state"])
+
+
+class BooleansDifference(Difference):
+
+ """Determine the difference in type attributes between two policies."""
+
+ added_booleans = DiffResultDescriptor("diff_booleans")
+ removed_booleans = DiffResultDescriptor("diff_booleans")
+ modified_booleans = DiffResultDescriptor("diff_booleans")
+
+ def diff_booleans(self):
+ """Generate the difference in type attributes between the policies."""
+
+ self.log.info("Generating Boolean differences from {0.left_policy} to {0.right_policy}".
+ format(self))
+
+ self.added_booleans, self.removed_booleans, matched_booleans = \
+ self._set_diff(
+ (SymbolWrapper(b) for b in self.left_policy.bools()),
+ (SymbolWrapper(b) for b in self.right_policy.bools()))
+
+ self.modified_booleans = dict()
+
+ for left_boolean, right_boolean in matched_booleans:
+ # Criteria for modified booleans
+ # 1. change to default state
+ if left_boolean.state != right_boolean.state:
+ self.modified_booleans[left_boolean] = modified_bool_record(right_boolean.state,
+ left_boolean.state)
+
+ #
+ # Internal functions
+ #
+ def _reset_diff(self):
+ """Reset diff results on policy changes."""
+ self.log.debug("Resetting Boolean differences")
+ self.added_booleans = None
+ self.removed_booleans = None
+ self.modified_booleans = None
diff --git a/tests/diff.py b/tests/diff.py
index 69a65b0..2d94d91 100644
--- a/tests/diff.py
+++ b/tests/diff.py
@@ -910,6 +910,23 @@ class PolicyDifferenceTest(ValidateRule, unittest.TestCase):
self.assertSetEqual(set(["modified_remove_attr"]),
self.diff.modified_type_attributes["an_attr"].removed_types)
+ #
+ # Booleans
+ #
+ def test_added_boolean(self):
+ """Diff: added boolean."""
+ self.assertSetEqual(set(["added_bool"]), self.diff.added_booleans)
+
+ def test_removed_boolean(self):
+ """Diff: removed boolean."""
+ self.assertSetEqual(set(["removed_bool"]), self.diff.removed_booleans)
+
+ def test_modified_boolean(self):
+ """Diff: modified boolean."""
+ self.assertEqual(1, len(self.diff.modified_booleans))
+ self.assertTrue(self.diff.modified_booleans["modified_bool"].added_state)
+ self.assertFalse(self.diff.modified_booleans["modified_bool"].removed_state)
+
class PolicyDifferenceTestNoDiff(unittest.TestCase):
@@ -1110,3 +1127,15 @@ class PolicyDifferenceTestNoDiff(unittest.TestCase):
def test_modified_type_attributes(self):
"""NoDiff: no modified type attribute rules."""
self.assertFalse(self.diff.modified_type_attributes)
+
+ def test_added_booleans(self):
+ """NoDiff: no added booleans."""
+ self.assertFalse(self.diff.added_booleans)
+
+ def test_removed_booleans(self):
+ """NoDiff: no removed booleans."""
+ self.assertFalse(self.diff.removed_booleans)
+
+ def test_modified_booleans(self):
+ """NoDiff: no modified booleans."""
+ self.assertFalse(self.diff.modified_booleans)
diff --git a/tests/diff_left.conf b/tests/diff_left.conf
index d4b9693..8a2ec7d 100644
--- a/tests/diff_left.conf
+++ b/tests/diff_left.conf
@@ -161,6 +161,11 @@ role modified_add_type;
role modified_remove_type;
role modified_remove_type types { system };
+# booleans
+bool same_bool true;
+bool removed_bool true;
+bool modified_bool false;
+
# Allow rule differences
type matched_source;
type matched_target;
diff --git a/tests/diff_right.conf b/tests/diff_right.conf
index dae33ca..5bf073c 100644
--- a/tests/diff_right.conf
+++ b/tests/diff_right.conf
@@ -162,6 +162,11 @@ role modified_add_type types { system };
role modified_remove_type;
+# booleans
+bool same_bool true;
+bool added_bool true;
+bool modified_bool true;
+
# Allow rule differences
type matched_source;
type matched_target;