From af5867cf3bbe0a251aa7ad0fb118a844e0bb4e0f Mon Sep 17 00:00:00 2001 From: Ruud Senden <8635138+rsenden@users.noreply.github.com> Date: Thu, 20 Jul 2023 14:18:44 +0200 Subject: [PATCH] chore: Various REST-related fixes & improvements fix: FoD & SC-DAST paging functionality feat: `fcli * rest call`: Add `--no-paging` and `--transform` options fix: `fcli * rest call`: Fix `--no-transform` behavior --- .../output/cli/mixin/OutputHelperMixins.java | 9 ++- .../rest/cli/cmd/AbstractRestCallCommand.java | 64 +++++++++++++++---- .../cli/common/rest/paging/PagingHelper.java | 2 +- .../output/cli/AbstractFoDOutputCommand.java | 4 +- ...n.java => FoDProductHelperBasicMixin.java} | 23 +------ .../mixin/FoDProductHelperStandardMixin.java | 38 +++++++++++ .../fod/rest/cli/cmd/FoDRestCallCommand.java | 24 ++++++- .../scan/cli/cmd/FoDScanWaitForCommand.java | 4 +- .../cli/fod/i18n/FoDMessages.properties | 5 ++ .../cli/cmd/AbstractSCDastOutputCommand.java | 4 +- ...ava => SCDastProductHelperBasicMixin.java} | 30 +-------- .../SCDastProductHelperStandardMixin.java | 38 +++++++++++ .../rest/helper/SCDastPagingHelper.java | 4 +- .../rest/cli/cmd/SCDastRestCallCommand.java | 24 ++++++- .../cli/cmd/SCDastScanWaitForCommand.java | 4 +- .../sc_dast/i18n/SCDastMessages.properties | 6 ++ ...AbstractSCSastControllerOutputCommand.java | 4 +- .../cmd/AbstractSCSastSSCOutputCommand.java | 4 +- ...astControllerProductHelperBasicMixin.java} | 14 +--- ...tControllerProductHelperStandardMixin.java | 28 ++++++++ .../SCSastSSCProductHelperBasicMixin.java | 28 ++++++++ ... SCSastSSCProductHelperStandardMixin.java} | 13 +--- .../cmd/SCSastControllerRestCallCommand.java | 23 ++++++- .../SCSastControllerScanWaitForCommand.java | 4 +- .../sc_sast/i18n/SCSastMessages.properties | 4 ++ .../cli/cmd/AbstractSSCOutputCommand.java | 4 +- ...n.java => SSCProductHelperBasicMixin.java} | 28 +------- .../mixin/SSCProductHelperStandardMixin.java | 38 +++++++++++ .../cli/cmd/SSCArtifactWaitForCommand.java | 4 +- .../ssc/rest/cli/cmd/SSCRestCallCommand.java | 24 ++++++- .../cli/ssc/i18n/SSCMessages.properties | 6 ++ .../cli/ftest/ssc/SSCRestCallSpec.groovy | 43 +++++++++++++ 32 files changed, 414 insertions(+), 138 deletions(-) rename fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/{FoDProductHelperMixin.java => FoDProductHelperBasicMixin.java} (70%) create mode 100644 fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperStandardMixin.java rename fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/{SCDastProductHelperMixin.java => SCDastProductHelperBasicMixin.java} (63%) create mode 100644 fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperStandardMixin.java rename fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/{SCSastControllerProductHelperMixin.java => SCSastControllerProductHelperBasicMixin.java} (66%) create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperStandardMixin.java create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperBasicMixin.java rename fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/{SCSastSSCProductHelperMixin.java => SCSastSSCProductHelperStandardMixin.java} (71%) rename fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/{SSCProductHelperMixin.java => SSCProductHelperBasicMixin.java} (58%) create mode 100644 fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperStandardMixin.java create mode 100644 fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCRestCallSpec.groovy diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/cli/mixin/OutputHelperMixins.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/cli/mixin/OutputHelperMixins.java index cd742da1e7..7044812531 100644 --- a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/cli/mixin/OutputHelperMixins.java +++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/output/cli/mixin/OutputHelperMixins.java @@ -71,6 +71,11 @@ public static class DetailsNoQuery extends Other { @Getter private StandardOutputConfig basicOutputConfig = StandardOutputConfig.details(); } + public static class DetailsWithQuery extends Other { + @Getter @Mixin private OutputWriterWithQueryFactoryMixin outputWriterFactory; + @Getter private StandardOutputConfig basicOutputConfig = StandardOutputConfig.details(); + } + public static class Add extends TableNoQuery { public static final String CMD_NAME = "add"; @@ -204,9 +209,7 @@ public static class Logout extends TableNoQuery { public static final String CMD_NAME = "logout"; } - public static class RestCall extends Other { + public static class RestCall extends DetailsWithQuery { public static final String CMD_NAME = "call"; - @Getter @Mixin private OutputWriterWithQueryFactoryMixin outputWriterFactory; - @Getter private StandardOutputConfig basicOutputConfig = StandardOutputConfig.table(); } } diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/cli/cmd/AbstractRestCallCommand.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/cli/cmd/AbstractRestCallCommand.java index 58df83a980..78c7af23b3 100644 --- a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/cli/cmd/AbstractRestCallCommand.java +++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/cli/cmd/AbstractRestCallCommand.java @@ -16,11 +16,14 @@ import java.nio.file.Path; import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.json.JsonHelper; import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.cli.cmd.IBaseRequestSupplier; import com.fortify.cli.common.output.product.IProductHelperSupplier; import com.fortify.cli.common.output.transform.IInputTransformer; import com.fortify.cli.common.output.transform.IRecordTransformer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; import com.fortify.cli.common.util.DisableTest; import com.fortify.cli.common.util.DisableTest.TestType; @@ -31,10 +34,23 @@ import kong.unirest.UnirestInstance; import lombok.Getter; import lombok.SneakyThrows; +import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; -public abstract class AbstractRestCallCommand extends AbstractOutputCommand implements IBaseRequestSupplier, IProductHelperSupplier, IInputTransformer, IRecordTransformer { +/** + * Abstract base class for 'fcli rest call' commands. Concrete implementations must + * implement the various abstract methods. As dictated by the {@link IProductHelperSupplier}, + * implementations must implement the {@link IProductHelperSupplier#getProductHelper()} method, + * but please note that the provided product helper may not implement any of the + * {@link IInputTransformer}, {@link IRecordTransformer}, {@link INextPageUrlProducerSupplier} + * or {@link INextPageUrlProducer} as this would break the --no-transform and --no-paging options. + * Instead, subclasses should implement the corresponding _* methods defined in this class, + * to enable/disable paging and transformations on demand. + * + * @author Ruud Senden + */ +public abstract class AbstractRestCallCommand extends AbstractOutputCommand implements IBaseRequestSupplier, IProductHelperSupplier, IInputTransformer, IRecordTransformer, INextPageUrlProducerSupplier { @Parameters(index = "0", arity = "1..1", descriptionKey = "api.uri") String uri; @Option(names = {"--request", "-X"}, required = false, defaultValue = "GET") @@ -42,10 +58,19 @@ public abstract class AbstractRestCallCommand extends AbstractOutputCommand impl @Getter private String httpMethod; @Option(names = {"--data", "-d"}, required = false) - @Getter private String data; // TODO Add ability to read data from file + @Getter private String data; - @Option(names="--no-transform", negatable = true, defaultValue = "false") - private boolean noTransform; + @Option(names="--no-paging", negatable = false, defaultValue = "false") + private boolean noPaging; + + @ArgGroup(exclusive = true) private TransformArgGroup transform = new TransformArgGroup(); + private static class TransformArgGroup { + @Option(names="--no-transform", negatable = false, defaultValue = "false") + private boolean noTransform; + + @Option(names={"-t", "--transform"}, paramLabel = "") + private String transformExpression; + } // TODO Add options for content-type, arbitrary headers, ...? @@ -64,21 +89,36 @@ public boolean isSingular() { } @Override - public JsonNode transformInput(JsonNode input) { - if ( !noTransform && getProductHelper() instanceof IInputTransformer ) { - input = ((IInputTransformer)getProductHelper()).transformInput(input); + public final JsonNode transformInput(JsonNode input) { + if ( StringUtils.isNotBlank(transform.transformExpression) ) { + input = JsonHelper.evaluateSpelExpression(input, transform.transformExpression, JsonNode.class); + } else if ( !transform.noTransform ) { + input = _transformInput(input); } return input; } - + @Override - public JsonNode transformRecord(JsonNode input) { - if ( !noTransform && getProductHelper() instanceof IRecordTransformer ) { - input = ((IRecordTransformer)getProductHelper()).transformRecord(input); + public final JsonNode transformRecord(JsonNode input) { + if ( !transform.noTransform ) { + input = _transformRecord(input); } return input; } - + + @Override + public final INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { + INextPageUrlProducer result = null; + if ( !noPaging ) { + result = _getNextPageUrlProducer(originalRequest); + } + return result; + } + + protected abstract JsonNode _transformRecord(JsonNode input); + protected abstract JsonNode _transformInput(JsonNode input); + protected abstract INextPageUrlProducer _getNextPageUrlProducer(HttpRequest originalRequest); + @SneakyThrows protected final HttpRequest prepareRequest(UnirestInstance unirest) { if ( StringUtils.isBlank(uri) ) { diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/paging/PagingHelper.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/paging/PagingHelper.java index 7cbc7017e5..64f48c08c4 100644 --- a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/paging/PagingHelper.java +++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/rest/paging/PagingHelper.java @@ -43,7 +43,7 @@ public static final URI addOrReplaceParam(URI uri, String param, Object newValue var pattern = String.format("([&?])(%s=)([^&]*)", param); var query = uri.getQuery().replaceAll(pattern, ""); var newParamAndValue = String.format("%s=%s", param, URLEncoder.encode(newValue.toString(), StandardCharsets.UTF_8)); - query = (StringUtils.isBlank(query) ? "" : "&") + newParamAndValue; + query = (StringUtils.isBlank(query) ? "" : query+"&") + newParamAndValue; return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), query, uri.getFragment()); } diff --git a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/cli/AbstractFoDOutputCommand.java b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/cli/AbstractFoDOutputCommand.java index 7bc91221a2..c24ede2902 100644 --- a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/cli/AbstractFoDOutputCommand.java +++ b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/cli/AbstractFoDOutputCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.product.IProductHelperSupplier; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.fod._common.output.mixin.FoDProductHelperMixin; +import com.fortify.cli.fod._common.output.mixin.FoDProductHelperStandardMixin; import kong.unirest.UnirestInstance; import lombok.Getter; @@ -24,7 +24,7 @@ public abstract class AbstractFoDOutputCommand extends AbstractOutputCommand implements IProductHelperSupplier, IUnirestInstanceSupplier { - @Getter @Mixin FoDProductHelperMixin productHelper; + @Getter @Mixin FoDProductHelperStandardMixin productHelper; public final UnirestInstance getUnirestInstance() { return productHelper.getUnirestInstance(); diff --git a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperMixin.java b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperBasicMixin.java similarity index 70% rename from fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperMixin.java rename to fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperBasicMixin.java index e75ec85374..a65709c490 100644 --- a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperMixin.java +++ b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperBasicMixin.java @@ -12,37 +12,20 @@ *******************************************************************************/ package com.fortify.cli.fod._common.output.mixin; -import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.http.proxy.helper.ProxyHelper; import com.fortify.cli.common.output.product.IProductHelper; -import com.fortify.cli.common.output.transform.IInputTransformer; -import com.fortify.cli.common.rest.paging.INextPageUrlProducer; -import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; import com.fortify.cli.common.rest.unirest.config.UnirestJsonHeaderConfigurer; import com.fortify.cli.common.rest.unirest.config.UnirestUnexpectedHttpResponseConfigurer; import com.fortify.cli.common.rest.unirest.config.UnirestUrlConfigConfigurer; import com.fortify.cli.common.session.cli.mixin.AbstractSessionUnirestInstanceSupplierMixin; -import com.fortify.cli.fod._common.rest.helper.FoDInputTransformer; -import com.fortify.cli.fod._common.rest.helper.FoDPagingHelper; import com.fortify.cli.fod._common.session.helper.FoDSessionDescriptor; import com.fortify.cli.fod._common.session.helper.FoDSessionHelper; -import kong.unirest.HttpRequest; import kong.unirest.UnirestInstance; -public class FoDProductHelperMixin extends AbstractSessionUnirestInstanceSupplierMixin - implements IProductHelper, IInputTransformer, INextPageUrlProducerSupplier -{ - @Override - public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { - return FoDPagingHelper.nextPageUrlProducer(originalRequest); - } - - @Override - public JsonNode transformInput(JsonNode input) { - return FoDInputTransformer.getItems(input); - } - +public class FoDProductHelperBasicMixin extends AbstractSessionUnirestInstanceSupplierMixin + implements IProductHelper +{ @Override protected final FoDSessionDescriptor getSessionDescriptor(String sessionName) { return FoDSessionHelper.instance().get(sessionName, true); diff --git a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperStandardMixin.java b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperStandardMixin.java new file mode 100644 index 0000000000..babbc2c519 --- /dev/null +++ b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/_common/output/mixin/FoDProductHelperStandardMixin.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2021, 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors ("Open Text") are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + *******************************************************************************/ +package com.fortify.cli.fod._common.output.mixin; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.output.transform.IInputTransformer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; +import com.fortify.cli.fod._common.rest.helper.FoDInputTransformer; +import com.fortify.cli.fod._common.rest.helper.FoDPagingHelper; + +import kong.unirest.HttpRequest; + +// IMPORTANT: When updating/adding any methods in this class, FoDRestCallCommand +// also likely needs to be updated +public class FoDProductHelperStandardMixin extends FoDProductHelperBasicMixin + implements IInputTransformer, INextPageUrlProducerSupplier +{ + @Override + public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { + return FoDPagingHelper.nextPageUrlProducer(originalRequest); + } + + @Override + public JsonNode transformInput(JsonNode input) { + return FoDInputTransformer.getItems(input); + } +} \ No newline at end of file diff --git a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/rest/cli/cmd/FoDRestCallCommand.java b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/rest/cli/cmd/FoDRestCallCommand.java index 660e36cfc5..1cdad665cc 100644 --- a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/rest/cli/cmd/FoDRestCallCommand.java +++ b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/rest/cli/cmd/FoDRestCallCommand.java @@ -12,12 +12,17 @@ *******************************************************************************/ package com.fortify.cli.fod.rest.cli.cmd; +import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractRestCallCommand; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; import com.fortify.cli.common.util.DisableTest; import com.fortify.cli.common.util.DisableTest.TestType; -import com.fortify.cli.fod._common.output.mixin.FoDProductHelperMixin; +import com.fortify.cli.fod._common.output.mixin.FoDProductHelperBasicMixin; +import com.fortify.cli.fod._common.rest.helper.FoDInputTransformer; +import com.fortify.cli.fod._common.rest.helper.FoDPagingHelper; +import kong.unirest.HttpRequest; import lombok.Getter; import picocli.CommandLine.Command; import picocli.CommandLine.Mixin; @@ -26,5 +31,20 @@ @DisableTest(TestType.CMD_DEFAULT_TABLE_OPTIONS_PRESENT) // Output columns depend on response contents public final class FoDRestCallCommand extends AbstractRestCallCommand { @Getter @Mixin private OutputHelperMixins.RestCall outputHelper; - @Getter @Mixin private FoDProductHelperMixin productHelper; + @Getter @Mixin private FoDProductHelperBasicMixin productHelper; + + @Override + protected INextPageUrlProducer _getNextPageUrlProducer(HttpRequest originalRequest) { + return FoDPagingHelper.nextPageUrlProducer(originalRequest); + } + + @Override + protected JsonNode _transformInput(JsonNode input) { + return FoDInputTransformer.getItems(input); + } + + @Override + protected JsonNode _transformRecord(JsonNode input) { + return input; + } } \ No newline at end of file diff --git a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/scan/cli/cmd/FoDScanWaitForCommand.java b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/scan/cli/cmd/FoDScanWaitForCommand.java index 6490f6d313..897c5217e8 100644 --- a/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/scan/cli/cmd/FoDScanWaitForCommand.java +++ b/fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/scan/cli/cmd/FoDScanWaitForCommand.java @@ -16,7 +16,7 @@ import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractWaitForCommand; import com.fortify.cli.common.rest.wait.WaitHelper.WaitHelperBuilder; -import com.fortify.cli.fod._common.output.mixin.FoDProductHelperMixin; +import com.fortify.cli.fod._common.output.mixin.FoDProductHelperStandardMixin; import com.fortify.cli.fod.scan.cli.mixin.FoDScanResolverMixin; import com.fortify.cli.fod.scan.helper.FoDScanHelper; import com.fortify.cli.fod.scan.helper.FoDScanStatus; @@ -27,7 +27,7 @@ @Command(name = OutputHelperMixins.WaitFor.CMD_NAME) public class FoDScanWaitForCommand extends AbstractWaitForCommand { - @Getter @Mixin FoDProductHelperMixin productHelper; + @Getter @Mixin FoDProductHelperStandardMixin productHelper; @Mixin private FoDScanResolverMixin.PositionalParameterMulti scansResolver; @Override diff --git a/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties b/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties index f7fbeb5e20..299bdce595 100644 --- a/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties +++ b/fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties @@ -104,9 +104,14 @@ fcli.fod.rest.usage.description = These commands allow for direct interaction wi somewhat similar to using 'curl' but benefiting from standard fcli functionality like session management \ (no need to manually specify Authorization header), rich output formatting options, and query functionality. fcli.fod.rest.call.usage.header = Call an individual Fortify FoD REST API endpoint. +fcli.fod.rest.call.no-paging = By default, this command will load all pages of data from FoD (from the \ + given offset if specified as a request parameter). Use this option to return only a single page. fcli.fod.rest.call.no-transform = By default, this command performs generic transformations on FoD REST \ responses, like only outputting the actual response data (contents of the 'items' property). Use this \ option to output the original response contents without transformations. +fcli.fod.rest.call.transform = This option allows for performing custom transformations on the response \ + data based on a Spring Expression Language (SpEL) expression. For example, this allows for retrieving \ + data from sub-properties, or using project selection/projection. ### For the "fod app" command ### diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/cmd/AbstractSCDastOutputCommand.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/cmd/AbstractSCDastOutputCommand.java index bf56267671..7385dc0987 100644 --- a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/cmd/AbstractSCDastOutputCommand.java +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/cmd/AbstractSCDastOutputCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.product.IProductHelperSupplier; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.sc_dast._common.output.cli.mixin.SCDastProductHelperMixin; +import com.fortify.cli.sc_dast._common.output.cli.mixin.SCDastProductHelperStandardMixin; import kong.unirest.UnirestInstance; import lombok.Getter; @@ -24,7 +24,7 @@ public abstract class AbstractSCDastOutputCommand extends AbstractOutputCommand implements IProductHelperSupplier, IUnirestInstanceSupplier { - @Getter @Mixin SCDastProductHelperMixin productHelper; + @Getter @Mixin SCDastProductHelperStandardMixin productHelper; public final UnirestInstance getUnirestInstance() { return productHelper.getUnirestInstance(); diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperMixin.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperBasicMixin.java similarity index 63% rename from fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperMixin.java rename to fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperBasicMixin.java index 9486ce499c..5b3d5bf6fa 100644 --- a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperMixin.java +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperBasicMixin.java @@ -12,46 +12,20 @@ *******************************************************************************/ package com.fortify.cli.sc_dast._common.output.cli.mixin; -import java.util.function.UnaryOperator; - -import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.http.proxy.helper.ProxyHelper; -import com.fortify.cli.common.output.cli.mixin.IOutputHelper; import com.fortify.cli.common.output.product.IProductHelper; -import com.fortify.cli.common.output.transform.IInputTransformer; -import com.fortify.cli.common.rest.paging.INextPageUrlProducer; -import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; -import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; import com.fortify.cli.common.rest.unirest.config.UnirestJsonHeaderConfigurer; import com.fortify.cli.common.rest.unirest.config.UnirestUnexpectedHttpResponseConfigurer; import com.fortify.cli.common.rest.unirest.config.UnirestUrlConfigConfigurer; import com.fortify.cli.common.session.cli.mixin.AbstractSessionUnirestInstanceSupplierMixin; -import com.fortify.cli.sc_dast._common.rest.helper.SCDastInputTransformer; -import com.fortify.cli.sc_dast._common.rest.helper.SCDastPagingHelper; import com.fortify.cli.sc_dast._common.session.helper.SCDastSessionDescriptor; import com.fortify.cli.sc_dast._common.session.helper.SCDastSessionHelper; -import kong.unirest.HttpRequest; import kong.unirest.UnirestInstance; -import lombok.Getter; -import lombok.Setter; -public class SCDastProductHelperMixin extends AbstractSessionUnirestInstanceSupplierMixin - implements IProductHelper, IInputTransformer, INextPageUrlProducerSupplier, IUnirestInstanceSupplier +public class SCDastProductHelperBasicMixin extends AbstractSessionUnirestInstanceSupplierMixin + implements IProductHelper { - @Getter @Setter private IOutputHelper outputHelper; - @Getter private UnaryOperator inputTransformer = SCDastInputTransformer::getItems; - - @Override - public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { - return SCDastPagingHelper.nextPageUrlProducer(originalRequest); - } - - @Override - public JsonNode transformInput(JsonNode input) { - return SCDastInputTransformer.getItems(input); - } - @Override protected final void configure(UnirestInstance unirest, SCDastSessionDescriptor sessionDescriptor) { UnirestUnexpectedHttpResponseConfigurer.configure(unirest); diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperStandardMixin.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperStandardMixin.java new file mode 100644 index 0000000000..caf7e6141b --- /dev/null +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/output/cli/mixin/SCDastProductHelperStandardMixin.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2021, 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors ("Open Text") are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + *******************************************************************************/ +package com.fortify.cli.sc_dast._common.output.cli.mixin; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.output.transform.IInputTransformer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; +import com.fortify.cli.sc_dast._common.rest.helper.SCDastInputTransformer; +import com.fortify.cli.sc_dast._common.rest.helper.SCDastPagingHelper; + +import kong.unirest.HttpRequest; + +// IMPORTANT: When updating/adding any methods in this class, SCDastControllerRestCallCommand +// also likely needs to be updated +public class SCDastProductHelperStandardMixin extends SCDastProductHelperBasicMixin + implements IInputTransformer, INextPageUrlProducerSupplier +{ + @Override + public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { + return SCDastPagingHelper.nextPageUrlProducer(originalRequest); + } + + @Override + public JsonNode transformInput(JsonNode input) { + return SCDastInputTransformer.getItems(input); + } +} \ No newline at end of file diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/rest/helper/SCDastPagingHelper.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/rest/helper/SCDastPagingHelper.java index 5af97efc4a..1e41ea66d1 100644 --- a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/rest/helper/SCDastPagingHelper.java +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/rest/helper/SCDastPagingHelper.java @@ -34,7 +34,9 @@ public static final INextPageUrlProducer nextPageUrlProducer(String uriString) { int totalCount = body.get("totalItems").asInt(); int limit = body.get("limit").asInt(); int newOffset = offset + limit; - if (newOffset < totalCount) { + // In exceptional cases, SC-DAST may return MAXINT for limit, in which case + // newOffset will become negative, hence we check whether newOffset > 0 + if (newOffset>0 && newOffset < totalCount) { return PagingHelper.addOrReplaceParam(uriString, "offset", newOffset); } } diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/rest/cli/cmd/SCDastRestCallCommand.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/rest/cli/cmd/SCDastRestCallCommand.java index ba07e3d13d..b62163b13f 100644 --- a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/rest/cli/cmd/SCDastRestCallCommand.java +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/rest/cli/cmd/SCDastRestCallCommand.java @@ -12,12 +12,17 @@ *******************************************************************************/ package com.fortify.cli.sc_dast.rest.cli.cmd; +import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractRestCallCommand; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; import com.fortify.cli.common.util.DisableTest; import com.fortify.cli.common.util.DisableTest.TestType; -import com.fortify.cli.sc_dast._common.output.cli.mixin.SCDastProductHelperMixin; +import com.fortify.cli.sc_dast._common.output.cli.mixin.SCDastProductHelperBasicMixin; +import com.fortify.cli.sc_dast._common.rest.helper.SCDastInputTransformer; +import com.fortify.cli.sc_dast._common.rest.helper.SCDastPagingHelper; +import kong.unirest.HttpRequest; import lombok.Getter; import picocli.CommandLine.Command; import picocli.CommandLine.Mixin; @@ -26,5 +31,20 @@ @DisableTest(TestType.CMD_DEFAULT_TABLE_OPTIONS_PRESENT) // Output columns depend on response contents public final class SCDastRestCallCommand extends AbstractRestCallCommand { @Getter @Mixin private OutputHelperMixins.RestCall outputHelper; - @Getter @Mixin SCDastProductHelperMixin productHelper; + @Getter @Mixin SCDastProductHelperBasicMixin productHelper; + + @Override + protected INextPageUrlProducer _getNextPageUrlProducer(HttpRequest originalRequest) { + return SCDastPagingHelper.nextPageUrlProducer(originalRequest); + } + + @Override + protected JsonNode _transformInput(JsonNode input) { + return SCDastInputTransformer.getItems(input); + } + + @Override + protected JsonNode _transformRecord(JsonNode input) { + return input; + } } \ No newline at end of file diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/scan/cli/cmd/SCDastScanWaitForCommand.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/scan/cli/cmd/SCDastScanWaitForCommand.java index 2f1cbc3f93..2022ccc991 100644 --- a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/scan/cli/cmd/SCDastScanWaitForCommand.java +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/scan/cli/cmd/SCDastScanWaitForCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractWaitForCommand; import com.fortify.cli.common.rest.wait.WaitHelper.WaitHelperBuilder; -import com.fortify.cli.sc_dast._common.output.cli.mixin.SCDastProductHelperMixin; +import com.fortify.cli.sc_dast._common.output.cli.mixin.SCDastProductHelperStandardMixin; import com.fortify.cli.sc_dast.scan.cli.mixin.SCDastScanResolverMixin; import com.fortify.cli.sc_dast.scan.helper.SCDastScanStatus; @@ -25,7 +25,7 @@ @Command(name = OutputHelperMixins.WaitFor.CMD_NAME) public class SCDastScanWaitForCommand extends AbstractWaitForCommand { - @Getter @Mixin SCDastProductHelperMixin productHelper; + @Getter @Mixin SCDastProductHelperStandardMixin productHelper; @Mixin private SCDastScanResolverMixin.PositionalParameterMulti scansResolver; @Override diff --git a/fcli-core/fcli-sc-dast/src/main/resources/com/fortify/cli/sc_dast/i18n/SCDastMessages.properties b/fcli-core/fcli-sc-dast/src/main/resources/com/fortify/cli/sc_dast/i18n/SCDastMessages.properties index 9f95f96db4..c7174480cc 100644 --- a/fcli-core/fcli-sc-dast/src/main/resources/com/fortify/cli/sc_dast/i18n/SCDastMessages.properties +++ b/fcli-core/fcli-sc-dast/src/main/resources/com/fortify/cli/sc_dast/i18n/SCDastMessages.properties @@ -96,9 +96,15 @@ fcli.sc-dast.rest.usage.description = These commands allow for direct interactio like session management (no need to manually specify Authorization header), rich output formatting \ options, and query functionality. fcli.sc-dast.rest.call.usage.header = Call an individual Fortify ScanCentral DAST REST API endpoint. +fcli.sc-dast.rest.call.no-paging = By default, this command will load all pages of data from ScanCentral \ + DAST (from the given offset if specified as a request parameter). Use this option to return only a \ + single page. fcli.sc-dast.rest.call.no-transform = By default, this command performs generic transformations on \ ScanCentral DAST REST responses, like only outputting the actual response data (contents of the \ 'item' or 'items' property). Use this option to output the original response contents without transformations. +fcli.sc-dast.rest.call.transform = This option allows for performing custom transformations on the response \ + data based on a Spring Expression Language (SpEL) expression. For example, this allows for retrieving \ + data from sub-properties, or using project selection/projection. # fcli sc-dast scan scan-id's[0] = One or more scan id's. diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastControllerOutputCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastControllerOutputCommand.java index 2afcc91584..3b02b53395 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastControllerOutputCommand.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastControllerOutputCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.product.IProductHelperSupplier; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastControllerProductHelperMixin; +import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastControllerProductHelperStandardMixin; import kong.unirest.UnirestInstance; import lombok.Getter; @@ -24,7 +24,7 @@ public abstract class AbstractSCSastControllerOutputCommand extends AbstractOutputCommand implements IProductHelperSupplier, IUnirestInstanceSupplier { - @Getter @Mixin SCSastControllerProductHelperMixin productHelper; + @Getter @Mixin SCSastControllerProductHelperStandardMixin productHelper; public final UnirestInstance getUnirestInstance() { return productHelper.getUnirestInstance(); diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastSSCOutputCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastSSCOutputCommand.java index 71fd60e218..995602d297 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastSSCOutputCommand.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/cmd/AbstractSCSastSSCOutputCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.product.IProductHelperSupplier; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastSSCProductHelperMixin; +import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastSSCProductHelperStandardMixin; import kong.unirest.UnirestInstance; import lombok.Getter; @@ -24,7 +24,7 @@ public abstract class AbstractSCSastSSCOutputCommand extends AbstractOutputCommand implements IProductHelperSupplier, IUnirestInstanceSupplier { - @Getter @Mixin SCSastSSCProductHelperMixin productHelper; + @Getter @Mixin SCSastSSCProductHelperStandardMixin productHelper; public final UnirestInstance getUnirestInstance() { return productHelper.getUnirestInstance(); diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperMixin.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperBasicMixin.java similarity index 66% rename from fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperMixin.java rename to fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperBasicMixin.java index dbdcacd903..c0e666d58c 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperMixin.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperBasicMixin.java @@ -12,25 +12,17 @@ *******************************************************************************/ package com.fortify.cli.sc_sast._common.output.cli.mixin; -import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.output.product.IProductHelper; -import com.fortify.cli.common.output.transform.IInputTransformer; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.sc_sast._common.rest.helper.SCSastInputTransformer; import com.fortify.cli.sc_sast._common.session.cli.mixin.AbstractSCSastUnirestInstanceSupplierMixin; import kong.unirest.UnirestInstance; -public class SCSastControllerProductHelperMixin extends AbstractSCSastUnirestInstanceSupplierMixin - implements IProductHelper, IInputTransformer, IUnirestInstanceSupplier +public class SCSastControllerProductHelperBasicMixin extends AbstractSCSastUnirestInstanceSupplierMixin + implements IProductHelper, IUnirestInstanceSupplier { @Override - public JsonNode transformInput(JsonNode input) { - return SCSastInputTransformer.getItems(input); - } - - @Override - public UnirestInstance getUnirestInstance() { + public final UnirestInstance getUnirestInstance() { return getControllerUnirestInstance(); } } \ No newline at end of file diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperStandardMixin.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperStandardMixin.java new file mode 100644 index 0000000000..8d8aa8810e --- /dev/null +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastControllerProductHelperStandardMixin.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2021, 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors ("Open Text") are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + *******************************************************************************/ +package com.fortify.cli.sc_sast._common.output.cli.mixin; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.output.transform.IInputTransformer; +import com.fortify.cli.sc_sast._common.rest.helper.SCSastInputTransformer; + +// IMPORTANT: When updating/adding any methods in this class, SCSastControllerRestCallCommand +// also likely needs to be updated +public class SCSastControllerProductHelperStandardMixin extends SCSastControllerProductHelperBasicMixin + implements IInputTransformer +{ + @Override + public JsonNode transformInput(JsonNode input) { + return SCSastInputTransformer.getItems(input); + } +} \ No newline at end of file diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperBasicMixin.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperBasicMixin.java new file mode 100644 index 0000000000..70ab833d7d --- /dev/null +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperBasicMixin.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright 2021, 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors ("Open Text") are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + *******************************************************************************/ +package com.fortify.cli.sc_sast._common.output.cli.mixin; + +import com.fortify.cli.common.output.product.IProductHelper; +import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; +import com.fortify.cli.sc_sast._common.session.cli.mixin.AbstractSCSastUnirestInstanceSupplierMixin; + +import kong.unirest.UnirestInstance; + +public class SCSastSSCProductHelperBasicMixin extends AbstractSCSastUnirestInstanceSupplierMixin + implements IProductHelper, IUnirestInstanceSupplier +{ + @Override + public final UnirestInstance getUnirestInstance() { + return getSscUnirestInstance(); + } +} \ No newline at end of file diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperMixin.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperStandardMixin.java similarity index 71% rename from fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperMixin.java rename to fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperStandardMixin.java index dd39562c23..183884e1c2 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperMixin.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/output/cli/mixin/SCSastSSCProductHelperStandardMixin.java @@ -13,20 +13,16 @@ package com.fortify.cli.sc_sast._common.output.cli.mixin; import com.fasterxml.jackson.databind.JsonNode; -import com.fortify.cli.common.output.product.IProductHelper; import com.fortify.cli.common.output.transform.IInputTransformer; import com.fortify.cli.common.rest.paging.INextPageUrlProducer; import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; -import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.sc_sast._common.session.cli.mixin.AbstractSCSastUnirestInstanceSupplierMixin; import com.fortify.cli.ssc._common.rest.helper.SSCInputTransformer; import com.fortify.cli.ssc._common.rest.helper.SSCPagingHelper; import kong.unirest.HttpRequest; -import kong.unirest.UnirestInstance; -public class SCSastSSCProductHelperMixin extends AbstractSCSastUnirestInstanceSupplierMixin - implements IProductHelper, IInputTransformer, IUnirestInstanceSupplier, INextPageUrlProducerSupplier +public class SCSastSSCProductHelperStandardMixin extends SCSastSSCProductHelperBasicMixin + implements IInputTransformer, INextPageUrlProducerSupplier { @Override public JsonNode transformInput(JsonNode input) { @@ -37,9 +33,4 @@ public JsonNode transformInput(JsonNode input) { public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { return SSCPagingHelper.nextPageUrlProducer(); } - - @Override - public UnirestInstance getUnirestInstance() { - return getSscUnirestInstance(); - } } \ No newline at end of file diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/rest/cli/cmd/SCSastControllerRestCallCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/rest/cli/cmd/SCSastControllerRestCallCommand.java index 9055c76284..6313d1d9d3 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/rest/cli/cmd/SCSastControllerRestCallCommand.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/rest/cli/cmd/SCSastControllerRestCallCommand.java @@ -12,12 +12,16 @@ *******************************************************************************/ package com.fortify.cli.sc_sast.rest.cli.cmd; +import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractRestCallCommand; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; import com.fortify.cli.common.util.DisableTest; import com.fortify.cli.common.util.DisableTest.TestType; -import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastControllerProductHelperMixin; +import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastControllerProductHelperBasicMixin; +import com.fortify.cli.sc_sast._common.rest.helper.SCSastInputTransformer; +import kong.unirest.HttpRequest; import lombok.Getter; import picocli.CommandLine.Command; import picocli.CommandLine.Mixin; @@ -26,5 +30,20 @@ @DisableTest(TestType.CMD_DEFAULT_TABLE_OPTIONS_PRESENT) // Output columns depend on response contents public final class SCSastControllerRestCallCommand extends AbstractRestCallCommand { @Getter @Mixin private OutputHelperMixins.RestCall outputHelper; - @Getter @Mixin private SCSastControllerProductHelperMixin productHelper; + @Getter @Mixin private SCSastControllerProductHelperBasicMixin productHelper; + + @Override + protected INextPageUrlProducer _getNextPageUrlProducer(HttpRequest originalRequest) { + return null; + } + + @Override + protected JsonNode _transformInput(JsonNode input) { + return SCSastInputTransformer.getItems(input); + } + + @Override + protected JsonNode _transformRecord(JsonNode input) { + return input; + } } \ No newline at end of file diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/scan/cli/cmd/SCSastControllerScanWaitForCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/scan/cli/cmd/SCSastControllerScanWaitForCommand.java index ff98c51366..58622c645f 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/scan/cli/cmd/SCSastControllerScanWaitForCommand.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/scan/cli/cmd/SCSastControllerScanWaitForCommand.java @@ -17,7 +17,7 @@ import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractWaitForCommand; import com.fortify.cli.common.rest.wait.WaitHelper.WaitHelperBuilder; -import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastControllerProductHelperMixin; +import com.fortify.cli.sc_sast._common.output.cli.mixin.SCSastControllerProductHelperStandardMixin; import com.fortify.cli.sc_sast.scan.cli.mixin.SCSastScanJobResolverMixin; import com.fortify.cli.sc_sast.scan.helper.SCSastControllerScanJobArtifactState; import com.fortify.cli.sc_sast.scan.helper.SCSastControllerScanJobState; @@ -31,7 +31,7 @@ @Command(name = OutputHelperMixins.WaitFor.CMD_NAME) public class SCSastControllerScanWaitForCommand extends AbstractWaitForCommand { - @Getter @Mixin SCSastControllerProductHelperMixin productHelper; + @Getter @Mixin SCSastControllerProductHelperStandardMixin productHelper; @Mixin private SCSastScanJobResolverMixin.PositionalParameterMulti scanJobsResolver; @Option(names={"-s", "--status-type"}, defaultValue="processing", required=true) private WaitType waitType; diff --git a/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/i18n/SCSastMessages.properties b/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/i18n/SCSastMessages.properties index e6655905fe..77bf81255a 100644 --- a/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/i18n/SCSastMessages.properties +++ b/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/i18n/SCSastMessages.properties @@ -97,7 +97,11 @@ fcli.sc-sast.rest.usage.description = These commands allow for direct interactio functionality like session management (no need to manually specify Authorization header), rich output \ formatting options, and query functionality. fcli.sc-sast.rest.call.usage.header = Call an individual ScanCentral SAST Controller REST API endpoint. +fcli.sc-sast.rest.call.no-paging = This option currently has no effect for ScanCentral SAST. fcli.sc-sast.rest.call.no-transform = This option currently has no effect for ScanCentral SAST. +fcli.sc-sast.rest.call.transform = This option allows for performing custom transformations on the response \ + data based on a Spring Expression Language (SpEL) expression. For example, this allows for retrieving \ + data from sub-properties, or using project selection/projection. # fcli sc-sast scan fcli.sc-sast.scan.usage.header = Manage ScanCentral SAST scans. diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/cmd/AbstractSSCOutputCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/cmd/AbstractSSCOutputCommand.java index af59bae7be..8249a72136 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/cmd/AbstractSSCOutputCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/cmd/AbstractSSCOutputCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand; import com.fortify.cli.common.output.product.IProductHelperSupplier; import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier; -import com.fortify.cli.ssc._common.output.cli.mixin.SSCProductHelperMixin; +import com.fortify.cli.ssc._common.output.cli.mixin.SSCProductHelperStandardMixin; import kong.unirest.UnirestInstance; import lombok.Getter; @@ -24,7 +24,7 @@ public abstract class AbstractSSCOutputCommand extends AbstractOutputCommand implements IProductHelperSupplier, IUnirestInstanceSupplier { - @Getter @Mixin SSCProductHelperMixin productHelper; + @Getter @Mixin SSCProductHelperStandardMixin productHelper; public UnirestInstance getUnirestInstance() { return productHelper.getUnirestInstance(); diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperMixin.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperBasicMixin.java similarity index 58% rename from fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperMixin.java rename to fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperBasicMixin.java index 42580a2043..95e3e76930 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperMixin.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperBasicMixin.java @@ -12,39 +12,17 @@ *******************************************************************************/ package com.fortify.cli.ssc._common.output.cli.mixin; -import java.util.function.UnaryOperator; - -import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.output.product.IProductHelper; -import com.fortify.cli.common.output.transform.IInputTransformer; -import com.fortify.cli.common.rest.paging.INextPageUrlProducer; -import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; import com.fortify.cli.common.session.cli.mixin.AbstractSessionUnirestInstanceSupplierMixin; -import com.fortify.cli.ssc._common.rest.helper.SSCInputTransformer; -import com.fortify.cli.ssc._common.rest.helper.SSCPagingHelper; import com.fortify.cli.ssc._common.session.helper.SSCSessionDescriptor; import com.fortify.cli.ssc._common.session.helper.SSCSessionHelper; import com.fortify.cli.ssc.token.helper.SSCTokenHelper; -import kong.unirest.HttpRequest; import kong.unirest.UnirestInstance; -import lombok.Getter; -public class SSCProductHelperMixin extends AbstractSessionUnirestInstanceSupplierMixin - implements IProductHelper, IInputTransformer, INextPageUrlProducerSupplier -{ - @Getter private UnaryOperator inputTransformer = SSCInputTransformer::getDataOrSelf; - - @Override - public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { - return SSCPagingHelper.nextPageUrlProducer(); - } - - @Override - public JsonNode transformInput(JsonNode input) { - return SSCInputTransformer.getDataOrSelf(input); - } - +public class SSCProductHelperBasicMixin extends AbstractSessionUnirestInstanceSupplierMixin + implements IProductHelper +{ @Override public final SSCSessionDescriptor getSessionDescriptor(String sessionName) { return SSCSessionHelper.instance().get(sessionName, true); diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperStandardMixin.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperStandardMixin.java new file mode 100644 index 0000000000..4748baf85c --- /dev/null +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/output/cli/mixin/SSCProductHelperStandardMixin.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright 2021, 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors ("Open Text") are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + *******************************************************************************/ +package com.fortify.cli.ssc._common.output.cli.mixin; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fortify.cli.common.output.transform.IInputTransformer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; +import com.fortify.cli.common.rest.paging.INextPageUrlProducerSupplier; +import com.fortify.cli.ssc._common.rest.helper.SSCInputTransformer; +import com.fortify.cli.ssc._common.rest.helper.SSCPagingHelper; + +import kong.unirest.HttpRequest; + +//IMPORTANT: When updating/adding any methods in this class, SSCRestCallCommand +//also likely needs to be updated +public class SSCProductHelperStandardMixin extends SSCProductHelperBasicMixin + implements IInputTransformer, INextPageUrlProducerSupplier +{ + @Override + public INextPageUrlProducer getNextPageUrlProducer(HttpRequest originalRequest) { + return SSCPagingHelper.nextPageUrlProducer(); + } + + @Override + public JsonNode transformInput(JsonNode input) { + return SSCInputTransformer.getDataOrSelf(input); + } +} diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/artifact/cli/cmd/SSCArtifactWaitForCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/artifact/cli/cmd/SSCArtifactWaitForCommand.java index cbe9459dd3..cbdbc0538f 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/artifact/cli/cmd/SSCArtifactWaitForCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/artifact/cli/cmd/SSCArtifactWaitForCommand.java @@ -15,7 +15,7 @@ import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractWaitForCommand; import com.fortify.cli.common.rest.wait.WaitHelper.WaitHelperBuilder; -import com.fortify.cli.ssc._common.output.cli.mixin.SSCProductHelperMixin; +import com.fortify.cli.ssc._common.output.cli.mixin.SSCProductHelperStandardMixin; import com.fortify.cli.ssc.artifact.cli.mixin.SSCArtifactResolverMixin; import com.fortify.cli.ssc.artifact.helper.SSCArtifactHelper; import com.fortify.cli.ssc.artifact.helper.SSCArtifactStatus; @@ -26,7 +26,7 @@ @Command(name = OutputHelperMixins.WaitFor.CMD_NAME) public class SSCArtifactWaitForCommand extends AbstractWaitForCommand { - @Getter @Mixin SSCProductHelperMixin productHelper; + @Getter @Mixin SSCProductHelperStandardMixin productHelper; @Mixin private SSCArtifactResolverMixin.PositionalParameterMulti artifactsResolver; @Override diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/rest/cli/cmd/SSCRestCallCommand.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/rest/cli/cmd/SSCRestCallCommand.java index b595ad3e16..48c288486b 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/rest/cli/cmd/SSCRestCallCommand.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/rest/cli/cmd/SSCRestCallCommand.java @@ -12,12 +12,17 @@ *******************************************************************************/ package com.fortify.cli.ssc.rest.cli.cmd; +import com.fasterxml.jackson.databind.JsonNode; import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins; import com.fortify.cli.common.rest.cli.cmd.AbstractRestCallCommand; +import com.fortify.cli.common.rest.paging.INextPageUrlProducer; import com.fortify.cli.common.util.DisableTest; import com.fortify.cli.common.util.DisableTest.TestType; -import com.fortify.cli.ssc._common.output.cli.mixin.SSCProductHelperMixin; +import com.fortify.cli.ssc._common.output.cli.mixin.SSCProductHelperBasicMixin; +import com.fortify.cli.ssc._common.rest.helper.SSCInputTransformer; +import com.fortify.cli.ssc._common.rest.helper.SSCPagingHelper; +import kong.unirest.HttpRequest; import lombok.Getter; import picocli.CommandLine.Command; import picocli.CommandLine.Mixin; @@ -26,5 +31,20 @@ @DisableTest(TestType.CMD_DEFAULT_TABLE_OPTIONS_PRESENT) // Output columns depend on response contents public final class SSCRestCallCommand extends AbstractRestCallCommand { @Getter @Mixin private OutputHelperMixins.RestCall outputHelper; - @Getter @Mixin private SSCProductHelperMixin productHelper; + @Getter @Mixin private SSCProductHelperBasicMixin productHelper; + + @Override + protected INextPageUrlProducer _getNextPageUrlProducer(HttpRequest originalRequest) { + return SSCPagingHelper.nextPageUrlProducer(); + } + + @Override + protected JsonNode _transformInput(JsonNode input) { + return SSCInputTransformer.getDataOrSelf(input); + } + + @Override + protected JsonNode _transformRecord(JsonNode input) { + return input; + } } \ No newline at end of file diff --git a/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties b/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties index b23abbd38c..6041597047 100644 --- a/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties +++ b/fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties @@ -108,9 +108,15 @@ fcli.ssc.rest.usage.description = These commands allow for direct interaction wi somewhat similar to using 'curl' but benefiting from standard fcli functionality like session management \ (no need to manually specify Authorization header), rich output formatting options, and query functionality. fcli.ssc.rest.call.usage.header = Call an individual Fortify SSC REST API endpoint. +fcli.ssc.rest.call.no-paging = By default, this command will load all pages of data from SSC \ + (from the given offset if specified as a request parameter). Use this option to return only a \ + single page. fcli.ssc.rest.call.no-transform = By default, this command performs generic transformations on SSC REST \ responses, like only outputting the actual response data (contents of the 'data' property). Use this \ option to output the original response contents without transformations. +fcli.ssc.rest.call.transform = This option allows for performing custom transformations on the response \ + data based on a Spring Expression Language (SpEL) expression. For example, this allows for retrieving \ + data from sub-properties, or using project selection/projection. # fcli ssc activity-feed fcli.ssc.activity-feed.usage.header = Manage SSC activity feed. diff --git a/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCRestCallSpec.groovy b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCRestCallSpec.groovy new file mode 100644 index 0000000000..d947628352 --- /dev/null +++ b/fcli-other/fcli-functional-test/src/ftest/groovy/com/fortify/cli/ftest/ssc/SSCRestCallSpec.groovy @@ -0,0 +1,43 @@ +/** + * Copyright 2023 Open Text. + * + * The only warranties for products and services of Open Text + * and its affiliates and licensors ("Open Text") are as may + * be set forth in the express warranty statements accompanying + * such products and services. Nothing herein should be construed + * as constituting an additional warranty. Open Text shall not be + * liable for technical or editorial errors or omissions contained + * herein. The information contained herein is subject to change + * without notice. + */ +package com.fortify.cli.ftest.ssc + +import static com.fortify.cli.ftest._common.spec.FcliSessionType.SSC + +import com.fortify.cli.ftest._common.Fcli +import com.fortify.cli.ftest._common.spec.FcliBaseSpec +import com.fortify.cli.ftest._common.spec.FcliSession +import com.fortify.cli.ftest._common.spec.Prefix +import com.fortify.cli.ftest.ssc._common.SSCAppVersion + +import spock.lang.AutoCleanup +import spock.lang.Shared + +@Prefix("ssc.rest.call") @FcliSession(SSC) +class SSCRestCallSpec extends FcliBaseSpec { + @Shared @AutoCleanup SSCAppVersion version = new SSCAppVersion().create() + + def "session-info"() { + def args = ["ssc", "rest", "call", "-X", "POST", "/api/v1/userSession/info", "-d", "ignored"] + when: + def result = Fcli.run(args) + then: + verifyAll(result.stdout) { + size()>0 + it[0] == '---' + it[1].startsWith '- ' + it.any { it =~ 'username' } + it.any { it =~ 'permissions' } + } + } +}