Skip to content

Commit e82fcad

Browse files
committed
PolicyDifference: Add type annotations.
Includes some minor code changes to fix errors from static type checking. Disable unsubscriptable-object pylint check on Wrapper subclass declarations, as this hits the bug described in pylint-dev/pylint#2822. Signed-off-by: Chris PeBenito <[email protected]>
1 parent aceedd8 commit e82fcad

30 files changed

+682
-393
lines changed

setools/diff/bool.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,28 @@
1717
# License along with SETools. If not, see
1818
# <http://www.gnu.org/licenses/>.
1919
#
20-
from collections import defaultdict, namedtuple
20+
from collections import defaultdict
21+
from typing import NamedTuple
22+
23+
from ..policyrep import SELinuxPolicy, Boolean
2124

2225
from .descriptors import DiffResultDescriptor
2326
from .difference import Difference, SymbolWrapper
27+
from .typing import SymbolCache
28+
29+
30+
_bool_cache: SymbolCache[Boolean] = defaultdict(dict)
31+
2432

33+
class ModifiedBoolean(NamedTuple):
2534

26-
modified_bool_record = namedtuple("modified_boolean", ["added_state", "removed_state"])
35+
"""Difference details for a modified Boolean."""
2736

28-
_bool_cache = defaultdict(dict)
37+
added_state: bool
38+
removed_state: bool
2939

3040

