From 5b97e2629f6d32b4726847419eac8bba556fe4f1 Mon Sep 17 00:00:00 2001 From: Mariano Abad Date: Tue, 7 Jul 2026 08:42:41 -0300 Subject: [PATCH 1/2] ci: build a separate rustdesk-unattended-wayland deb for the drm feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hzhou asked for the drm/kms capture to ship as its own deb instead of baked into the stock package, so installing it is an explicit choice. build.py now names the --drm build rustdesk-unattended-wayland (Conflicts/Replaces/Provides rustdesk — install one or the other, they share files), and the linux CI job builds it as a separate x86_64 artifact after the stock deb/rpm so the drm relink cant leak into them. --- .github/workflows/flutter-build.yml | 24 ++++++++++++++++++++++++ build.py | 24 ++++++++++++++++++------ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/.github/workflows/flutter-build.yml b/.github/workflows/flutter-build.yml index 1164d163ef0..f3212f42754 100644 --- a/.github/workflows/flutter-build.yml +++ b/.github/workflows/flutter-build.yml @@ -1679,6 +1679,23 @@ jobs: mv "$name" /workspace/"${name%%.rpm}-suse.rpm" done + # --- opt-in unattended-wayland (DRM/KMS) variant: a separate deb --- + # Ships the privileged drmtap-helper so enabling consent-free capture + # is an explicit install choice (the package name states what it does). + # Built last so the drm relink can't leak into the stock deb/rpm above. + # x86_64 only (the unattended/kiosk/server use case); the package + # Conflicts/Replaces the stock rustdesk package (install one or other). + if [[ "${{ matrix.job.arch }}" == "x86_64" ]]; then + pushd /workspace + echo -e "start packaging unattended-wayland (DRM) deb" + cargo build --locked --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste,drm --release + python3 ./build.py --flutter --drm --skip-cargo + for name in rustdesk-unattended-wayland*??.deb; do + mv "$name" "${name%%.deb}-${{ matrix.job.arch }}.deb" + done + popd + fi + - name: Publish debian/rpm package if: env.UPLOAD_ARTIFACT == 'true' uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1 @@ -1696,6 +1713,13 @@ jobs: name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb path: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb + - name: Upload unattended-wayland deb + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + if: matrix.job.arch == 'x86_64' && env.UPLOAD_ARTIFACT == 'true' + with: + name: rustdesk-unattended-wayland-${{ env.VERSION }}-${{ matrix.job.arch }}.deb + path: rustdesk-unattended-wayland-${{ env.VERSION }}-${{ matrix.job.arch }}.deb + # only x86_64 for arch since we can not find newest arm64 docker image to build # old arch image does not make sense for arch since it is "arch" which always update to date # and failed to makepkg arm64 on x86_64 diff --git a/build.py b/build.py index 86950845b5b..de42736ccd9 100755 --- a/build.py +++ b/build.py @@ -297,22 +297,29 @@ def get_features(args): return features -def generate_control_file(version, extra_depends=""): +def generate_control_file(version, extra_depends="", package_name="rustdesk"): control_file_path = "../res/DEBIAN/control" system2('/bin/rm -rf %s' % control_file_path) - content = """Package: rustdesk + # An alternative-build package (e.g. the opt-in unattended-wayland / DRM + # variant) installs the same files as the stock `rustdesk` package, so it + # must conflict with / replace it: you install one OR the other, not both. + variant_control = "" + if package_name != "rustdesk": + variant_control = "Conflicts: rustdesk\nReplaces: rustdesk\nProvides: rustdesk\n" + + content = """Package: %s Section: net Priority: optional Version: %s Architecture: %s Maintainer: rustdesk Homepage: https://rustdesk.com -Depends: libgtk-3-0t64 | libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2t64 | libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s%s +%sDepends: libgtk-3-0t64 | libgtk-3-0, libxcb-randr0, libxdo3 | libxdo4, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2t64 | libasound2, libsystemd0, curl, libva2, libva-drm2, libva-x11-2, libgstreamer-plugins-base1.0-0, libpam0g, gstreamer1.0-pipewire%s%s Recommends: libayatana-appindicator3-1 Description: A remote control software. -""" % (version, get_deb_arch(), get_deb_extra_depends(), extra_depends) +""" % (package_name, version, get_deb_arch(), variant_control, get_deb_extra_depends(), extra_depends) file = open(control_file_path, "w") file.write(content) file.close() @@ -369,17 +376,22 @@ def build_flutter_deb(version, features): system2('mkdir -p tmpdeb/usr/lib/rustdesk') system2('cp ../target/release/drmtap-helper tmpdeb/usr/lib/rustdesk/drmtap-helper') + # A DRM build ships as a separately-named, opt-in package so installing it is + # an explicit choice — the package name itself states what it enables. It is + # an alternative build of the same app, so generate_control_file marks it + # Conflicts/Replaces/Provides rustdesk (install one or the other). + package_name = 'rustdesk-unattended-wayland' if ships_helper else 'rustdesk' system2('mkdir -p tmpdeb/DEBIAN') # postinst runs setcap (from libcap2-bin) on the helper; make it a hard # dependency so a DRM package can't install an unusable, cap-less helper. - generate_control_file(version, ", libcap2-bin" if ships_helper else "") + generate_control_file(version, ", libcap2-bin" if ships_helper else "", package_name) system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/') md5_file_folder("tmpdeb/") system2('dpkg-deb -b tmpdeb rustdesk.deb;') system2('/bin/rm -rf tmpdeb/') system2('/bin/rm -rf ../res/DEBIAN/control') - os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version) + os.rename('rustdesk.deb', '../%s-%s.deb' % (package_name, version)) os.chdir("..") From d0dc83676fb0bd07af4c0484fd4aaace688b18a0 Mon Sep 17 00:00:00 2001 From: Mariano Abad Date: Tue, 7 Jul 2026 10:29:41 -0300 Subject: [PATCH 2/2] drm: bump libdrmtap-sys to 0.4.5 (HDR guard for old libdrm) 0.4.5 guards the HDR metadata readout behind a build-time feature probe so the drm C sources compile against an older libdrm (the CI deb-build container), not only modern desktops. Fixes the unattended-wayland deb build in CI. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- libs/scrap/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 07818deeb05..d3a3654d624 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4467,9 +4467,9 @@ dependencies = [ [[package]] name = "libdrmtap-sys" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5386662822807db26dd77fc4603f886c78cbb386ef3985fd1db36d1139a23ca0" +checksum = "2b11669c93786775711332ff36a5784b3e7be1eda96e51acb3c47cb47f720be0" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index dc22bf6d83b..e6f89b18f07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,7 +179,7 @@ ttf-parser = "0.25" [target.'cfg(target_os = "linux")'.dependencies] # Direct dep so build.rs receives DEP_DRMTAP_HELPER_BIN via the `links` mechanism. # Exact pin: the helper is a privileged TCB component, keep it on the audited version. -libdrmtap-sys = { version = "=0.4.4", optional = true } +libdrmtap-sys = { version = "=0.4.5", optional = true } libxdo-sys = "0.11" psimple = { package = "libpulse-simple-binding", version = "2.27" } pulse = { package = "libpulse-binding", version = "2.27" } diff --git a/libs/scrap/Cargo.toml b/libs/scrap/Cargo.toml index 1ac84888239..6758e9a77b9 100644 --- a/libs/scrap/Cargo.toml +++ b/libs/scrap/Cargo.toml @@ -56,7 +56,7 @@ pkg-config = { version = "0.3.27", optional = true } # DRM/KMS capture bindings (statically embeds the libdrmtap C sources). # Enabled via the `drm` feature; not required for PipeWire/X11-only builds. # Exact pin: the helper is a privileged TCB component, keep it on the audited version. -libdrmtap-sys = { version = "=0.4.4", optional = true } +libdrmtap-sys = { version = "=0.4.5", optional = true } dbus = { version = "0.9", optional = true } tracing = { version = "0.1", optional = true } gstreamer = { version = "0.16", optional = true }