diff --git a/apps/dashboard/src/main/java/com/akto/action/testing/StartTestAction.java b/apps/dashboard/src/main/java/com/akto/action/testing/StartTestAction.java index 7ab4be3d8d..c92807e112 100644 --- a/apps/dashboard/src/main/java/com/akto/action/testing/StartTestAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/testing/StartTestAction.java @@ -24,6 +24,7 @@ import com.akto.log.LoggerMaker; import com.akto.log.LoggerMaker.LogDb; import com.akto.util.Constants; +import com.akto.util.enums.GlobalEnums; import com.akto.util.enums.GlobalEnums.TestErrorSource; import com.akto.utils.DeleteTestRunUtils; import com.akto.utils.Utils; @@ -40,6 +41,7 @@ import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -507,21 +509,25 @@ public String fetchTestingRunResultSummary() { } } + private static Bson vulnerableFilter = Filters.and( + Filters.eq(TestingRunResult.VULNERABLE, true), + Filters.in(TestingRunResult.IS_IGNORED_RESULT, Arrays.asList(null, false)) + ); + private List prepareTestRunResultsFilters(ObjectId testingRunResultSummaryId, QueryMode queryMode) { List filterList = new ArrayList<>(); filterList.add(Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, testingRunResultSummaryId)); Bson filtersForTestingRunResults = com.akto.action.testing.Utils.createFiltersForTestingReport(reportFilterList); if(!filtersForTestingRunResults.equals(Filters.empty())) filterList.add(filtersForTestingRunResults); - if(queryMode == null) { if(fetchOnlyVulnerable) { - filterList.add(Filters.eq(TestingRunResult.VULNERABLE, true)); + filterList.add(vulnerableFilter); } } else { switch (queryMode) { case VULNERABLE: - filterList.add(Filters.eq(TestingRunResult.VULNERABLE, true)); + filterList.add(vulnerableFilter); break; case SKIPPED_EXEC_API_REQUEST_FAILED: filterList.add(Filters.eq(TestingRunResult.VULNERABLE, false)); @@ -1043,6 +1049,80 @@ public String modifyTestingRunConfig(){ return SUCCESS.toUpperCase(); } + public String handleRefreshTableCount(){ + if(this.testingRunResultSummaryHexId == null || this.testingRunResultSummaryHexId.isEmpty()){ + addActionError("Invalid summary id"); + return ERROR.toUpperCase(); + } + int accountId = Context.accountId.get(); + executorService.schedule( new Runnable() { + public void run() { + Context.accountId.set(accountId); + try { + ObjectId summaryObjectId = new ObjectId(testingRunResultSummaryHexId); + List testingRunResults = TestingRunResultDao.instance.findAll( + Filters.and( + Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, summaryObjectId), + vulnerableFilter + ), + Projections.include(TestingRunResult.API_INFO_KEY, TestingRunResult.TEST_SUB_TYPE) + ); + + if(testingRunResults.isEmpty()){ + return; + } + + Set issuesIds = new HashSet<>(); + Map mapIssueToResultId = new HashMap<>(); + Set ignoredResults = new HashSet<>(); + for(TestingRunResult runResult: testingRunResults){ + TestingIssuesId issuesId = new TestingIssuesId(runResult.getApiInfoKey(), TestErrorSource.AUTOMATED_TESTING , runResult.getTestSubType()); + issuesIds.add(issuesId); + mapIssueToResultId.put(issuesId, runResult.getId()); + ignoredResults.add(runResult.getId()); + } + + List issues = TestingRunIssuesDao.instance.findAll( + Filters.and( + Filters.in(Constants.ID, issuesIds), + Filters.eq(TestingRunIssues.TEST_RUN_ISSUES_STATUS, GlobalEnums.TestRunIssueStatus.OPEN) + ), Projections.include(TestingRunIssues.KEY_SEVERITY) + ); + + Map totalCountIssues = new HashMap<>(); + totalCountIssues.put("HIGH", 0); + totalCountIssues.put("MEDIUM", 0); + totalCountIssues.put("LOW", 0); + + for(TestingRunIssues runIssue: issues){ + int initCount = totalCountIssues.getOrDefault(runIssue.getSeverity().name(), 0); + totalCountIssues.put(runIssue.getSeverity().name(), initCount + 1); + if(mapIssueToResultId.containsKey(runIssue.getId())){ + ObjectId resId = mapIssueToResultId.get(runIssue.getId()); + ignoredResults.remove(resId); + } + } + + // update testing run result summary + TestingRunResultSummariesDao.instance.updateOne( + Filters.eq(Constants.ID, summaryObjectId), + Updates.set(TestingRunResultSummary.COUNT_ISSUES, totalCountIssues) + ); + + // update testing run results, by setting them isIgnored true + TestingRunResultDao.instance.updateMany( + Filters.in(Constants.ID, ignoredResults), + Updates.set(TestingRunResult.IS_IGNORED_RESULT, true) + ); + } catch (Exception e) { + e.printStackTrace(); + } + } + }, 0 , TimeUnit.SECONDS); + + return SUCCESS.toUpperCase(); + } + public void setType(TestingEndpoints.Type type) { this.type = type; diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index 26c53faa7f..87e820086c 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -3513,6 +3513,27 @@ + + + + + TEST_RESULTS + READ + + + + 403 + false + ^actionErrors.* + + + + 422 + false + ^actionErrors.* + + + diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/SingleTestRunPage.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/SingleTestRunPage.js index 52392bad1d..7d8a463543 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/SingleTestRunPage.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/SingleTestRunPage.js @@ -616,6 +616,13 @@ const editableConfigsComp = ( } } + const handleRefreshTableCount = async(summaryHexId) => { + await api.handleRefreshTableCount(summaryHexId).then((res) => { + func.setToast("Re-calculating issues count") + setSecondaryPopover(false) + }) + } + const EmptyData = () => { return(
@@ -710,6 +717,11 @@ const editableConfigsComp = ( content: 'Edit testing config settings', icon: EditMajor, onAction: () => { setShowEditableSettings(true); handleAddSettings(); } + }, + { + content: 'Re-Calculate Issues Count', + icon: RefreshMajor, + onAction: () => {handleRefreshTableCount(currentSummary.hexId)} } ]}) const moreActionsComp = ( diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultFlyout.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultFlyout.jsx index a0036fa44c..0fcce76c27 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultFlyout.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultFlyout.jsx @@ -15,7 +15,6 @@ import "./style.css" import ActivityTracker from '../../dashboard/components/ActivityTracker' import observeFunc from "../../observe/transform.js" import settingFunctions from '../../settings/module.js' -import DropdownSearch from '../../../components/shared/DropdownSearch.jsx' import JiraTicketCreationModal from '../../../components/shared/JiraTicketCreationModal.jsx' function TestRunResultFlyout(props) { diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js index a3d530a321..7fdbe5579c 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/api.js @@ -494,5 +494,12 @@ export default { method: 'post', data: {...filters, issueIds, endTimeStamp} }) + }, + handleRefreshTableCount(testingRunResultSummaryHexId) { + return request({ + url: '/api/handleRefreshTableCount', + method: 'post', + data: {testingRunResultSummaryHexId} + }) } } \ No newline at end of file diff --git a/libs/dao/src/main/java/com/akto/dao/testing_run_findings/TestingRunIssuesDao.java b/libs/dao/src/main/java/com/akto/dao/testing_run_findings/TestingRunIssuesDao.java index e43fef603e..0c213ccebe 100644 --- a/libs/dao/src/main/java/com/akto/dao/testing_run_findings/TestingRunIssuesDao.java +++ b/libs/dao/src/main/java/com/akto/dao/testing_run_findings/TestingRunIssuesDao.java @@ -19,6 +19,7 @@ import com.akto.dao.test_editor.YamlTemplateDao; import com.akto.dto.test_editor.YamlTemplate; import com.akto.dto.test_run_findings.TestingIssuesId; +import com.akto.util.Constants; import com.akto.util.enums.GlobalEnums; import com.akto.util.enums.MongoDBEnums; import com.mongodb.BasicDBObject; @@ -60,6 +61,9 @@ public void createIndicesIfAbsent() { MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); fieldNames = new String[] {TestingRunIssues.LATEST_TESTING_RUN_SUMMARY_ID}; MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); + + fieldNames = new String[] {Constants.ID, TestingRunIssues.TEST_RUN_ISSUES_STATUS}; + MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, true); } diff --git a/libs/dao/src/main/java/com/akto/dto/testing/TestingRunResult.java b/libs/dao/src/main/java/com/akto/dto/testing/TestingRunResult.java index 777f352b9a..dadb433a56 100644 --- a/libs/dao/src/main/java/com/akto/dto/testing/TestingRunResult.java +++ b/libs/dao/src/main/java/com/akto/dto/testing/TestingRunResult.java @@ -46,6 +46,8 @@ public class TestingRunResult implements Comparable { public static final String TEST_RUN_RESULT_SUMMARY_ID = "testRunResultSummaryId"; private ObjectId testRunResultSummaryId; + public static final String IS_IGNORED_RESULT = "isIgnoredResult"; + private boolean isIgnoredResult ; public static final String ERRORS_LIST = "errorsList"; private List errorsList; @@ -343,4 +345,12 @@ public List getErrorsList() { public void setErrorsList(List errorsList) { this.errorsList = errorsList; } + + public boolean isIgnoredResult() { + return isIgnoredResult; + } + + public void setIgnoredResult(boolean isIgnoredResult) { + this.isIgnoredResult = isIgnoredResult; + } }