Skip to content

Commit f93aab1

Browse files
committed
Merge remote-tracking branch 'origin/pr/319'
* origin/pr/319: Fix repo setting logic in global config
2 parents 00edd60 + a4865c2 commit f93aab1

2 files changed

Lines changed: 136 additions & 50 deletions

File tree

qubes_config/global_config/updates_handler.py

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,19 @@ def __init__(self, gtk_builder: Gtk.Builder):
8383
self.problems_repo_box: Gtk.Box = gtk_builder.get_object("updates_problem_repo")
8484
self.problems_label: Gtk.Label = gtk_builder.get_object("updates_problem_label")
8585

86-
# the code below relies on dicts in Python 3.6+ keeping the
87-
# order of items
88-
self.repo_to_widget_mapping = [
89-
{
90-
"qubes-dom0-current": self.dom0_stable_radio,
91-
"qubes-dom0-security-testing": self.dom0_testing_sec_radio,
92-
"qubes-dom0-current-testing": self.dom0_testing_radio,
93-
},
94-
{
95-
"qubes-templates-itl": self.template_official,
96-
"qubes-templates-itl-testing": self.template_official_testing,
97-
},
98-
{
99-
"qubes-templates-community": self.template_community,
100-
"qubes-templates-community-testing": self.template_community_testing, # pylint: disable=line-too-long
101-
},
86+
self.dom0_update_repo_mapping = [
87+
("qubes-dom0-current", self.dom0_stable_radio),
88+
("qubes-dom0-security-testing", self.dom0_testing_sec_radio),
89+
("qubes-dom0-current-testing", self.dom0_testing_radio),
10290
]
91+
92+
self.repo_to_widget_mapping = {
93+
"qubes-templates-itl": self.template_official,
94+
"qubes-templates-itl-testing": self.template_official_testing,
95+
"qubes-templates-community": self.template_community,
96+
"qubes-templates-community-testing": self.template_community_testing, # pylint: disable=line-too-long
97+
}
98+
10399
self.initial_state: Dict[str, bool] = {}
104100

105101
self.template_community.connect("toggled", self._community_toggled)
@@ -140,16 +136,26 @@ def _load_data(self):
140136
)
141137

142138
def _load_state(self):
143-
for repo_dict in self.repo_to_widget_mapping:
144-
for repo, widget in repo_dict.items():
145-
if repo not in self.repos:
146-
continue
147-
if self.repos[repo]["enabled"]:
148-
widget.set_active(self.repos[repo]["enabled"])
139+
found_dom0_widget = None
140+
for repo, widget in self.dom0_update_repo_mapping:
141+
if repo not in self.repos:
142+
continue
143+
if self.repos[repo]["enabled"]:
144+
found_dom0_widget = widget
145+
else:
146+
break
147+
if found_dom0_widget:
148+
found_dom0_widget.set_active(True)
149149

150-
for repo_dict in self.repo_to_widget_mapping:
151-
for repo, widget in repo_dict.items():
152-
self.initial_state[repo] = widget.get_active()
150+
for repo, widget in self.dom0_update_repo_mapping:
151+
self.initial_state[repo] = widget.get_active()
152+
153+
for repo, widget in self.repo_to_widget_mapping.items():
154+
if repo not in self.repos:
155+
continue
156+
if self.repos[repo]["enabled"]:
157+
widget.set_active(self.repos[repo]["enabled"])
158+
self.initial_state[repo] = widget.get_active()
153159

154160
@staticmethod
155161
def _run_qrexec_repo(service, arg=""):
@@ -176,15 +182,17 @@ def get_unsaved(self) -> str:
176182
itl_changed = False
177183
community_changed = False
178184

179-
for repo_dict in self.repo_to_widget_mapping:
180-
for repo, widget in repo_dict.items():
181-
if self.initial_state[repo] != widget.get_active():
182-
if "dom0" in repo:
183-
dom0_changed = True
184-
elif "community" in repo:
185-
community_changed = True
186-
elif "itl" in repo:
187-
itl_changed = True
185+
for repo, widget in self.dom0_update_repo_mapping:
186+
if self.initial_state[repo] != widget.get_active():
187+
dom0_changed = True
188+
break
189+
190+
for repo, widget in self.repo_to_widget_mapping.items():
191+
if self.initial_state[repo] != widget.get_active():
192+
if "community" in repo:
193+
community_changed = True
194+
elif "itl" in repo:
195+
itl_changed = True
188196
unsaved = []
189197
if dom0_changed:
190198
unsaved.append(_("dom0 update source"))
@@ -199,27 +207,37 @@ def save(self):
199207
"""Save all changes."""
200208
if not self.repos:
201209
return
202-
for repo_dict in self.repo_to_widget_mapping:
203-
found = False
204-
for repo, widget in repo_dict.items():
205-
try:
206-
if widget.get_active():
207-
found = True
208-
self._set_repository(repo, True)
209-
else:
210-
self._set_repository(repo, not found)
211-
except RuntimeError as ex:
212-
raise qubesadmin.exc.QubesException(
213-
"Failed to set repository data: " f"{escape(str(ex))}"
214-
) from ex
210+
211+
dom0_cutoff_found = False
212+
for repo, widget in self.dom0_update_repo_mapping:
213+
state = not dom0_cutoff_found # before cutoff, everything is True, after it
214+
# it is false
215+
try:
216+
self._set_repository(repo, state)
217+
except RuntimeError as ex:
218+
raise qubesadmin.exc.QubesException(
219+
"Failed to set repository data: " f"{escape(str(ex))}"
220+
) from ex
221+
if widget.get_active():
222+
dom0_cutoff_found = True
223+
224+
for repo, widget in self.repo_to_widget_mapping.items():
225+
try:
226+
self._set_repository(repo, widget.get_active())
227+
except RuntimeError as ex:
228+
raise qubesadmin.exc.QubesException(
229+
"Failed to set repository data: " f"{escape(str(ex))}"
230+
) from ex
215231
self._load_data()
216232
self._load_state()
217233

