forked from SELinuxProject/setools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new ConstraintQueryTab implementation.
Signed-off-by: Chris PeBenito <chpebeni@linux.microsoft.com>
- Loading branch information
Showing
6 changed files
with
336 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
# SPDX-License-Identifier: LGPL-2.1-only | ||
|
||
from PyQt6 import QtWidgets | ||
import setools | ||
|
||
from . import criteria, models, tab | ||
|
||
__all__ = ("ConstraintQueryTab",) | ||
|
||
|
||
class ConstraintQueryTab(tab.TableResultTabWidget): | ||
|
||
"""A constraint query.""" | ||
|
||
section = tab.AnalysisSection.Rules | ||
tab_title = "Constraints" | ||
mlsonly = False | ||
|
||
def __init__(self, policy: "setools.SELinuxPolicy", _, /, *, | ||
parent: QtWidgets.QWidget | None = None) -> None: | ||
|
||
super().__init__(setools.ConstraintQuery(policy), None, enable_criteria=True, | ||
parent=parent) | ||
|
||
self.setWhatsThis("<b>Search constraints in a SELinux policy.</b>") | ||
|
||
# | ||
# Set up criteria widgets | ||
# | ||
rt = criteria.ConstrainType("Rule Type", self.query, parent=self.criteria_frame) | ||
rt.setToolTip("The rule types for constraint matching.") | ||
rt.setWhatsThis( | ||
""" | ||
<p><b>Select rule types for constraint matching.</b></p> | ||
<p>If a rule's has a one of the selected types, it will be returned.</p> | ||
""") | ||
|
||
user = criteria.UserNameWidget("User In Expression", | ||
self.query, | ||
"user", | ||
enable_regex=True, | ||
parent=self.criteria_frame) | ||
user.setToolTip("Search for a user in the expression.") | ||
user.setWhatsThis( | ||
""" | ||
<p><b>Search for users in a constraint expression..</b></p> | ||
<p>If a constraint's expression has this user in its expression, | ||
it will be returned.</p> | ||
""") | ||
|
||
role = criteria.RoleNameWidget("Role In Expression", | ||
self.query, | ||
"role", | ||
enable_regex=True, | ||
parent=self.criteria_frame) | ||
role.setToolTip("Search for a role in the expression.") | ||
role.setWhatsThis( | ||
""" | ||
<p><b>Search for roles in a constraint expression..</b></p> | ||
<p>If a constraint's expression has this role in its expression, | ||
it will be returned.</p> | ||
""") | ||
|
||
type_ = criteria.TypeOrAttrNameWidget("Type In Expression", | ||
self.query, | ||
"type_", | ||
mode=criteria.TypeOrAttrNameWidget.Mode.type_only, | ||
enable_regex=True, | ||
enable_indirect=False, | ||
parent=self.criteria_frame) | ||
type_.setToolTip("Search for a type in the expression.") | ||
type_.setWhatsThis( | ||
""" | ||
<p><b>Search for types in a constraint expression..</b></p> | ||
<p>If a constraint's expression has this type in its expression, | ||
it will be returned.</p> | ||
""") | ||
|
||
tclass = criteria.ObjClassCriteriaWidget("Object Class", | ||
self.query, | ||
"tclass", | ||
parent=self.criteria_frame) | ||
tclass.setToolTip("The object class(es) for constraint matching.") | ||
tclass.setWhatsThis( | ||
""" | ||
<p><b>Select object classes for constraint matching.</b></p> | ||
<p>A rule will be returned if its object class is one of the selected | ||
classes</p> | ||
""") | ||
|
||
perms = criteria.PermissionCriteriaWidget("Permission Set", | ||
self.query, | ||
"perms", | ||
enable_equal=True, | ||
enable_subset=True, | ||
parent=self.criteria_frame) | ||
perms.setToolTip("The permission(s) for constraint matching.") | ||
perms.setWhatsThis( | ||
""" | ||
<p><b>Select permissions for constraint matching.</b></p> | ||
<p>Available permissions are dependent on the selected object | ||
classes. If multiple classes are selected, only permissions | ||
available in all of the classes are available.</p> | ||
""") | ||
|
||
# Connect signals | ||
tclass.selectionChanged.connect(perms.set_classes) | ||
|
||
# Add widgets to layout | ||
self.criteria_frame_layout.addWidget(rt, 0, 0, 1, 1) | ||
self.criteria_frame_layout.addWidget(user, 0, 1, 1, 1) | ||
self.criteria_frame_layout.addWidget(role, 1, 0, 1, 1) | ||
self.criteria_frame_layout.addWidget(type_, 1, 1, 1, 1) | ||
self.criteria_frame_layout.addWidget(tclass, 2, 0, 1, 1) | ||
self.criteria_frame_layout.addWidget(perms, 2, 1, 1, 1) | ||
self.criteria_frame_layout.addWidget(self.buttonBox, 3, 0, 1, 2) | ||
|
||
# Save widget references | ||
self.criteria = (rt, user, role, type_, tclass, perms) | ||
|
||
# Set result table's model | ||
self.table_results_model = models.ConstraintTable(self.table_results) | ||
|
||
|
||
if __name__ == '__main__': | ||
import sys | ||
import warnings | ||
import pprint | ||
import logging | ||
|
||
logging.basicConfig(level=logging.DEBUG, | ||
format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') | ||
warnings.simplefilter("default") | ||
|
||
app = QtWidgets.QApplication(sys.argv) | ||
mw = QtWidgets.QMainWindow() | ||
widget = ConstraintQueryTab(setools.SELinuxPolicy(), mw) | ||
mw.setCentralWidget(widget) | ||
mw.resize(widget.size()) | ||
whatsthis = QtWidgets.QWhatsThis.createAction(mw) | ||
mw.menuBar().addAction(whatsthis) # type: ignore[union-attr] | ||
mw.setStatusBar(QtWidgets.QStatusBar(mw)) | ||
mw.show() | ||
rc = app.exec() | ||
pprint.pprint(widget.save()) | ||
sys.exit(rc) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# SPDX-License-Identifier: LGPL-2.1-only | ||
|
||
from PyQt6 import QtWidgets | ||
import setools | ||
|
||
from .checkboxset import CheckboxSetCriteriaWidget | ||
|
||
DEFAULT_CHECKED = ("constrain",) | ||
|
||
__all__ = ('ConstrainType',) | ||
|
||
|
||
class ConstrainType(CheckboxSetCriteriaWidget): | ||
|
||
""" | ||
Criteria selection widget presenting type enforcement rule types as a series | ||
of checkboxes. The selected checkboxes are then merged into a single Python | ||
list consisting of object names (constraint types) and stored in the query's | ||
specified attribute. | ||
""" | ||
|
||
def __init__(self, title: str, query: setools.PolicyQuery, attrname: str = "ruletype", | ||
parent: QtWidgets.QWidget | None = None) -> None: | ||
|
||
super().__init__(title, query, attrname, (rt.name for rt in setools.ConstraintRuletype), | ||
num_cols=2, parent=parent) | ||
|
||
for name, widget in self.criteria.items(): | ||
widget.setChecked(name in DEFAULT_CHECKED) | ||
widget.setToolTip(f"Match {name} rules.") | ||
widget.setWhatsThis( | ||
f""" | ||
<p><b>Match {name} rules</b></p> | ||
<p>If a rule has the {name} rule type, it will be returned.</p> | ||
""") | ||
|
||
|
||
if __name__ == '__main__': | ||
import sys | ||
import logging | ||
import warnings | ||
|
||
logging.basicConfig(level=logging.DEBUG, | ||
format='%(asctime)s|%(levelname)s|%(name)s|%(message)s') | ||
warnings.simplefilter("default") | ||
|
||
q = setools.ConstraintQuery(setools.SELinuxPolicy()) | ||
|
||
app = QtWidgets.QApplication(sys.argv) | ||
mw = QtWidgets.QMainWindow() | ||
w = ConstrainType("Test constrain ruletypes", q, parent=mw) | ||
w.setToolTip("test tooltip") | ||
w.setWhatsThis("test whats this") | ||
mw.setCentralWidget(w) | ||
mw.resize(w.size()) | ||
whatsthis = QtWidgets.QWhatsThis.createAction(mw) | ||
mw.menuBar().addAction(whatsthis) # type: ignore[union-attr] | ||
mw.show() | ||
rc = app.exec() | ||
sys.exit(rc) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
import typing | ||
|
||
from PyQt6 import QtWidgets | ||
from pytestqt.qtbot import QtBot | ||
|
||
import setools | ||
from setoolsgui.widgets.constraintquery import ConstraintQueryTab | ||
from setoolsgui.widgets import models | ||
|
||
from .criteria.util import build_mock_policy | ||
|
||
|
||
def test_docs(qtbot: QtBot) -> None: | ||
"""Check that docs are provided for the widget.""" | ||
mock_policy = build_mock_policy() | ||
widget = ConstraintQueryTab(mock_policy, None) | ||
qtbot.addWidget(widget) | ||
|
||
assert widget.whatsThis() | ||
assert widget.table_results.whatsThis() | ||
assert widget.raw_results.whatsThis() | ||
|
||
for w in widget.criteria: | ||
assert w.toolTip() | ||
assert w.whatsThis() | ||
|
||
results = typing.cast(QtWidgets.QTabWidget, widget.results) | ||
for index in range(results.count()): | ||
assert results.tabWhatsThis(index) | ||
|
||
|
||
def test_layout(qtbot: QtBot) -> None: | ||
"""Test the layout of the criteria frame.""" | ||
mock_policy = build_mock_policy() | ||
widget = ConstraintQueryTab(mock_policy, None) | ||
qtbot.addWidget(widget) | ||
|
||
rt, user, role, type_, tclass, perms = widget.criteria | ||
|
||
assert widget.criteria_frame_layout.columnCount() == 2 | ||
assert widget.criteria_frame_layout.rowCount() == 4 | ||
assert widget.criteria_frame_layout.itemAtPosition(0, 0).widget() == rt | ||
assert widget.criteria_frame_layout.itemAtPosition(0, 1).widget() == user | ||
assert widget.criteria_frame_layout.itemAtPosition(1, 0).widget() == role | ||
assert widget.criteria_frame_layout.itemAtPosition(1, 1).widget() == type_ | ||
assert widget.criteria_frame_layout.itemAtPosition(2, 0).widget() == tclass | ||
assert widget.criteria_frame_layout.itemAtPosition(2, 1).widget() == perms | ||
assert widget.criteria_frame_layout.itemAtPosition(3, 0).widget() == widget.buttonBox | ||
assert widget.criteria_frame_layout.itemAtPosition(3, 1).widget() == widget.buttonBox | ||
|
||
|
||
def test_criteria_mapping(qtbot: QtBot) -> None: | ||
"""Test that widgets save to the correct query fields.""" | ||
mock_policy = build_mock_policy() | ||
widget = ConstraintQueryTab(mock_policy, None) | ||
qtbot.addWidget(widget) | ||
|
||
rt, user, role, type_, tclass, perms = widget.criteria | ||
|
||
assert isinstance(widget.query, setools.ConstraintQuery) | ||
assert isinstance(widget.table_results_model, models.ConstraintTable) | ||
assert rt.attrname == "ruletype" | ||
assert user.attrname == "user" | ||
assert role.attrname == "role" | ||
assert type_.attrname == "type_" | ||
assert tclass.attrname == "tclass" | ||
assert perms.attrname == "perms" |