diff --git a/apps/dashboard/src/main/java/com/akto/action/ApiCollectionsAction.java b/apps/dashboard/src/main/java/com/akto/action/ApiCollectionsAction.java index 45b2194dc7..db9372f096 100644 --- a/apps/dashboard/src/main/java/com/akto/action/ApiCollectionsAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/ApiCollectionsAction.java @@ -578,7 +578,7 @@ public String fetchSensitiveInfoInCollections(){ sensitiveSubtypes.addAll(SingleTypeInfoDao.instance.sensitiveSubTypeNames()); List sensitiveSubtypesInRequest = SingleTypeInfoDao.instance.sensitiveSubTypeInRequestNames(); - this.sensitiveUrlsInResponse = SingleTypeInfoDao.instance.getSensitiveApisCount(sensitiveSubtypes, true, Filters.empty()); + this.sensitiveUrlsInResponse = SingleTypeInfoDao.instance.getSensitiveApisCount(sensitiveSubtypes, true, Filters.nin(SingleTypeInfo._COLLECTION_IDS, deactivatedCollections)); sensitiveSubtypes.addAll(sensitiveSubtypesInRequest); this.sensitiveSubtypesInCollection = SingleTypeInfoDao.instance.getSensitiveSubtypesDetectedForCollection(sensitiveSubtypes); diff --git a/apps/dashboard/src/main/java/com/akto/action/JiraIntegrationAction.java b/apps/dashboard/src/main/java/com/akto/action/JiraIntegrationAction.java index 8c59b635f7..9019620b34 100644 --- a/apps/dashboard/src/main/java/com/akto/action/JiraIntegrationAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/JiraIntegrationAction.java @@ -1,9 +1,19 @@ package com.akto.action; import java.io.File; +import java.net.URL; import java.util.*; import java.util.concurrent.TimeUnit; +import com.akto.dao.test_editor.YamlTemplateDao; +import com.akto.dao.testing.TestingRunResultDao; +import com.akto.dto.ApiInfo; +import com.akto.dto.test_editor.Info; +import com.akto.dto.test_editor.YamlTemplate; +import com.akto.dto.test_run_findings.TestingRunIssues; +import com.akto.dto.testing.TestResult; +import com.akto.dto.testing.TestingRunResult; +import com.mongodb.client.model.Projections; import org.apache.commons.io.FileUtils; import org.bson.conversions.Bson; @@ -15,6 +25,7 @@ import com.akto.dto.OriginalHttpResponse; import com.akto.dto.jira_integration.JiraIntegration; import com.akto.dto.jira_integration.JiraMetaData; +import com.akto.dto.test_run_findings.TestingIssuesId; import com.akto.log.LoggerMaker; import com.akto.log.LoggerMaker.LogDb; import com.akto.parsers.HttpCallParser; @@ -56,6 +67,7 @@ public class JiraIntegrationAction extends UserAction { private final String META_ENDPOINT = "/rest/api/3/issue/createmeta"; private final String CREATE_ISSUE_ENDPOINT = "/rest/api/3/issue"; + private final String CREATE_ISSUE_ENDPOINT_BULK = "/rest/api/3/issue/bulk"; private final String ATTACH_FILE_ENDPOINT = "/attachments"; private static final LoggerMaker loggerMaker = new LoggerMaker(ApiExecutor.class); private static final OkHttpClient client = CoreHTTPClient.client.newBuilder() @@ -189,42 +201,12 @@ public String fetchIntegration() { public String createIssue() { BasicDBObject reqPayload = new BasicDBObject(); - BasicDBObject fields = new BasicDBObject(); - - String endpoint = jiraMetaData.getEndPointStr().replace("Endpoint - ", ""); - String truncatedEndpoint = endpoint; - if(endpoint.length() > 30) { - truncatedEndpoint = endpoint.substring(0, 15) + "..." + endpoint.substring(endpoint.length() - 15); - } - - String endpointMethod = jiraMetaData.getTestingIssueId().getApiInfoKey().getMethod().name(); - - // issue title - fields.put("summary", "Akto Report - " + jiraMetaData.getIssueTitle() + " (" + endpointMethod + " - " + truncatedEndpoint + ")"); jiraIntegration = JiraIntegrationDao.instance.findOne(new BasicDBObject()); - - // issue type (TASK) - BasicDBObject issueTypeObj = new BasicDBObject(); - issueTypeObj.put("id", this.issueType); - fields.put("issuetype", issueTypeObj); - - // project id - BasicDBObject project = new BasicDBObject(); - project.put("key", this.projId); - fields.put("project", project); - - // issue description - BasicDBObject description = new BasicDBObject(); - description.put("type", "doc"); - description.put("version", 1); - BasicDBList contentList = new BasicDBList(); - contentList.add(buildContentDetails(jiraMetaData.getHostStr(), null)); - contentList.add(buildContentDetails(jiraMetaData.getEndPointStr(), null)); - contentList.add(buildContentDetails("Issue link - Akto dashboard", jiraMetaData.getIssueUrl())); - contentList.add(buildContentDetails(jiraMetaData.getIssueDescription(), null)); - description.put("content", contentList); - - fields.put("description", description); + if(jiraIntegration == null) { + addActionError("Jira is not integrated."); + return ERROR.toUpperCase(); + } + BasicDBObject fields = jiraTicketPayloadCreator(jiraMetaData); reqPayload.put("fields", fields); @@ -376,6 +358,244 @@ private BasicDBObject buildContentDetails(String txt, String link) { return details; } + String aktoDashboardHost; + List issuesIds; + private String errorMessage; + public String bulkCreateJiraTickets (){ + if(issuesIds == null || issuesIds.isEmpty()){ + addActionError("Cannot create an empty jira issue."); + return ERROR.toUpperCase(); + } + + if((projId == null || projId.isEmpty()) || (issueType == null || issueType.isEmpty())){ + addActionError("Project ID or Issue Type cannot be empty."); + return ERROR.toUpperCase(); + } + + jiraIntegration = JiraIntegrationDao.instance.findOne(new BasicDBObject()); + if(jiraIntegration == null) { + addActionError("Jira is not integrated."); + return ERROR.toUpperCase(); + } + + List jiraMetaDataList = new ArrayList<>(); + Bson projection = Projections.include(YamlTemplate.INFO); + List testingSubCategories = new ArrayList<>(); + for(TestingIssuesId testingIssuesId : issuesIds) { + testingSubCategories.add(testingIssuesId.getTestSubCategory()); + } + List yamlTemplateList = YamlTemplateDao.instance.findAll(Filters.in("_id", testingSubCategories), projection); + Map testSubTypeToInfoMap = new HashMap<>(); + for(YamlTemplate yamlTemplate : yamlTemplateList) { + if(yamlTemplate == null || yamlTemplate.getInfo() == null) { + loggerMaker.errorAndAddToDb("ERROR: YamlTemplate or YamlTemplate.info is null", LogDb.DASHBOARD); + continue; + } + Info info = yamlTemplate.getInfo(); + testSubTypeToInfoMap.put(info.getSubCategory(), info); + } + + List testingRunResultList = new ArrayList<>(); + int existingIssues = 0; + List testingRunIssuesList = TestingRunIssuesDao.instance.findAll(Filters.and( + Filters.in("_id", issuesIds), + Filters.exists("jiraIssueUrl", true) + )); + Set testingRunIssueIds = new HashSet<>(); + for (TestingRunIssues testingRunIssues : testingRunIssuesList) { + testingRunIssueIds.add(testingRunIssues.getId()); + } + + for(TestingIssuesId testingIssuesId : issuesIds) { + if(testingRunIssueIds.contains(testingIssuesId)) { + existingIssues++; + continue; + } + + Info info = testSubTypeToInfoMap.get(testingIssuesId.getTestSubCategory()); + + TestingRunResult testingRunResult = TestingRunResultDao.instance.findOne(Filters.and( + Filters.in(TestingRunResult.TEST_SUB_TYPE, testingIssuesId.getTestSubCategory()), + Filters.in(TestingRunResult.API_INFO_KEY, testingIssuesId.getApiInfoKey()) + ), Projections.include("_id", TestingRunResult.TEST_RESULTS)); + + if(testingRunResult == null) { + loggerMaker.errorAndAddToDb("Error: Testing Run Result not found", LogDb.DASHBOARD); + continue; + } + + testingRunResultList.add(testingRunResult); + + JiraMetaData jiraMetaData; + try { + String inputUrl = testingIssuesId.getApiInfoKey().getUrl(); + + URL url = new URL(inputUrl); + String hostname = url.getHost(); + String endpoint = url.getPath(); + + jiraMetaData = new JiraMetaData( + info.getName(), + "Host - "+hostname, + endpoint, + aktoDashboardHost+"/dashboard/issues?result="+testingRunResult.getId().toHexString(), + info.getDescription(), + testingIssuesId + ); + + } catch (Exception e) { + loggerMaker.errorAndAddToDb("Error while parsing the url: " + e.getMessage(), LogDb.DASHBOARD); + continue; + } + + jiraMetaDataList.add(jiraMetaData); + } + + BasicDBObject reqPayload = new BasicDBObject(); + BasicDBList issueUpdates = new BasicDBList(); + + if(existingIssues == issuesIds.size()) { + errorMessage = "All selected issues already have existing Jira tickets. No new tickets were created."; + } else if(existingIssues > 0) { + errorMessage = "Jira tickets created for all selected issues, except for " + existingIssues + " issues that already have tickets."; + } + + if(jiraMetaDataList.isEmpty()) { + return Action.SUCCESS.toUpperCase(); + } + + for (JiraMetaData jiraMetaData : jiraMetaDataList) { + BasicDBObject fields = jiraTicketPayloadCreator(jiraMetaData); + + // Prepare the issue object + BasicDBObject issueObject = new BasicDBObject(); + issueObject.put("fields", fields); + issueUpdates.add(issueObject); + } + + // Prepare the full request payload + reqPayload.put("issueUpdates", issueUpdates); + + // URL for bulk create issues + String url = jiraIntegration.getBaseUrl() + CREATE_ISSUE_ENDPOINT_BULK; + String authHeader = Base64.getEncoder().encodeToString((jiraIntegration.getUserEmail() + ":" + jiraIntegration.getApiToken()).getBytes()); + + Map> headers = new HashMap<>(); + headers.put("Authorization", Collections.singletonList("Basic " + authHeader)); + + OriginalHttpRequest request = new OriginalHttpRequest(url, "", "POST", reqPayload.toString(), headers, ""); + + try { + OriginalHttpResponse response = ApiExecutor.sendRequest(request, true, null, false, new ArrayList<>()); + String responsePayload = response.getBody(); + + if (response.getStatusCode() > 201 || responsePayload == null) { + loggerMaker.errorAndAddToDb("Error while creating Jira issues in bulk, URL not accessible, request body " + + request.getBody() + " ,response body " + response.getBody() + " ,response status " + response.getStatusCode(), + LoggerMaker.LogDb.DASHBOARD); + + if (responsePayload != null) { + try { + BasicDBObject obj = BasicDBObject.parse(responsePayload); + List errorMessages = (List) obj.get("errorMessages"); + String error; + if (errorMessages.size() == 0) { + BasicDBObject errObj = BasicDBObject.parse(obj.getString("errors")); + error = errObj.getString("project"); + } else { + error = errorMessages.get(0); + } + addActionError(error); + } catch (Exception e) { + // Handle exception + } + } + + return Action.ERROR.toUpperCase(); + } + + BasicDBObject payloadObj; + try { + payloadObj = BasicDBObject.parse(responsePayload); + List issues = (List) payloadObj.get("issues"); + for (BasicDBObject issue : issues) { + String issueKey = issue.getString("key"); + String jiraTicketUrl = jiraIntegration.getBaseUrl() + "/browse/" + issueKey; + + for (JiraMetaData metaData : jiraMetaDataList) { + TestingRunIssuesDao.instance.getMCollection().updateOne( + Filters.eq(Constants.ID, metaData.getTestingIssueId()), + Updates.combine(Updates.set("jiraIssueUrl", jiraTicketUrl)), + new UpdateOptions().upsert(false) + ); + } + } + + for (int i = 0; i < issues.size(); i++) { + BasicDBObject issue = issues.get(i); + TestingRunResult testingRunResult = testingRunResultList.get(i); + String issueKey = issue.getString("key"); + TestResult genericTestResult = (TestResult) testingRunResult.getTestResults().get(testingRunResult.getTestResults().size() - 1); + setIssueId(issueKey); + setOrigReq(genericTestResult.getOriginalMessage()); + setTestReq(genericTestResult.getMessage()); + String status = attachFileToIssue(); + if (status.equals(ERROR.toUpperCase())) { + return ERROR.toUpperCase(); + } + } + } catch (Exception e) { + loggerMaker.errorAndAddToDb(e, "Error processing Jira bulk issue response " + e.getMessage(), LoggerMaker.LogDb.DASHBOARD); + return Action.ERROR.toUpperCase(); + } + + } catch (Exception e) { + loggerMaker.errorAndAddToDb(e, "Error making Jira bulk create request: " + e.getMessage(), LoggerMaker.LogDb.DASHBOARD); + return Action.ERROR.toUpperCase(); + } + + return Action.SUCCESS.toUpperCase(); + } + + private BasicDBObject jiraTicketPayloadCreator(JiraMetaData jiraMetaData) { + BasicDBObject fields = new BasicDBObject(); + String endpoint = jiraMetaData.getEndPointStr().replace("Endpoint - ", ""); + String truncatedEndpoint = endpoint; + if(endpoint.length() > 30) { + truncatedEndpoint = endpoint.substring(0, 15) + "..." + endpoint.substring(endpoint.length() - 15); + } + + String endpointMethod = jiraMetaData.getTestingIssueId().getApiInfoKey().getMethod().name(); + + // issue title + fields.put("summary", "Akto Report - " + jiraMetaData.getIssueTitle() + " (" + endpointMethod + " - " + truncatedEndpoint + ")"); + + // Issue type (TASK) + BasicDBObject issueTypeObj = new BasicDBObject(); + issueTypeObj.put("id", this.issueType); + fields.put("issuetype", issueTypeObj); + + // Project ID + BasicDBObject project = new BasicDBObject(); + project.put("key", this.projId); + fields.put("project", project); + + // Issue description + BasicDBObject description = new BasicDBObject(); + description.put("type", "doc"); + description.put("version", 1); + BasicDBList contentList = new BasicDBList(); + contentList.add(buildContentDetails(jiraMetaData.getHostStr(), null)); + contentList.add(buildContentDetails(jiraMetaData.getEndPointStr(), null)); + contentList.add(buildContentDetails("Issue link - Akto dashboard", jiraMetaData.getIssueUrl())); + contentList.add(buildContentDetails(jiraMetaData.getIssueDescription(), null)); + description.put("content", contentList); + + fields.put("description", description); + + return fields; + } + public String getBaseUrl() { return baseUrl; } @@ -467,5 +687,16 @@ public String getJiraTicketKey() { public void setJiraTicketKey(String jiraTicketKey) { this.jiraTicketKey = jiraTicketKey; } - + + public void setIssuesIds(List issuesIds) { + this.issuesIds = issuesIds; + } + + public void setAktoDashboardHost(String aktoDashboardHost) { + this.aktoDashboardHost = aktoDashboardHost; + } + + public String getErrorMessage() { + return errorMessage; + } } diff --git a/apps/dashboard/src/main/resources/struts.xml b/apps/dashboard/src/main/resources/struts.xml index 9c1cd9c624..c55eba1cc0 100644 --- a/apps/dashboard/src/main/resources/struts.xml +++ b/apps/dashboard/src/main/resources/struts.xml @@ -6343,6 +6343,28 @@ + + + + + ISSUES + READ_WRITE + User created jira issues in bulk + + + + 403 + false + ^actionErrors.* + + + + 422 + false + ^actionErrors.*, ^responses.* + + + diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/JiraTicketCreationModal.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/JiraTicketCreationModal.jsx new file mode 100644 index 0000000000..f367a87736 --- /dev/null +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/JiraTicketCreationModal.jsx @@ -0,0 +1,60 @@ +import { Modal, Text, VerticalStack } from '@shopify/polaris' +import React, { useState } from 'react' +import DropdownSearch from './DropdownSearch' + +const JiraTicketCreationModal = ({ activator, modalActive, setModalActive, handleSaveAction, jiraProjectMaps, setProjId, setIssueType, projId, issueType, issueId }) => { + const [isCreatingTicket, setIsCreatingTicket] = useState(false) + + const getValueFromIssueType = (projId, issueId) => { + if(Object.keys(jiraProjectMaps).length > 0 && projId.length > 0 && issueId.length > 0){ + const jiraTemp = jiraProjectMaps[projId].filter(x => x.issueId === issueId) + if(jiraTemp.length > 0){ + return jiraTemp[0].issueType + } + } + return issueType + } + + return ( + setModalActive(false)} + size="small" + title={Configure jira ticket details} + primaryAction={{ + content: 'Create ticket', + onAction: () => { + setIsCreatingTicket(true) + handleSaveAction(issueId) + setIsCreatingTicket(false) + }, + disabled: (!projId || !issueType || isCreatingTicket) + }} + > + + + {return{label: x, value: x}}): []} + setSelected={setProjId} + preSelected={projId} + value={projId} + /> + + 0 ? jiraProjectMaps[projId].map((x) => {return{label: x.issueType, value: x.issueId}}) : []} + setSelected={setIssueType} + preSelected={issueType} + value={getValueFromIssueType(projId, issueType)} + /> + + + + ) +} + +export default JiraTicketCreationModal \ No newline at end of file diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/IssuesPage/IssuesPage.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/IssuesPage/IssuesPage.jsx index a0704569c9..66e1d251cf 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/IssuesPage/IssuesPage.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/IssuesPage/IssuesPage.jsx @@ -6,7 +6,7 @@ import Store from "../../../store"; import func from "@/util/func"; import { MarkFulfilledMinor, ReportMinor, ExternalMinor } from '@shopify/polaris-icons'; import PersistStore from "../../../../main/PersistStore"; -import { Button, HorizontalGrid, HorizontalStack, IndexFiltersMode } from "@shopify/polaris"; +import { Button, HorizontalGrid, HorizontalStack, IndexFiltersMode, Modal, Text, VerticalStack } from "@shopify/polaris"; import EmptyScreensLayout from "../../../components/banners/EmptyScreensLayout"; import { ISSUES_PAGE_DOCS_URL } from "../../../../main/onboardingData"; import {SelectCollectionComponent} from "../../testing/TestRunsPage/TestrunsBannerComponent" @@ -27,6 +27,9 @@ import SpinnerCentered from "../../../components/progress/SpinnerCentered.jsx"; import TableStore from "../../../components/tables/TableStore.js"; import CriticalFindingsGraph from "./CriticalFindingsGraph.jsx"; import CriticalUnsecuredAPIsOverTimeGraph from "./CriticalUnsecuredAPIsOverTimeGraph.jsx"; +import DropdownSearch from "../../../components/shared/DropdownSearch.jsx"; +import settingFunctions from "../../settings/module.js"; +import JiraTicketCreationModal from "../../../components/shared/JiraTicketCreationModal.jsx"; const sortOptions = [ { label: 'Severity', value: 'severity asc', directionLabel: 'Highest', sortKey: 'severity', columnIndex: 2 }, @@ -127,6 +130,11 @@ function IssuesPage() { const [selected, setSelected] = useState(0) const [tableLoading, setTableLoading] = useState(false) const [issuesDataCount, setIssuesDataCount] = useState([]) + const [jiraModalActive, setJiraModalActive] = useState(false) + const [selectedIssuesItems, setSelectedIssuesItems] = useState([]) + const [jiraProjectMaps,setJiraProjectMap] = useState({}) + const [issueType, setIssueType] = useState(''); + const [projId, setProjId] = useState('') const [currDateRange, dispatchCurrDateRange] = useReducer(produce((draft, action) => func.dateRangeReducer(draft, action)), values.ranges[5]) @@ -166,6 +174,7 @@ function IssuesPage() { TableStore.getState().setSelectedItems([]) selectItems([]) setKey(!key) + setSelectedIssuesItems([]) } useEffect(() => { @@ -200,6 +209,19 @@ function IssuesPage() { filtersOptions = func.getCollectionFilters(filtersOptions) + const handleSaveJiraAction = () => { + setToast(true, false, "Please wait while we create your Jira ticket.") + setJiraModalActive(false) + api.bulkCreateJiraTickets(selectedIssuesItems, window.location.origin, projId, issueType).then((res) => { + if(res?.errorMessage) { + setToast(true, false, res?.errorMessage) + } else { + setToast(true, false, `${selectedIssuesItems.length} jira ticket${selectedIssuesItems.length === 1 ? "" : "s"} created.`) + } + resetResourcesSelected() + }) + } + let promotedBulkActions = (selectedResources) => { let items if(selectedResources.length > 0 && typeof selectedResources[0][0] === 'string') { @@ -222,6 +244,22 @@ function IssuesPage() { resetResourcesSelected() }) } + + function createJiraTicketBulk () { + setSelectedIssuesItems(items) + settingFunctions.fetchJiraIntegration().then((jirIntegration) => { + if(jirIntegration.projectIdsMap !== null && Object.keys(jirIntegration.projectIdsMap).length > 0){ + setJiraProjectMap(jirIntegration.projectIdsMap) + if(Object.keys(jirIntegration.projectIdsMap).length > 0){ + setProjId(Object.keys(jirIntegration.projectIdsMap)[0]) + } + }else{ + setProjId(jirIntegration.projId) + setIssueType(jirIntegration.issueType) + } + setJiraModalActive(true) + }) + } let issues = [{ content: 'False positive', @@ -234,6 +272,10 @@ function IssuesPage() { { content: 'No time to fix', onAction: () => { ignoreAction("No time to fix") } + }, + { + content: 'Create jira ticket', + onAction: () => { createJiraTicketBulk() } }] let reopen = [{ @@ -246,12 +288,12 @@ function IssuesPage() { switch (status) { case "OPEN": ret = [].concat(issues); break; - case "IGNORED": if (items.length == 1) { - ret = [].concat(issues); - } + case "IGNORED": ret = ret.concat(reopen); break; case "FIXED": + default: + ret = [] } return ret; @@ -474,6 +516,16 @@ function IssuesPage() { secondaryActions={ dispatchCurrDateRange({ type: "update", period: dateObj.period, title: dateObj.title, alias: dateObj.alias })} />} /> {(resultId !== null && resultId.length > 0) ? : null} + ) } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/api.js index 23ab2ab8c4..f262ab32c7 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/api.js @@ -51,4 +51,11 @@ export default { data: {startTimeStamp, endTimeStamp} }) }, + bulkCreateJiraTickets(issuesIds, aktoDashboardHost, projId, issueType){ + return request({ + url: 'api/bulkCreateJiraTickets', + method: 'post', + data: {issuesIds, aktoDashboardHost, projId, issueType} + }) + } } \ No newline at end of file diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx index 389d192c68..f620e47144 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiCollections.jsx @@ -763,7 +763,7 @@ function ApiCollections() { key={refreshData} pageLimit={100} data={data[selectedTab]} - sortOptions={ selectedTab === 'groups' ? [...tempSortOptions, ...sortOptions] : sortOptions} + sortOptions={ selectedTab === 'groups' ? [...tempSortOptions, ...sortOptions] : sortOptions} resourceName={resourceName} filters={[]} disambiguateLabel={disambiguateLabel} 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 95c4690ccd..7ad8dbde32 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 @@ -16,6 +16,7 @@ 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) { @@ -129,17 +130,6 @@ function TestRunResultFlyout(props) { window.open(navUrl, "_blank") } - const getValueFromIssueType = (projId, issueId) => { - if(Object.keys(jiraProjectMaps).length > 0 && projId.length > 0 && issueId.length > 0){ - const jiraTemp = jiraProjectMaps[projId].filter(x => x.issueId === issueId) - if(jiraTemp.length > 0){ - return jiraTemp[0].issueType - } - } - return issueType - - } - function ActionsComp (){ const issuesActions = issueDetails?.testRunIssueStatus === "IGNORED" ? [...issues, ...reopen] : issues return( @@ -190,39 +180,18 @@ function TestRunResultFlyout(props) { {selectedTestRunResult && selectedTestRunResult.vulnerable && - Create Jira Ticket} - open={modalActive} - onClose={() => setModalActive(false)} - size="small" - title={Configure jira ticket details} - primaryAction={{ - content: 'Create ticket', - onAction: () => handleSaveAction(issueDetails.id) - }} - > - - - {return{label: x, value: x}}): []} - setSelected={setProjId} - preSelected={projId} - value={projId} - /> - - 0 ? jiraProjectMaps[projId].map((x) => {return{label: x.issueType, value: x.issueId}}) : []} - setSelected={setIssueType} - preSelected={issueType} - value={getValueFromIssueType(projId, issueType)} - /> - - - + modalActive={modalActive} + setModalActive={setModalActive} + handleSaveAction={handleSaveAction} + jiraProjectMaps={jiraProjectMaps} + setProjId={setProjId} + setIssueType={setIssueType} + projId={projId} + issueType={issueType} + issueId={issueDetails.id} + /> } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultPage.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultPage.jsx index 02447bb8b1..0c45df452b 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultPage.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunResultPage/TestRunResultPage.jsx @@ -169,6 +169,9 @@ function TestRunResultPage(props) { let jiraTicketKey = "" await createJiraTicketApiCall("Host - "+hostName, pathname, window.location.href, description, issueTitle, issueId, projId, issueType).then(async(res)=> { + if(res?.errorMessage) { + setToast(true, true, res?.errorMessage) + } jiraTicketKey = res await fetchData(); setToast(true,false,"Jira Ticket Created, scroll down to view") diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx index 83e1044105..c548053ce8 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/vulnerability_report/VulnerabilityReport.jsx @@ -83,7 +83,7 @@ const VulnerabilityReport = () => { } setCurrentDate(startTimestamp) }) - + while (true) { let testingRunCountsFromDB = 0 await api.fetchVulnerableTestingRunResults(testingRunSummaryId, resultsCount).then(async(resp) => { @@ -289,7 +289,7 @@ const VulnerabilityReport = () => { const reportSummaryItems = [ { - title: "Total Vulnerable APIs", + title: "Vulnerable APIs found", data: totalApisTested, }, {