31-
def boolean_wrapper(policy, boolean):
41+
def boolean_wrapper(policy: SELinuxPolicy, boolean: Boolean) -> SymbolWrapper[Boolean]:
3242
"""
3343
Wrap booleans from the specified policy.
3444
@@ -51,7 +61,7 @@ class BooleansDifference(Difference):
5161
removed_booleans = DiffResultDescriptor("diff_booleans")
5262
modified_booleans = DiffResultDescriptor("diff_booleans")
5363

54-
def diff_booleans(self):
64+
def diff_booleans(self) -> None:
5565
"""Generate the difference in type attributes between the policies."""
5666

5767
self.log.info("Generating Boolean differences from {0.left_policy} to {0.right_policy}".
@@ -68,13 +78,13 @@ def diff_booleans(self):
6878
# Criteria for modified booleans
6979
# 1. change to default state
7080
if left_boolean.state != right_boolean.state:
71-
self.modified_booleans[left_boolean] = modified_bool_record(right_boolean.state,
72-
left_boolean.state)
81+
self.modified_booleans[left_boolean] = ModifiedBoolean(right_boolean.state,
82+
left_boolean.state)
7383

7484
#
7585
# Internal functions
7686
#
77-
def _reset_diff(self):
87+
def _reset_diff(self) -> None:
7888
"""Reset diff results on policy changes."""
7989
self.log.debug("Resetting Boolean differences")
8090
self.added_booleans = None

setools/diff/bounds.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@
1717
# License along with SETools. If not, see
1818
# <http://www.gnu.org/licenses/>.
1919
#
20-
from collections import namedtuple
20+
from typing import cast, List, NamedTuple, Optional
2121

22-
from ..policyrep import BoundsRuletype
22+
from ..policyrep import Bounds, BoundsRuletype, Type
2323
from .descriptors import DiffResultDescriptor
2424
from .difference import Difference, Wrapper
2525
from .types import type_wrapper_factory
2626

2727

28-
modified_bounds_record = namedtuple("modified_bound", ["rule", "added_bound", "removed_bound"])
28+
class ModifiedBounds(NamedTuple):
29+
30+
"""Difference details for a modified bounds rule."""
31+
32+
rule: Bounds
33+
added_bound: Type
34+
removed_bound: Type
2935

3036

3137
class BoundsDifference(Difference):
@@ -37,10 +43,10 @@ class BoundsDifference(Difference):
3743
modified_typebounds = DiffResultDescriptor("diff_typebounds")
3844

3945
# Lists of rules for each policy
40-
_left_typebounds = None
41-
_right_typebounds = None
46+
_left_typebounds: Optional[List[Bounds]] = None
47+
_right_typebounds: Optional[List[Bounds]] = None
4248

43-
def diff_typebounds(self):
49+
def diff_typebounds(self) -> None:
4450
"""Generate the difference in typebound rules between the policies."""
4551

4652
self.log.info("Generating typebounds differences from {0.left_policy} to {0.right_policy}".
@@ -50,21 +56,21 @@ def diff_typebounds(self):
5056
self._create_typebound_lists()
5157

5258
self.added_typebounds, self.removed_typebounds, matched_typebounds = self._set_diff(
53-
(BoundsWrapper(c) for c in self._left_typebounds),
54-
(BoundsWrapper(c) for c in self._right_typebounds),
59+
(BoundsWrapper(c) for c in cast(List[Bounds], self._left_typebounds)),
60+
(BoundsWrapper(c) for c in cast(List[Bounds], self._right_typebounds)),
5561
key=lambda b: str(b.child))
5662

5763
self.modified_typebounds = []
5864

5965
for left_bound, right_bound in matched_typebounds:
6066
if type_wrapper_factory(left_bound.parent) != type_wrapper_factory(right_bound.parent):
61-
self.modified_typebounds.append(modified_bounds_record(
67+
self.modified_typebounds.append(ModifiedBounds(
6268
left_bound, right_bound.parent, left_bound.parent))
6369

6470
#
6571
# Internal functions
6672
#
67-
def _create_typebound_lists(self):
73+
def _create_typebound_lists(self) -> None:
6874
"""Create rule lists for both policies."""
6975
self._left_typebounds = []
7076
for rule in self.left_policy.bounds():
@@ -82,7 +88,7 @@ def _create_typebound_lists(self):
8288
self.log.error("Unknown rule type: {0} (This is an SETools bug)".
8389
format(rule.ruletype))
8490

85-
def _reset_diff(self):
91+
def _reset_diff(self) -> None:
8692
"""Reset diff results on policy changes."""
8793
self.log.debug("Resetting all *bounds differences")
8894
self.added_typebounds = None
@@ -93,13 +99,14 @@ def _reset_diff(self):
9399
self._right_typebounds = None
94100

95101

96-
class BoundsWrapper(Wrapper):
102+
# Pylint bug: https://github.com/PyCQA/pylint/issues/2822
103+
class BoundsWrapper(Wrapper[Bounds]): # pylint: disable=unsubscriptable-object
97104

98105
"""Wrap *bounds for diff purposes."""
99106

100107
__slots__ = ("ruletype", "parent", "child")
101108

102-
def __init__(self, rule):
109+
def __init__(self, rule: Bounds) -> None:
103110
self.origin = rule
104111
self.ruletype = rule.ruletype
105112
self.parent = type_wrapper_factory(rule.parent)

setools/diff/commons.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616
# License along with SETools. If not, see
1717
# <http://www.gnu.org/licenses/>.
1818
#
19-
from collections import namedtuple
19+
from typing import NamedTuple, Set
2020

2121
from .descriptors import DiffResultDescriptor
2222
from .difference import Difference, SymbolWrapper
2323

2424

25-
modified_commons_record = namedtuple("modified_common", ["added_perms",
26-
"removed_perms",
27-
"matched_perms"])
25+
class ModifiedCommon(NamedTuple):
26+
27+
"""Difference details for a modified common permission set."""
28+
29+
added_perms: Set[str]
30+
removed_perms: Set[str]
31+
matched_perms: Set[str]
2832

2933

3034
class CommonDifference(Difference):
@@ -38,7 +42,7 @@ class CommonDifference(Difference):
3842
removed_commons = DiffResultDescriptor("diff_commons")
3943
modified_commons = DiffResultDescriptor("diff_commons")
4044

41-
def diff_commons(self):
45+
def diff_commons(self) -> None:
4246
"""Generate the difference in commons between the policies."""
4347

4448
self.log.info(
@@ -58,14 +62,14 @@ def diff_commons(self):
5862
unwrap=False)
5963

6064
if added_perms or removed_perms:
61-
self.modified_commons[left_common] = modified_commons_record(added_perms,
62-
removed_perms,
63-
matched_perms)
65+
self.modified_commons[left_common] = ModifiedCommon(added_perms,
66+
removed_perms,
67+
matched_perms)
6468

6569
#
6670
# Internal functions
6771
#
68-
def _reset_diff(self):
72+
def _reset_diff(self) -> None:
6973
"""Reset diff results on policy changes."""
7074
self.log.debug("Resetting common differences")
7175
self.added_commons = None

setools/diff/conditional.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
#
2020
from collections import defaultdict
2121

22+
from ..policyrep import Conditional
23+
2224
from .difference import Wrapper
25+
from .typing import Cache
2326

2427

25-
_cond_cache = defaultdict(dict)
28+
_cond_cache: Cache[Conditional, "ConditionalWrapper"] = defaultdict(dict)
2629

2730

28-
def conditional_wrapper_factory(cond):
31+
def conditional_wrapper_factory(cond: Conditional) -> "ConditionalWrapper":
2932
"""
3033
Wrap type attributes from the specified policy.
3134
@@ -40,13 +43,14 @@ def conditional_wrapper_factory(cond):
4043
return a
4144

