From 64286074ba763d4a1e8879d8af69eee34d32cfa6 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Fri, 8 Jul 2022 00:17:11 +0000 Subject: [PATCH] 8289030: [macos] app image signature invalid when creating DMG or PKG Reviewed-by: asemenyuk --- .../jdk/jpackage/internal/MacAppBundler.java | 4 +- .../jpackage/internal/MacAppImageBuilder.java | 10 +- .../internal/MacBaseInstallerBundler.java | 37 +++-- .../resources/MacResources.properties | 1 + .../resources/MacResources_de.properties | 1 + .../resources/MacResources_ja.properties | 1 + .../resources/MacResources_zh_CN.properties | 1 + .../internal/AbstractAppImageBuilder.java | 2 + .../jpackage/internal/AppImageBundler.java | 6 +- .../jdk/jpackage/internal/AppImageFile.java | 4 +- .../jdk/jpackage/internal/IOUtils.java | 13 +- .../jdk/jpackage/test/JPackageCommand.java | 14 +- .../jpackage/macosx/SigningPackageTest.java | 6 +- .../macosx/SigningPackageTwoStepTest.java | 142 ++++++++++++++++++ 14 files changed, 215 insertions(+), 27 deletions(-) create mode 100644 test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index d726ef07a53..4cf697f4f35 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -38,7 +38,9 @@ import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; public class MacAppBundler extends AppImageBundler { public MacAppBundler() { - setAppImageSupplier(MacAppImageBuilder::new); + setAppImageSupplier(imageOutDir -> { + return new MacAppImageBuilder(imageOutDir, isDependentTask()); + }); setParamsValidator(MacAppBundler::doValidate); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 393b2381c50..f165c149b04 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -90,6 +90,8 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { private final Path runtimeDir; private final Path runtimeRoot; + private final boolean withPackageFile; + private static List keyChains; public static final BundlerParamInfo @@ -243,10 +245,11 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { (s, p) -> Arrays.asList(s.split("(,|\\s)+")) ); - public MacAppImageBuilder(Path imageOutDir) { + public MacAppImageBuilder(Path imageOutDir, boolean withPackageFile) { super(imageOutDir); this.root = imageOutDir; + this.withPackageFile = withPackageFile; this.contentsDir = root.resolve("Contents"); this.resourcesDir = appLayout.destktopIntegrationDirectory(); this.macOSDir = appLayout.launchersDirectory(); @@ -309,6 +312,11 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { // Copy class path entries to Java folder copyApplication(params); + if (withPackageFile) { + new PackageFile(APP_NAME.fetchFrom(params)).save( + ApplicationLayout.macAppImage().resolveAt(root)); + } + /*********** Take care of "config" files *******/ createResource(TEMPLATE_BUNDLE_ICON, params) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index b603975ad2f..5e1d311bdbe 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -29,6 +29,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.file.Files; +import java.nio.file.LinkOption; import java.nio.file.Path; import java.text.MessageFormat; import java.util.ArrayList; @@ -113,7 +114,8 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { } public MacBaseInstallerBundler() { - appImageBundler = new MacAppBundler().setDependentTask(true); + appImageBundler = new MacAppBundler() + .setDependentTask(true); } protected void validateAppImageAndBundeler( @@ -136,11 +138,18 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { I18N.getString( "message.app-image-requires-app-name.advice")); } - if (Optional.ofNullable( - SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { - // if signing bundle with app-image, warn user if app-image - // is not already signed. - if (!(AppImageFile.load(applicationImage).isSigned())) { + if (AppImageFile.load(applicationImage).isSigned()) { + if (!Files.exists( + PackageFile.getPathInAppImage(applicationImage))) { + Log.info(MessageFormat.format(I18N.getString( + "warning.per.user.app.image.signed"), + PackageFile.getPathInAppImage(applicationImage))); + } + } else { + if (Optional.ofNullable( + SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { + // if signing bundle with app-image, warn user if app-image + // is not already signed. Log.info(MessageFormat.format(I18N.getString( "warning.unsigned.app.image"), getID())); } @@ -158,17 +167,19 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { StandardBundlerParam.getPredefinedAppImage(params); if (predefinedImage != null) { appDir = appImageRoot.resolve(APP_NAME.fetchFrom(params) + ".app"); - IOUtils.copyRecursive(predefinedImage, appDir); + IOUtils.copyRecursive(predefinedImage, appDir, + LinkOption.NOFOLLOW_LINKS); + + // Create PackageFile if predefined app image is not signed + if (!StandardBundlerParam.isRuntimeInstaller(params) && + !AppImageFile.load(predefinedImage).isSigned()) { + new PackageFile(APP_NAME.fetchFrom(params)).save( + ApplicationLayout.macAppImage().resolveAt(appDir)); + } } else { appDir = appImageBundler.execute(params, appImageRoot); } - if (!StandardBundlerParam.isRuntimeInstaller(params)) { - new PackageFile(APP_NAME.fetchFrom(params)).save( - ApplicationLayout.macAppImage().resolveAt(appDir)); - Files.deleteIfExists(AppImageFile.getPathInAppImage(appDir)); - } - return appDir; } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index f3002e962e2..c575df2494e 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -94,3 +94,4 @@ message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trus message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue. message.install-dir-ignored=Warning: "--install-dir" is not supported by DMG and will be default to /Applications. warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}. +warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 340eb05f539..ffa43ae99fc 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -90,3 +90,4 @@ message.signing.pkg=Warnung: Zum Signieren von PKG m\u00FCssen Sie m\u00F6gliche message.setfile.dmg=Das Festlegen des benutzerdefinierten Symbols f\u00FCr die DMG-Datei wurde \u00FCbersprungen, weil das Utility "SetFile" nicht gefunden wurde. Durch Installieren von Xcode mit Befehlszeilentools sollte dieses Problem behoben werden. message.install-dir-ignored=Warnung: "--install-dir" wird von DMG nicht unterst\u00FCtzt. Stattdessen wird standardm\u00E4\u00DFig /Applications verwendet. warning.unsigned.app.image=Warnung: Nicht signiertes app-image wird zum Erstellen von signiertem {0} verwendet. +warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index 61bf6a712d4..4b817b89999 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -94,3 +94,4 @@ message.signing.pkg=\u8B66\u544A: PKG\u3078\u306E\u7F72\u540D\u306E\u5834\u5408\ message.setfile.dmg='SetFile'\u30E6\u30FC\u30C6\u30A3\u30EA\u30C6\u30A3\u304C\u898B\u3064\u304B\u3089\u306A\u3044\u305F\u3081\u3001DMG\u30D5\u30A1\u30A4\u30EB\u3067\u306E\u30AB\u30B9\u30BF\u30E0\u30FB\u30A2\u30A4\u30B3\u30F3\u306E\u8A2D\u5B9A\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F\u3002Xcode\u3068\u30B3\u30DE\u30F3\u30C9\u30FB\u30E9\u30A4\u30F3\u30FB\u30C4\u30FC\u30EB\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3059\u308B\u3068\u3001\u3053\u306E\u554F\u984C\u306F\u89E3\u6C7A\u3055\u308C\u307E\u3059\u3002 message.install-dir-ignored=\u8B66\u544A: "--install-dir"\u306FDMG\u3067\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002/Applications\u306B\u30C7\u30D5\u30A9\u30EB\u30C8\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002 warning.unsigned.app.image=\u8B66\u544A: \u7F72\u540D\u3055\u308C\u3066\u3044\u306A\u3044app-image\u3092\u4F7F\u7528\u3057\u3066\u7F72\u540D\u3055\u308C\u305F{0}\u3092\u4F5C\u6210\u3057\u307E\u3059\u3002 +warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index 39440bcf552..8d424b02840 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -94,3 +94,4 @@ message.signing.pkg=\u8B66\u544A\uFF1A\u8981\u5BF9 PKG \u8FDB\u884C\u7B7E\u540D\ message.setfile.dmg=\u7531\u4E8E\u672A\u627E\u5230 'SetFile' \u5B9E\u7528\u7A0B\u5E8F\uFF0C\u8DF3\u8FC7\u4E86\u9488\u5BF9 DMG \u6587\u4EF6\u8BBE\u7F6E\u5B9A\u5236\u56FE\u6807\u7684\u64CD\u4F5C\u3002\u5B89\u88C5\u5E26\u547D\u4EE4\u884C\u5DE5\u5177\u7684 Xcode \u5E94\u80FD\u89E3\u51B3\u6B64\u95EE\u9898\u3002 message.install-dir-ignored=\u8B66\u544A\uFF1A"--install-dir" \u4E0D\u53D7 DMG \u652F\u6301\uFF0C\u5C06\u9ED8\u8BA4\u4E3A /Applications\u3002 warning.unsigned.app.image=\u8B66\u544A\uFF1A\u4F7F\u7528\u672A\u7B7E\u540D\u7684 app-image \u751F\u6210\u5DF2\u7B7E\u540D\u7684 {0}\u3002 +warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index 72d85affb72..4a8ee4f5017 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -76,7 +76,9 @@ public abstract class AbstractAppImageBuilder { IOUtils.copyRecursive(SOURCE_DIR.fetchFrom(params), appLayout.appDirectory()); } + AppImageFile.save(root, params); + List items = APP_CONTENT.fetchFrom(params); for (String item : items) { IOUtils.copyRecursive(Path.of(item), diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java index e6de4934c91..9953b7a856e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,6 +112,10 @@ class AppImageBundler extends AbstractBundler { return this; } + final boolean isDependentTask() { + return dependentTask; + } + final AppImageBundler setAppImageSupplier( Function v) { appImageSupplier = v; diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index 85838d41b0e..c66cb47cf2e 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -146,7 +146,7 @@ public final class AppImageFile { return mainClass; } - boolean isSigned() { + public boolean isSigned() { return signed; } @@ -218,7 +218,7 @@ public final class AppImageFile { * @return valid info about application image or null * @throws IOException */ - static AppImageFile load(Path appImageDir) { + public static AppImageFile load(Path appImageDir) { try { Document doc = readXml(appImageDir); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java index 53ac19ea88b..3f7e4983e9d 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/IOUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.nio.file.FileVisitResult; import java.nio.file.Files; +import java.nio.file.CopyOption; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; @@ -112,12 +113,14 @@ public class IOUtils { } } - public static void copyRecursive(Path src, Path dest) throws IOException { - copyRecursive(src, dest, List.of()); + public static void copyRecursive(Path src, Path dest, CopyOption... options) + throws IOException { + copyRecursive(src, dest, List.of(), options); } public static void copyRecursive(Path src, Path dest, - final List excludes) throws IOException { + final List excludes, CopyOption... options) + throws IOException { Files.walkFileTree(src, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(final Path dir, @@ -134,7 +137,7 @@ public class IOUtils { public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { if (!excludes.contains(file.toFile().getName())) { - Files.copy(file, dest.resolve(src.relativize(file))); + Files.copy(file, dest.resolve(src.relativize(file)), options); } return FileVisitResult.CONTINUE; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 9a45f65297f..639eeaf380b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -820,7 +820,7 @@ public final class JPackageCommand extends CommandArguments { private void assertAppImageFile() { final Path lookupPath = AppImageFile.getPathInAppImage(Path.of("")); - if (isRuntime() || !isImagePackageType()) { + if (isRuntime() || (!isImagePackageType() && !TKit.isOSX())) { assertFileInAppImage(lookupPath, null); } else { assertFileInAppImage(lookupPath, lookupPath); @@ -833,7 +833,17 @@ public final class JPackageCommand extends CommandArguments { if (isRuntime() || isImagePackageType() || TKit.isLinux()) { assertFileInAppImage(lookupPath, null); } else { - assertFileInAppImage(lookupPath, lookupPath); + if (TKit.isOSX() && hasArgument("--app-image")) { + String appImage = getArgumentValue("--app-image", + () -> null); + if (AppImageFile.load(Path.of(appImage)).isSigned()) { + assertFileInAppImage(lookupPath, null); + } else { + assertFileInAppImage(lookupPath, lookupPath); + } + } else { + assertFileInAppImage(lookupPath, lookupPath); + } } } diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index 2fa9e452cfb..f355a28b6a3 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ import java.nio.file.Path; +import jdk.jpackage.internal.ApplicationLayout; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; @@ -75,7 +76,8 @@ public class SigningPackageTest { private static void verifyAppImageInDMG(JPackageCommand cmd) { MacHelper.withExplodedDmg(cmd, dmgImage -> { - Path launcherPath = dmgImage.resolve(Path.of("Contents", "MacOS", cmd.name())); + Path launcherPath = ApplicationLayout.platformAppImage() + .resolveAt(dmgImage).launchersDirectory().resolve(cmd.name()); // We will be called with all folders in DMG since JDK-8263155, but // we only need to verify app. if (dmgImage.endsWith(cmd.name() + ".app")) { diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java new file mode 100644 index 00000000000..5dde721bdad --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Path; +import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Annotations.Parameter; + +/** + * Note: Testing unsgined app image is done to verify support for per-user + * configuration by checking for PackageFile. + * Tests generation of dmg and pkg from signed or unsigned predefined app image. + * Test will generate pkg and verifies its signature. It verifies that dmg + * is not signed, but app image inside dmg is signed or unsigned. This test + * requires that the machine is configured with test certificate for + * "Developer ID Installer: jpackage.openjdk.java.net" in + * jpackagerTest keychain with + * always allowed access to this keychain for user which runs test. + * note: + * "jpackage.openjdk.java.net" can be over-ridden by systerm property + * "jpackage.mac.signing.key.user.name", and + * "jpackagerTest" can be over-ridden by system property + * "jpackage.mac.signing.keychain" + */ + +/* + * @test + * @summary jpackage with --type pkg,dmg --app-image + * @library ../helpers + * @library /test/lib + * @library base + * @key jpackagePlatformPackage + * @build SigningBase + * @build SigningCheck + * @build jtreg.SkippedException + * @build jdk.jpackage.test.* + * @build SigningPackageTwoStepTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @requires (os.family == "mac") + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningPackageTwoStepTest + */ +public class SigningPackageTwoStepTest { + + private static void verifyPKG(JPackageCommand cmd) { + if (!cmd.hasArgument("--mac-sign")) { + return; // Nothing to check if not signed + } + + Path outputBundle = cmd.outputBundle(); + SigningBase.verifyPkgutil(outputBundle); + SigningBase.verifySpctl(outputBundle, "install"); + } + + private static void verifyDMG(JPackageCommand cmd) { + // DMG always unsigned, so we will check it + Path outputBundle = cmd.outputBundle(); + SigningBase.verifyCodesign(outputBundle, false); + } + + private static void verifyAppImageInDMG(JPackageCommand cmd) { + MacHelper.withExplodedDmg(cmd, dmgImage -> { + // We will be called with all folders in DMG since JDK-8263155, but + // we only need to verify app. + if (dmgImage.endsWith(cmd.name() + ".app")) { + boolean isSigned = cmd.hasArgument("--mac-sign"); + Path launcherPath = ApplicationLayout.platformAppImage() + .resolveAt(dmgImage).launchersDirectory().resolve(cmd.name()); + SigningBase.verifyCodesign(launcherPath, isSigned); + SigningBase.verifyCodesign(dmgImage, isSigned); + if (isSigned) { + SigningBase.verifySpctl(dmgImage, "exec"); + } + } + }); + } + + @Test + @Parameter("true") + @Parameter("false") + public static void test(boolean signAppImage) throws Exception { + SigningCheck.checkCertificates(); + + Path appimageOutput = TKit.createTempDirectory("appimage"); + + JPackageCommand appImageCmd = JPackageCommand.helloAppImage() + .setArgumentValue("--dest", appimageOutput); + if (signAppImage) { + appImageCmd.addArguments("--mac-sign") + .addArguments("--mac-signing-key-user-name", + SigningBase.DEV_NAME) + .addArguments("--mac-signing-keychain", + SigningBase.KEYCHAIN); + } + + new PackageTest() + .addRunOnceInitializer(() -> appImageCmd.execute()) + .forTypes(PackageType.MAC) + .addInitializer(cmd -> { + cmd.addArguments("--app-image", appImageCmd.outputBundle()); + cmd.removeArgumentWithValue("--input"); + if (signAppImage) { + cmd.addArguments("--mac-sign", + "--mac-signing-key-user-name", + SigningBase.DEV_NAME, + "--mac-signing-keychain", + SigningBase.KEYCHAIN); + } + }) + .forTypes(PackageType.MAC_PKG) + .addBundleVerifier(SigningPackageTwoStepTest::verifyPKG) + .forTypes(PackageType.MAC_DMG) + .addBundleVerifier(SigningPackageTwoStepTest::verifyDMG) + .addBundleVerifier(SigningPackageTwoStepTest::verifyAppImageInDMG) + .run(); + } +}