Skip to content

Commit

Permalink
Merge pull request #1840 from akto-api-security/fix/test_result_ignor…
Browse files Browse the repository at this point in the history
…ed_counts

fix: fixed vul and ignored testing counts
  • Loading branch information
Ark2307 authored Dec 24, 2024
2 parents fa3e79e + c91e68f commit 4d8be68
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -510,26 +510,8 @@ private List<Bson> prepareTestRunResultsFilters(ObjectId testingRunResultSummary
List<Bson> filterList = new ArrayList<>();
filterList.add(Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, testingRunResultSummaryId));

if(filters != null && !filters.isEmpty()) {
for(Map.Entry<String, List> filterEntry : filters.entrySet()) {
String key = filterEntry.getKey();
switch (key) {
case "severityStatus":
filterList.add(Filters.in(TestingRunResult.TEST_RESULTS+"."+GenericTestResult._CONFIDENCE, filterEntry.getValue()));
break;
case "apiCollectionId":
case "collectionIds":
filterList.add(Filters.in(TestingRunResult.API_INFO_KEY+"."+ApiInfo.ApiInfoKey.API_COLLECTION_ID, filterEntry.getValue()));
break;
case "method":
filterList.add(Filters.in(TestingRunResult.API_INFO_KEY+"."+ApiInfo.ApiInfoKey.METHOD, filterEntry.getValue()));
break;
case "categoryFilter":
filterList.add(Filters.in(TestingRunResult.TEST_SUPER_TYPE, filterEntry.getValue()));
break;
}
}
}
Bson filtersForTestingRunResults = com.akto.action.testing.Utils.createFiltersForTestingReport(reportFilterList);
if(!filtersForTestingRunResults.equals(Filters.empty())) filterList.add(filtersForTestingRunResults);

if(queryMode == null) {
if(fetchOnlyVulnerable) {
Expand Down Expand Up @@ -569,9 +551,28 @@ private List<Bson> prepareTestRunResultsFilters(ObjectId testingRunResultSummary
}
}

if(filterList.isEmpty()) {
filterList.add(Filters.empty());
}

return filterList;
}

public static Bson prepareTestingRunResultCustomSorting(String sortKey, int sortOrder) {
Bson sortStage = null;
if (TestingRunIssues.KEY_SEVERITY.equals(sortKey)) {
sortStage = (sortOrder == 1) ?
Aggregates.sort(Sorts.ascending("severityValue", TestingRunResult.END_TIMESTAMP)) :
Aggregates.sort(Sorts.descending("severityValue", TestingRunResult.END_TIMESTAMP));
} else if ("time".equals(sortKey)) {
sortStage = (sortOrder == 1) ?
Aggregates.sort(Sorts.ascending(TestingRunResult.END_TIMESTAMP)) :
Aggregates.sort(Sorts.descending(TestingRunResult.END_TIMESTAMP));
}

return sortStage;
}