4245

43-
class ConditionalWrapper(Wrapper):
46+
# Pylint bug: https://github.com/PyCQA/pylint/issues/2822
47+
class ConditionalWrapper(Wrapper[Conditional]): # pylint: disable=unsubscriptable-object
4448

4549
"""Wrap conditional policy expressions to allow comparisons by truth table."""
4650

4751
__slots__ = ("truth_table")
4852

49-
def __init__(self, cond):
53+
def __init__(self, cond: Conditional) -> None:
5054
self.origin = cond
5155
self.truth_table = cond.truth_table()
5256

setools/diff/constraints.py

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
# <http://www.gnu.org/licenses/>.
1919
#
2020
from collections import defaultdict
21+
from typing import FrozenSet, List, Optional, Union
22+
23+
from ..policyrep import AnyConstraint, ConstraintRuletype, Role, Type, User
2124

22-
from ..policyrep import ConstraintRuletype
2325
from .descriptors import DiffResultDescriptor
2426
from .difference import Difference, SymbolWrapper, Wrapper
2527
from .objclass import class_wrapper_factory
28+
from .typing import RuleList
2629

2730

2831
class ConstraintsDifference(Difference):
@@ -55,10 +58,10 @@ class ConstraintsDifference(Difference):
5558
removed_mlsvalidatetrans = DiffResultDescriptor("diff_mlsvalidatetrans")
5659

5760
# Lists of rules for each policy
58-
_left_constraints = None
59-
_right_constraints = None
61+
_left_constraints: RuleList[ConstraintRuletype, AnyConstraint] = None
62+
_right_constraints: RuleList[ConstraintRuletype, AnyConstraint] = None
6063

61-
def diff_constrains(self):
64+
def diff_constrains(self) -> None:
6265
"""Generate the difference in constraint rules between the policies."""
6366

