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
Qt 6: Make sure macOS sandboxing is reenabled #7278
Comments
Is here anything I could help with to progress with this issue? |
We need to implement support for symlinks in PyInstaller so we can satisfy PyInstaller's current assumptions about library locations and stop butchering Qt .framework bundles. Until this is done and the structure of those .framework bundles is properly preserved, it's either disabled sandbox or non-functioning executable (unless, perhaps behavior changed in 6.4.0...). Or, you can use PySide6 < Qt 6.3.1 and undo the effect of runtime hook from pyinstaller/pyinstaller#6903 by resetting |
Actually, until this is sorted out on PyInstaller's side as described above, you could fix it yourself as a post-processing step in your build process. What you need to do is, for each .framework bundle that is collected into Below is an example program and a fix-up python script: Test program - program.py
# program.py
import sys
import signal
import os
if 'QTWEBENGINE_DISABLE_SANDBOX' in os.environ:
print("Re-enabling sandbox...")
del os.environ['QTWEBENGINE_DISABLE_SANDBOX']
from PySide6 import QtWidgets, QtWebEngineWidgets, QtCore
app = QtWidgets.QApplication(sys.argv)
signal.signal(signal.SIGINT, signal.SIG_DFL)
view = QtWebEngineWidgets.QWebEngineView()
view.setUrl(QtCore.QUrl.fromUserInput("http://www.google.com"))
view.show()
sys.exit(app.exec()) Fix-up script - fixup_qtwebengine.py
# fixup_qtwebengine.py
import pathlib
import sys
if len(sys.argv) != 2:
print(f"Usage {sys.argv[0]} <path-to-app-bundle>")
sys.exit(1)
app_bundle = pathlib.Path(sys.argv[1])
assert app_bundle.name.endswith('.app'), "The given path does not end with an .app"
print(f"Attempting to fix up QtWebEngine in .app bundle: {app_bundle}")
top_level = app_bundle / "Contents" / "MacOS"
qt_libdir = top_level / "PySide6" / "Qt" / "lib"
# For collected Qt .framework bundles, replace the copy of lib in top-level directory
# with symlink to the copy from the .framework bundle
for framework in qt_libdir.iterdir():
if not framework.is_dir():
continue
if not framework.match("**/*.framework"):
continue
# Infer shared lib name from .framework name
lib_name = framework.name[:-len('.framework')]
framework_lib_file = framework / "Versions" / "A" / lib_name
assert framework_lib_file.is_file(), "Framework lib file does not exist!"
# Check if library exists in top-level directory
lib_file = top_level / lib_name
if not lib_file.is_file():
continue
rel_framework_lib_file = framework_lib_file.relative_to(top_level)
print(f"Replacing {lib_file!s} with symbolic link to {framework_lib_file!s}; rel path: {rel_framework_lib_file}")
lib_file.unlink()
lib_file.symlink_to(rel_framework_lib_file)
# Remove redundant QtWebEngine files - these are actually just symlinks to
# counterparts in Resources
for file in top_level.glob("qtwebengine_*.pak"):
print(f"Removing {file}")
file.unlink()
# Remove redundant QtWebEngine files in Resources (the useful copy is
# located within the collected .framework bundle)
resources_dir = app_bundle / "Contents" / "Resources"
for file in resources_dir.glob("qtwebengine_*.pak"):
print(f"Removing {file}")
file.unlink() Freeze the program in onedir windowed mode:
Trying to run the resulting app bundle:
crashes the QtWebEngineProcess helper processes due to sandbox errors:
Fix up the bundle using the script:
And now
runs as expected. Don't forget to re-sign the bundle. |
PyInstaller has a new release coming up that should address this. It fixes some issues and hacks around collecting stuff (especially around Qt wrappers it seems) and packaging stuff for macOS. The release notes for 5.13.0 (the previous release) says that those changes can be breaking and will only be included in a 6.0.0 release. That has me a bit worried since we want to re-enable webengine (actually chromium) sandbox on mac for the 3.0 release. We do have a WIP PR up to enable that on our side but since there is an upstream fix now it would be good to look at that. I've hacked up a branch to do the nightly build jobs with an updated PyInstaller (from their develop branch) to have an early look at any issues. It's failing 🥲 macOS:
windows:
I've changed the build_release tox job to pass PYINSTALLER_COMPILE_BOOTLOADER through for now to tell pyinstaller to rebuild it's bootloader. Seems to work transparently but I guess we don't want to keep this there after the new release comes out. As to how we can check that sandboxing is re-enabled on macOS, since the
We are already doing (3) but have removed it temporarily for macOS. So just removing that should be fine 🤞. Checking a renderer CLI args in a "unit" test probably wouldn't be too hard either. |
You can check if the sandbox is enabled in macOS activity monitor. You can right click on the column names and add the "sandbox" column. The qutebrowser's main process should not be sandboxed but all child processes. It's the same with chrome. |
The contents are now distributed between
For "regular" onedir builds, the layout has also changed - everything but the executable is put into a sub-directory (although that's a different PR). As a side note, for the |
Apparently you may need to do this when running from develop to make the bootloader have the correct search paths ref #7278 (comment) For the record the macOS CI is currently failing with dlopen: dlopen(/Users/runner/work/qutebrowser/qutebrowser/dist/qutebrowser.app/Contents/MacOS/libpython3.10.dylib, 10): image not found And upon inspection of dist/ that file seems to be at ./qutebrowser.app/Contents/Resources/libpython3.10.dylib ./qutebrowser.app/Contents/Frameworks/libpython3.10.dylib ./qutebrowser/_internal/libpython3.10.dylib Lets see if the updated bootloader finds that.
Aha, thanks for the info! I'll try to see if I can get that working on CI. Is that a normal step for using develop or just because stuff moved recently and the boatloader hasn't been rebuilt and commited back to the repo yet? |
We usually rebuild and commit bootloaders only when we make new release, so if you want to use |
Looks like the smoke test is working with pyinstaller develop now 🎉. And that includes removing the allowance for "Sandboxing disabled by user", so it should be sandboxing now. The relevant production code change was just:
To follow the recommended way of finding data files. (The comment above the changed line is probably no-longer true. But probably you want to call it frozen-assets or something anyway? Like why risk the conflict at all?) There's still some work to do to clean up our build scripts, and I would like to arrange a bit of manual testing (esp for the mac build), but this seems pretty de-risked now in my opinion. I'm not sure how to suggest going about manual testing. If you install these versions you should not open your normal qutebrowser profile with them, wait until a proper release comes out. You could install them and open a temp basedir for testing (find the executable and open it with -T on the command line) the re-install the last release afterwards. So you can open your normal profile again. Sounds cumbersome. You should be able to install as an alternate user or in a VM too... |
@toofar PyInstaller seems to support importlib.resources nowadays - while you're at it, any chance you could try what happens if you drop that |
Yep, looks like that works (at least as per the smoke tests) after adjusting the data paths to match the source build:
|
Alright, seems to work on a mac I managed to scrounge up. I'll work on cleaning up my branch this week and than I guess we'll hope a PyInstaller release comes out before the other tasks in the milestone get done (probably 2-3 weeks). |
Apparently you may need to do this when running from develop to make the bootloader have the correct search paths ref #7278 (comment) For the record the macOS CI is currently failing with dlopen: dlopen(/Users/runner/work/qutebrowser/qutebrowser/dist/qutebrowser.app/Contents/MacOS/libpython3.10.dylib, 10): image not found And upon inspection of dist/ that file seems to be at ./qutebrowser.app/Contents/Resources/libpython3.10.dylib ./qutebrowser.app/Contents/Frameworks/libpython3.10.dylib ./qutebrowser/_internal/libpython3.10.dylib Lets see if the updated bootloader finds that.
Apparently you may need to do this when running from develop to make the bootloader have the correct search paths ref #7278 (comment) For the record the macOS CI is currently failing with dlopen: dlopen(/Users/runner/work/qutebrowser/qutebrowser/dist/qutebrowser.app/Contents/MacOS/libpython3.10.dylib, 10): image not found And upon inspection of dist/ that file seems to be at ./qutebrowser.app/Contents/Resources/libpython3.10.dylib ./qutebrowser.app/Contents/Frameworks/libpython3.10.dylib ./qutebrowser/_internal/libpython3.10.dylib Lets see if the updated bootloader finds that.
See pyinstaller/pyinstaller#6903 and #7252 (comment)
The text was updated successfully, but these errors were encountered: