fix: turning off default picocli behavior we don't want (#38070)

closes: #38065

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2025-03-14 05:20:26 -04:00 committed by GitHub
parent 290905c9cf
commit f69261daad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 47 additions and 10 deletions

View File

@ -28,12 +28,14 @@ import static org.keycloak.client.admin.cli.KcAdmMain.CMD;
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
@Command(name = "config", description = "COMMAND [ARGUMENTS]", subcommands = {
@Command(name = ConfigCmd.NAME, description = "COMMAND [ARGUMENTS]", subcommands = {
ConfigCredentialsCmd.class,
ConfigTruststoreCmd.class
} )
public class ConfigCmd extends AbstractAuthOptionsCmd {
public static final String NAME = "config";
@Override
protected void process() {

View File

@ -33,9 +33,11 @@ import static org.keycloak.client.cli.util.IoUtil.printOut;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
@Command(name = "credentials", description = "--server SERVER_URL --realm REALM [ARGUMENTS]")
@Command(name = ConfigCredentialsCmd.NAME, description = "--server SERVER_URL --realm REALM [ARGUMENTS]")
public class ConfigCredentialsCmd extends BaseConfigCredentialsCmd {
static final String NAME = "credentials";
public ConfigCredentialsCmd() {
super(KcAdmMain.COMMAND_STATE);
}
@ -62,4 +64,8 @@ public class ConfigCredentialsCmd extends BaseConfigCredentialsCmd {
super.process();
}
}
String getPassword() {
return this.password;
}
}

View File

@ -22,6 +22,7 @@ import org.keycloak.client.cli.common.BaseGlobalOptionsCmd;
import java.io.PrintWriter;
import java.io.StringWriter;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import static org.keycloak.client.admin.cli.KcAdmMain.CMD;
@ -51,6 +52,9 @@ subcommands = {
})
public class KcAdmCmd extends BaseGlobalOptionsCmd {
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@Override
protected boolean nothingToDo() {
return true;

View File

@ -44,19 +44,20 @@ public class Globals {
CryptoIntegration.init(cl);
System.setProperty(BaseAuthOptionsCmd.DEFAULT_CONFIG_PATH_STRING_KEY, defaultConfigFile);
CommandLine cli = createCommandLine(rootCommand, command);
CommandLine cli = createCommandLine(rootCommand, command, new PrintWriter(System.err, true));
int exitCode = cli.execute(args);
System.exit(exitCode);
}
public static CommandLine createCommandLine(BaseGlobalOptionsCmd rootCommand, String command) {
public static CommandLine createCommandLine(BaseGlobalOptionsCmd rootCommand, String command, PrintWriter errorWriter) {
CommandSpec spec = CommandSpec.forAnnotatedObject(rootCommand).name(command);
CommandLine cmd = new CommandLine(spec);
cmd.setExpandAtFiles(false);
cmd.setPosixClusteredShortOptionsAllowed(false);
cmd.setExecutionExceptionHandler(new ExecutionExceptionHandler());
cmd.setParameterExceptionHandler(new ShortErrorMessageHandler());
cmd.setErr(new PrintWriter(System.err, true));
cmd.setErr(errorWriter);
return cmd;
}

View File

@ -0,0 +1,23 @@
package org.keycloak.client.admin.cli.commands;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import org.junit.Test;
import org.keycloak.client.cli.common.Globals;
import picocli.CommandLine;
public class KcAdmCliTest {
@Test
public void testAtFileDisabled() {
KcAdmCmd command = new KcAdmCmd();
CommandLine cli = Globals.createCommandLine(command, "kcadm", new PrintWriter(new ByteArrayOutputStream()));
cli.execute("config", "credentials", "--user", "user", "--password", "@@password", "--server", "server");
ConfigCredentialsCmd cmd = command.spec.subcommands().get(ConfigCmd.NAME).getSubcommands().get(ConfigCredentialsCmd.NAME).getCommand();
assertEquals("@@password", cmd.getPassword());
}
}

View File

@ -629,7 +629,8 @@ public class Picocli {
consumer.accept(spec);
CommandLine cmd = new CommandLine(spec);
cmd.setExpandAtFiles(false);
cmd.setPosixClusteredShortOptionsAllowed(false);
cmd.setExecutionExceptionHandler(this.errorHandler);
cmd.setParameterExceptionHandler(new ShortErrorMessageHandler());
cmd.setHelpFactory(new HelpFactory());

View File

@ -77,7 +77,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
if(args == null) {
return Collections.emptyList();
}
List<String> result = new ArrayList<String>();
boolean escaped = false;
StringBuilder arg = new StringBuilder();
@ -101,7 +101,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
}
}
result.add(arg.toString());
return result;
}
@ -167,7 +167,7 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
PropertyMapper<?> mapper = PropertyMappers.getMapper(key);
// the weaknesses here:
// - needs to know all of the short name options that accept a value
// - does not know all of the picocli parsing rules. picocli will accept -cffile, and short option grouping - that's not accounted for
// - Even though We've explicitly disabled PosixClusteredShortOptionsAllowed, it may not know all of the picocli parsing rules.
if (mapper != null || SHORT_OPTIONS_ACCEPTING_VALUE.contains(key) || arg.startsWith(SPI_OPTION_PREFIX)) {
i++; // consume next as a value to the key
value = args.get(i);