6467
self.log.info("Generating constraint differences from {0.left_policy} to {0.right_policy}".
@@ -67,11 +70,14 @@ def diff_constrains(self):
6770
if self._left_constraints is None or self._right_constraints is None:
6871
self._create_constrain_lists()
6972

73+
assert self._left_constraints is not None, "Left constraints didn't load, this a bug."
74+
assert self._right_constraints is not None, "Right constraints didn't load, this a bug."
75+
7076
self.added_constrains, self.removed_constrains, _ = self._set_diff(
7177
(ConstraintWrapper(c) for c in self._left_constraints[ConstraintRuletype.constrain]),
7278
(ConstraintWrapper(c) for c in self._right_constraints[ConstraintRuletype.constrain]))
7379

74-
def diff_mlsconstrains(self):
80+
def diff_mlsconstrains(self) -> None:
7581
"""Generate the difference in MLS constraint rules between the policies."""
7682

7783
self.log.info(
@@ -81,13 +87,16 @@ def diff_mlsconstrains(self):
8187
if self._left_constraints is None or self._right_constraints is None:
8288
self._create_constrain_lists()
8389

90+
assert self._left_constraints is not None, "Left constraints didn't load, this a bug."
91+
assert self._right_constraints is not None, "Right constraints didn't load, this a bug."
92+
8493
self.added_mlsconstrains, self.removed_mlsconstrains, _ = self._set_diff(
8594
(ConstraintWrapper(c) for c in self._left_constraints[
8695
ConstraintRuletype.mlsconstrain]),
8796
(ConstraintWrapper(c) for c in self._right_constraints[
8897
ConstraintRuletype.mlsconstrain]))
8998

90-
def diff_validatetrans(self):
99+
def diff_validatetrans(self) -> None:
91100
"""Generate the difference in validatetrans rules between the policies."""
92101

93102
self.log.info(
@@ -97,13 +106,16 @@ def diff_validatetrans(self):
97106
if self._left_constraints is None or self._right_constraints is None:
98107
self._create_constrain_lists()
99108

109+
assert self._left_constraints is not None, "Left constraints didn't load, this a bug."
110+
assert self._right_constraints is not None, "Right constraints didn't load, this a bug."
111+
100112
self.added_validatetrans, self.removed_validatetrans, _ = self._set_diff(
101113
(ConstraintWrapper(c) for c in self._left_constraints[
102114
ConstraintRuletype.validatetrans]),
103115
(ConstraintWrapper(c) for c in self._right_constraints[
104116
ConstraintRuletype.validatetrans]))
105117

106-
def diff_mlsvalidatetrans(self):
118+
def diff_mlsvalidatetrans(self) -> None:
107119
"""Generate the difference in MLS validatetrans rules between the policies."""
108120

109121
self.log.info(
@@ -113,6 +125,9 @@ def diff_mlsvalidatetrans(self):
113125
if self._left_constraints is None or self._right_constraints is None:
114126
self._create_constrain_lists()
115127

128+
assert self._left_constraints is not None, "Left constraints didn't load, this a bug."
129+
assert self._right_constraints is not None, "Right constraints didn't load, this a bug."
130+
116131
self.added_mlsvalidatetrans, self.removed_mlsvalidatetrans, _ = self._set_diff(
117132
(ConstraintWrapper(c) for c in self._left_constraints[
118133
ConstraintRuletype.mlsvalidatetrans]),
@@ -122,7 +137,7 @@ def diff_mlsvalidatetrans(self):
122137
#
123138
# Internal functions
124139
#
125-
def _create_constrain_lists(self):
140+
def _create_constrain_lists(self) -> None:
126141
"""Create rule lists for both policies."""
127142
self._left_constraints = defaultdict(list)
128143
self.log.debug("Building constraint lists from {0.left_policy}".format(self))
@@ -142,7 +157,7 @@ def _create_constrain_lists(self):
142157

143158
self.log.debug("Completed building constraint rule lists.")
144159

145-
def _reset_diff(self):
160+
def _reset_diff(self) -> None:
146161
"""Reset diff results on policy changes."""
147162
self.log.debug("Resetting all constraints differences")
148163
self.added_constrains = None
@@ -159,26 +174,28 @@ def _reset_diff(self):
159174
self._right_constraints = None
160175

161176

162-
class ConstraintWrapper(Wrapper):
177+
# Pylint bug: https://github.com/PyCQA/pylint/issues/2822
178+
class ConstraintWrapper(Wrapper[AnyConstraint]): # pylint: disable=unsubscriptable-object
163179

164180
"""Wrap constraints for diff purposes."""
165181

166182
__slots__ = ("ruletype", "tclass", "perms", "expr")
167183

168-
def __init__(self, rule):
184+
def __init__(self, rule: AnyConstraint) -> None:
169185
self.origin = rule
170186
self.ruletype = rule.ruletype
171187
self.tclass = class_wrapper_factory(rule.tclass)
172188

173189
try:
174-
self.perms = rule.perms
190+
self.perms: Optional[FrozenSet[str]] = rule.perms
175191
except AttributeError:
176192
# (mls)validatetrans
177193
self.perms = None
178194

179195
self.key = hash(rule)
180196

181-
self.expr = []
197+
self.expr: List[Union[FrozenSet[SymbolWrapper[Union[Role, Type, User]]], str]] = []
198+
182199
for op in rule.expression:
183200
if isinstance(op, frozenset):
184201
# lists of types/users/roles

0 commit comments

Comments
 (0)