mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-20 10:27:52 +00:00
8377331: jpackage: improve sign errors reporting
Reviewed-by: almatvee
This commit is contained in:
parent
40bf0870f7
commit
5152fdcd49
@ -24,7 +24,6 @@
|
||||
*/
|
||||
package jdk.jpackage.internal;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT;
|
||||
import static jdk.jpackage.internal.model.MacPackage.RUNTIME_BUNDLE_LAYOUT;
|
||||
import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer;
|
||||
@ -40,7 +39,6 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.jpackage.internal.Codesign.CodesignException;
|
||||
import jdk.jpackage.internal.model.Application;
|
||||
import jdk.jpackage.internal.model.ApplicationLayout;
|
||||
@ -63,9 +61,10 @@ final class AppImageSigner {
|
||||
throw handleCodesignException(app, ex);
|
||||
} catch (ExceptionBox ex) {
|
||||
if (ex.getCause() instanceof CodesignException codesignEx) {
|
||||
handleCodesignException(app, codesignEx);
|
||||
throw handleCodesignException(app, codesignEx);
|
||||
} else {
|
||||
throw ex;
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -165,13 +164,9 @@ final class AppImageSigner {
|
||||
}
|
||||
}
|
||||
|
||||
private static CodesignException handleCodesignException(MacApplication app, CodesignException ex) {
|
||||
// Log output of "codesign" in case of error. It should help
|
||||
// user to diagnose issues when using --mac-app-image-sign-identity.
|
||||
// In addition add possible reason for failure. For example
|
||||
// "--app-content" can fail "codesign".
|
||||
|
||||
private static IOException handleCodesignException(MacApplication app, CodesignException ex) {
|
||||
if (!app.contentDirSources().isEmpty()) {
|
||||
// Additional content may cause signing error.
|
||||
Log.info(I18N.getString("message.codesign.failed.reason.app.content"));
|
||||
}
|
||||
|
||||
@ -182,11 +177,7 @@ final class AppImageSigner {
|
||||
Log.info(I18N.getString("message.codesign.failed.reason.xcode.tools"));
|
||||
}
|
||||
|
||||
// Log "codesign" output
|
||||
Log.info(I18N.format("error.tool.failed.with.output", "codesign"));
|
||||
Log.info(Stream.of(ex.getOutput()).collect(joining("\n")).strip());
|
||||
|
||||
return ex;
|
||||
return ex.getCause();
|
||||
}
|
||||
|
||||
private static boolean isXcodeDevToolsInstalled() {
|
||||
|
||||
@ -34,22 +34,21 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jdk.jpackage.internal.util.CommandOutputControl.UnexpectedExitCodeException;
|
||||
|
||||
public final class Codesign {
|
||||
|
||||
public static final class CodesignException extends Exception {
|
||||
|
||||
CodesignException(String[] output) {
|
||||
this.output = output;
|
||||
CodesignException(UnexpectedExitCodeException cause) {
|
||||
super(Objects.requireNonNull(cause));
|
||||
}
|
||||
|
||||
String[] getOutput() {
|
||||
return output;
|
||||
@Override
|
||||
public UnexpectedExitCodeException getCause() {
|
||||
return (UnexpectedExitCodeException)super.getCause();
|
||||
}
|
||||
|
||||
private final String[] output;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
@ -96,9 +95,10 @@ public final class Codesign {
|
||||
var exec = Executor.of(cmdline).args(path.toString()).saveOutput(true);
|
||||
configureExecutor.ifPresent(configure -> configure.accept(exec));
|
||||
|
||||
var result = exec.execute();
|
||||
if (result.getExitCode() != 0) {
|
||||
throw new CodesignException(result.getOutput().toArray(String[]::new));
|
||||
try {
|
||||
exec.execute().expectExitCode(0);
|
||||
} catch (UnexpectedExitCodeException ex) {
|
||||
throw new CodesignException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,6 @@ error.certificate.expired=Certificate expired {0}
|
||||
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.tool.failed.with.output="{0}" failed with following output:
|
||||
error.invalid-runtime-image-missing-file=Runtime image "{0}" is missing "{1}" file
|
||||
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
|
||||
|
||||
@ -271,11 +271,9 @@ public final class Main {
|
||||
}
|
||||
|
||||
messagePrinter.accept(I18N.format("message.error-header", msg));
|
||||
if (!verbose) {
|
||||
messagePrinter.accept(I18N.format("message.failed-command-output-header"));
|
||||
try (var lines = new BufferedReader(new StringReader(commandOutput)).lines()) {
|
||||
lines.forEach(messagePrinter);
|
||||
}
|
||||
messagePrinter.accept(I18N.format("message.failed-command-output-header"));
|
||||
try (var lines = new BufferedReader(new StringReader(commandOutput)).lines()) {
|
||||
lines.forEach(messagePrinter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
package jdk.jpackage.test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Validates failed command error in jpackage's output.
|
||||
*/
|
||||
public final class FailedCommandErrorValidator {
|
||||
|
||||
public FailedCommandErrorValidator(Pattern cmdlinePattern) {
|
||||
this.cmdlinePattern = Objects.requireNonNull(cmdlinePattern);
|
||||
}
|
||||
|
||||
public TKit.TextStreamVerifier.Group createGroup() {
|
||||
var asPredicate = cmdlinePattern.asPredicate();
|
||||
|
||||
var errorMessage = exitCode().map(v -> {
|
||||
return JPackageStringBundle.MAIN.cannedFormattedString("error.command-failed-unexpected-exit-code", v, "");
|
||||
}).orElseGet(() -> {
|
||||
return JPackageStringBundle.MAIN.cannedFormattedString("error.command-failed-unexpected-output", "");
|
||||
});
|
||||
|
||||
var errorMessageWithPrefix = JPackageCommand.makeError(errorMessage).getValue();
|
||||
|
||||
var group = TKit.TextStreamVerifier.group();
|
||||
|
||||
group.add(TKit.assertTextStream(cmdlinePattern.pattern()).predicate(line -> {
|
||||
if (line.startsWith(errorMessageWithPrefix)) {
|
||||
line = line.substring(errorMessageWithPrefix.length());
|
||||
return asPredicate.test(line);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
group.add(TKit.assertTextStream(
|
||||
JPackageStringBundle.MAIN.cannedFormattedString("message.failed-command-output-header").getValue()
|
||||
).predicate(String::equals));
|
||||
|
||||
outputVerifier().ifPresent(group::add);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
public void applyTo(JPackageCommand cmd) {
|
||||
cmd.validateOutput(createGroup().create());
|
||||
}
|
||||
|
||||
public FailedCommandErrorValidator validator(TKit.TextStreamVerifier.Group v) {
|
||||
outputValidator = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FailedCommandErrorValidator validator(List<TKit.TextStreamVerifier> validators) {
|
||||
var group = TKit.TextStreamVerifier.group();
|
||||
validators.forEach(group::add);
|
||||
return validator(group);
|
||||
}
|
||||
|
||||
public FailedCommandErrorValidator validators(TKit.TextStreamVerifier... validators) {
|
||||
return validator(List.of(validators));
|
||||
}
|
||||
|
||||
public FailedCommandErrorValidator output(List<String> v) {
|
||||
return validator(v.stream().map(TKit::assertTextStream).toList());
|
||||
}
|
||||
|
||||
public FailedCommandErrorValidator output(String... output) {
|
||||
return output(List.of(output));
|
||||
}
|
||||
|
||||
public FailedCommandErrorValidator exitCode(int v) {
|
||||
exitCode = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
private Optional<Integer> exitCode() {
|
||||
return Optional.ofNullable(exitCode);
|
||||
}
|
||||
|
||||
private Optional<TKit.TextStreamVerifier.Group> outputVerifier() {
|
||||
return Optional.ofNullable(outputValidator);
|
||||
}
|
||||
|
||||
private final Pattern cmdlinePattern;
|
||||
private TKit.TextStreamVerifier.Group outputValidator;
|
||||
private Integer exitCode;
|
||||
}
|
||||
@ -906,6 +906,11 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public JPackageCommand validateOutput(TKit.TextStreamVerifier.Group group) {
|
||||
group.tryCreate().ifPresent(this::validateOutput);
|
||||
return this;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CannedArgument {
|
||||
public String value(JPackageCommand cmd);
|
||||
@ -947,11 +952,11 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
|
||||
public JPackageCommand validateOutput(CannedFormattedString... str) {
|
||||
// Will look up the given errors in the order they are specified.
|
||||
Stream.of(str).map(this::getValue)
|
||||
validateOutput(Stream.of(str).map(this::getValue)
|
||||
.map(TKit::assertTextStream)
|
||||
.reduce(TKit.TextStreamVerifier.group(),
|
||||
TKit.TextStreamVerifier.Group::add,
|
||||
TKit.TextStreamVerifier.Group::add).tryCreate().ifPresent(this::validateOutput);
|
||||
TKit.TextStreamVerifier.Group::add));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@ -782,6 +782,10 @@ public final class MacHelper {
|
||||
return sign(cmd);
|
||||
}
|
||||
|
||||
public Optional<Name> optionName() {
|
||||
return type.mapOptionName(certRequest.type());
|
||||
}
|
||||
|
||||
public List<String> asCmdlineArgs() {
|
||||
String[] args = new String[2];
|
||||
applyTo((optionName, optionValue) -> {
|
||||
@ -791,6 +795,10 @@ public final class MacHelper {
|
||||
return List.of(args);
|
||||
}
|
||||
|
||||
public Optional<Boolean> passThrough() {
|
||||
return optionName().map(Name::passThrough);
|
||||
}
|
||||
|
||||
private void applyTo(BiConsumer<String, String> sink) {
|
||||
type.mapOptionName(certRequest.type()).ifPresent(optionName -> {
|
||||
sink.accept(optionName.optionName(), optionValue());
|
||||
@ -886,6 +894,14 @@ public final class MacHelper {
|
||||
return signKeyOption.certRequest();
|
||||
}
|
||||
|
||||
public Optional<SignKeyOption.Name> optionName() {
|
||||
return signKeyOption.optionName();
|
||||
}
|
||||
|
||||
public Optional<Boolean> passThrough() {
|
||||
return signKeyOption.passThrough();
|
||||
}
|
||||
|
||||
public JPackageCommand addTo(JPackageCommand cmd) {
|
||||
Optional.ofNullable(cmd.getArgumentValue("--mac-signing-keychain")).ifPresentOrElse(configuredKeychain -> {
|
||||
if (!configuredKeychain.equals(keychain.name())) {
|
||||
|
||||
@ -65,6 +65,7 @@ import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.internal.util.OperatingSystem;
|
||||
@ -1082,6 +1083,11 @@ public final class TKit {
|
||||
predicate(String::contains);
|
||||
}
|
||||
|
||||
TextStreamVerifier(Pattern value) {
|
||||
this(Objects.requireNonNull(value).pattern());
|
||||
predicate(value.asPredicate());
|
||||
}
|
||||
|
||||
TextStreamVerifier(TextStreamVerifier other) {
|
||||
predicate = other.predicate;
|
||||
label = other.label;
|
||||
@ -1091,6 +1097,10 @@ public final class TKit {
|
||||
value = other.value;
|
||||
}
|
||||
|
||||
public TextStreamVerifier copy() {
|
||||
return new TextStreamVerifier(this);
|
||||
}
|
||||
|
||||
public TextStreamVerifier label(String v) {
|
||||
label = v;
|
||||
return this;
|
||||
@ -1101,6 +1111,13 @@ public final class TKit {
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextStreamVerifier predicate(Predicate<String> v) {
|
||||
Objects.requireNonNull(v);
|
||||
return predicate((str, _) -> {
|
||||
return v.test(str);
|
||||
});
|
||||
}
|
||||
|
||||
public TextStreamVerifier negate() {
|
||||
negate = true;
|
||||
return this;
|
||||
@ -1116,7 +1133,12 @@ public final class TKit {
|
||||
return this;
|
||||
}
|
||||
|
||||
private String findMatch(Iterator<String> lineIt) {
|
||||
public TextStreamVerifier mutate(Consumer<TextStreamVerifier> mutator) {
|
||||
mutator.accept(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
private String find(Iterator<String> lineIt) {
|
||||
while (lineIt.hasNext()) {
|
||||
final var line = lineIt.next();
|
||||
if (predicate.test(line, value)) {
|
||||
@ -1131,7 +1153,7 @@ public final class TKit {
|
||||
}
|
||||
|
||||
public void apply(Iterator<String> lineIt) {
|
||||
final String matchedStr = findMatch(lineIt);
|
||||
final String matchedStr = find(lineIt);
|
||||
final String labelStr = Optional.ofNullable(label).orElse("output");
|
||||
if (negate) {
|
||||
String msg = String.format(
|
||||
@ -1180,6 +1202,11 @@ public final class TKit {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Group mutate(Consumer<Group> mutator) {
|
||||
mutator.accept(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return verifiers.isEmpty();
|
||||
}
|
||||
@ -1226,6 +1253,18 @@ public final class TKit {
|
||||
return new TextStreamVerifier(what);
|
||||
}
|
||||
|
||||
public static TextStreamVerifier assertTextStream(Pattern what) {
|
||||
return new TextStreamVerifier(what);
|
||||
}
|
||||
|
||||
public static Consumer<Iterator<String>> assertEndOfTextStream() {
|
||||
return it -> {
|
||||
var tail = new ArrayList<String>();
|
||||
it.forEachRemaining(tail::add);
|
||||
assertStringListEquals(List.of(), tail, "Check the end of the output");
|
||||
};
|
||||
}
|
||||
|
||||
public record PathSnapshot(List<String> contentHashes) {
|
||||
public PathSnapshot {
|
||||
contentHashes.forEach(Objects::requireNonNull);
|
||||
|
||||
@ -279,9 +279,7 @@ public class MainTest extends JUnitAdapter {
|
||||
expectedOutput.add(ExceptionFormatter.STACK_TRACE);
|
||||
}
|
||||
expectedOutput.add(expect.getValue());
|
||||
if (!verbose) {
|
||||
expectedOutput.add(ExceptionFormatter.FAILED_COMMAND_OUTPUT);
|
||||
}
|
||||
expectedOutput.add(ExceptionFormatter.FAILED_COMMAND_OUTPUT);
|
||||
data.add(new ErrorReporterTestSpec(cause, expect.getKey(), verbose, expectedOutput));
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,22 +22,23 @@
|
||||
*/
|
||||
|
||||
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY;
|
||||
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY_APP_IMAGE;
|
||||
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_FULL_NAME;
|
||||
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_USER_SHORT_NAME;
|
||||
import static jdk.jpackage.test.MacHelper.SignKeyOption.Type.SIGN_KEY_IDENTITY_APP_IMAGE;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.jpackage.test.Annotations.Parameter;
|
||||
import jdk.jpackage.test.Annotations.ParameterSupplier;
|
||||
import jdk.jpackage.test.Annotations.Test;
|
||||
import jdk.jpackage.test.CannedFormattedString;
|
||||
import jdk.jpackage.test.FailedCommandErrorValidator;
|
||||
import jdk.jpackage.test.JPackageCommand;
|
||||
import jdk.jpackage.test.JPackageStringBundle;
|
||||
import jdk.jpackage.test.MacHelper;
|
||||
@ -74,22 +75,32 @@ public class MacSignTest {
|
||||
Files.createDirectory(appContent);
|
||||
Files.createFile(appContent.resolve("file"));
|
||||
|
||||
final List<CannedFormattedString> expectedStrings = new ArrayList<>();
|
||||
expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.app.content"));
|
||||
final var group = TKit.TextStreamVerifier.group();
|
||||
|
||||
expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("error.tool.failed.with.output", "codesign"));
|
||||
group.add(TKit.assertTextStream(JPackageStringBundle.MAIN.cannedFormattedString(
|
||||
"message.codesign.failed.reason.app.content").getValue()).predicate(String::equals));
|
||||
|
||||
final var xcodeWarning = TKit.assertTextStream(JPackageStringBundle.MAIN.cannedFormattedString(
|
||||
"message.codesign.failed.reason.xcode.tools").getValue()).predicate(String::equals);
|
||||
|
||||
final var xcodeWarning = JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.xcode.tools");
|
||||
if (!MacHelper.isXcodeDevToolsInstalled()) {
|
||||
expectedStrings.add(xcodeWarning);
|
||||
group.add(xcodeWarning);
|
||||
}
|
||||
|
||||
MacSign.withKeychain(keychain -> {
|
||||
var keychain = SigningBase.StandardKeychain.MAIN.keychain();
|
||||
|
||||
var signingKeyOption = new SignKeyOptionWithKeychain(
|
||||
SIGN_KEY_IDENTITY,
|
||||
SigningBase.StandardCertificateRequest.CODESIGN,
|
||||
keychain);
|
||||
var signingKeyOption = new SignKeyOptionWithKeychain(
|
||||
SIGN_KEY_IDENTITY,
|
||||
SigningBase.StandardCertificateRequest.CODESIGN,
|
||||
keychain);
|
||||
|
||||
new FailedCommandErrorValidator(Pattern.compile(String.format(
|
||||
"/usr/bin/codesign -s %s -vvvv --timestamp --options runtime --prefix \\S+ --keychain %s --entitlements \\S+ \\S+",
|
||||
Pattern.quote(String.format("'%s'", signingKeyOption.certRequest().name())),
|
||||
Pattern.quote(keychain.name())
|
||||
))).exitCode(1).createGroup().mutate(group::add);
|
||||
|
||||
MacSign.withKeychain(_ -> {
|
||||
|
||||
// --app-content and --type app-image
|
||||
// Expect `message.codesign.failed.reason.app.content` message in the log.
|
||||
@ -97,51 +108,49 @@ public class MacSignTest {
|
||||
// To make jpackage fail, specify bad additional content.
|
||||
JPackageCommand.helloAppImage()
|
||||
.ignoreDefaultVerbose(true)
|
||||
.validateOutput(expectedStrings.toArray(CannedFormattedString[]::new))
|
||||
.validateOutput(group.create())
|
||||
.addArguments("--app-content", appContent)
|
||||
.mutate(signingKeyOption::addTo)
|
||||
.mutate(cmd -> {
|
||||
if (MacHelper.isXcodeDevToolsInstalled()) {
|
||||
// Check there is no warning about missing xcode command line developer tools.
|
||||
cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate());
|
||||
cmd.validateOutput(xcodeWarning.copy().negate());
|
||||
}
|
||||
}).execute(1);
|
||||
|
||||
}, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain());
|
||||
}, MacSign.Keychain.UsageBuilder::addToSearchList, keychain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testCodesignUnspecifiedFailure() throws IOException {
|
||||
|
||||
var appImageCmd = JPackageCommand.helloAppImage().setFakeRuntime();
|
||||
|
||||
appImageCmd.executeIgnoreExitCode().assertExitCodeIsZero();
|
||||
public static void testCodesignUnspecificFailure() throws IOException {
|
||||
|
||||
// This test expects jpackage to respond in a specific way on a codesign failure.
|
||||
// The simplest option to trigger codesign failure is to request the signing of an invalid bundle.
|
||||
// Create app content directory with the name known to fail signing.
|
||||
final var appContent = appImageCmd.appLayout().contentDirectory().resolve("foo.1");
|
||||
Files.createDirectory(appContent);
|
||||
Files.createFile(appContent.resolve("file"));
|
||||
// There are a few ways to make jpackage fail signing. One is using an erroneous
|
||||
// combination of a signing key and a keychain.
|
||||
|
||||
final List<CannedFormattedString> expectedStrings = new ArrayList<>();
|
||||
expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("error.tool.failed.with.output", "codesign"));
|
||||
var signingKeyOption = new SignKeyOption(
|
||||
SIGN_KEY_IDENTITY,
|
||||
SigningBase.StandardCertificateRequest.CODESIGN_ACME_TECH_LTD.certRequest(
|
||||
SigningBase.StandardKeychain.MAIN.keychain()));
|
||||
|
||||
MacSign.withKeychain(keychain -> {
|
||||
|
||||
var signingKeyOption = new SignKeyOptionWithKeychain(
|
||||
SIGN_KEY_IDENTITY,
|
||||
SigningBase.StandardCertificateRequest.CODESIGN,
|
||||
keychain);
|
||||
// Build a matcher for jpackage's failed command output.
|
||||
var errorValidator = new FailedCommandErrorValidator(Pattern.compile(String.format(
|
||||
"/usr/bin/codesign -s %s -vvvv --timestamp --options runtime --prefix \\S+ --keychain %s",
|
||||
Pattern.quote(String.format("'%s'", signingKeyOption.certRequest().name())),
|
||||
Pattern.quote(keychain.name())
|
||||
))).exitCode(1).output(String.format("%s: no identity found", signingKeyOption.certRequest().name())).createGroup();
|
||||
|
||||
new JPackageCommand().setPackageType(PackageType.IMAGE)
|
||||
JPackageCommand.helloAppImage()
|
||||
.setFakeRuntime()
|
||||
.ignoreDefaultVerbose(true)
|
||||
.validateOutput(expectedStrings.toArray(CannedFormattedString[]::new))
|
||||
.addArguments("--app-image", appImageCmd.outputBundle())
|
||||
.validateOutput(errorValidator.create())
|
||||
.mutate(signingKeyOption::addTo)
|
||||
.mutate(MacHelper.useKeychain(keychain))
|
||||
.execute(1);
|
||||
|
||||
}, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.MAIN.keychain());
|
||||
}, MacSign.Keychain.UsageBuilder::addToSearchList, SigningBase.StandardKeychain.DUPLICATE.keychain());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user