-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check for network connection before running preflight updater #743
Check for network connection before running preflight updater #743
Conversation
bc0b71b
to
404abee
Compare
993e085
to
150d80b
Compare
This is failing on CI due to #745, which I've proposed a fix for, but |
launcher/tests/test_updaterapp.py
Outdated
# If we're in a PYyQt4 virtual environment, it will be called `.venv-pyqt4` when set up | ||
# according to our instructions with the pyqt4 venv Makefile target, and we should use | ||
# the PyQt4 dependencies. Otherwise, use PyQt5 | ||
if sys.prefix.endswith("pyqt4"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little bit brittle because it relies on the name of the virtual environment to decide whether we should import PyQt4 or PyQt5. If a user didn't follow the developer docs (which include Makefile targets for PyQt4-based venv and PyQt5 based venv) and made up an unexpected name for their pyqt4 venv, this check wouldn't work. However, it would default to PyQt5, which is the newer/more common standard.
I'm open to feedback if there's a better way of managing this for testing purposes though!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All prod installs on Qubes 4.0 are still using PyQt4, via F25 in dom0, so that should be the default. The logic in the if
statement on L14 seems to invert the "use 4 unless 5 is requested" pragma introduced back in #610. Taking a closer look, we're using Python3.8 in CI to test the launcher code, but dom0 is still on 3.5. This isn't a regression introduced by your changes, @rocodes, but your changes are surfacing them. =) I'll take a look at what switching CI over to a more prod-like testing environment would take, and report back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing CI, lifesaver. :)
My comment here (around PyQt4 vs PyQt5 being the default) was only relevant to machines that are performing unit testing (for machines that run test_updaterapp.py
specifically). But in any case, I've reworked this section to flip the logic to be more consistent with the rest of the codebase, and to check the SDW_UPDATER_QT
environment variable to decide which version of PyQt to import (note: this means test environments must follow the dev docs and always set the environment variable before running tests).
150d80b
to
3076ea0
Compare
@rocodes I took a look at the CI and unbroke it as best I could. Also sprinkled in some container updates as described in freedomofpress/securedrop-client#1384, because it was convenient.
The tests are passing, so to my eye, this PR is ready for review! Happy to run through a deep review if you feel you're finished with logic changes for now. |
@conorsch yup, ready for you, and thanks for your work on CI :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Encountered two (2) problems during local testing:
- network check always returns False, so updater doesn't run; see comments about
--pass-io
- some of the helpful logging messages never make it to disk; the problem seems only to affect logging calls like L206; I did see log messages like those on L139.
Magnificent test plan, thanks for taking the time!
result = subprocess.check_output(["qvm-run", "sys-net", command]) | ||
return result is not None and result.decode("utf-8") == "full" | ||
except subprocess.CalledProcessError: | ||
logger.error("{} (connectivity check) failed".format(command.decode("utf-8"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging is good! More logging! However, I wasn't able to find this message in the logs during my testing. Logging the actual return value would be helpful during debugging sessions. From the docs:
If the return code was non-zero it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute and any output in the output attribute.
So I suggest something like:
except subprocess.CalledProcessError as e:
logger.error("{} (connectivity check) failed; state reported as '{}'".format(command.decode("utf-8"), e.output))
Make sure you can find that string in the on-disk log files when a failure event is hit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you -addressed in d5f2d1d (Note this log message will not be encountered in a no-network scenario; in that case nmcli will still return 0 but the error log will read Network connectivity check failed
).
@@ -158,6 +189,26 @@ def exit_launcher(self): | |||
sys.exit() | |||
|
|||
|
|||
def _is_netcheck_successful() -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logically the _is_netcheck_successful
seems like a utility to me, and therefore best resides in sdw_util/
. That's a nit, so don't change it just for cleanliness's sake, but given the logging problems mentioned in this review on L206, maybe moving into utils will make the logging config easier to bootstrap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left this as-is because this is currently the only place we have a need for connectivity checking in the Updater code, and I have a vague future wish to disentangle some of the dependencies in UI classes (so eg Updater.py can import Util.py, but maybe some day in the distant future the UpdaterApp, more UI-focused, won't have dependencies outside of the sdw_updater_gui
package). However, I agree that some methods (this netcheck
, and maybe launch_securedrop_client
) could belong elsewhere.
a8ec752
to
25eb65f
Compare
… set in Qubes global prefs and use it to check for network connetivity. Only launch UpdateThread if network check is successful.
Add override method to sdw-launcher that allows user to skip network check with --skip-netcheck flag.
25eb65f
to
d5f2d1d
Compare
This looks and works great! Followed the test plan, success rate was 💯 Logging also works as expected, showing connectivity or lack thereof in dom0 and failure to detect Qubes OS outside of dom0, including netcheck skips. Nice work! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Tested mostly in dom0, and confirmed that log messages were recorded correctly when network was disconnected. Online via wifi or ethernet was correctly understood as "online". Dabbled with the qt4/pqt5 differences in the dev env, and both appeared to work well (with qt5 unsurprisingly looking subtly spiffier).
Thanks for your patience and fortitude on getting this change to land, @rocodes!
Check for network connection before running preflight updater
Status
Ready for review
Description of Changes
Fixes #633
Towards #649
Changes proposed in this pull request:
--skip-netcheck
, to bypass the network check and allow the Prelight Updater to run as usual (this is for development/testing purposes).UpdaterApp.py
to test the above functionality.Testing
Manual testing in Qubes/dom0
Check out this branch and
make clone
it into dom0. Disconnect your computer from the internet.python3 /opt/securedrop/launcher/sdw-launcher.py
and click "Apply Updates." Observe an immediate network failure error message.Manual testing outside of dom0
python3 /opt/securedrop/launcher/sdw-launcher.py
. When you attempt to apply updates you should see the "network failed" message (regardless of your network status).python3 /opt/securedrop/launcher/sdw-launcher.py --skip-netcheck
and you should be able to continue to the updater "run" (which will not actually run or apply updates since you're outside of dom0). The network error dialog view should not appear. The updater "run" will finish with a failure message. (Note: you will encounter error messages printed to the console relating to the failure to run some updater functionality outside of dom0:sudo: qubes-dom0-update: command not found
,sudo: qubesctl: command not found
,Running 'echo '3' > /home/user/.securedrop_client/sdw-update-status' on sd-app \ sd-app: Failed to access 'default_user' property
)export SDW_UPDATER_QT=4
for PyQt4 (and 5 for PyQt5) as per these instructions.