String testingRunResultSummaryHexId;
List<TestingRunResult> testingRunResults;
private boolean fetchOnlyVulnerable;
Expand All @@ -595,6 +596,12 @@ public String fetchTestingRunResults() {
if (testingRunResultSummaryHexId != null) loggerMaker.infoAndAddToDb("fetchTestingRunResults called for hexId=" + testingRunResultSummaryHexId);
if (queryMode != null) loggerMaker.infoAndAddToDb("fetchTestingRunResults called for queryMode="+queryMode);

Bson ignoredIssuesFilters = Filters.and(
Filters.in(TestingRunIssues.TEST_RUN_ISSUES_STATUS, "IGNORED"),
Filters.in(TestingRunIssues.LATEST_TESTING_RUN_SUMMARY_ID, testingRunResultSummaryId)
);
List<TestingRunIssues> issueslist = TestingRunIssuesDao.instance.findAll(ignoredIssuesFilters, Projections.include("_id"));

List<Bson> testingRunResultFilters = prepareTestRunResultsFilters(testingRunResultSummaryId, queryMode);

if(queryMode == QueryMode.SKIPPED_EXEC || queryMode == QueryMode.SKIPPED_EXEC_NEED_CONFIG){
Expand All @@ -609,19 +616,13 @@ public String fetchTestingRunResults() {

try {
int pageLimit = limit <= 0 ? 150 : limit;
Bson sortStage = null;
if (TestingRunIssues.KEY_SEVERITY.equals(sortKey)) {
sortStage = (sortOrder == 1) ?
Aggregates.sort(Sorts.ascending("severityValue", TestingRunResult.END_TIMESTAMP)) :
Aggregates.sort(Sorts.descending("severityValue", TestingRunResult.END_TIMESTAMP));
} else if ("time".equals(sortKey)) {
sortStage = (sortOrder == 1) ?
Aggregates.sort(Sorts.ascending(TestingRunResult.END_TIMESTAMP)) :
Aggregates.sort(Sorts.descending(TestingRunResult.END_TIMESTAMP));
}
Bson sortStage = prepareTestingRunResultCustomSorting(sortKey, sortOrder);

Bson filters = testingRunResultFilters.isEmpty() ? Filters.empty() : Filters.and(testingRunResultFilters);
this.testingRunResults = TestingRunResultDao.instance
.fetchLatestTestingRunResultWithCustomAggregations(Filters.and(testingRunResultFilters), pageLimit, skip, sortStage);
.fetchLatestTestingRunResultWithCustomAggregations(filters, pageLimit, skip, sortStage);

removeTestingRunResultsByIssues(testingRunResults, issueslist, false);

testCountMap = new HashMap<>();
for(QueryMode qm : QueryMode.values()) {
Expand All @@ -635,20 +636,42 @@ public String fetchTestingRunResults() {
testCountMap.put(qm.toString(), count);
}

Bson ignoredIssuesFilters = Filters.and(
Filters.in(TestingRunIssues.TEST_RUN_ISSUES_STATUS, Arrays.asList("IGNORED", "FIXED")),
Filters.in(TestingRunIssues.LATEST_TESTING_RUN_SUMMARY_ID, testingRunResultSummaryId)
);
int count = (int) TestingRunIssuesDao.instance.count(ignoredIssuesFilters);
testCountMap.put(QueryMode.VULNERABLE.name(), Math.abs(testCountMap.getOrDefault(QueryMode.VULNERABLE.name(), 0)-count));
testCountMap.put("IGNORED_ISSUES", count);
testCountMap.put(QueryMode.VULNERABLE.name(), Math.abs(testCountMap.getOrDefault(QueryMode.VULNERABLE.name(), 0)- issueslist.size()));
testCountMap.put("IGNORED_ISSUES", issueslist.size());
} catch (Exception e) {
loggerMaker.errorAndAddToDb(e, "error in fetchLatestTestingRunResult: " + e);
}

return SUCCESS.toUpperCase();
}

public static void removeTestingRunResultsByIssues(List<TestingRunResult> testingRunResults,
List<TestingRunIssues> testingRunIssues,
boolean retainByIssues) {
Set<String> issuesSet = new HashSet<>();
for (TestingRunIssues issue : testingRunIssues) {
String apiInfoKeyString = issue.getId().getApiInfoKey().toString();
String key = apiInfoKeyString + "|" + issue.getId().getTestSubCategory();
issuesSet.add(key);
}

Iterator<TestingRunResult> resultIterator = testingRunResults.iterator();

while (resultIterator.hasNext()) {
TestingRunResult result = resultIterator.next();
String apiInfoKeyString = result.getApiInfoKey().toString();
String resultKey = apiInfoKeyString + "|" + result.getTestSubType();

boolean matchFound = issuesSet.contains(resultKey);

if (retainByIssues && !matchFound) {
resultIterator.remove();
} else if (!retainByIssues && matchFound) {
resultIterator.remove();
}
}
}

private Map<String, List<String>> reportFilterList;

public String fetchVulnerableTestRunResults() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static Bson createFiltersForTestingReport(Map<String, List<String>> filte
String key = entry.getKey();
List<String> value = entry.getValue();

if (value.size() == 0) continue;
if (value.isEmpty()) continue;
List<Integer> collectionIds = new ArrayList<>();
if(key.equals(SingleTypeInfo._API_COLLECTION_ID)){
for(String str: value){
Expand All @@ -32,6 +32,7 @@ public static Bson createFiltersForTestingReport(Map<String, List<String>> filte
case SingleTypeInfo._METHOD:
filterList.add(Filters.in(TestingRunResult.API_INFO_KEY + "." + ApiInfoKey.METHOD, value));
break;
case SingleTypeInfo._COLLECTION_IDS:
case SingleTypeInfo._API_COLLECTION_ID:
filterList.add(Filters.in(TestingRunResult.API_INFO_KEY + "." + ApiInfoKey.API_COLLECTION_ID, collectionIds));
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.akto.action.ExportSampleDataAction;
import com.akto.action.UserAction;
import com.akto.action.testing.Utils;
import com.akto.dao.HistoricalDataDao;
import com.akto.dao.RBACDao;
import com.akto.action.testing.StartTestAction;
Expand Down Expand Up @@ -527,12 +528,38 @@ public String bulkUpdateIssueStatus () {

String latestTestingRunSummaryId;
List<String> issueStatusQuery;
List<TestingRunResult> testingRunResultList;
private Map<String, List<String>> filters;
public String fetchIssuesByStatusAndSummaryId() {
Bson filters = Filters.and(
Bson triFilters = Filters.and(
Filters.in(TestingRunIssues.TEST_RUN_ISSUES_STATUS, issueStatusQuery),
Filters.in(TestingRunIssues.LATEST_TESTING_RUN_SUMMARY_ID, new ObjectId(latestTestingRunSummaryId))
);
issues = TestingRunIssuesDao.instance.findAll(filters);
issues = TestingRunIssuesDao.instance.findAll(triFilters, Projections.include("_id"));

List<Bson> testingRunResultsFilterList = new ArrayList<>();
for(TestingRunIssues issue: issues) {
testingRunResultsFilterList.add(Filters.and(
Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, new ObjectId(latestTestingRunSummaryId)),
Filters.eq(TestingRunResult.VULNERABLE, true),
Filters.eq(TestingRunResult.API_INFO_KEY, issue.getId().getApiInfoKey()),
Filters.eq(TestingRunResult.TEST_SUB_TYPE, issue.getId().getTestSubCategory())
));
}

List<Bson> filtersList = new ArrayList<>();
if(!testingRunResultsFilterList.isEmpty()) filtersList.add(Filters.or(testingRunResultsFilterList));
Bson filtersForTestingRunResults = Utils.createFiltersForTestingReport(filters);
if(!filtersForTestingRunResults.equals(Filters.empty())) filtersList.add(filtersForTestingRunResults);
Bson sortStage = StartTestAction.prepareTestingRunResultCustomSorting(sortKey, sortOrder);

if(filtersList.isEmpty()) {
testingRunResultList = new ArrayList<>();
return SUCCESS.toUpperCase();
}

testingRunResultList = TestingRunResultDao.instance.fetchLatestTestingRunResultWithCustomAggregations(Filters.and(filtersList), limit, skip, sortStage);

return SUCCESS.toUpperCase();
}

Expand Down Expand Up @@ -824,6 +851,14 @@ public TestingRunResultSummary getTestingRunResultSummary() {
return testingRunResultSummary;
}

public List<TestingRunResult> getTestingRunResultList() {
return testingRunResultList;
}

public void setFilters(Map<String, List<String>> filters) {
this.filters = filters;
}

public void setReportFilterList(Map<String, List<String>> reportFilterList) {
this.reportFilterList = reportFilterList;
}
Expand Down
4 changes: 1 addition & 3 deletions apps/dashboard/src/main/resources/struts.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7538,9 +7538,7 @@
<param name="ignoreHierarchy">false</param>
<param name="includeProperties">^actionErrors.*</param>
</result>
<result name="SUCCESS" type="json">
<param name="root">issues</param>
</result>
<result name="SUCCESS" type="json"/>
<result name="ERROR" type="json">
<param name="statusCode">422</param>
<param name="ignoreHierarchy">false</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ function SingleTestRunPage() {
const fetchTableData = async (sortKey, sortOrder, skip, limit, filters, filterOperators, queryValue) => {
let testRunResultsRes = []
let testRunCountMap = []
let totalIgnoredIssuesCount = 0
const { testingRun, workflowTest, testingRunType } = testingRunResultSummariesObj
if(testingRun === undefined){
return {value: [], total: 0}
Expand All @@ -261,35 +262,14 @@ function SingleTestRunPage() {

setSelectedTestRun(localSelectedTestRun);
if(localSelectedTestRun.testingRunResultSummaryHexId) {
if(selectedTab === 'ignored_issues' || selectedTab === 'vulnerable') {
let vulnerableTestingRunResults = []
await api.fetchTestingRunResults(localSelectedTestRun.testingRunResultSummaryHexId, "VULNERABLE", sortKey, sortOrder, skip, limit, filters, queryValue).then(({ testingRunResults, testCountMap }) => {
testRunCountMap = testCountMap
vulnerableTestingRunResults = testingRunResults
testRunResultsRes = transform.prepareTestRunResults(hexId, testingRunResults, subCategoryMap, subCategoryFromSourceConfigMap)
const orderedValues = tableTabsOrder.map(key => testCountMap[tableTabMap[key]] || 0)
setTestRunResultsCount(orderedValues)
})
if(selectedTab === 'ignored_issues') {
let ignoredTestRunResults = []
await api.fetchIssuesByStatusAndSummaryId(localSelectedTestRun.testingRunResultSummaryHexId, ["IGNORED", "FIXED"]).then((issues) => {
const ignoredTestingResults = vulnerableTestingRunResults.filter(result => {
return issues.some(issue =>
issue.id.apiInfoKey.apiCollectionId === result.apiInfoKey.apiCollectionId &&
issue.id.apiInfoKey.method === result.apiInfoKey.method &&
issue.id.apiInfoKey.url === result.apiInfoKey.url &&
issue.id.testSubCategory === result.testSubType
)
})

ignoredTestRunResults = transform.prepareTestRunResults(hexId, ignoredTestingResults, subCategoryMap, subCategoryFromSourceConfigMap)
})

const updatedVulnerableTestRunResults = testRunResultsRes.filter(result => {
return !ignoredTestRunResults.some(ignoredResult => {
return JSON.stringify(result) === JSON.stringify(ignoredResult)
})
await api.fetchIssuesByStatusAndSummaryId(localSelectedTestRun.testingRunResultSummaryHexId, ["IGNORED"], sortKey, sortOrder, skip, limit, filters).then((resp) => {
const ignoredIssuesTestingResult = resp?.testingRunResultList || [];
ignoredTestRunResults = transform.prepareTestRunResults(hexId, ignoredIssuesTestingResult, subCategoryMap, subCategoryFromSourceConfigMap)
})
testRunResultsRes = selectedTab === 'vulnerable' ? updatedVulnerableTestRunResults : ignoredTestRunResults
testRunResultsRes = ignoredTestRunResults
totalIgnoredIssuesCount = ignoredTestRunResults.length
} else {
await api.fetchTestingRunResults(localSelectedTestRun.testingRunResultSummaryHexId, tableTabMap[selectedTab], sortKey, sortOrder, skip, limit, filters, queryValue).then(({ testingRunResults, testCountMap, errorEnums }) => {
testRunCountMap = testCountMap
Expand All @@ -305,7 +285,7 @@ function SingleTestRunPage() {
}
}
fillTempData(testRunResultsRes, selectedTab)
return {value: transform.getPrettifiedTestRunResults(testRunResultsRes), total: testRunCountMap[tableTabMap[selectedTab]]}
return {value: transform.getPrettifiedTestRunResults(testRunResultsRes), total: selectedTab === 'ignored_issues' ? totalIgnoredIssuesCount : testRunCountMap[tableTabMap[selectedTab]]}
}

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ export default {
})
return resp
},
async fetchTestingRunResults(testingRunResultSummaryHexId, queryMode, sortKey, sortOrder, skip, limit, filters, queryValue) {
async fetchTestingRunResults(testingRunResultSummaryHexId, queryMode, sortKey, sortOrder, skip, limit, reportFilterList, queryValue) {
const resp = await request({
url: '/api/fetchTestingRunResults',
method: 'post',
data: {
testingRunResultSummaryHexId, queryMode, sortKey, sortOrder, skip, limit, filters, queryValue
testingRunResultSummaryHexId, queryMode, sortKey, sortOrder, skip, limit, reportFilterList, queryValue
}
})
return resp
Expand Down Expand Up @@ -450,11 +450,11 @@ export default {
data: {deltaTimeForScheduledSummaries}
})
},
fetchIssuesByStatusAndSummaryId(latestTestingRunSummaryId, issueStatusQuery) {
fetchIssuesByStatusAndSummaryId(latestTestingRunSummaryId, issueStatusQuery, sortKey, sortOrder, skip, limit, filters) {
return request({
url: '/api/fetchIssuesByStatusAndSummaryId',
method: 'post',
data: { latestTestingRunSummaryId, issueStatusQuery }
data: { latestTestingRunSummaryId, issueStatusQuery, sortKey, sortOrder, skip, limit, filters }
})
},
modifyTestingRunConfig(testingRunConfigId, testConfigsAdvancedSettings){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,20 @@ const VulnerabilityReport = () => {
if (window.location.pathname.includes('testing')) {
const testingRunSummaryId = currentFilters.testingRunResultSummaryId[0]
await api.fetchTestingRunResultsSummary(testingRunSummaryId).then((resp) => {
let startTimestamp = '-'
if(resp == null) {
setScanTime('-')
} else if(resp?.state === 'COMPLETED') {
const time = func.getTimeTakenByTest(resp?.startTimestamp, resp?.endTimestamp)
setScanTime(time || '-')
startTimestamp = func.getFormattedDate(resp?.startTimestamp)
} else {
setScanTime("-")
startTimestamp = func.getFormattedDate(resp?.startTimestamp)
}
setCurrentDate(startTimestamp)

if(resp?.startTimestamp) {
setCurrentDate(func.getFormattedDate(resp?.startTimestamp))
} else {
setCurrentDate('-')
}
})

while (true) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ public void createIndicesIfAbsent() {

fieldNames = new String[]{TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, TestingRunResult.TEST_SUPER_TYPE};
MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, false);

fieldNames = new String[]{TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, TestingRunResult.VULNERABLE, TestingRunResult.API_INFO_KEY, TestingRunResult.TEST_SUB_TYPE};
MCollection.createIndexIfAbsent(getDBName(), getCollName(), fieldNames, false);
}

public void convertToCappedCollection() {
Expand Down

0 comments on commit 4d8be68

Please sign in to comment.