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 CommonQueyTab implementation.
Signed-off-by: Chris PeBenito <pebenito@ieee.org>
- Loading branch information
Showing
10 changed files
with
274 additions
and
0 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,79 @@ | ||
# SPDX-License-Identifier: LGPL-2.1-only | ||
|
||
from PyQt6 import QtWidgets | ||
import setools | ||
|
||
from . import criteria, models, tab | ||
|
||
__all__ = ("CommonQueryTab",) | ||
|
||
|
||
class CommonQueryTab(tab.TableResultTabWidget): | ||
|
||
"""A common permission set query.""" | ||
|
||
section = tab.AnalysisSection.Components | ||
tab_title = "Common Permision Sets" | ||
mlsonly = False | ||
|
||
def __init__(self, policy: setools.SELinuxPolicy, _, /, *, | ||
parent: QtWidgets.QWidget | None = None) -> None: | ||
|
||
super().__init__(setools.CommonQuery(policy), None, enable_criteria=True, | ||
enable_browser=True, parent=parent) | ||
|
||
self.setWhatsThis("<b>Search common permission sets in an SELinux policy.</b>") | ||
|
||
# | ||
# Set up criteria widgets | ||
# | ||
name = criteria.CommonName("Name", self.query, "name", enable_regex=True, | ||
parent=self.criteria_frame) | ||
name.setToolTip("Search for common permission sets by name.") | ||
name.setWhatsThis("<p>Search for common permission set by name.</p>") | ||
|
||
perms = criteria.PermissionCriteriaWidget("Permissions", self.query, "perms", | ||
enable_equal=True) | ||
perms.setToolTip("Search for common permission sets by permissions.") | ||
perms.setWhatsThis("<p>Search for common permission set by permissions.</p>") | ||
|
||
# Add widgets to layout | ||
self.criteria_frame_layout.addWidget(name, 0, 0, 1, 1) | ||
self.criteria_frame_layout.addWidget(perms, 0, 1, 1, 1) | ||
self.criteria_frame_layout.addWidget(self.buttonBox, 1, 0, 1, 2) | ||
|
||
# Save widget references | ||
self.criteria = (name, perms) | ||
|
||
# Set result table's model | ||
self.table_results_model = models.CommonTable(self.table_results) | ||
|
||
# | ||
# Set up browser | ||
# | ||
self.browser.setModel(models.CommonTable(self.browser, | ||
data=sorted(self.query.policy.commons()))) | ||
|
||
|
||
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 = CommonQueryTab(setools.SELinuxPolicy(), mw) | ||
mw.setCentralWidget(widget) | ||
mw.resize(1280, 1024) | ||
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,59 @@ | ||
# SPDX-License-Identifier: LGPL-2.1-only | ||
|
||
from PyQt6 import QtCore, QtWidgets | ||
import setools | ||
|
||
from .criteria import OptionsPlacement | ||
from .name import NameCriteriaWidget | ||
|
||
# Regex for exact matches to roles | ||
VALIDATE_EXACT = r"[A-Za-z0-9._-]*" | ||
|
||
__all__ = ("CommonName",) | ||
|
||
|
||
class CommonName(NameCriteriaWidget): | ||
|
||
""" | ||
Widget providing a QLineEdit that saves the input to the attributes | ||
of the specified query. This supports inputs of common names. | ||
""" | ||
|
||
indirect_toggled = QtCore.pyqtSignal(bool) | ||
|
||
def __init__(self, title: str, query: setools.PolicyQuery, attrname: str, /, *, | ||
parent: QtWidgets.QWidget | None = None, | ||
options_placement: OptionsPlacement = OptionsPlacement.RIGHT, | ||
required: bool = False, enable_regex: bool = True): | ||
|
||
# Create completion list | ||
completion = list[str](r.name for r in query.policy.commons()) | ||
|
||
super().__init__(title, query, attrname, completion, VALIDATE_EXACT, | ||
enable_regex=enable_regex, required=required, parent=parent, | ||
options_placement=options_placement) | ||
|
||
|
||
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.CommonQuery(setools.SELinuxPolicy()) | ||
|
||
app = QtWidgets.QApplication(sys.argv) | ||
mw = QtWidgets.QMainWindow() | ||
widget = CommonName("Test Common", q, "name", parent=mw) | ||
widget.setToolTip("test tooltip") | ||
widget.setWhatsThis("test whats this") | ||
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() | ||
sys.exit(app.exec()) |
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,44 @@ | ||
# SPDX-License-Identifier: LGPL-2.1-only | ||
from PyQt6 import QtGui, QtWidgets | ||
import setools | ||
|
||
from . import util | ||
|
||
__all__ = ('common_detail', 'common_detail_action', 'common_tooltip') | ||
|
||
|
||
def common_detail(common: setools.Common, parent: QtWidgets.QWidget | None = None) -> None: | ||
"""Display a dialog with common details.""" | ||
|
||
util.display_object_details( | ||
f"{common} Details", | ||
f""" | ||
<h1>Common Name</h1> | ||
<p>{common}<p> | ||
<h2>Permissions ({len(common.perms)})</h2> | ||
<ul> | ||
{"".join(f"<li>{p}</li>" for p in sorted(common.perms))} | ||
</ul> | ||
""", | ||
parent) | ||
|
||
|
||
def common_detail_action(common: setools.Common, | ||
parent: QtWidgets.QWidget | None = None) -> QtGui.QAction: | ||
"""Return a QAction that, when triggered, opens a common detail popup.""" | ||
a = QtGui.QAction(f"Properties of {common}") | ||
a.triggered.connect(lambda x: common_detail(common, parent)) | ||
return a | ||
|
||
|
||
def common_tooltip(common: setools.Common) -> str: | ||
"""Return tooltip text for this common.""" | ||
nperms = len(common.perms) | ||
if nperms == 0: | ||
return f"{common} is a common permission set with no permissions defined." | ||
elif nperms > 5: | ||
return f"{common} is a common permission set with {nperms} permissions defined." | ||
else: | ||
return f"{common} is a common permission set with permissions: " \ | ||
f"{', '.join(common.perms)}" |
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
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,24 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
from PyQt6 import QtCore | ||
import pytest | ||
from pytestqt.qtbot import QtBot | ||
|
||
from setoolsgui.widgets import criteria | ||
|
||
|
||
@pytest.fixture | ||
def widget(mock_query, request: pytest.FixtureRequest, qtbot: QtBot) -> criteria.CommonName: | ||
"""Pytest fixture to set up the widget.""" | ||
marker = request.node.get_closest_marker("obj_args") | ||
kwargs = marker.kwargs if marker else {} | ||
w = criteria.CommonName(request.node.name, mock_query, "name", **kwargs) | ||
qtbot.addWidget(w) | ||
w.show() | ||
return w | ||
|
||
|
||
def test_base_settings(widget: criteria.CommonName, mock_query) -> None: | ||
"""Test base properties of widget.""" | ||
model = widget.criteria.completer().model() | ||
assert isinstance(model, QtCore.QStringListModel) | ||
assert sorted(c.name for c in mock_query.policy.commons()) == model.stringList() |
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,56 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
import typing | ||
|
||
from PyQt6 import QtWidgets | ||
import pytest | ||
from pytestqt.qtbot import QtBot | ||
|
||
import setools | ||
from setoolsgui.widgets.commonquery import CommonQueryTab | ||
|
||
|
||
@pytest.fixture | ||
def widget(mock_policy, request: pytest.FixtureRequest, qtbot: QtBot) -> CommonQueryTab: | ||
"""Pytest fixture to set up the widget.""" | ||
marker = request.node.get_closest_marker("obj_args") | ||
kwargs = marker.kwargs if marker else {} | ||
w = CommonQueryTab(mock_policy, None, **kwargs) | ||
qtbot.addWidget(w) | ||
w.show() | ||
return w | ||
|
||
|
||
def test_docs(widget: CommonQueryTab) -> None: | ||
"""Check that docs are provided for the 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(widget: CommonQueryTab) -> None: | ||
"""Test the layout of the criteria frame.""" | ||
name, perms = widget.criteria | ||
|
||
assert widget.criteria_frame_layout.columnCount() == 2 | ||
assert widget.criteria_frame_layout.rowCount() == 2 | ||
assert widget.criteria_frame_layout.itemAtPosition(0, 0).widget() == name | ||
assert widget.criteria_frame_layout.itemAtPosition(0, 1).widget() == perms | ||
assert widget.criteria_frame_layout.itemAtPosition(1, 0).widget() == widget.buttonBox | ||
assert widget.criteria_frame_layout.itemAtPosition(1, 1).widget() == widget.buttonBox | ||
|
||
|
||
def test_criteria_mapping(widget: CommonQueryTab) -> None: | ||
"""Test that widgets save to the correct query fields.""" | ||
name, state = widget.criteria | ||
|
||
assert isinstance(widget.query, setools.CommonQuery) | ||
assert name.attrname == "name" | ||
assert state.attrname == "perms" |