Add the comment about 'if arch' for the 'cut_attack_surface' checks
[kconfig-hardened-check.git] / kernel_hardening_checker / engine.py
index 2a371e464ef24d1917527fb859cae4c07b359292..ee56d637b9b763e0dec0e9cfc41d38fcab3827cc 100644 (file)
@@ -9,15 +9,15 @@ This module is the engine of checks.
 """
 
 # pylint: disable=missing-class-docstring,missing-function-docstring
-# pylint: disable=line-too-long,invalid-name,too-many-branches
+# pylint: disable=line-too-long,too-many-branches
 
 from __future__ import annotations
 import sys
 
-from typing import Union, Optional, List, Dict, OrderedDict, Tuple
+from typing import Union, Optional, List, Dict, Tuple
 StrOrNone = Optional[str]
-TupleOrNone = Optional[Tuple]
-TupleOrOrderedDict = Union[Tuple, OrderedDict[str, str]]
+TupleOrNone = Optional[Tuple[int, ...]]
+DictOrTuple = Union[Dict[str, str], Tuple[int, ...]]
 StrOrBool = Union[str, bool]
 
 GREEN_COLOR = '\x1b[32m'
@@ -133,8 +133,8 @@ class OptCheck:
 
 
 class KconfigCheck(OptCheck):
-    def __init__(self, *args, **kwargs) -> None:
-        super().__init__(*args, **kwargs)
+    def __init__(self, *args: str) -> None:
+        super().__init__(*args)
         self.name = f'CONFIG_{self.name}'
 
     @property
@@ -161,16 +161,18 @@ class VersionCheck:
         assert(all(map(lambda x: isinstance(x, int), ver_expected))), \
                f'invalid expected version "{ver_expected}" for VersionCheck (2)'
         self.ver_expected = ver_expected
-        self.ver = (0, 0, 0) # type: Tuple[int, int, int]
+        self.ver = (0, 0, 0) # type: Tuple[int, ...]
         self.result = None # type: str | None
 
     @property
     def opt_type(self) -> str:
         return 'version'
 
-    def set_state(self, data: Tuple) -> None:
+    def set_state(self, data: Tuple[int, ...]) -> None:
         assert(data and isinstance(data, tuple) and len(data) >= 3), \
-               f'invalid version "{data}" for VersionCheck'
+               f'invalid version "{data}" for VersionCheck (1)'
+        assert(all(map(lambda x: isinstance(x, int), data))), \
+               f'invalid version "{data}" for VersionCheck (2)'
         self.ver = data[:3]
 
     def check(self) -> None:
@@ -338,7 +340,7 @@ ChecklistObjType = Union[KconfigCheck, CmdlineCheck, SysctlCheck, OR, AND]
 AnyOptCheckType = Union[KconfigCheck, CmdlineCheck, SysctlCheck, VersionCheck, OR, AND]
 
 
-def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: TupleOrOrderedDict, data_type: str) -> None:
+def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: DictOrTuple, data_type: str) -> None:
     assert(opt.opt_type != 'complex'), f'unexpected opt_type "{opt.opt_type}" for {opt}'
     assert(opt.opt_type in SIMPLE_OPTION_TYPES), f'invalid opt_type "{opt.opt_type}"'
     assert(data_type in SIMPLE_OPTION_TYPES), f'invalid data_type "{data_type}"'
@@ -348,7 +350,7 @@ def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: TupleOrOrderedD
         return
 
     if data_type in ('kconfig', 'cmdline', 'sysctl'):
-        assert(isinstance(data, OrderedDict)), \
+        assert(isinstance(data, dict)), \
                f'unexpected data with data_type {data_type}'
         assert(isinstance(opt, SimpleNamedOptCheckTypes)), \
                f'unexpected VersionCheck with opt_type "{opt.opt_type}"'
@@ -361,7 +363,7 @@ def populate_simple_opt_with_data(opt: SimpleOptCheckType, data: TupleOrOrderedD
         opt.set_state(data)
 
 
-def populate_opt_with_data(opt: AnyOptCheckType, data: TupleOrOrderedDict, data_type: str) -> None:
+def populate_opt_with_data(opt: AnyOptCheckType, data: DictOrTuple, data_type: str) -> None:
     assert(opt.opt_type != 'version'), 'a single VersionCheck is useless'
     if opt.opt_type != 'complex':
         assert(isinstance(opt, SimpleOptCheckTypes)), \
@@ -380,39 +382,43 @@ def populate_opt_with_data(opt: AnyOptCheckType, data: TupleOrOrderedDict, data_
                 populate_opt_with_data(o, data, data_type)
 
 
-def populate_with_data(checklist: List, data: TupleOrOrderedDict, data_type: str) -> None:
+def populate_with_data(checklist: List[ChecklistObjType], data: DictOrTuple, data_type: str) -> None:
     for opt in checklist:
         populate_opt_with_data(opt, data, data_type)
 
 
-def override_expected_value(checklist: List, name: str, new_val: str) -> None:
+def override_expected_value(checklist: List[ChecklistObjType], name: str, new_val: str) -> None:
     for opt in checklist:
         if opt.name == name:
-            assert(opt.opt_type in ('kconfig', 'cmdline', 'sysctl')), \
-                   f'overriding an expected value for "{opt.opt_type}" checks is not supported yet'
+            assert(isinstance(opt, SimpleNamedOptCheckTypes)), \
+                   f'overriding an expected value for {opt}" is not supported yet'
             opt.expected = new_val
 
 
-def perform_checks(checklist: List) -> None:
+def perform_checks(checklist: List[ChecklistObjType]) -> None:
     for opt in checklist:
         opt.check()
 
 
-def print_unknown_options(checklist: List, parsed_options: OrderedDict[str, str], opt_type: str) -> None:
+def print_unknown_options(checklist: List[ChecklistObjType], parsed_options: Dict[str, str], opt_type: str) -> None:
     known_options = []
 
     for o1 in checklist:
-        if o1.opt_type != 'complex':
+        if isinstance(o1, SimpleOptCheckTypes):
+            assert(o1.opt_type != 'complex'), f'{o1} with complex opt_type'
+            assert(not isinstance(o1, VersionCheck)), 'single VersionCheck in checklist'
             known_options.append(o1.name)
             continue
         for o2 in o1.opts:
-            if o2.opt_type != 'complex':
+            if isinstance(o2, SimpleOptCheckTypes):
+                assert(o2.opt_type != 'complex'), f'{o2} with complex opt_type'
                 if hasattr(o2, 'name'):
                     known_options.append(o2.name)
                 continue
             for o3 in o2.opts:
-                assert(o3.opt_type != 'complex'), \
+                assert(isinstance(o3, SimpleOptCheckTypes)), \
                        f'unexpected ComplexOptCheck inside {o2.name}'
+                assert(o3.opt_type != 'complex'), f'{o3} with complex opt_type'
                 if hasattr(o3, 'name'):
                     known_options.append(o3.name)