Add issue get command for FoD and SSC - #978
Conversation
There was a problem hiding this comment.
Pull request overview
Adds new get subcommands to the ssc issue and fod issue command groups to retrieve a single issue/vulnerability by identifier, supporting optional embedded data and avoiding manual client-side filtering workflows.
Changes:
- Added
fcli ssc issue get <id> --av <appversion>command and supporting i18n/table output definitions. - Added
fcli fod issue get <id|vulnId> --rel <release>command with i18n updates and command registration. - Refactored SSC issue option message keys so
--embed/--includedescriptions can be shared beyond thelistcommand.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| fcli-core/fcli-ssc/src/main/resources/com/fortify/cli/ssc/i18n/SSCMessages.properties | Adds SSC issue-get help + table defaults; renames embed/include message keys for reuse. |
| fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/mixin/SSCIssueIncludeMixin.java | Updates description key to new shared SSC issue include message key. |
| fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/cmd/SSCIssueGetCommand.java | New SSC leaf command to fetch a single issue for an app version. |
| fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/issue/cli/cmd/SSCIssueCommands.java | Registers SSCIssueGetCommand under ssc issue. |
| fcli-core/fcli-fod/src/main/resources/com/fortify/cli/fod/i18n/FoDMessages.properties | Adds FoD issue-get help text keys. |
| fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/issue/cli/cmd/FoDIssueGetCommand.java | New FoD leaf command to fetch a single vulnerability for a release. |
| fcli-core/fcli-fod/src/main/java/com/fortify/cli/fod/issue/cli/cmd/FoDIssueCommands.java | Registers FoDIssueGetCommand under fod issue. |
rsenden
left a comment
There was a problem hiding this comment.
Apart from the individual comments on implementation details, we need to decide on what id's we should support, which is a tradeoff between fcli consistency vs usability.
For (almost) all other get commands in fcli, we just accept a single type of id, which corresponds to the id expected by the corresponding REST endpoint. This is what you've implemented for SSC, and would simplify the FoD implementation.
Also, we want to ensure consistency between issue get and issue update commands; these should accept the same type(s) of id('s). I think both FoD and SSC issue update commands currently only accept a single type of id (id for SSC, vulnId for FoD), so we should have the issue get commands accept those same types of id's only.
Having said that, for future consideration, we might want to consider deviating from this approach given that issues have multiple id's (id, issue instance id, and for FoD, vulnId).
For example, although users can see the SSC issue id in the output of the issue list command, I don't think this id is visible anywhere in the SSC UI. So, if users view an issue in SSC and then want to work on this issue in fcli (through issue get or issue update commands), they need to somehow figure out the issue id. Even SSC itself uses issueInstanceId filter instead of passing the issue id when opening the details for a given issue in a different browser window.
We can leave support for multiple types of id's as a future enhancement, although we need to think about the potential impact on command structure, for example whether we should have explicit options instead of a positional parameter (but that's inconsistent with other fcli get commands), to be able to differentiate between --id and --instance-id for example if we can't automatically determine the type of id being queried by the user. Alternatively, we can just try passing the given id through multiple REST queries on different fields (like you're more or less doing for FoD now, but not optimal from performance perspective), or support an optional prefix for the positional parameter, i.e., fcli ssc issue get instance-id:... vs fcli ssc issue get id:....
Somewhat related, for the issue update commands, I can imagine having a generic query option, i.e., update all issues that match a given query to perform bulk update, for example updating all issues in SQL Injection category, but again that's a potential future enhancement.
To summarize, maybe best to just have the issue get commands accept the same type of id as accepted by the issue update command for now, and raising an enhancement request for supporting additional id types on the issue get and issue update commands (again, these should be consistent as to what id types they support, likely through some shared helper class or resolver mixin), and another enhancement request for adding query support on the issue update command (maybe such an ER already exists though).
| } | ||
|
|
||
| private HttpRequest<?> getBaseRequest(UnirestInstance unirest, String appVersionId) { | ||
| return unirest.get(SSCUrls.PROJECT_VERSION_ISSUE(appVersionId, id)).queryString("qm", "issues"); |
There was a problem hiding this comment.
Please double-check, but I think qm request parameter is not supported by SSC on this endpoint.
Also, we could consider using the issueDetails endpoint instead as that doesn't require application version to be specified (thereby simplifying CLI usage), but output of that endpoint is not the same as what we return on the list command, so users may not expect that inconsistency.
There was a problem hiding this comment.
Verified the SSC api reference , query parameter is available for this endpoint.
There was a problem hiding this comment.
Code still shows qm request parameter, which is not supported on GET /projectVersions/{parentId}/issues/{id} endpoint.
rsenden
left a comment
There was a problem hiding this comment.
Please check review comments. Also, as there's been some refactoring on FoD issue-related classes in http-mcp branch (which has higher priority to be merged than this PR), let's wait until that branch has been merged to dev/v3.x first, then update this PR as needed before merging it.
| } | ||
|
|
||
| private HttpRequest<?> getBaseRequest(UnirestInstance unirest, String appVersionId) { | ||
| return unirest.get(SSCUrls.PROJECT_VERSION_ISSUE(appVersionId, id)).queryString("qm", "issues"); |
| } | ||
|
|
||
| private HttpRequest<?> getBaseRequest(UnirestInstance unirest, String appVersionId) { | ||
| return unirest.get(SSCUrls.PROJECT_VERSION_ISSUE(appVersionId, id)).queryString("qm", "issues"); |
There was a problem hiding this comment.
Code still shows qm request parameter, which is not supported on GET /projectVersions/{parentId}/issues/{id} endpoint.
|
|
||
| private HttpRequest<?> getBaseRequest(UnirestInstance unirest, String appVersionId) { | ||
| return unirest.get(SSCUrls.PROJECT_VERSION_ISSUE(appVersionId, id)) | ||
| .queryString("showHidden", "true") |
There was a problem hiding this comment.
I think the PROJECT_VERSION_ISSUE endpoint doesn't support these query parameters; it will always return the issue that corresponds to the given id, independent of whether that issue is hidden, removed, or suppressed.
| } | ||
|
|
||
| @Override | ||
| public HttpRequest<?> updateRequest(HttpRequest<?> request) { |
There was a problem hiding this comment.
I don't understand this code:
- The
PROJECT_VERSION_ISSUEendpoint used by this command doesn't support theqmquery parameter - Even if
qmwas supported, I don't see whyembedNameswould need to be appended to its value; embed names are fcli-specific identifiers that SSC doesn't have any knowledge about (apart from that they may overlap with SSC endpoint names, but even then still not valid values forqmrequest parameter).
|
|
||
| @Override | ||
| public final void addEmbedRequests(SSCBulkRequestBuilder builder, UnirestInstance unirest, JsonNode record) { | ||
| // Skip if data is already present in the record (e.g. returned by SSC via qm parameter) |
There was a problem hiding this comment.
This assumption is nonsense; SSC qm parameter (which is not even supported on the endpoint that's used by the issue get command) doesn't control embedding of extra data. Please undo all irrelevant code changes to this class and all related classes (i.e., remove all getEmbedFieldName methods)
| FoDReleaseDescriptor releaseDescriptor = releaseResolver.getReleaseDescriptor(unirest); | ||
| String releaseId = releaseDescriptor.getReleaseId().toString(); | ||
| JsonNode issue = findIssue(unirest, releaseDescriptor); | ||
| if ( issue instanceof ObjectNode issueObject ) { |
There was a problem hiding this comment.
What if issue is not instance of ObjectNode? In that case, we don't add release id/name, don't pass the node through transformRecord, and output is undefined.
It would be better to have findIssue return an ObjectNode, either through simple cast (throwing an exception if it's not an ObjectNode, which I guess is very unlikely to happen), or explicit check (throwing an explicit exception in case the issue is not of type ObjectNode).
| String releaseId = releaseDescriptor.getReleaseId().toString(); | ||
| JsonNode issue = findIssue(unirest, releaseDescriptor); | ||
| if ( issue instanceof ObjectNode issueObject ) { | ||
| issueObject.put("releaseId", releaseId); |
There was a problem hiding this comment.
Doesn't the issue object already contain releaseId and releaseName?
| if ( issue instanceof ObjectNode issueObject ) { | ||
| issueObject.put("releaseId", releaseId); | ||
| issueObject.put("releaseName", releaseDescriptor.getReleaseName()); | ||
| FoDIssueHelper.transformRecord(issueObject, IssueAggregationData.forSingleRelease(issueObject)); |
There was a problem hiding this comment.
I think this transformation is mostly meant for the list command, which can list issues from either an FoD app or release. Not sure whether it makes sense to add this data, although it does ensure that list and get commands output the same data. But if we want such consistency, then maybe the get command should accept either --rel or --app, with similar behavior as the list command (i.e., locate the given vuln id in either single release or all releases for given app, then transform based on appropriate IssueAggregationData factory method).

Added issue get command for both SSC and FoD to fetch a single issue by ID, avoiding full list + client-side filtering.
Supports optional --embed to include additional issue details.
fcli fod issue get
fcli ssc issue get
feat: Add get command for fcli ssc issue and fcli fod issue(#974 )