From fea49b2c0839c4851b2e449b6a5e922cc5a610c4 Mon Sep 17 00:00:00 2001
From: Ruud Senden <8635138+rsenden@users.noreply.github.com>
Date: Fri, 9 Feb 2024 18:23:51 +0100
Subject: [PATCH] chore: Partial data-extract implementation
---
.../expression/wrapper/SimpleExpression.java | 47 +++
.../wrapper/SimpleExpressionDeserializer.java | 55 ++++
.../wrapper/TemplateExpression.java | 47 +++
.../TemplateExpressionDeserializer.java | 58 ++++
.../expression/wrapper/WrappedExpression.java | 292 ++++++++++++++++++
.../sc_sast/_main/cli/cmd/SCSastCommands.java | 2 +
.../cmd/AbstractDataExtractCreateCommand.java | 173 +++++++++++
...stractDataExtractListTemplatesCommand.java | 32 ++
.../helper/DataExtractParamHelper.java | 25 ++
.../_common/helper/DataExtractRestHelper.java | 39 +++
.../helper/DataExtractTemplateDescriptor.java | 60 ++++
.../helper/DataExtractTemplateHelper.java | 86 ++++++
.../cli/cmd/SCSastDataExtractCommands.java | 26 ++
.../cmd/SCSastDataExtractCreateCommand.java | 55 ++++
.../cli/data_extract/templates/SC-SAST.zip | Bin 200 -> 0 bytes
.../templates/github-code-scanning.yaml | 19 ++
.../sc_sast/i18n/SCSastMessages.properties | 6 +
17 files changed, 1022 insertions(+)
create mode 100644 fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpression.java
create mode 100644 fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpressionDeserializer.java
create mode 100644 fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpression.java
create mode 100644 fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpressionDeserializer.java
create mode 100644 fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/WrappedExpression.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractCreateCommand.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractListTemplatesCommand.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractParamHelper.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractRestHelper.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateDescriptor.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateHelper.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCommands.java
create mode 100644 fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCreateCommand.java
delete mode 100644 fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/data_extract/templates/SC-SAST.zip
create mode 100644 fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/data_extract/templates/github-code-scanning.yaml
diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpression.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpression.java
new file mode 100644
index 0000000000..23625e90f1
--- /dev/null
+++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpression.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * (c) Copyright 2020 Micro Focus or one of its affiliates, a Micro Focus company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ ******************************************************************************/
+package com.fortify.cli.common.spring.expression.wrapper;
+
+import org.springframework.expression.Expression;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+/**
+ *
This is a simple wrapper class for a Spring {@link Expression}
+ * instance. It's main use is in combination with
+ * {@link SimpleExpressionDeserializer} to allow automatic
+ * conversion from String values to simple {@link Expression}
+ * instances in JSON/YAML documents.
+ *
+ * The reason for needing this wrapper class is to differentiate
+ * with templated {@link Expression} instances that are handled
+ * by {@link TemplateExpressionDeserializer}.
+ */
+@JsonDeserialize(using = SimpleExpressionDeserializer.class)
+public class SimpleExpression extends WrappedExpression {
+ public SimpleExpression(Expression target) {
+ super(target);
+ }
+}
diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpressionDeserializer.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpressionDeserializer.java
new file mode 100644
index 0000000000..790d39d63f
--- /dev/null
+++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/SimpleExpressionDeserializer.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * (c) Copyright 2020 Micro Focus or one of its affiliates, a Micro Focus company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ ******************************************************************************/
+package com.fortify.cli.common.spring.expression.wrapper;
+
+import java.io.IOException;
+
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+/**
+ * This Jackson deserializer allows parsing String values into an
+ * SpEL Expression object.
+ */
+@Component
+public final class SimpleExpressionDeserializer extends StdDeserializer {
+ private static final long serialVersionUID = 1L;
+ private static final SpelExpressionParser parser = new SpelExpressionParser();
+ public SimpleExpressionDeserializer() { this(null); }
+ public SimpleExpressionDeserializer(Class> vc) { super(vc); }
+
+ @Override
+ public SimpleExpression deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+ JsonNode node = jp.getCodec().readTree(jp);
+ return node==null || node.isNull() ? null : new SimpleExpression(parser.parseExpression(node.asText()));
+ }
+}
diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpression.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpression.java
new file mode 100644
index 0000000000..ec37450f8d
--- /dev/null
+++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpression.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * (c) Copyright 2020 Micro Focus or one of its affiliates, a Micro Focus company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ ******************************************************************************/
+package com.fortify.cli.common.spring.expression.wrapper;
+
+import org.springframework.expression.Expression;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+/**
+ * This is a simple wrapper class for a Spring {@link Expression}
+ * instance. It's main use is in combination with
+ * {@link TemplateExpressionDeserializer} to allow automatic
+ * conversion from String values to templated {@link Expression}
+ * instances.
+ *
+ * The reason for needing this wrapper class is to differentiate
+ * with non-templated {@link Expression} instances that are
+ * handled by {@link SimpleExpressionDeserializer}.
+ */
+@JsonDeserialize(using = TemplateExpressionDeserializer.class)
+public class TemplateExpression extends WrappedExpression {
+ public TemplateExpression(Expression target) {
+ super(target);
+ }
+}
diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpressionDeserializer.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpressionDeserializer.java
new file mode 100644
index 0000000000..7ad93c0af3
--- /dev/null
+++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/TemplateExpressionDeserializer.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * (c) Copyright 2020 Micro Focus or one of its affiliates, a Micro Focus company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ ******************************************************************************/
+package com.fortify.cli.common.spring.expression.wrapper;
+
+import java.beans.PropertyEditor;
+import java.io.IOException;
+
+import org.springframework.expression.common.TemplateParserContext;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+/**
+ * This {@link PropertyEditor} allows parsing String values into a
+ * TemplateExpression object.
+ */
+@Component
+public final class TemplateExpressionDeserializer extends StdDeserializer {
+ private static final long serialVersionUID = 1L;
+ private static final SpelExpressionParser parser = new SpelExpressionParser();
+ private static final TemplateParserContext templateContext = new TemplateParserContext("${","}");
+ public TemplateExpressionDeserializer() { this(null); }
+ public TemplateExpressionDeserializer(Class> vc) { super(vc); }
+
+ @Override
+ public TemplateExpression deserialize(JsonParser jp, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+ JsonNode node = jp.getCodec().readTree(jp);
+ return node==null || node.isNull() ? null : new TemplateExpression(parser.parseExpression(node.asText(), templateContext));
+ }
+}
diff --git a/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/WrappedExpression.java b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/WrappedExpression.java
new file mode 100644
index 0000000000..c06bbe1132
--- /dev/null
+++ b/fcli-core/fcli-common/src/main/java/com/fortify/cli/common/spring/expression/wrapper/WrappedExpression.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * (c) Copyright 2020 Micro Focus or one of its affiliates, a Micro Focus company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including without
+ * limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ ******************************************************************************/
+package com.fortify.cli.common.spring.expression.wrapper;
+
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.EvaluationException;
+import org.springframework.expression.Expression;
+
+/**
+ * This is a simple wrapper class for a Spring {@link Expression}
+ * instance. This class is used as a based class for both
+ * {@link SimpleExpression} and {@link TemplateExpression}.
+ */
+public class WrappedExpression implements Expression {
+ private final Expression target;
+
+ /**
+ * Constructor for configuring the expression to be wrapped
+ * @param target {@link Expression} to be wrapped
+ */
+ public WrappedExpression(Expression target) {
+ this.target = target;
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue()
+ * @return The evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public Object getValue() throws EvaluationException {
+ return target.getValue();
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(Object)
+ * @param rootObject the root object against which to evaluate the expression
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public Object getValue(Object rootObject) throws EvaluationException {
+ return target.getValue(rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(java.lang.Class)
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public T getValue(Class desiredResultType) throws EvaluationException {
+ return target.getValue(desiredResultType);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(Object, java.lang.Class)
+ * @param rootObject the root object against which to evaluate the expression
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public T getValue(Object rootObject,Class desiredResultType) throws EvaluationException {
+ return target.getValue(rootObject, desiredResultType);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(EvaluationContext)
+ * @param context the context in which to evaluate the expression
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ *
+ */
+ public Object getValue(EvaluationContext context) throws EvaluationException {
+ return target.getValue(context);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(EvaluationContext, Object)
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ *
+ */
+ public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return target.getValue(context, rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(EvaluationContext, java.lang.Class)
+ * @param context the context in which to evaluate the expression
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public T getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException {
+ return target.getValue(context, desiredResultType);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValue(EvaluationContext, Object, java.lang.Class)
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @param desiredResultType the class the caller would like the result to be
+ * @return the evaluation result
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType) throws EvaluationException {
+ return target.getValue(context, rootObject, desiredResultType);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueType()
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public Class> getValueType() throws EvaluationException {
+ return target.getValueType();
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueType(Object)
+ * @param rootObject the root object against which to evaluate the expression
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public Class> getValueType(Object rootObject) throws EvaluationException {
+ return target.getValueType(rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueType(EvaluationContext)
+ * @param context the context in which to evaluate the expression
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public Class> getValueType(EvaluationContext context) throws EvaluationException {
+ return target.getValueType(context);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueType(EvaluationContext, Object)
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @return the most general type of value that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public Class> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return target.getValueType(context, rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueTypeDescriptor()
+ * @return a type descriptor for values that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
+ return target.getValueTypeDescriptor();
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueTypeDescriptor(Object)
+ * @param rootObject the root object against which to evaluate the expression
+ * @return a type descriptor for values that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
+ return target.getValueTypeDescriptor(rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueTypeDescriptor(EvaluationContext)
+ * @param context the context in which to evaluate the expression
+ * @return a type descriptor for values that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
+ return target.getValueTypeDescriptor(context);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getValueTypeDescriptor(EvaluationContext, Object)
+ * @param context the context in which to evaluate the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @return a type descriptor for values that can be set on this context
+ * @throws EvaluationException if there is a problem determining the type
+ */
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return target.getValueTypeDescriptor(context, rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#isWritable(EvaluationContext)
+ * @param context the context in which the expression should be checked
+ * @return {@code true} if the expression is writable; {@code false} otherwise
+ * @throws EvaluationException if there is a problem determining if it is writable
+ */
+ public boolean isWritable(EvaluationContext context) throws EvaluationException {
+ return target.isWritable(context);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#isWritable(EvaluationContext, Object)
+ * @param context the context in which the expression should be checked
+ * @param rootObject the root object against which to evaluate the expression
+ * @return {@code true} if the expression is writable; {@code false} otherwise
+ * @throws EvaluationException if there is a problem determining if it is writable
+ */
+ public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
+ return target.isWritable(context, rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#isWritable(Object)
+ * @param rootObject the root object against which to evaluate the expression
+ * @return {@code true} if the expression is writable; {@code false} otherwise
+ * @throws EvaluationException if there is a problem determining if it is writable
+ */
+ public boolean isWritable(Object rootObject) throws EvaluationException {
+ return target.isWritable(rootObject);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#setValue(EvaluationContext, Object)
+ * @param context the context in which to set the value of the expression
+ * @param value the new value
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public void setValue(EvaluationContext context, Object value) throws EvaluationException {
+ target.setValue(context, value);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#setValue(Object, Object)
+ * @param rootObject the root object against which to evaluate the expression
+ * @param value the new value
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public void setValue(Object rootObject, Object value) throws EvaluationException {
+ target.setValue(rootObject, value);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#setValue(EvaluationContext, Object, Object)
+ * @param context the context in which to set the value of the expression
+ * @param rootObject the root object against which to evaluate the expression
+ * @param value the new value
+ * @throws EvaluationException if there is a problem during evaluation
+ */
+ public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
+ target.setValue(context, rootObject, value);
+ }
+
+ /**
+ * @see org.springframework.expression.Expression#getExpressionString()
+ * @return the original expression string
+ */
+ public String getExpressionString() {
+ return target.getExpressionString();
+ }
+
+ /**
+ * @return String representation for this {@link WrappedExpression}
+ */
+ @Override
+ public String toString() {
+ return this.getClass().getSimpleName()+"("+getExpressionString()+")";
+ }
+
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_main/cli/cmd/SCSastCommands.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_main/cli/cmd/SCSastCommands.java
index 299f8bf401..52b45d2985 100644
--- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_main/cli/cmd/SCSastCommands.java
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_main/cli/cmd/SCSastCommands.java
@@ -14,6 +14,7 @@
import com.fortify.cli.common.cli.cmd.AbstractContainerCommand;
import com.fortify.cli.sc_sast._common.session.cli.cmd.SCSastSessionCommands;
+import com.fortify.cli.sc_sast.data_extract.cli.cmd.SCSastDataExtractCommands;
import com.fortify.cli.sc_sast.rest.cli.cmd.SCSastControllerRestCommands;
import com.fortify.cli.sc_sast.scan.cli.cmd.SCSastScanCommands;
import com.fortify.cli.sc_sast.sensor.cli.cmd.SCSastSensorCommands;
@@ -33,6 +34,7 @@
// 'rest' has a different header ('Interact with' compared to most
// other commands ('Manage').
SCSastSessionCommands.class,
+ SCSastDataExtractCommands.class,
SCSastScanCommands.class,
SCSastSensorCommands.class,
SCSastControllerRestCommands.class,
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractCreateCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractCreateCommand.java
new file mode 100644
index 0000000000..a67fa9e2ee
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractCreateCommand.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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.data_extract._common.cli.cmd;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.BooleanNode;
+import com.fasterxml.jackson.databind.node.DoubleNode;
+import com.fasterxml.jackson.databind.node.FloatNode;
+import com.fasterxml.jackson.databind.node.IntNode;
+import com.fasterxml.jackson.databind.node.LongNode;
+import com.fasterxml.jackson.databind.node.NullNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.node.TextNode;
+import com.fortify.cli.common.cli.cmd.AbstractRunnableCommand;
+import com.fortify.cli.common.json.JsonHelper;
+import com.fortify.cli.common.progress.cli.mixin.ProgressWriterFactoryMixin;
+import com.fortify.cli.common.progress.helper.IProgressWriterI18n;
+import com.fortify.cli.common.spring.expression.wrapper.TemplateExpression;
+import com.fortify.cli.common.util.StringUtils;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractParamHelper;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractRestHelper;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractTemplateDescriptor;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractTemplateDescriptor.DataExtractTemplateParameterDescriptor;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractTemplateDescriptor.DataExtractTemplateRequestDescriptor;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractTemplateHelper;
+
+import lombok.Builder;
+import lombok.RequiredArgsConstructor;
+import picocli.CommandLine.Mixin;
+import picocli.CommandLine.Option;
+
+public abstract class AbstractDataExtractCreateCommand extends AbstractRunnableCommand implements Runnable {
+ @Option(names={"-t", "--template"}, required=true)
+ private String template;
+ @Option(names={"-p", "--parameters"}, required=false, split=",")
+ private Map parameters = new LinkedHashMap<>();
+ @Mixin private ProgressWriterFactoryMixin progressWriterFactory;
+
+ @Override
+ public final void run() {
+ initMixins();
+ try ( var progressWriter = progressWriterFactory.create() ) {
+ progressWriter.writeProgress("Loading template %s", template);
+ var templateDescriptor = DataExtractTemplateHelper.load(getType(), template);
+ progressWriter.writeProgress("Evaluating parameters");
+ var parameterValues = new DataExtractParameterBuilder(
+ templateDescriptor, toMap(getParamHelpers(), DataExtractParamHelper::getType), parameters).build();
+ DataExtractRunner.builder()
+ .progressWriter(progressWriter)
+ .data(parameterValues)
+ .restHelpers(toMap(getRestHelpers(), DataExtractRestHelper::getName))
+ .template(templateDescriptor)
+ .build().run();
+ }
+ }
+
+ protected abstract List getRestHelpers();
+ protected abstract List getParamHelpers();
+
+ protected abstract String getType();
+
+ private static final Map toMap(List list, Function keyFunction) {
+ return list.stream().collect(Collectors.toMap(keyFunction, Function.identity()));
+ }
+
+ @RequiredArgsConstructor
+ private static final class DataExtractParameterBuilder {
+ private static final ObjectMapper objectMapper = JsonHelper.getObjectMapper();
+ private final DataExtractTemplateDescriptor template;
+ private final Map paramHelpers;
+ private final Map parameterValues;
+
+ public final ObjectNode build() {
+ var result = objectMapper.createObjectNode();
+ var templateParameters = template.getParameters();
+ if ( templateParameters!=null ) {
+ templateParameters.forEach(p->addParameter(result, p));
+ }
+ return result;
+ }
+
+ private void addParameter(ObjectNode result, DataExtractTemplateParameterDescriptor parameter) {
+ var name = parameter.getName();
+ var value = parameterValues.get(name);
+ if ( value==null ) {
+ var defaultValueExpression = parameter.getDefaultValue();
+ value = defaultValueExpression==null
+ ? null
+ : defaultValueExpression.getValue(result, String.class);
+ }
+ result.set(name, convert(value, parameter));
+ }
+
+ private JsonNode convert(String value, DataExtractTemplateParameterDescriptor parameter) {
+ var name = parameter.getName();
+ var type = StringUtils.isBlank(parameter.getType()) ? "string" : parameter.getType();
+ var required = parameter.isRequired();
+ if ( StringUtils.isBlank(value) && required ) {
+ throw new IllegalArgumentException(String.format("Required parameter %s not specified", name));
+ }
+ if ( value==null ) { return NullNode.instance; }
+ try {
+ switch (type.toLowerCase()) {
+ case "string": return new TextNode(value);
+ case "boolean": return BooleanNode.valueOf(Boolean.parseBoolean(value));
+ case "int": return IntNode.valueOf(Integer.parseInt(value));
+ case "long": return LongNode.valueOf(Long.parseLong(value));
+ case "double": return DoubleNode.valueOf(Double.parseDouble(value));
+ case "float": return FloatNode.valueOf(Float.parseFloat(value));
+ // TODO Add BigIntegerNode/DecimalNode/ShortNode support?
+ }
+ } catch ( RuntimeException e ) {
+ throw new IllegalArgumentException(String.format("Error converting %s to %s for parameter %s", value, type, name), e);
+ }
+ var paramHelper = paramHelpers.get(type);
+ if ( paramHelper!=null ) {
+ return paramHelper.getConverter().apply(value);
+ } else {
+ throw new IllegalStateException(String.format("Unknown parameter type %s for parameter %s", type, name));
+ }
+ }
+
+ }
+
+ @Builder
+ private static final class DataExtractRunner implements Runnable {
+ private final IProgressWriterI18n progressWriter;
+ private final DataExtractTemplateDescriptor template;
+ private final ObjectNode data;
+ private final Map restHelpers;
+
+ @Override
+ public void run() {
+ template.getRequests().forEach(this::executeRequest);
+ }
+
+ private void executeRequest(DataExtractTemplateRequestDescriptor requestDescriptor) {
+ var name = requestDescriptor.getName();
+ var from = requestDescriptor.getFrom();
+ var uri = JsonHelper.evaluateSpelExpression(data, requestDescriptor.getUri(), String.class);
+ var query = evaluateQuery(requestDescriptor.getQuery());
+ var helper = restHelpers.get(from);
+ // TODO Handle paging
+ // TODO Handle forEach
+ var body = helper.getUnirestInstance().get(uri).queryString(query).asObject(JsonNode.class).getBody();
+
+ System.out.println(body);
+ }
+
+ private Map evaluateQuery(Map queryExpressions) {
+ Map result = new LinkedHashMap<>(queryExpressions.size());
+ queryExpressions.entrySet().forEach(e->result.put(e.getKey(), JsonHelper.evaluateSpelExpression(data, e.getValue(), String.class)));
+ return result;
+ }
+ }
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractListTemplatesCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractListTemplatesCommand.java
new file mode 100644
index 0000000000..1f43f133b1
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/cli/cmd/AbstractDataExtractListTemplatesCommand.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.data_extract._common.cli.cmd;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fortify.cli.common.output.cli.cmd.AbstractOutputCommand;
+import com.fortify.cli.common.output.cli.cmd.IJsonNodeSupplier;
+
+public abstract class AbstractDataExtractListTemplatesCommand extends AbstractOutputCommand implements IJsonNodeSupplier {
+ @Override
+ public final JsonNode getJsonNode() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ @Override
+ public final boolean isSingular() {
+ return false;
+ }
+ protected abstract String getType();
+
+
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractParamHelper.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractParamHelper.java
new file mode 100644
index 0000000000..0233bf1a72
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractParamHelper.java
@@ -0,0 +1,25 @@
+/**
+ * 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.sc_sast.data_extract._common.helper;
+
+import java.util.function.Function;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import lombok.Data;
+
+@Data
+public final class DataExtractParamHelper {
+ private final String type;
+ private final Function converter;
+}
\ No newline at end of file
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractRestHelper.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractRestHelper.java
new file mode 100644
index 0000000000..aa09e50f53
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractRestHelper.java
@@ -0,0 +1,39 @@
+/**
+ * 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.sc_sast.data_extract._common.helper;
+
+import com.fortify.cli.common.output.product.IProductHelper;
+import com.fortify.cli.common.rest.unirest.IUnirestInstanceSupplier;
+
+import kong.unirest.UnirestInstance;
+import lombok.Data;
+
+@Data
+public final class DataExtractRestHelper implements AutoCloseable {
+ private final String name;
+ private final IUnirestInstanceSupplier unirestInstanceSupplier;
+ private final IProductHelper productHelper;
+ private UnirestInstance unirestInstance;
+ public final UnirestInstance getUnirestInstance() {
+ if ( unirestInstance==null ) {
+ unirestInstance = unirestInstanceSupplier.getUnirestInstance();
+ }
+ return unirestInstance;
+ }
+ @Override
+ public void close() throws Exception {
+ if ( unirestInstance!=null ) {
+ unirestInstance.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateDescriptor.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateDescriptor.java
new file mode 100644
index 0000000000..ace9e26f63
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateDescriptor.java
@@ -0,0 +1,60 @@
+/**
+ * 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.sc_sast.data_extract._common.helper;
+
+import java.util.List;
+import java.util.Map;
+
+import com.formkiq.graalvm.annotations.Reflectable;
+import com.fortify.cli.common.spring.expression.wrapper.TemplateExpression;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Reflectable @NoArgsConstructor
+@Data
+public class DataExtractTemplateDescriptor {
+ private String name; // Set based on filename during load
+ private String description;
+ private List parameters;
+ private List requests;
+
+ @Reflectable @NoArgsConstructor
+ @Data
+ public static final class DataExtractTemplateParameterDescriptor {
+ private String name;
+ private String description;
+ private String type;
+ private TemplateExpression defaultValue;
+ private boolean required = true;
+ }
+
+ @Reflectable @NoArgsConstructor
+ @Data
+ public static final class DataExtractTemplateRequestDescriptor {
+ private String name;
+ private TemplateExpression uri;
+ private String from;
+ private Map query;
+ private DataExtractTemplateRequestForEachDescriptor forEach;
+ }
+
+ @Reflectable @NoArgsConstructor
+ @Data
+ public static final class DataExtractTemplateRequestForEachDescriptor {
+ private String name;
+ private List requests;
+ }
+
+
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateHelper.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateHelper.java
new file mode 100644
index 0000000000..3b6918046b
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/_common/helper/DataExtractTemplateHelper.java
@@ -0,0 +1,86 @@
+/**
+ * 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.sc_sast.data_extract._common.helper;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fortify.cli.common.util.FileUtils;
+
+import lombok.SneakyThrows;
+
+public class DataExtractTemplateHelper {
+ private static final ObjectMapper yamlObjectMapper = new ObjectMapper(new YAMLFactory());
+ private DataExtractTemplateHelper() {}
+
+ public static final DataExtractTemplateDescriptor load(String type, String name) {
+ var resourceFile = getTemplateResourceFile(type, name);
+ try ( var is = FileUtils.getResourceInputStream(resourceFile) ) {
+ return load(resourceFile, is);
+ } catch ( IOException e ) {
+ throw new RuntimeException("Error loading template "+name, e);
+ }
+ }
+
+ public static final Stream list(String type) {
+ return Stream.of(getTemplateResources(type))
+ .map(DataExtractTemplateHelper::load);
+ }
+
+ private static final String getTemplatesResourceDir(String type) {
+ return String.format("com/fortify/cli/%s/data_extract/templates", type.toLowerCase().replace('-', '_'));
+ }
+
+ private static final String getTemplateResourceFile(String type, String name) {
+ return String.format("%s/%s.yaml", getTemplatesResourceDir(type), name);
+ }
+
+ @SneakyThrows
+ private static final Resource[] getTemplateResources(String type) {
+ var matchPattern = String.format("%s/*.yaml", getTemplatesResourceDir(type));
+ return new PathMatchingResourcePatternResolver().getResources(matchPattern);
+ }
+
+ private static final DataExtractTemplateDescriptor load(String fileName, InputStream is) {
+ if ( is==null ) {
+ // TODO Use more descriptive exception message
+ throw new IllegalStateException("Can't read "+fileName);
+ }
+ try {
+ var result = yamlObjectMapper.readValue(is, DataExtractTemplateDescriptor.class);
+ result.setName(getTemplateName(fileName));
+ return result;
+ } catch (IOException e) {
+ throw new RuntimeException("Error loading template "+fileName, e);
+ }
+ }
+
+ private static final DataExtractTemplateDescriptor load(Resource resource) {
+ try ( var is = resource.getInputStream() ) {
+ return load(resource.getFilename(), is);
+ } catch (IOException e) {
+ throw new RuntimeException("Error loading template "+resource.getFilename(), e);
+ }
+ }
+
+ private static final String getTemplateName(String fileName) {
+ return Path.of(fileName).getFileName().toString().replace(".yaml", "");
+ }
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCommands.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCommands.java
new file mode 100644
index 0000000000..2f0eb66b36
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCommands.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * 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.data_extract.cli.cmd;
+
+import com.fortify.cli.common.cli.cmd.AbstractContainerCommand;
+
+import picocli.CommandLine.Command;
+
+@Command(
+ name = "data-extract",
+ subcommands = {
+ SCSastDataExtractCreateCommand.class,
+ }
+)
+public class SCSastDataExtractCommands extends AbstractContainerCommand {
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCreateCommand.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCreateCommand.java
new file mode 100644
index 0000000000..fa02f85f21
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/data_extract/cli/cmd/SCSastDataExtractCreateCommand.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.data_extract.cli.cmd;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins;
+import com.fortify.cli.sc_sast._common.rest.helper.SCSastControllerProductHelper;
+import com.fortify.cli.sc_sast._common.rest.helper.SCSastSSCProductHelper;
+import com.fortify.cli.sc_sast._common.session.cli.mixin.SCSastUnirestInstanceSupplierMixin;
+import com.fortify.cli.sc_sast.data_extract._common.cli.cmd.AbstractDataExtractCreateCommand;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractParamHelper;
+import com.fortify.cli.sc_sast.data_extract._common.helper.DataExtractRestHelper;
+import com.fortify.cli.ssc.appversion.helper.SSCAppVersionHelper;
+
+import lombok.Getter;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.Mixin;
+
+@Command(name = OutputHelperMixins.Create.CMD_NAME)
+public class SCSastDataExtractCreateCommand extends AbstractDataExtractCreateCommand {
+ @Getter @Mixin private SCSastUnirestInstanceSupplierMixin unirestInstanceSupplier;
+
+ @Override
+ protected final String getType() {
+ return "SC-SAST";
+ }
+
+ @Override
+ protected final List getRestHelpers() {
+ return Arrays.asList(
+ new DataExtractRestHelper("ssc", unirestInstanceSupplier::getSscUnirestInstance, SCSastSSCProductHelper.INSTANCE),
+ new DataExtractRestHelper("sc-sast", unirestInstanceSupplier::getControllerUnirestInstance, SCSastControllerProductHelper.INSTANCE)
+ );
+ }
+
+ @Override
+ protected final List getParamHelpers() {
+ return Arrays.asList(
+ new DataExtractParamHelper("appversion_single", v->
+ SSCAppVersionHelper.getRequiredAppVersion(unirestInstanceSupplier.getSscUnirestInstance(), v, ":").asJsonNode())
+ );
+ }
+}
diff --git a/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/data_extract/templates/SC-SAST.zip b/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/data_extract/templates/SC-SAST.zip
deleted file mode 100644
index 1b82ba32a22f924c0992f82213ceb0041b8bc8f2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 200
zcmWIWW@h1H00Dj%j|eaWN=P!uFr;UeWRxc9Cg-Q5>J}#_=H+GPrR!BD=H`Tka56CW
zHXlg^;nE6j21b?_%nS@*BEXxGNsbwpp%QRAmNbHxc&uQBSb0l6t
F0RY0&CsY6c
diff --git a/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/data_extract/templates/github-code-scanning.yaml b/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/data_extract/templates/github-code-scanning.yaml
new file mode 100644
index 0000000000..5deb837905
--- /dev/null
+++ b/fcli-core/fcli-sc-sast/src/main/resources/com/fortify/cli/sc_sast/data_extract/templates/github-code-scanning.yaml
@@ -0,0 +1,19 @@
+description: |
+ bla
+
+parameters:
+ - name: appversion
+ type: appversion_single
+
+requests:
+ - name: issues
+ uri: /api/v1/projectVersions/${appversion.id}/issues
+ query:
+ filter: ISSUE[11111111-1111-1111-1111-111111111151]:SCA
+ from: ssc
+ forEach:
+ name: issue
+ requests:
+ - name: issue-details
+ uri: /api/v1/issueDetails/${issue.id}
+ from: ssc
\ No newline at end of file
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 9c79d702ee..c2b599dc69 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
@@ -101,6 +101,12 @@ fcli.sc-sast.session.list.usage.description.1 = For sessions created using user
fcli.sc-sast.session.list.usage.description.2 = For sessions created using a pre-generated token, fcli cannot \
display session expiration date or status, as SSC doesn't allow for obtaining this information.
+# fcli sc-sast data-extract
+fcli.sc-sast.data-extract.usage.header = TODO
+fcli.sc-sast.data-extract.create.usage.header = TODO
+fcli.sc-sast.data-extract.create.template = TODO
+fcli.sc-sast.data-extract.create.parameters = TODO
+
# fcli sc-sast scan
fcli.sc-sast.scan.usage.header = Manage ScanCentral SAST scans.
fcli.sc-sast.scan.cancel.usage.header = Cancel a previously submitted scan request.