218234
def reset(self):
219235
"""Reset any user changes."""
220-
for repo_dict in self.repo_to_widget_mapping:
221-
for repo, widget in repo_dict.items():
222-
widget.set_active(self.initial_state[repo])
236+
for repo, widget in self.dom0_update_repo_mapping:
237+
widget.set_active(self.initial_state[repo])
238+
239+
for repo, widget in self.repo_to_widget_mapping.items():
240+
widget.set_active(self.initial_state[repo])
223241

224242

225243
class UpdateCheckerHandler:

qubes_config/tests/test_update_handler.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ def __init__(self, stdout=b"", returncode=0, stderr=None):
6666
qubes-templates-community\0c\0disabled"""
6767

6868

69+
SECURITY = """qubes-dom0-current-testing\0c\0disabled
70+
qubes-dom0-security-testing\0c\0enabled
71+
qubes-dom0-current\0c\0enabled
72+
qubes-templates-itl-testing\0c\0enabled
73+
qubes-templates-itl\0c\0enabled
74+
qubes-templates-community-testing\0c\0disabled
75+
qubes-templates-community\0c\0disabled"""
76+
77+
6978
MISSING = """qubes-dom0-current\0c\0enabled"""
7079

7180

@@ -92,6 +101,20 @@ def test_repo_handler_minimal(mock_output, real_builder):
92101
assert not handler.template_community_testing.get_sensitive()
93102

94103

104+
@patch("qubes_config.global_config.updates_handler.qrexec_call")
105+
def test_repo_handler_security(mock_output, real_builder):
106+
mock_output.return_value = SECURITY
107+
handler = RepoHandler(real_builder)
108+
assert handler.dom0_testing_sec_radio.get_active()
109+
assert not handler.dom0_testing_radio.get_active()
110+
assert not handler.dom0_stable_radio.get_active()
111+
assert handler.template_official_testing.get_active()
112+
assert handler.template_official.get_active()
113+
assert not handler.template_community_testing.get_active()
114+
assert not handler.template_community.get_active()
115+
assert not handler.template_community_testing.get_sensitive()
116+
117+
95118
@patch("qubes_config.global_config.updates_handler.qrexec_call")
96119
def test_repo_handler_missing_repos(mock_output, real_builder):
97120
mock_output.return_value = MISSING
@@ -214,6 +237,51 @@ def test_repo_handler_save_2(real_builder):
214237
handler.save()
215238

216239

240+
def test_repo_handler_save_3(real_builder):
241+
with patch(
242+
"qubes_config.global_config.updates_handler.qrexec_call",
243+
partial(mock_qrexec, repo_list=SECURITY),
244+
):
245+
handler = RepoHandler(real_builder)
246+
247+
assert handler.dom0_testing_sec_radio.get_sensitive()
248+
assert not handler.dom0_stable_radio.get_active()
249+
assert handler.template_official_testing.get_active()
250+
251+
handler.dom0_stable_radio.set_active(True)
252+
handler.template_official_testing.set_active(False)
253+
254+
changed_result = """qubes-dom0-current-testing\0c\0disabled
255+
qubes-dom0-security-testing\0c\0disabled
256+
qubes-dom0-current\0c\0enabled
257+
qubes-templates-itl-testing\0c\0disabled
258+
qubes-templates-itl\0c\0enabled
259+
qubes-templates-community-testing\0c\0disabled
260+
qubes-templates-community\0c\0disabled"""
261+
262+
with patch(
263+
"qubes_config.global_config.updates_handler.qrexec_call",
264+
partial(
265+
mock_qrexec,
266+
repo_list=changed_result,
267+
enable_repos=[
268+
"qubes-dom0-current",
269+
"qubes-templates-itl",
270+
],
271+
disable_repos=[
272+
"qubes-dom0-current-testing",
273+
"qubes-dom0-security-testing",
274+
"qubes-templates-community",
275+
"qubes-templates-itl-testing",
276+
"qubes-templates-community-testing",
277+
],
278+
),
279+
):
280+
handler.save()
281+
assert handler.dom0_stable_radio.get_active()
282+
assert not handler.template_official_testing.get_active()
283+
284+
217285
def test_repo_handler_save_fail(real_builder):
218286
with patch(
219287
"qubes_config.global_config.updates_handler.qrexec_call",

0 commit comments

Comments
 (0)