Skip to content

Commit

Permalink
feat: FoD: fcli fod app create-web-app add option `--auto-required-…
Browse files Browse the repository at this point in the history
…attrs` to automatically set required attribute values (closes #311)

chore: correct descriptions of application:release mixin
  • Loading branch information
kadraman committed Jun 1, 2023
1 parent f9b262d commit c32e604
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.ArrayList;
import java.util.Map;

@ReflectiveAccess
@Data
@EqualsAndHashCode(callSuper = true)
Expand All @@ -42,6 +45,6 @@ public class FoDAttributeDescriptor extends JsonNodeHolder {
private String attributeDataType;
private Boolean isRequired;
private Boolean isRestricted;
// pickListValues ...
private ArrayList<FoDPickListDescriptor> picklistValues;
private String value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,23 @@
******************************************************************************/
package com.fortify.cli.fod.entity.app.attr.cli.helper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.*;

import javax.validation.ValidationException;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fortify.cli.common.json.JsonHelper;
import com.fortify.cli.fod.entity.lookup.helper.FoDLookupDescriptor;
import com.fortify.cli.fod.rest.FoDUrls;

import kong.unirest.GetRequest;
import kong.unirest.UnirestInstance;
import lombok.Getter;
import lombok.SneakyThrows;

public class FoDAttributeHelper {
@Getter private static ObjectMapper objectMapper = new ObjectMapper();
Expand All @@ -61,6 +62,43 @@ public static final FoDAttributeDescriptor getAttributeDescriptor(UnirestInstanc
return attr.size() == 0 ? null : JsonHelper.treeToValue(attr.get(0), FoDAttributeDescriptor.class);
}

@SneakyThrows
public static final Map<String, String> getRequiredAttributes(UnirestInstance unirestInstance) {
Map<String, String> reqAttrs = new HashMap<>();
GetRequest request = unirestInstance.get(FoDUrls.ATTRIBUTES)
.queryString("filters", "isRequired:true");
JsonNode items = request.asObject(ObjectNode.class).getBody().get("items");
List<FoDAttributeDescriptor> lookupList = objectMapper.readValue(objectMapper.writeValueAsString(items),
new TypeReference<List<FoDAttributeDescriptor>>() {
});
Iterator<FoDAttributeDescriptor> lookupIterator = lookupList.iterator();
while (lookupIterator.hasNext()) {
FoDAttributeDescriptor currentLookup = lookupIterator.next();
// currentLookup.getAttributeTypeId() == 1 is "Application" - filter above does not support querying on this yet!
if (currentLookup.getIsRequired() && currentLookup.getAttributeTypeId() == 1) {
switch (currentLookup.getAttributeDataType()) {
case "Text":
reqAttrs.put(currentLookup.getName(), "autofilled by fcli");
break;
case "Boolean":
reqAttrs.put(currentLookup.getName(), String.valueOf(false));
break;
case "User":
// use the first user in the list
reqAttrs.put(currentLookup.getName(), currentLookup.getPicklistValues().get(0).getName());
break;
case "Picklist":
// use the first value in the picklist
reqAttrs.put(currentLookup.getName(), currentLookup.getPicklistValues().get(0).getName());
break;
default:
break;
}
}
}
return reqAttrs;
}

public static JsonNode mergeAttributesNode(UnirestInstance unirest,
ArrayList<FoDAttributeDescriptor> current,
Map<String, String> updates) {
Expand Down Expand Up @@ -96,8 +134,13 @@ public static JsonNode getAttributesNode(ArrayList<FoDAttributeDescriptor> attri
return attrArray;
}

public static JsonNode getAttributesNode(UnirestInstance unirest, Map<String, String> attributes) {
public static JsonNode getAttributesNode(UnirestInstance unirest, Map<String, String> attributes, Boolean autoReqdAttributes) {
Map<String, String> attributesMap = (Map<String, String>) attributes;
if (autoReqdAttributes) {
// find any required attributes
Map<String, String> reqAttributesMap = getRequiredAttributes(unirest);
attributesMap = reqAttributesMap;
}
ArrayNode attrArray = getObjectMapper().createArrayNode();
if (attributesMap == null || attributesMap.isEmpty()) return attrArray;
for (Map.Entry<String, String> attr : attributesMap.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*******************************************************************************
* (c) Copyright 2020 Micro Focus or one of its affiliates
*
* 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.fod.entity.app.attr.cli.helper;

import com.fortify.cli.common.json.JsonNodeHolder;
import io.micronaut.core.annotation.ReflectiveAccess;
import lombok.Data;
import lombok.EqualsAndHashCode;

@ReflectiveAccess
@Data
@EqualsAndHashCode(callSuper = true)
public class FoDPickListDescriptor extends JsonNodeHolder {
private Integer id;
private String name;
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ public abstract class FoDAppCreateAppCommand extends AbstractFoDJsonNodeOutputCo
protected String owner;
@Option(names = {"--user-groups", "--groups"}, required = false, split=",")
protected ArrayList<String> userGroups;
@Option(names={"--auto-required-attrs"}, required = false)
protected boolean autoRequiredAttrs = false;

@Mixin
protected FoDCriticalityTypeOptions.RequiredOption criticalityType;
Expand All @@ -94,7 +96,7 @@ public JsonNode getJsonNode(UnirestInstance unirest) {
.setOwnerId(userDescriptor.getUserId())
.setApplicationType(FoDAppTypeOptions.FoDAppType.Web.getName())
.setHasMicroservices(false)
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes()))
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes(), autoRequiredAttrs))
.setUserGroupIds(FoDUserGroupHelper.getUserGroupsNode(unirest, userGroups));

return FoDAppHelper.createApp(unirest, appCreateRequest).asJsonNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ public JsonNode getJsonNode(UnirestInstance unirest) {
.setOwnerId(userDescriptor.getUserId())
.setApplicationType(FoDAppTypeOptions.FoDAppType.Microservice.getName())
.setHasMicroservices(true)
.setAutoReqdAttrs(autoRequiredAttrs)
.setMicroservices(FoDAppHelper.getMicroservicesNode(microservices))
.setReleaseMicroserviceName(releaseMicroservice)
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes()))
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes(), autoRequiredAttrs))
.setUserGroupIds(FoDUserGroupHelper.getUserGroupsNode(unirest, userGroups));

return FoDAppHelper.createApp(unirest, appCreateRequest).asJsonNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public JsonNode getJsonNode(UnirestInstance unirest) {
.setOwnerId(userDescriptor.getUserId())
.setApplicationType(FoDAppTypeOptions.FoDAppType.Mobile.getName())
.setHasMicroservices(false)
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes()))
.setAutoReqdAttrs(autoRequiredAttrs)
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes(), autoRequiredAttrs))
.setUserGroupIds(FoDUserGroupHelper.getUserGroupsNode(unirest, userGroups));

