1# Copyright 2015, Tresys Technology, LLC
2#
3# This file is part of SETools.
4#
5# SETools is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as
7# published by the Free Software Foundation, either version 2.1 of
8# the License, or (at your option) any later version.
9#
10# SETools is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public
16# License along with SETools.  If not, see
17# <http://www.gnu.org/licenses/>.
18#
19from collections import namedtuple
20
21from .descriptors import DiffResultDescriptor
22from .difference import Difference, SymbolWrapper
23
24
25modified_types_record = namedtuple("modified_type", ["added_attributes",
26                                                     "removed_attributes",
27                                                     "matched_attributes",
28                                                     "modified_permissive",
29                                                     "permissive",
30                                                     "added_aliases",
31                                                     "removed_aliases",
32                                                     "matched_aliases"])
33
34
35class TypesDifference(Difference):
36
37    """Determine the difference in types between two policies."""
38
39    added_types = DiffResultDescriptor("diff_types")
40    removed_types = DiffResultDescriptor("diff_types")
41    modified_types = DiffResultDescriptor("diff_types")
42
43    def diff_types(self):
44        """Generate the difference in types between the policies."""
45
46        self.log.info(
47            "Generating type differences from {0.left_policy} to {0.right_policy}".format(self))
48
49        self.added_types, self.removed_types, matched_types = self._set_diff(
50            (SymbolWrapper(t) for t in self.left_policy.types()),
51            (SymbolWrapper(t) for t in self.right_policy.types()))
52
53        self.modified_types = dict()
54
55        for left_type, right_type in matched_types:
56            # Criteria for modified types
57            # 1. change to attribute set, or
58            # 2. change to alias set, or
59            # 3. different permissive setting
60            added_attr, removed_attr, matched_attr = self._set_diff(
61                (SymbolWrapper(a) for a in left_type.attributes()),
62                (SymbolWrapper(a) for a in right_type.attributes()))
63
64            added_aliases, removed_aliases, matched_aliases = self._set_diff(left_type.aliases(),
65                                                                             right_type.aliases())
66
67            left_permissive = left_type.ispermissive
68            right_permissive = right_type.ispermissive
69            mod_permissive = left_permissive != right_permissive
70
71            if added_attr or removed_attr or added_aliases or removed_aliases or mod_permissive:
72                self.modified_types[left_type] = modified_types_record(added_attr,
73                                                                       removed_attr,
74                                                                       matched_attr,
75                                                                       mod_permissive,
76                                                                       left_permissive,
77                                                                       added_aliases,
78                                                                       removed_aliases,
79                                                                       matched_aliases)
80
81    #
82    # Internal functions
83    #
84    def _reset_diff(self):
85        """Reset diff results on policy changes."""
86        self.log.debug("Resetting type differences")
87        self.added_types = None
88        self.removed_types = None
89        self.modified_types = None
90