From 1f5ce2dc0c06a15751386d27d38e810689d96b95 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Fri, 20 Mar 2026 15:22:19 -0400 Subject: [PATCH 1/7] 8371924: --mac-app-store should be accepted option for app image signing --- .../jdk/jpackage/internal/MacFromOptions.java | 22 ++++----- .../internal/MacRuntimeValidator.java | 32 +++++++++---- .../resources/MacResources.properties | 1 + .../jpackage/internal/cli/StandardOption.java | 2 +- .../cli/OptionsValidationFailTest.excludes | 1 + .../jpackage/internal/cli/jpackage-options.md | 2 +- .../macosx/SigningAppImageTwoStepsTest.java | 37 ++++++++++++++- test/jdk/tools/jpackage/share/ErrorTest.java | 45 +++++++++++++++++-- 8 files changed, 116 insertions(+), 26 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java index 20dcbcf57427a..2c247ed398970 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacFromOptions.java @@ -27,8 +27,6 @@ import static jdk.jpackage.internal.FromOptions.buildApplicationBuilder; import static jdk.jpackage.internal.FromOptions.createPackageBuilder; import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT; -import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasJliLib; -import static jdk.jpackage.internal.MacRuntimeValidator.validateRuntimeHasNoBinDir; import static jdk.jpackage.internal.OptionUtils.isBundlingOperation; import static jdk.jpackage.internal.cli.StandardBundlingOperation.CREATE_MAC_PKG; import static jdk.jpackage.internal.cli.StandardOption.APPCLASS; @@ -203,12 +201,14 @@ private static ApplicationBuilder createApplicationBuilder(Options options) { final var predefinedRuntimeLayout = PREDEFINED_RUNTIME_IMAGE.findIn(options) .map(MacPackage::guessRuntimeLayout); - predefinedRuntimeLayout.ifPresent(layout -> { - validateRuntimeHasJliLib(layout); - if (MAC_APP_STORE.containsIn(options)) { - validateRuntimeHasNoBinDir(layout); - } - }); + predefinedRuntimeLayout.ifPresent(MacRuntimeValidator::validateRuntimeHasJliLib); + + if (MAC_APP_STORE.containsIn(options)) { + PREDEFINED_APP_IMAGE.findIn(options) + .map(APPLICATION_LAYOUT::resolveAt) + .ifPresent(MacRuntimeValidator::validateRuntimeHasNoBinDir); + predefinedRuntimeLayout.ifPresent(MacRuntimeValidator::validateRuntimeHasNoBinDir); + } final var launcherFromOptions = new LauncherFromOptions().faMapper(MacFromOptions::createMacFa); @@ -269,11 +269,13 @@ private static ApplicationWithDetails createMacApplicationInternal(Options optio final boolean sign = MAC_SIGN.getFrom(options); final boolean appStore; - if (PREDEFINED_APP_IMAGE.containsIn(options)) { + if (MAC_APP_STORE.containsIn(options)) { + appStore = MAC_APP_STORE.getFrom(options); + } else if (PREDEFINED_APP_IMAGE.containsIn(options)) { final var appImageFileOptions = appBuilder.externalApplication().orElseThrow().extra(); appStore = MAC_APP_STORE.getFrom(appImageFileOptions); } else { - appStore = MAC_APP_STORE.getFrom(options); + appStore = false; } appBuilder.appStore(appStore); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java index cfab12cbcbad5..42b68056119ee 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java @@ -30,6 +30,10 @@ import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.function.Predicate; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ApplicationLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.JPackageException; import jdk.jpackage.internal.model.RuntimeLayout; final class MacRuntimeValidator { @@ -45,17 +49,29 @@ static void validateRuntimeHasJliLib(RuntimeLayout runtimeLayout) { throw new UncheckedIOException(ex); } - throw I18N.buildConfigException("error.invalid-runtime-image-missing-file", + throw new JPackageException(I18N.format("error.invalid-runtime-image-missing-file", runtimeLayout.rootDirectory(), - runtimeLayout.unresolve().runtimeDirectory().resolve("lib/**").resolve(jliName)).create(); + runtimeLayout.unresolve().runtimeDirectory().resolve("lib/**").resolve(jliName))); } - static void validateRuntimeHasNoBinDir(RuntimeLayout runtimeLayout) { - if (Files.isDirectory(runtimeLayout.runtimeDirectory().resolve("bin"))) { - throw I18N.buildConfigException() - .message("error.invalid-runtime-image-bin-dir", runtimeLayout.rootDirectory()) - .advice("error.invalid-runtime-image-bin-dir.advice", "--mac-app-store") - .create(); + static void validateRuntimeHasNoBinDir(AppImageLayout appImageLayout) { + if (Files.isDirectory(appImageLayout.runtimeDirectory().resolve("bin"))) { + switch (appImageLayout) { + case RuntimeLayout runtimeLayout -> { + throw new ConfigException( + I18N.format("error.invalid-runtime-image-bin-dir", runtimeLayout.rootDirectory()), + I18N.format("error.invalid-runtime-image-bin-dir.advice", "--mac-app-store")); + } + case ApplicationLayout appLayout -> { + throw new JPackageException(I18N.format("error.invalid-app-image-runtime-image-bin-dir", + appLayout.rootDirectory().relativize(appLayout.runtimeDirectory()), + appLayout.rootDirectory())); + } + default -> { + throw new IllegalArgumentException(); + } + } + } } } 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 90c4162b80e20..95fff00152b08 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 @@ -29,6 +29,7 @@ error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=Multiple certificates matching name [{0}] found in keychain [{1}] error.app-image.mac-sign.required=--mac-sign option is required with predefined application image and with type [app-image] error.invalid-runtime-image-missing-file=Runtime image "{0}" is missing "{1}" file +error.invalid-app-image-runtime-image-bin-dir=Runtime directory {0} in the predefined application image [{1}] should not contain "bin" folder error.invalid-runtime-image-bin-dir=Runtime image "{0}" should not contain "bin" folder error.invalid-runtime-image-bin-dir.advice=Use --strip-native-commands jlink option when generating runtime image used with {0} option error.invalid-app-image-plist-file=Invalid "{0}" file in the predefined application image diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java index c2338b87fada1..438a5ac3e6fba 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/cli/StandardOption.java @@ -342,7 +342,7 @@ public boolean test(Path path) { public static final OptionValue MAC_SIGN = booleanOption("mac-sign").scope(MAC_SIGNING).addAliases("s").create(); - public static final OptionValue MAC_APP_STORE = booleanOption("mac-app-store").create(); + public static final OptionValue MAC_APP_STORE = booleanOption("mac-app-store").scope(MAC_SIGNING).create(); public static final OptionValue MAC_APP_CATEGORY = stringOption("mac-app-category").create(); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes index 32968db0606d2..19478aaa4a7d3 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/OptionsValidationFailTest.excludes @@ -40,6 +40,7 @@ ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--app-version, 1234]; errors=[ ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--app-version, 256.1]; errors=[message.error-header+[error.msi-product-version-major-out-of-range], message.advice-header+[error.version-string-wrong-format.advice]]) ErrorTest.test(WIN_MSI; app-desc=Hello; args-add=[--launcher-as-service]; errors=[message.error-header+[error.missing-service-installer], message.advice-header+[error.missing-service-installer.advice]]) ErrorTest.test(args-add=[@foo]; errors=[message.error-header+[ERR_CannotParseOptions, foo]]) +ErrorTest.testMacSignAppStoreInvalidRuntime ErrorTest.testMacSignWithoutIdentity(IMAGE; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) ErrorTest.testMacSignWithoutIdentity(IMAGE; args-add=[--app-image, @@APP_IMAGE_WITH_SHORT_NAME@@, --mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) ErrorTest.testMacSignWithoutIdentity(MAC_DMG; app-desc=Hello; args-add=[--mac-sign, --mac-signing-keychain, @@EMPTY_KEYCHAIN@@]; errors=[message.error-header+[error.cert.not.found, CODE_SIGN, EMPTY_KEYCHAIN]]) diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md index 64d3c6c075b64..59ae0d176c1e2 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/cli/jpackage-options.md @@ -29,7 +29,7 @@ | --linux-shortcut | linux-deb, linux-rpm | x | x | x | USE_LAST | | --mac-app-category | mac-bundle | x | x | | USE_LAST | | --mac-app-image-sign-identity | mac | x | x | | USE_LAST | -| --mac-app-store | mac-bundle | x | x | | USE_LAST | +| --mac-app-store | mac | x | x | | USE_LAST | | --mac-dmg-content | mac-dmg | x | x | | CONCATENATE | | --mac-entitlements | mac | x | x | | USE_LAST | | --mac-installer-sign-identity | mac-pkg | x | x | | USE_LAST | diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index a6d94b59bd90b..4ab2d448e9f2b 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -21,11 +21,14 @@ * questions. */ +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.jpackage.test.AdditionalLauncher; @@ -35,6 +38,7 @@ import jdk.jpackage.test.MacHelper.SignKeyOption; import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -68,6 +72,22 @@ public static void test(TestSpec spec) { spec.test(); } + @Test + public static void testAppStore() { + + var sign = new SignKeyOptionWithKeychain( + SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME, + SigningBase.StandardCertificateRequest.CODESIGN, + SigningBase.StandardKeychain.MAIN.keychain()); + + var spec = new TestSpec(Optional.empty(), sign); + + spec.signAppImage(spec.createAppImage(), Optional.of(cmd -> { + cmd.addArgument("--mac-app-store"); + })); + } + + public record TestSpec(Optional signAppImage, SignKeyOptionWithKeychain sign) { public TestSpec { @@ -133,7 +153,7 @@ private SignKeyOptionWithKeychain createSignKeyOption() { private SignKeyOptionWithKeychain sign; } - void test() { + Path createAppImage() { var appImageCmd = JPackageCommand.helloAppImage() .setFakeRuntime() .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); @@ -150,16 +170,29 @@ void test() { }, signOption.keychain()); }, appImageCmd::execute); + return appImageCmd.outputBundle(); + } + + void signAppImage(Path appImage, Optional> mutator) { + Objects.requireNonNull(appImage); + Objects.requireNonNull(mutator); + MacSign.withKeychain(keychain -> { var cmd = new JPackageCommand() .setPackageType(PackageType.IMAGE) - .addArguments("--app-image", appImageCmd.outputBundle()) + .addArguments("--app-image", appImage) .mutate(sign::addTo); + mutator.ifPresent(cmd::mutate); + cmd.executeAndAssertHelloAppImageCreated(); MacSignVerify.verifyAppImageSigned(cmd, sign.certRequest()); }, sign.keychain()); } + + void test() { + signAppImage(createAppImage(), Optional.empty()); + } } public static Collection test() { diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index 2797115b202f7..fbaec8283e86e 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -26,7 +26,6 @@ import static jdk.internal.util.OperatingSystem.LINUX; import static jdk.internal.util.OperatingSystem.MACOS; import static jdk.internal.util.OperatingSystem.WINDOWS; -import static jdk.jpackage.internal.util.PListWriter.writeDict; import static jdk.jpackage.internal.util.PListWriter.writePList; import static jdk.jpackage.internal.util.XmlUtils.createXml; import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer; @@ -35,6 +34,7 @@ import static jdk.jpackage.test.JPackageCommand.makeAdvice; import static jdk.jpackage.test.JPackageCommand.makeError; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -56,6 +56,7 @@ import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.CannedArgument; import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; @@ -699,11 +700,48 @@ public static Collection testAdditionLaunchers() { )); } + @Test(ifOS = MACOS) + public static void testMacSignAppStoreInvalidRuntime() throws IOException { + + // Create app image with the runtime directory content that will fail the subsequent signing jpackage command. + var appImageCmd = JPackageCommand.helloAppImage().setFakeRuntime(); + appImageCmd.executeAndAssertImageCreated(); + Files.createDirectory(appImageCmd.appLayout().runtimeHomeDirectory().resolve("bin")); + + final var keychain = SignEnvMock.SingleCertificateKeychain.FOO.keychain(); + + var spec = testSpec() + .noAppDesc() + .addArgs("--mac-app-store", "--mac-sign", "--app-image", appImageCmd.outputBundle().toString()) + .error("error.invalid-app-image-runtime-image-bin-dir", + ApplicationLayout.macAppImage().runtimeHomeDirectory(), appImageCmd.outputBundle()) + .create(); + + TKit.withNewState(() -> { + var script = Script.build() + // Disable the mutation making mocks "run once". + .commandMockBuilderMutator(null) + // Replace "/usr/bin/security" with the mock bound to the keychain mock. + .map(MacSignMockUtils.securityMock(SignEnvMock.VALUE)) + // Don't mock other external commands. + .use(VerbatimCommandMock.INSTANCE) + .createLoop(); + + // Create jpackage tool provider using the /usr/bin/security mock. + var jpackage = JPackageMockUtils.createJPackageToolProvider(OperatingSystem.MACOS, script); + + // Override the default jpackage tool provider with the one using the /usr/bin/security mock. + JPackageCommand.useToolProviderByDefault(jpackage); + + spec.test(); + }); + } + @Test(ifOS = MACOS) @ParameterSupplier @ParameterSupplier("testMacPkgSignWithoutIdentity") public static void testMacSignWithoutIdentity(TestSpec spec) { - // The test called JPackage Command.useToolProviderBy Default(), + // The test calls JPackageCommand.useToolProviderByDefault(), // which alters global variables in the test library, // so run the test case with a new global state to isolate the alteration of the globals. TKit.withNewState(() -> { @@ -998,8 +1036,7 @@ public static Collection testMac() { // Test a few app-image options that should not be used when signing external app image testCases.addAll(Stream.of( new ArgumentGroup("--app-version", "2.0"), - new ArgumentGroup("--name", "foo"), - new ArgumentGroup("--mac-app-store") + new ArgumentGroup("--name", "foo") ).flatMap(argGroup -> { var withoutSign = testSpec() .noAppDesc() From 4e2bead7275c53f712716611bd988f147cd5136e Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 22 Mar 2026 12:10:37 -0400 Subject: [PATCH 2/7] LauncherVerifier: better logging of entitlements validation --- .../jdk/jpackage/test/LauncherVerifier.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index f9fcfb905af32..61ee36e30a408 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -372,14 +372,21 @@ private void verifyMacEntitlements(JPackageCommand cmd) throws SAXException, IOE TKit.assertTrue(entitlements.isPresent(), String.format("Check [%s] launcher is signed with entitlements", name)); + String expectedEntitlementsOrigin; + var customFile = Optional.ofNullable(cmd.getArgumentValue("--mac-entitlements")).map(Path::of); - if (customFile.isEmpty()) { + if (customFile.isPresent()) { + expectedEntitlementsOrigin = String.format("Custom entitlements file [%s]", customFile.get()); + } else { // Try from the resource dir. var resourceDirFile = Optional.ofNullable(cmd.getArgumentValue("--resource-dir")).map(Path::of).map(resourceDir -> { return resourceDir.resolve(cmd.name() + ".entitlements"); }).filter(Files::exists); if (resourceDirFile.isPresent()) { customFile = resourceDirFile; + expectedEntitlementsOrigin = "Custom entitlements from the resource directory"; + } else { + expectedEntitlementsOrigin = null; } } @@ -388,11 +395,14 @@ private void verifyMacEntitlements(JPackageCommand cmd) throws SAXException, IOE expected = new PListReader(Files.readAllBytes(customFile.orElseThrow())).toMap(true); } else if (cmd.hasArgument("--mac-app-store")) { expected = DefaultEntitlements.APP_STORE; + expectedEntitlementsOrigin = "App Store entitlements"; } else { + expectedEntitlementsOrigin = "Default entitlements"; expected = DefaultEntitlements.STANDARD; } - TKit.assertEquals(expected, entitlements.orElseThrow().toMap(true), String.format("Check [%s] launcher is signed with expected entitlements", name)); + TKit.assertEquals(expected, entitlements.orElseThrow().toMap(true), + String.format("Check [%s] launcher is signed with %s", name, expectedEntitlementsOrigin)); } private void executeLauncher(JPackageCommand cmd) throws IOException { From b40c0fc0457d5a6f85fa906f693c46de5bb16413 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 22 Mar 2026 12:11:17 -0400 Subject: [PATCH 3/7] SigningAppImageTest: bugfix --- test/jdk/tools/jpackage/macosx/SigningAppImageTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 3a257a425b639..fc146270ab842 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -64,7 +64,6 @@ public static void test(SignKeyOptionWithKeychain sign) { var testAL = new AdditionalLauncher("testAL"); testAL.applyTo(cmd); - cmd.executeAndAssertHelloAppImageCreated(); MacSign.withKeychain(keychain -> { sign.addTo(cmd); From cd39555a3e1c9b3a7e94a25878083df993244d15 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Sun, 22 Mar 2026 12:15:13 -0400 Subject: [PATCH 4/7] JPackageCommand: enhance usePredefinedAppImage() to enable automatic entitlements validation of additional launchers in two-phase app image packaging/signing scenarios; add missing verifyMutable() calls; SigningAppImageTwoStepsTest: follow-up change --- .../helpers/jdk/jpackage/test/JPackageCommand.java | 12 +++++++++++- .../macosx/SigningAppImageTwoStepsTest.java | 13 +++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) 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 6b1f67d50f41d..4c5447ce4ddfd 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -392,7 +392,6 @@ public JPackageCommand setInputToEmptyDirectory() { } public JPackageCommand setFakeRuntime() { - verifyMutable(); addPrerequisiteAction(cmd -> { cmd.setArgumentValue("--runtime-image", createInputRuntimeImage(RuntimeImageType.RUNTIME_TYPE_FAKE)); }); @@ -400,12 +399,22 @@ public JPackageCommand setFakeRuntime() { return this; } + public JPackageCommand usePredefinedAppImage(JPackageCommand appImageCmd) { + appImageCmd.verifyIsOfType(PackageType.IMAGE); + verifyIsOfType(PackageType.IMAGE); + appImageCmd.getVerifyActionsWithRole(ActionRole.LAUNCHER_VERIFIER).forEach(verifier -> { + addVerifyAction(verifier, ActionRole.LAUNCHER_VERIFIER); + }); + return usePredefinedAppImage(appImageCmd.outputBundle()); + } + public JPackageCommand usePredefinedAppImage(Path predefinedAppImagePath) { return setArgumentValue("--app-image", Objects.requireNonNull(predefinedAppImagePath)) .removeArgumentWithValue("--input"); } JPackageCommand addPrerequisiteAction(ThrowingConsumer action) { + verifyMutable(); prerequisiteActions.add(action); return this; } @@ -421,6 +430,7 @@ enum ActionRole { } JPackageCommand addVerifyAction(ThrowingConsumer action, ActionRole actionRole) { + verifyMutable(); verifyActions.add(action, actionRole); return this; } diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index 4ab2d448e9f2b..20af957204443 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -21,8 +21,6 @@ * questions. */ -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -38,7 +36,6 @@ import jdk.jpackage.test.MacHelper.SignKeyOption; import jdk.jpackage.test.MacHelper.SignKeyOptionWithKeychain; import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.ApplicationLayout; import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -153,7 +150,7 @@ private SignKeyOptionWithKeychain createSignKeyOption() { private SignKeyOptionWithKeychain sign; } - Path createAppImage() { + JPackageCommand createAppImage() { var appImageCmd = JPackageCommand.helloAppImage() .setFakeRuntime() .setArgumentValue("--dest", TKit.createTempDirectory("appimage")); @@ -170,17 +167,17 @@ Path createAppImage() { }, signOption.keychain()); }, appImageCmd::execute); - return appImageCmd.outputBundle(); + return appImageCmd; } - void signAppImage(Path appImage, Optional> mutator) { - Objects.requireNonNull(appImage); + void signAppImage(JPackageCommand appImageCmd, Optional> mutator) { + Objects.requireNonNull(appImageCmd); Objects.requireNonNull(mutator); MacSign.withKeychain(keychain -> { var cmd = new JPackageCommand() .setPackageType(PackageType.IMAGE) - .addArguments("--app-image", appImage) + .usePredefinedAppImage(appImageCmd) .mutate(sign::addTo); mutator.ifPresent(cmd::mutate); From 4c0d9f25da410d1c01fae6a1e23e272f88ca9464 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 23 Mar 2026 11:01:43 -0400 Subject: [PATCH 5/7] Update copyright year --- .../classes/jdk/jpackage/internal/MacRuntimeValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java index 42b68056119ee..340078849c75a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacRuntimeValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 From f414ff15d782e017db77e6be9f799ab5b8e903d4 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 23 Mar 2026 11:05:13 -0400 Subject: [PATCH 6/7] Apply blessed-modifier-order.sh --- .../jpackage/helpers/jdk/jpackage/test/JPackageCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4c5447ce4ddfd..4fad120d0f687 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -2043,7 +2043,7 @@ private enum DefaultToolProviderKey { // `--runtime-image` parameter set. public static final Path DEFAULT_RUNTIME_IMAGE = Optional.ofNullable(TKit.getConfigProperty("runtime-image")).map(Path::of).orElse(null); - public final static String DEFAULT_VERSION = "1.0"; + public static final String DEFAULT_VERSION = "1.0"; // [HH:mm:ss.SSS] private static final Pattern TIMESTAMP_REGEXP = Pattern.compile( From 465541c7d46bc825540e368b5f7748494ac4ec4c Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 23 Mar 2026 11:20:23 -0400 Subject: [PATCH 7/7] LauncherVerifier: log message reworded --- .../helpers/jdk/jpackage/test/LauncherVerifier.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index 61ee36e30a408..7657517bad5ff 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -376,7 +376,7 @@ private void verifyMacEntitlements(JPackageCommand cmd) throws SAXException, IOE var customFile = Optional.ofNullable(cmd.getArgumentValue("--mac-entitlements")).map(Path::of); if (customFile.isPresent()) { - expectedEntitlementsOrigin = String.format("Custom entitlements file [%s]", customFile.get()); + expectedEntitlementsOrigin = String.format("custom entitlements from [%s] file", customFile.get()); } else { // Try from the resource dir. var resourceDirFile = Optional.ofNullable(cmd.getArgumentValue("--resource-dir")).map(Path::of).map(resourceDir -> { @@ -384,7 +384,7 @@ private void verifyMacEntitlements(JPackageCommand cmd) throws SAXException, IOE }).filter(Files::exists); if (resourceDirFile.isPresent()) { customFile = resourceDirFile; - expectedEntitlementsOrigin = "Custom entitlements from the resource directory"; + expectedEntitlementsOrigin = "custom entitlements from the resource directory"; } else { expectedEntitlementsOrigin = null; } @@ -397,7 +397,7 @@ private void verifyMacEntitlements(JPackageCommand cmd) throws SAXException, IOE expected = DefaultEntitlements.APP_STORE; expectedEntitlementsOrigin = "App Store entitlements"; } else { - expectedEntitlementsOrigin = "Default entitlements"; + expectedEntitlementsOrigin = "default entitlements"; expected = DefaultEntitlements.STANDARD; }