From e8d2bd92b369645c9a4e6e84d208a995821797ef Mon Sep 17 00:00:00 2001 From: Ankit Rathod Date: Mon, 9 Mar 2026 15:52:11 +0530 Subject: [PATCH] feat: add default empty string for missing buildId in FPRInfo and update related logic in AviatorStreamProcessor test: add unit test for FPRInfo to verify default buildId behavior refactor: enhance logging and request handling in AviatorSSCAuditHelper --- .../cli/aviator/fpr/model/FPRInfo.java | 5 +++ .../aviator/grpc/AviatorStreamProcessor.java | 29 +++++++----- .../cli/aviator/audit/IssueAuditorTest.java | 31 +++++++++++++ .../ssc/helper/AviatorSSCAuditHelper.java | 45 +++++++++++++++---- 4 files changed, 89 insertions(+), 21 deletions(-) diff --git a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/fpr/model/FPRInfo.java b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/fpr/model/FPRInfo.java index 650f5d92e1..3ad0db1243 100644 --- a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/fpr/model/FPRInfo.java +++ b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/fpr/model/FPRInfo.java @@ -52,6 +52,7 @@ public class FPRInfo { public FPRInfo(FprHandle fprHandle) { FPRName = String.valueOf(fprHandle.getFprPath().getFileName()); + buildId = ""; try { extractInfoFromAuditFvdlStreaming(fprHandle); } catch (Exception e) { @@ -151,6 +152,10 @@ private void extractInfoFromAuditFvdlStreaming(FprHandle fprHandle) throws Excep } catch (javax.xml.stream.XMLStreamException e) { throw new Exception("Failed to parse audit.fvdl using streaming parser", e); } + + if (buildId == null) { + buildId = ""; + } } /** diff --git a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorStreamProcessor.java b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorStreamProcessor.java index 8f89f10183..1a42a6fec4 100644 --- a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorStreamProcessor.java +++ b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorStreamProcessor.java @@ -52,6 +52,7 @@ import com.fortify.cli.aviator.util.FileTypeLanguageMapperUtil; import com.fortify.cli.aviator.util.FileUtil; import com.fortify.cli.aviator.util.FprHandle; +import com.fortify.cli.aviator.util.StringUtil; import io.grpc.Status; import io.grpc.StatusRuntimeException; @@ -488,19 +489,23 @@ public void onCompleted() { private void sendInitRequest() throws Exception { String initRequestId = UUID.randomUUID().toString(); + StreamInitRequest.Builder initRequestBuilder = StreamInitRequest.newBuilder() + .setStreamId(currentStreamState.streamId) + .setRequestId(initRequestId) + .setToken(currentStreamState.token) + .setApplicationName(currentStreamState.projectName) + .setSscApplicationName(currentStreamState.SSCApplicationName) + .setSscApplicationVersion(currentStreamState.SSCApplicationVersion) + .setTotalReportedIssues(currentStreamState.totalRequests) + .setTotalIssuesToPredict(currentStreamState.totalRequests); + + if (!StringUtil.isEmpty(currentStreamState.FPRBuildId)) { + initRequestBuilder.setFprBuildId(currentStreamState.FPRBuildId); + } + UserPromptRequest initRequest = UserPromptRequest.newBuilder() - .setInit(StreamInitRequest.newBuilder() - .setStreamId(currentStreamState.streamId) - .setRequestId(initRequestId) - .setToken(currentStreamState.token) - .setApplicationName(currentStreamState.projectName) - .setSscApplicationName(currentStreamState.SSCApplicationName) - .setSscApplicationVersion(currentStreamState.SSCApplicationVersion) - .setFprBuildId(currentStreamState.FPRBuildId) - .setTotalReportedIssues(currentStreamState.totalRequests) - .setTotalIssuesToPredict(currentStreamState.totalRequests) - .build()) - .build(); + .setInit(initRequestBuilder.build()) + .build(); requestHandler.sendRequest(initRequest); LOG.info("Client Id for stream initialization {}", currentStreamState.streamId); diff --git a/fcli-core/fcli-aviator-common/src/test/java/com/fortify/cli/aviator/audit/IssueAuditorTest.java b/fcli-core/fcli-aviator-common/src/test/java/com/fortify/cli/aviator/audit/IssueAuditorTest.java index 79a2c5b4ec..cee9ef7e6b 100644 --- a/fcli-core/fcli-aviator-common/src/test/java/com/fortify/cli/aviator/audit/IssueAuditorTest.java +++ b/fcli-core/fcli-aviator-common/src/test/java/com/fortify/cli/aviator/audit/IssueAuditorTest.java @@ -81,6 +81,37 @@ void tearDown() throws IOException { } } + @Test + void testFprInfoMissingBuildIdDefaultsToEmptyString() throws Exception { + if (fprHandle != null) { + fprHandle.close(); + fprHandle = null; + } + if (tempFprFile != null) { + Files.deleteIfExists(tempFprFile); + } + + tempFprFile = Files.createTempFile("test_aviator_missing_build", ".fpr"); + try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(tempFprFile))) { + ZipEntry entry = new ZipEntry("audit.fvdl"); + zos.putNextEntry(entry); + String minimalXml = "test-uuid"; + zos.write(minimalXml.getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + + ZipEntry indexEntry = new ZipEntry("src-archive/index.xml"); + zos.putNextEntry(indexEntry); + String indexXml = ""; + zos.write(indexXml.getBytes(StandardCharsets.UTF_8)); + zos.closeEntry(); + } + + fprHandle = new FprHandle(tempFprFile); + FPRInfo fprInfo = new FPRInfo(fprHandle); + + assertEquals("", fprInfo.getBuildId()); + } + @Test void testFilterVulnerabilities_LegacySyntaxWithSpaces() throws Exception { diff --git a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/ssc/helper/AviatorSSCAuditHelper.java b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/ssc/helper/AviatorSSCAuditHelper.java index 93fe7278e2..df21a6b07c 100644 --- a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/ssc/helper/AviatorSSCAuditHelper.java +++ b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/ssc/helper/AviatorSSCAuditHelper.java @@ -196,28 +196,33 @@ public static String getProgressMessage(FPRAuditResult auditResult) { public static long getAuditableIssueCount(UnirestInstance unirest, SSCAppVersionDescriptor av, AviatorLoggerImpl logger, boolean noFilterSet, SSCIssueFilterSetOptionMixin filterSetOptions, List folderNames) { logger.progress("Status: Checking for auditable issues..."); - GetRequest request = unirest.get(SSCUrls.PROJECT_VERSION_ISSUES(av.getVersionId())) - .queryString("limit", PAGE_LIMIT) - .queryString("embed", "auditValues") - .queryString("qm", "issues") - .queryString("q", "audited:false"); + LOG.debug("Starting auditable issue count for SSC version {} (application='{}', version='{}') with pageLimit={}, noFilterSet={}", + av.getVersionId(), av.getApplicationName(), av.getVersionName(), PAGE_LIMIT, noFilterSet); // Apply filter set if specified SSCIssueFilterSetDescriptor filterSetDescriptor = null; + String filterSetGuid = null; if (!noFilterSet) { SSCIssueFilterSetHelper filterSetHelper = new SSCIssueFilterSetHelper(unirest, av.getVersionId()); filterSetDescriptor = filterSetHelper.getDescriptorByTitleOrId(filterSetOptions.getFilterSetTitleOrId(), false); if (filterSetDescriptor != null) { logger.progress("Status: Applying filter set '%s' for issue count check", filterSetDescriptor.getTitle()); - request.queryString("filterset", filterSetDescriptor.getGuid()); + filterSetGuid = filterSetDescriptor.getGuid(); + LOG.debug("Applied SSC filter set '{}' with guid {} while counting auditable issues for version {}", + filterSetDescriptor.getTitle(), filterSetGuid, av.getVersionId()); + } else { + LOG.debug("No SSC filter set resolved from options while counting auditable issues for version {}", + av.getVersionId()); } } // Apply folder filter if specified + String folderFilter = null; if (folderNames != null && !folderNames.isEmpty()) { - String folderFilter = getFolderFilter(noFilterSet, filterSetDescriptor, folderNames); - request.queryString("filter", folderFilter); + folderFilter = getFolderFilter(noFilterSet, filterSetDescriptor, folderNames); logger.progress("Status: Applying folder filter for: %s", String.join(", ", folderNames)); + LOG.debug("Applied folder filter '{}' for folders {} while counting auditable issues for version {}", + folderFilter, folderNames, av.getVersionId()); } long totalAuditableCount = 0; @@ -226,7 +231,21 @@ public static long getAuditableIssueCount(UnirestInstance unirest, SSCAppVersion try { do { - JsonNode response = request.queryString("start", start).asObject(JsonNode.class).getBody(); + GetRequest request = unirest.get(SSCUrls.PROJECT_VERSION_ISSUES(av.getVersionId())) + .queryString("limit", PAGE_LIMIT) + .queryString("embed", "auditValues") + .queryString("qm", "issues") + .queryString("q", "audited:false") + .queryString("start", start); + if (filterSetGuid != null) { + request.queryString("filterset", filterSetGuid); + } + if (folderFilter != null) { + request.queryString("filter", folderFilter); + } + LOG.debug("Requesting SSC issues page for version {} with start={} and limit={}", + av.getVersionId(), start, PAGE_LIMIT); + JsonNode response = request.asObject(JsonNode.class).getBody(); if (response == null || !response.has("data")) { LOG.warn("Invalid response received from issue check; proceeding with FPR download."); logger.progress("WARN: Invalid response from issue check. Proceeding with FPR download."); @@ -234,6 +253,8 @@ public static long getAuditableIssueCount(UnirestInstance unirest, SSCAppVersion } if (totalFromServer == -1) { totalFromServer = response.get("count").asLong(0); + LOG.debug("SSC reported {} total issues matching the initial auditable count query for version {}", + totalFromServer, av.getVersionId()); } ArrayNode issues = (ArrayNode) response.get("data"); @@ -242,12 +263,18 @@ public static long getAuditableIssueCount(UnirestInstance unirest, SSCAppVersion .filter(issue -> !isProcessedByAviator(issue)) .count(); totalAuditableCount += auditableOnPage; + LOG.debug("Processed SSC issues page for version {}: pageStart={}, pageSize={}, auditableOnPage={}, cumulativeAuditableCount={}, totalFromServer={}", + av.getVersionId(), start, issues.size(), auditableOnPage, totalAuditableCount, totalFromServer); start += issues.size(); } else { + LOG.debug("SSC returned no more issues for version {} at start={}; stopping pagination with cumulativeAuditableCount={} and totalFromServer={}", + av.getVersionId(), start, totalAuditableCount, totalFromServer); break; // No more issues } } while (start < totalFromServer); + LOG.debug("Completed auditable issue count for version {}: totalAuditableCount={}, totalFromServer={}", + av.getVersionId(), totalAuditableCount, totalFromServer); logger.progress("Status: Found %d auditable issues.", totalAuditableCount); return totalAuditableCount; } catch (UnexpectedHttpResponseException e) {