Skip to content

Commit

Permalink
feat: Add fcli ssc issue list command
Browse files Browse the repository at this point in the history
  • Loading branch information
rsenden committed Apr 2, 2024
1 parent 0aec5fc commit 1a9ac33
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
SSCIssueGroupGetCommand.class,
SSCIssueGroupListCommand.class,
SSCIssueCountCommand.class,
SSCIssueListCommand.class,
}
)
public class SSCIssueCommands extends AbstractContainerCommand {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*******************************************************************************
* 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.issue.cli.cmd;

import com.fortify.cli.common.output.cli.mixin.OutputHelperMixins;
import com.fortify.cli.common.rest.query.IServerSideQueryParamGeneratorSupplier;
import com.fortify.cli.common.rest.query.IServerSideQueryParamValueGenerator;
import com.fortify.cli.ssc._common.output.cli.cmd.AbstractSSCBaseRequestOutputCommand;
import com.fortify.cli.ssc._common.rest.query.SSCQParamGenerator;
import com.fortify.cli.ssc._common.rest.query.SSCQParamValueGenerators;
import com.fortify.cli.ssc._common.rest.query.cli.mixin.SSCQParamMixin;
import com.fortify.cli.ssc.appversion.cli.mixin.SSCAppVersionResolverMixin;
import com.fortify.cli.ssc.issue.cli.mixin.SSCIssueBulkEmbedMixin;
import com.fortify.cli.ssc.issue.cli.mixin.SSCIssueFilterSetResolverMixin;
import com.fortify.cli.ssc.issue.helper.SSCIssueFilterHelper;
import com.fortify.cli.ssc.issue.helper.SSCIssueFilterSetDescriptor;

import kong.unirest.GetRequest;
import kong.unirest.HttpRequest;
import kong.unirest.UnirestInstance;
import lombok.Getter;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;

@Command(name = OutputHelperMixins.List.CMD_NAME)
public class SSCIssueListCommand extends AbstractSSCBaseRequestOutputCommand implements IServerSideQueryParamGeneratorSupplier {
@Getter @Mixin private OutputHelperMixins.List outputHelper;
@Mixin private SSCAppVersionResolverMixin.RequiredOption parentResolver;
@Mixin private SSCIssueFilterSetResolverMixin.FilterSetOption filterSetResolver;
@Mixin private SSCQParamMixin qParamMixin;
@Option(names="--filter", required=false) private String filter;

// For some reason, SSC q param doesn't use same property names as returned by SSC,
// so we list the proper mappings below. TODO Any other useful server-side queries?
@Getter private IServerSideQueryParamValueGenerator serverSideQueryParamGenerator = new SSCQParamGenerator()
.add("issueName", "category", SSCQParamValueGenerators::wrapInQuotes)
.add("fullFileName", "file", SSCQParamValueGenerators::wrapInQuotes);
@Mixin private SSCIssueBulkEmbedMixin bulkEmbedMixin;

@Override
public HttpRequest<?> getBaseRequest(UnirestInstance unirest) {
String appVersionId = parentResolver.getAppVersionId(unirest);
SSCIssueFilterSetDescriptor filterSetDescriptor = filterSetResolver.getFilterSetDescriptor(unirest, appVersionId);
GetRequest request = unirest.get("/api/v1/projectVersions/{id}/issues?limit=100&qm=issues")
.routeParam("id", appVersionId);
if ( filterSetDescriptor!=null ) {
request.queryString("filterset", filterSetDescriptor.getGuid());
}
if ( filter!=null ) {
request.queryString("filter", new SSCIssueFilterHelper(unirest, appVersionId).getFilter(filter));
}
return request;
}

@Override
public boolean isSingular() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*******************************************************************************
* 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.issue.cli.mixin;

import com.fortify.cli.common.util.DisableTest;
import com.fortify.cli.common.util.DisableTest.TestType;
import com.fortify.cli.ssc._common.output.cli.mixin.AbstractSSCBulkEmbedMixin;
import com.fortify.cli.ssc.issue.helper.SSCIssueEmbedderSupplier;

import lombok.Getter;
import picocli.CommandLine.Option;

public class SSCIssueBulkEmbedMixin extends AbstractSSCBulkEmbedMixin {
@DisableTest(TestType.MULTI_OPT_PLURAL_NAME)
@Option(names = "--embed", required = false, split = ",", descriptionKey = "fcli.ssc.issue.embed" )
@Getter private SSCIssueEmbedderSupplier[] embedSuppliers;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*******************************************************************************
* 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.issue.helper;

import java.util.function.Supplier;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fortify.cli.ssc._common.rest.bulk.ISSCEntityEmbedder;
import com.fortify.cli.ssc._common.rest.bulk.ISSCEntityEmbedderSupplier;
import com.fortify.cli.ssc._common.rest.bulk.SSCBulkRequestBuilder;
import com.fortify.cli.ssc._common.rest.helper.SSCInputTransformer;

import kong.unirest.HttpRequest;
import kong.unirest.UnirestInstance;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public enum SSCIssueEmbedderSupplier implements ISSCEntityEmbedderSupplier {
details(SSCIssueDetailsEmbedder::new),
comments(SSCIssueCommentsEmbedder::new),
auditHistory(SSCIssueAuditHistoryEmbedder::new),
;

private final Supplier<ISSCEntityEmbedder> supplier;

public ISSCEntityEmbedder createEntityEmbedder() {
return supplier.get();
}

private static abstract class AbstractSSCIssueEmbedder implements ISSCEntityEmbedder {
@Override
public void addEmbedRequests(SSCBulkRequestBuilder builder, UnirestInstance unirest, JsonNode record) {
var id = record.get("id").asText();
builder.request(getBaseRequest(unirest)
.routeParam("id", id)
.queryString("limit", "-1"),
response->process((ObjectNode)record, SSCInputTransformer.getDataOrSelf(response)));
}

protected abstract HttpRequest<?> getBaseRequest(UnirestInstance unirest);
protected abstract void process(ObjectNode record, JsonNode response);
}

private static final class SSCIssueDetailsEmbedder extends AbstractSSCIssueEmbedder {
@Override
protected HttpRequest<?> getBaseRequest(UnirestInstance unirest) {
return unirest.get("/api/v1/issueDetails/{id}");
}
@Override
protected void process(ObjectNode record, JsonNode response) {
record.set("details", response);
}
}

private static final class SSCIssueAuditHistoryEmbedder extends AbstractSSCIssueEmbedder {
@Override
protected HttpRequest<?> getBaseRequest(UnirestInstance unirest) {
return unirest.get("/api/v1/issues/{id}/auditHistory?limit=-1");
}
@Override
protected void process(ObjectNode record, JsonNode response) {
record.set("auditHistory", response);
}
}

private static final class SSCIssueCommentsEmbedder extends AbstractSSCIssueEmbedder {
@Override
protected HttpRequest<?> getBaseRequest(UnirestInstance unirest) {
return unirest.get("/api/v1/issues/{id}/comments?limit=-1");
}
@Override
protected void process(ObjectNode record, JsonNode response) {
record.set("comments", response);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,13 @@ fcli.ssc.issue.count.by = Vulnerability grouping type. See 'fcli ssc issue list-
allowed values. Default value: ${DEFAULT-VALUE}.
fcli.ssc.issue.count.filter = Filter issue counts using the given (friendly or technical) filter. \
See 'fcli ssc issue list-filters' for allowed values.
fcli.ssc.issue.list.usage.header = List application version vulnerabilities.
fcli.ssc.issue.list.filter = Filter issues using the given (friendly or technical) filter. \
See 'fcli ssc issue list-filters' for allowed values.
fcli.ssc.issue.list.embed = Embed extra application version data. Allowed values: ${COMPLETION-CANDIDATES}. \
Using the --output option, this extra data can be included in the output. Using the --query option, \
this extra data can be queried upon. To get an understanding of the structure and contents of the \
embedded data, use the --output json or --output yaml options.
fcli.ssc.issue.get-filter.usage.header = Get issue filter details.
fcli.ssc.issue.filter = Technical or friendly filter as returned by the 'fcli ssc issue list-filters' command.
fcli.ssc.issue.list-filters.usage.header = List application version issue filters.
Expand Down Expand Up @@ -522,6 +529,7 @@ fcli.ssc.artifact.output.table.options = id,scanTypes,lastScanDate,uploadDate,st
fcli.ssc.attribute.output.table.options = id,category,guid,name,valueString
fcli.ssc.attribute.definition.output.table.options = id,category,guid,name,type,required
fcli.ssc.issue.count.output.table.options = cleanName,totalCount,auditedCount
fcli.ssc.issue.list.output.table.options = id,primaryLocation,lineNumber,issueName
fcli.ssc.issue.filter-set.output.table.options = guid,title,defaultFilterSet
fcli.ssc.issue.group.output.table.options = guid,displayName,entityType
fcli.ssc.issue.filter.output.table.options = entityType,friendlyFilter,technicalFilter
Expand Down

0 comments on commit 1a9ac33

Please sign in to comment.