From 0041f1f2301d27d00811b96c401fa5af068e54c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moon=20dav=C3=A9?= Date: Thu, 17 Sep 2026 13:25:50 -0400 Subject: [PATCH 1/2] Add permissions check in CI; expand scope of permissions fix in snapcraft.yml and flathub.yml --- .github/workflows/build.yml | 8 ++++++++ app/build.gradle.kts | 7 +++++++ app/linux/flathub.yml | 2 +- app/linux/snapcraft.yml | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4355a69c5..bbca994d60 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -77,6 +77,14 @@ jobs: - name: Package Processing with Gradle run: ./gradlew packageDistributionForCurrentOS + - name: Verify binary permissions in .deb + if: matrix.os_prefix == 'linux' + run: | + DEB=$(ls app/build/compose/binaries/main/deb/processing*.deb) + dpkg-deb -x "$DEB" /tmp/debcheck + test -x /tmp/debcheck/opt/processing/lib/app/resources/jdk/bin/java + test -x /tmp/debcheck/opt/processing/lib/app/resources/modes/java/application/launch4j/bin/windres + - name: Add artifact uses: actions/upload-artifact@v4 if: ${{ github.event_name != 'pull_request' }} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c536cc4658..6360dd0e9c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -675,4 +675,11 @@ afterEvaluate { dependsOn("includeJdk") finalizedBy("setExecutablePermissions") } + // finalizedBy above only guarantees setExecutablePermissions runs after + // createDistributable, not before packageDeb, which merely depends on + // createDistributable transitively - without this, jpackage can read the + // app image before permissions are restored on it. + tasks.named("packageDeb").configure { + dependsOn("setExecutablePermissions") + } } diff --git a/app/linux/flathub.yml b/app/linux/flathub.yml index c92ab17d9d..64126595a5 100644 --- a/app/linux/flathub.yml +++ b/app/linux/flathub.yml @@ -19,7 +19,7 @@ modules: - ar x processing.deb - tar --zstd -xf data.tar.zst - mv opt/processing/* /app/ - - find /app/lib/app/resources/jdk/bin -type f -exec chmod +x {} + + - find /app/lib/app/resources -path "*/bin/*" -type f -exec chmod +x {} + # Install the desktop file and icon - install -D /app/lib/processing-Processing.desktop /app/share/applications/$identifier.desktop diff --git a/app/linux/snapcraft.yml b/app/linux/snapcraft.yml index 8206681ef0..b9a2268884 100644 --- a/app/linux/snapcraft.yml +++ b/app/linux/snapcraft.yml @@ -39,4 +39,4 @@ parts: override-prime: | snapcraftctl prime rm -vf usr/lib/jvm/java-17-openjdk-*/lib/security/cacerts - chmod -R +x opt/processing/lib/app/resources/jdk \ No newline at end of file + find opt/processing/lib/app/resources -path "*/bin/*" -type f -exec chmod +x {} + \ No newline at end of file From b729882c9a9aef8b2f23bc0c450a028e0306cba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?moon=20dav=C3=A9?= Date: Thu, 17 Sep 2026 14:33:23 -0400 Subject: [PATCH 2/2] make permissions changes at end --- app/build.gradle.kts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6360dd0e9c..ebbc09c8a1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -667,6 +667,37 @@ tasks.register("setExecutablePermissions") { } } +tasks.register("fixDebPermissions") { + description = "Rebuilds the .deb so binaries under opt/processing/lib/app/resources keep their executable bit " + + "(jpackage's own deb assembly does not reliably preserve it for arbitrary resource files)" + group = "compose desktop" + onlyIf { OperatingSystem.current().isLinux } + + val execOps = objects.newInstance().execOps + + doLast { + val debDir = layout.buildDirectory.dir("compose/binaries/main/deb").get().asFile + val deb = debDir.listFiles { f -> f.name.startsWith("processing") && f.name.endsWith(".deb") } + ?.singleOrNull() + ?: throw GradleException("Expected exactly one processing*.deb in $debDir") + + val extractDir = debDir.resolve("${deb.nameWithoutExtension}-fixperms") + extractDir.deleteRecursively() + + execOps.exec { + commandLine( + "fakeroot", "bash", "-c", + "dpkg-deb -R '${deb.absolutePath}' '${extractDir.absolutePath}' && " + + "find '${extractDir.absolutePath}/opt/processing/lib/app/resources' " + + "-path '*/bin/*' -type f -exec chmod +x {} + && " + + "dpkg-deb -b '${extractDir.absolutePath}' '${deb.absolutePath}'" + ) + } + + extractDir.deleteRecursively() + } +} + afterEvaluate { tasks.named("prepareAppResources").configure { dependsOn("includeProcessingResources") @@ -681,5 +712,9 @@ afterEvaluate { // app image before permissions are restored on it. tasks.named("packageDeb").configure { dependsOn("setExecutablePermissions") + // jpackage's own --type deb assembly doesn't reliably preserve the + // executable bit on arbitrary resource binaries (java, windres, ...); + // rebuild the .deb afterward via dpkg-deb to force it back on. + finalizedBy("fixDebPermissions") } }