From d4ae7cc71bfbe8391ffdecb7f9b66ee081f01f38 Mon Sep 17 00:00:00 2001 From: NeroShooter Date: Sat, 24 Oct 2026 16:34:45 +0200 Subject: [PATCH 1/3] fix(macos): strip quarantine before bootstrapping the broker service Files copied from a browser-downloaded DMG inherit com.apple.quarantine. launchd refuses the quarantined LaunchDaemon plist, so the installer failed with "Bootstrap failed: 5: Input/output error". Remove the attribute from the installed apps, plist, and /usr/local files before bootstrapping the service. Co-Authored-By: Claude Opus 5.5 --- scripts/macos/install.command | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/macos/install.command b/scripts/macos/install.command index 81054de..5bd109e 100755 --- a/scripts/macos/install.command +++ b/scripts/macos/install.command @@ -35,6 +35,7 @@ fi /usr/bin/sudo /bin/rm -rf "${legacy_broker_app}" "${installed_broker_app}" "${installed_control_app}" /usr/bin/sudo /usr/bin/ditto "${broker_app}" "${installed_broker_app}" /usr/bin/sudo /usr/bin/ditto "${control_app}" "${installed_control_app}" +/usr/bin/sudo /usr/bin/xattr -dr com.apple.quarantine "${installed_broker_app}" "${installed_control_app}" /usr/bin/sudo /usr/sbin/chown -R root:wheel "${installed_broker_app}" "${installed_control_app}" /usr/bin/sudo /bin/chmod -R a+rX "${installed_broker_app}" "${installed_control_app}" /usr/bin/sudo /bin/chmod -R go-w "${installed_broker_app}" "${installed_control_app}" @@ -43,6 +44,7 @@ fi /usr/bin/sudo /usr/bin/install -m 0644 \ "${image_root}/${launchd_plist}" "${service_plist}" /usr/bin/sudo /usr/sbin/chown root:wheel "${service_plist}" +/usr/bin/sudo /usr/bin/xattr -dr com.apple.quarantine "${service_plist}" if [[ -d "${image_root}/usr/local/include/libvirtualhid" ]]; then /usr/bin/sudo /usr/bin/ditto "${image_root}/usr/local/include/libvirtualhid" /usr/local/include/libvirtualhid @@ -62,6 +64,14 @@ if [[ -d "${image_root}/usr/local/share/licenses/libvirtualhid" ]]; then /usr/bin/sudo /usr/bin/ditto "${image_root}/usr/local/share/licenses/libvirtualhid" /usr/local/share/licenses/libvirtualhid fi +for installed_path in /usr/local/include/libvirtualhid /usr/local/lib/libvirtualhid.a \ + /usr/local/bin/libvirtualhid-license /usr/local/lib/cmake/libvirtualhid \ + /usr/local/share/licenses/libvirtualhid; do + if [[ -e "${installed_path}" ]]; then + /usr/bin/sudo /usr/bin/xattr -dr com.apple.quarantine "${installed_path}" + fi +done + /usr/bin/sudo /bin/launchctl bootstrap system "${service_plist}" /usr/bin/sudo /bin/launchctl kickstart -k "system/${bundle_id}" echo 'Virtual HID Broker and Virtual HID Control installed in /Applications.' From 06216cd9471fd10d3251ddef49ce09df1e1d2f7a Mon Sep 17 00:00:00 2001 From: NeroShooter Date: Wed, 28 Oct 2026 09:56:46 +0100 Subject: [PATCH 2/3] test(macos): cover installer quarantine handling Run install.command against a sandboxed fixture with quarantined and clean payloads, with and without the optional /usr/local files, and assert that nothing is quarantined when launchd bootstraps the service. Run the fixture in the macOS broker workflow. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci-macos-broker.yml | 3 ++ tests/scripts/test-macos-install.py | 78 +++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/scripts/test-macos-install.py diff --git a/.github/workflows/ci-macos-broker.yml b/.github/workflows/ci-macos-broker.yml index 15fcb65..344b9cc 100644 --- a/.github/workflows/ci-macos-broker.yml +++ b/.github/workflows/ci-macos-broker.yml @@ -45,6 +45,9 @@ jobs: - name: Install dependencies run: brew install cmake + - name: Test macOS installer quarantine handling + run: python3 tests/scripts/test-macos-install.py scripts/macos/install.command + - name: Configure universal build env: BUILD_VERSION: ${{ inputs.release_version }} diff --git a/tests/scripts/test-macos-install.py b/tests/scripts/test-macos-install.py new file mode 100644 index 0000000..dc5e621 --- /dev/null +++ b/tests/scripts/test-macos-install.py @@ -0,0 +1,78 @@ +import os +from pathlib import Path +import re +import subprocess +import sys +import tempfile + + +def run(*args): + return subprocess.run(args, check=True, capture_output=True, text=True).stdout + + +installer = Path(sys.argv[1]).read_text() +for quarantined in (False, True): + for optional in (False, True): + with tempfile.TemporaryDirectory(prefix="libvirtualhid-install-", dir="/private/tmp") as temp: + root = Path(temp) + image = root / "image with spaces" + destination = root / "installed" + for name in ("VirtualHIDBroker.app", "VirtualHIDControl.app"): + executable = image / name / "Contents/MacOS/example" + executable.parent.mkdir(parents=True) + executable.write_text("fixture") + (image / "dev.lizardbyte.app.libvirtualhid.plist").write_text("fixture") + if optional: + for name in ( + "include/libvirtualhid/gamepad.hpp", + "lib/libvirtualhid.a", + "bin/libvirtualhid-license", + "lib/cmake/libvirtualhid/libvirtualhid-config.cmake", + "share/licenses/libvirtualhid/LICENSE.md", + ): + path = image / "usr/local" / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("fixture") + run("/usr/bin/xattr", "-wr", "user.review_marker", "preserve", str(image)) + if quarantined: + run("/usr/bin/xattr", "-wr", "com.apple.quarantine", "0083;12345678;Safari;test", str(image)) + (destination / "Applications").mkdir(parents=True) + (destination / "Library/LaunchDaemons").mkdir(parents=True) + # Redirect fixed installation paths, leaving image-relative payload paths intact. + source = re.sub( + r"(?&2 + return 1 + fi + /usr/bin/touch "$TEST_BOOTSTRAPPED" + fi + return 0 ;; + esac + "$@" +} +''' + script = image / "Install libvirtualhid.command" + script.write_text(stubs + source) + marker = root / "bootstrapped" + env = dict(os.environ, TEST_DESTINATION=str(destination), TEST_BOOTSTRAPPED=str(marker)) + result = subprocess.run(["/bin/bash", str(script)], env=env, capture_output=True, text=True) + assert result.returncode == 0, (quarantined, optional, result.stderr) + assert marker.exists(), "bootstrap was skipped" + assert "user.review_marker: preserve" in run("/usr/bin/xattr", "-lr", str(destination)) + if quarantined: + assert "com.apple.quarantine" in run("/usr/bin/xattr", "-lr", str(image)) + print(f"PASS: quarantined={quarantined}, optional_payload={optional}") From fa442840e9a14bfdccfcc74af87d95583f05ced2 Mon Sep 17 00:00:00 2001 From: Dave Lane <42013603+ReenigneArcher@users.noreply.github.com> Date: Thu, 29 Oct 2026 23:20:59 -0400 Subject: [PATCH 3/3] ci: add shared Flake8 configuration --- .flake8 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..a8948ef --- /dev/null +++ b/.flake8 @@ -0,0 +1,7 @@ +[flake8] +filename = + *.py +max-line-length = 120 +extend-exclude = + .venv/ + venv/