return FoDAppHelper.createApp(unirest, appCreateRequest).asJsonNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public JsonNode getJsonNode(UnirestInstance unirest) {
.setOwnerId(userDescriptor.getUserId())
.setApplicationType(FoDAppTypeOptions.FoDAppType.Web.getName())
.setHasMicroservices(false)
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes()))
.setAutoReqdAttrs(autoRequiredAttrs)
.setAttributes(FoDAttributeHelper.getAttributesNode(unirest, appAttrs.getAttributes(), autoRequiredAttrs))
.setUserGroupIds(FoDUserGroupHelper.getUserGroupsNode(unirest, userGroups));

return FoDAppHelper.createApp(unirest, appCreateRequest).asJsonNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class FoDAppCreateRequest {
private String releaseMicroserviceName;
private JsonNode attributes;
private JsonNode userGroupIds;
private Boolean autoRequiredAttrs;

public FoDAppCreateRequest setApplicationName(String name) {
this.applicationName = name;
Expand Down Expand Up @@ -125,4 +126,9 @@ public FoDAppCreateRequest setUserGroupIds(JsonNode ids) {
return this;
}

public FoDAppCreateRequest setAutoReqdAttrs(Boolean autoRequiredAttrs) {
this.autoRequiredAttrs = autoRequiredAttrs;
return this;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ fcli.fod.usage.header = Commands for interacting with Fortify on Demand (FoD).

# Mixins
ApplicationMixin = Application id or name.
ApplicationReleaseMixin = Application release id or <application>:<release> name.
ApplicationReleaseMixin = If creating a new application this should be the application and release name in the \
format <application>:<release>. If specifying an existing release you can provide either the \
release id, e.g. 1234 or the combined <application>:<release> name.
ApplicationMicroserviceMixin = Application microservice id or <application>:<microservice> name.
ScanMixin = Scan id(s).
AnalysisStatusMixin = Scan analysis status. Valid values: ${COMPLETION-CANDIDATES}.
Expand Down Expand Up @@ -45,7 +47,7 @@ fcli.fod.app.usage.header = Commands for interacting with applications on Fortif

# For the "fod app create-web-app" command
fcli.fod.app.create-web-app.usage.header = Create a new web application (with a release) on Fortify on Demand (FoD). \
Please note some attributes might be mandatory depending on the configuration of your tenant. Please check from the \
Please note some attributes might be mandatory depending on the configuration of your tenant. Please check the \
Fortify on Demand web portal first.
fcli.fod.app.create-web-app.application-name = The name of the application to create.
fcli.fod.app.create-web-app.release-name = The name of the release to create for the application.
Expand All @@ -58,10 +60,11 @@ fcli.fod.app.create-web-app.criticality = The business criticality of the applic
fcli.fod.app.create-web-app.status = The SDLC lifecycle status of the release. Valid values: ${COMPLETION-CANDIDATES}
fcli.fod.app.create-web-app.attr = Attribute id or name and its value to set on the application.
fcli.fod.app.create-web-app.skip-if-exists = Check to see if application already exists before creating.
fcli.fod.app.create-web-app.auto-required-attrs = Automatically set a default value for required attributes.

# For the "fod app create-mobile-app" command
fcli.fod.app.create-mobile-app.usage.header = Create a new mobile application (with a release) on Fortify on Demand (FoD). \
Please note some attributes might be mandatory depending on the configuration of your tenant. Please check from the \
Please note some attributes might be mandatory depending on the configuration of your tenant. Please check the \
Fortify on Demand web portal first.
fcli.fod.app.create-mobile-app.application-name = ${fcli.fod.app.create-web-app.application-name}
fcli.fod.app.create-mobile-app.release-name = ${fcli.fod.app.create-web-app.release-name}
Expand All @@ -74,10 +77,11 @@ fcli.fod.app.create-mobile-app.criticality = ${fcli.fod.app.create-web-app.criti
fcli.fod.app.create-mobile-app.status = ${fcli.fod.app.create-web-app.status}
fcli.fod.app.create-mobile-app.attr = ${fcli.fod.app.create-web-app.attr}
fcli.fod.app.create-mobile-app.skip-if-exists = ${fcli.fod.app.create-web-app.skip-if-exists}
fcli.fod.app.create-mobile-app.auto-required-attrs = ${fcli.fod.app.create-web-app.auto-required-attrs}

# For the "fod app create-microservice-app" command
fcli.fod.app.create-microservice-app.usage.header = Create a new microservices application (with a release) on Fortify on Demand (FoD). \
Please note some attributes might be mandatory depending on the configuration of your tenant. Please check from the \
Please note some attributes might be mandatory depending on the configuration of your tenant. Please check the \
Fortify on Demand web portal first.
fcli.fod.app.create-microservice-app.missing-microservice = Missing option: if 'Microservice' type is specified then one or more 'microservice' options need to specified.
fcli.fod.app.create-microservice-app.invalid-microservice = Invalid option: the 'release-microservice' option specified was not found in the 'microservice' options.
Expand All @@ -94,6 +98,7 @@ fcli.fod.app.create-microservice-app.criticality = ${fcli.fod.app.create-web-app
fcli.fod.app.create-microservice-app.status = ${fcli.fod.app.create-web-app.status}
fcli.fod.app.create-microservice-app.attr = ${fcli.fod.app.create-web-app.attr}
fcli.fod.app.create-microservice-app.skip-if-exists = ${fcli.fod.app.create-web-app.skip-if-exists}
fcli.fod.app.create-microservice-app.auto-required-attrs = ${fcli.fod.app.create-web-app.auto-required-attrs}

# For the "fod app delete" command
fcli.fod.app.delete.usage.header = Delete an application from Fortify on Demand (FoD).
Expand Down

0 comments on commit c32e604

Please sign in to comment.