diff --git a/apps/dashboard/src/main/java/com/akto/action/HomeAction.java b/apps/dashboard/src/main/java/com/akto/action/HomeAction.java index eecf44372f..efa1615d77 100644 --- a/apps/dashboard/src/main/java/com/akto/action/HomeAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/HomeAction.java @@ -51,6 +51,9 @@ public String execute() { if (GithubLogin.getClientId() != null) { servletRequest.setAttribute("githubClientId", new String(Base64.getEncoder().encode(GithubLogin.getClientId().getBytes()))); } + if (GithubLogin.getGithubUrl() != null) { + servletRequest.setAttribute("githubUrl", GithubLogin.getGithubUrl()); + } if(OktaLogin.getAuthorisationUrl() != null){ servletRequest.setAttribute("oktaAuthUrl", new String(Base64.getEncoder().encode(OktaLogin.getAuthorisationUrl().getBytes()))); } diff --git a/apps/dashboard/src/main/java/com/akto/action/SignupAction.java b/apps/dashboard/src/main/java/com/akto/action/SignupAction.java index e3c7ae1ffb..774c868b8b 100644 --- a/apps/dashboard/src/main/java/com/akto/action/SignupAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/SignupAction.java @@ -434,27 +434,59 @@ public String registerViaEmail() { } public String registerViaGithub() { + logger.info("registerViaGithub"); if (!DashboardMode.isOnPremDeployment()) return Action.ERROR.toUpperCase(); GithubLogin ghLoginInstance = GithubLogin.getInstance(); if (ghLoginInstance == null) { return ERROR.toUpperCase(); } + logger.info("Found github instance"); Config.GithubConfig githubConfig = GithubLogin.getInstance().getGithubConfig(); if (githubConfig == null) { return ERROR.toUpperCase(); } + logger.info("Found github configuration"); BasicDBObject params = new BasicDBObject(); params.put("client_id", githubConfig.getClientId()); params.put("client_secret", githubConfig.getClientSecret()); params.put("code", this.code); + logger.info("Github code length: {}", this.code.length()); try { - Map tokenData = CustomHttpRequest.postRequest("https://github.com/login/oauth/access_token", params); + String githubUrl = githubConfig.getGithubUrl(); + if (StringUtils.isEmpty(githubUrl)) githubUrl = "https://github.com"; + + String githubApiUrl = githubConfig.getGithubApiUrl(); + if (StringUtils.isEmpty(githubApiUrl)) githubApiUrl = "https://api.github.com"; + + if (githubApiUrl.endsWith("/")) githubApiUrl = githubApiUrl.substring(0, githubApiUrl.length() - 1); + if (githubUrl.endsWith("/")) githubUrl = githubUrl.substring(0, githubUrl.length() - 1); + + logger.info("Github URL: {}", githubUrl); + logger.info("Github API URL: {}", githubApiUrl); + + Map tokenData = CustomHttpRequest.postRequest(githubUrl + "/login/oauth/access_token", params); + logger.info("Post request to {} success", githubUrl); + String accessToken = tokenData.get("access_token").toString(); + if (StringUtils.isEmpty(accessToken)){ + logger.info("Access token empty"); + } else { + logger.info("Access token length: {}", accessToken.length()); + } + String refreshToken = tokenData.getOrDefault("refresh_token", "").toString(); - int refreshTokenExpiry = Integer.parseInt(tokenData.getOrDefault("refresh_token_expires_in", "0").toString()); - Map userData = CustomHttpRequest.getRequest("https://api.github.com/user", "Bearer " + accessToken); + if (StringUtils.isEmpty(refreshToken)){ + logger.info("Refresh token empty"); + } else { + logger.info("Refresh token length: {}", refreshToken.length()); + } + + int refreshTokenExpiry = (int) Double.parseDouble(tokenData.getOrDefault("refresh_token_expires_in", "0").toString()); + Map userData = CustomHttpRequest.getRequest(githubApiUrl + "/user", "Bearer " + accessToken); + logger.info("Get request to {} success", githubApiUrl); String company = "sso"; String username = userData.get("login").toString() + "@" + company; + logger.info("username {}", username); SignupInfo.GithubSignupInfo ghSignupInfo = new SignupInfo.GithubSignupInfo(accessToken, refreshToken, refreshTokenExpiry, username); shouldLogin = "true"; createUserAndRedirect(username, username, ghSignupInfo, 1000000, Config.ConfigType.GITHUB.toString()); @@ -462,7 +494,12 @@ public String registerViaGithub() { logger.info("Executed registerViaGithub"); } catch (IOException e) { + e.printStackTrace(); + logger.error(e.getMessage()); return ERROR.toUpperCase(); + } catch (Exception e) { + e.printStackTrace(); + logger.error(e.getMessage()); } return SUCCESS.toUpperCase(); } 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 03ec2c5314..87044bfbe4 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 @@ -691,7 +691,6 @@ public String stopAllTests() { } public String stopTest() { - // stop only scheduled and running tests Bson filter = Filters.or( Filters.eq(TestingRun.STATE, State.SCHEDULED), Filters.eq(TestingRun.STATE, State.RUNNING)); @@ -701,6 +700,11 @@ public String stopTest() { TestingRunDao.instance.updateOne( Filters.and(filter, Filters.eq(Constants.ID, testingId)), Updates.set(TestingRun.STATE, State.STOPPED)); + Bson testingSummaryFilter = Filters.and( + Filters.eq(TestingRunResultSummary.TESTING_RUN_ID,testingId), + filter + ); + TestingRunResultSummariesDao.instance.updateManyNoUpsert(testingSummaryFilter, Updates.set(TestingRunResultSummary.STATE, State.STOPPED)); return SUCCESS.toUpperCase(); } catch (Exception e) { loggerMaker.errorAndAddToDb(e, "ERROR: Stop test failed - " + e.toString(), LogDb.DASHBOARD); diff --git a/apps/dashboard/src/main/java/com/akto/action/testing_issues/IssuesAction.java b/apps/dashboard/src/main/java/com/akto/action/testing_issues/IssuesAction.java index d320d026e1..ae56978489 100644 --- a/apps/dashboard/src/main/java/com/akto/action/testing_issues/IssuesAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/testing_issues/IssuesAction.java @@ -182,6 +182,13 @@ public String fetchTestingRunResult() { Filters.eq(TestingRunResult.API_INFO_KEY, issue.getId().getApiInfoKey()) ); testingRunResult = TestingRunResultDao.instance.findOne(filterForRunResult); + if (issue.isUnread()) { + logger.info("Issue id from db to be marked as read " + issueId); + Bson update = Updates.combine(Updates.set(TestingRunIssues.UNREAD, false), + Updates.set(TestingRunIssues.LAST_UPDATED, Context.now())); + TestingRunIssues updatedIssue = TestingRunIssuesDao.instance.updateOneNoUpsert(Filters.eq(ID, issueId), update); + issueId = updatedIssue.getId(); + } return SUCCESS.toUpperCase(); } diff --git a/apps/dashboard/src/main/java/com/akto/action/user/GithubSsoAction.java b/apps/dashboard/src/main/java/com/akto/action/user/GithubSsoAction.java index 1fa369c18d..c458bf6d17 100644 --- a/apps/dashboard/src/main/java/com/akto/action/user/GithubSsoAction.java +++ b/apps/dashboard/src/main/java/com/akto/action/user/GithubSsoAction.java @@ -22,6 +22,7 @@ import okhttp3.OkHttpClient; +import org.apache.commons.lang3.StringUtils; import org.kohsuke.github.GitHub; import org.kohsuke.github.GitHubBuilder; import org.kohsuke.github.connector.GitHubConnector; @@ -123,6 +124,8 @@ public String addGithubAppSecretKey() { private String githubAppSecretKey; private String githubAppId; private String testingRunSummaryHexId; + private String githubUrl; + private String githubApiUrl; public String addGithubSso() { if(!DashboardMode.isOnPremDeployment()){ @@ -146,6 +149,8 @@ public String addGithubSso() { Config.GithubConfig ghConfig = new Config.GithubConfig(); ghConfig.setClientId(githubClientId); ghConfig.setClientSecret(githubClientSecret); + if (!StringUtils.isEmpty(githubUrl)) ghConfig.setGithubUrl(githubUrl); + if (!StringUtils.isEmpty(githubApiUrl)) ghConfig.setGithubApiUrl(githubApiUrl); ConfigsDao.instance.insertOne(ghConfig); @@ -168,6 +173,8 @@ public String execute() throws Exception { if (githubConfig != null) { this.githubClientId = githubConfig.getClientId(); + this.githubApiUrl = githubConfig.getGithubApiUrl(); + this.githubUrl = githubConfig.getGithubUrl(); } return SUCCESS.toUpperCase(); @@ -208,4 +215,20 @@ public String getGithubAppId() { public void setGithubAppId(String githubAppId) { this.githubAppId = githubAppId; } + + public void setGithubUrl(String githubUrl) { + this.githubUrl = githubUrl; + } + + public void setGithubApiUrl(String githubApiUrl) { + this.githubApiUrl = githubApiUrl; + } + + public String getGithubUrl() { + return githubUrl; + } + + public String getGithubApiUrl() { + return githubApiUrl; + } } diff --git a/apps/dashboard/src/main/java/com/akto/utils/GithubLogin.java b/apps/dashboard/src/main/java/com/akto/utils/GithubLogin.java index 7b90788c27..7637b81959 100644 --- a/apps/dashboard/src/main/java/com/akto/utils/GithubLogin.java +++ b/apps/dashboard/src/main/java/com/akto/utils/GithubLogin.java @@ -40,6 +40,18 @@ public static String getClientId() { return ghConfig.getClientId(); } + public static String getGithubUrl() { + if (getInstance() == null) return null; + + GithubConfig ghConfig = getInstance().getGithubConfig(); + if (ghConfig == null) return null; + + String githubUrl = ghConfig.getGithubUrl(); + if (githubUrl == null) return null; + if (githubUrl.endsWith("/")) githubUrl = githubUrl.substring(0, githubUrl.length() - 1); + return githubUrl; + } + private GithubLogin() { } diff --git a/apps/dashboard/web/pages/login.jsp b/apps/dashboard/web/pages/login.jsp index 06b9c3d249..981ad39f3c 100644 --- a/apps/dashboard/web/pages/login.jsp +++ b/apps/dashboard/web/pages/login.jsp @@ -62,6 +62,7 @@ window.RELEASE_VERSION_GLOBAL = '${requestScope.AktoVersionGlobal}'; window.AKTO_UI_MODE = '${requestScope.aktoUIMode}' window.GITHUB_CLIENT_ID=atob('${requestScope.githubClientId}') + window.GITHUB_URL='${requestScope.githubUrl}' window.STIGG_CUSTOMER_ID='${requestScope.stiggCustomerId}' window.STIGG_CUSTOMER_TOKEN='${requestScope.stiggCustomerToken}' window.STIGG_CLIENT_KEY='${requestScope.stiggClientKey}' diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/ConditionsPicker.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/ConditionsPicker.jsx index 6679ebe790..abb451da47 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/ConditionsPicker.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/ConditionsPicker.jsx @@ -1,4 +1,4 @@ -import { Button, LegacyCard, VerticalStack, Text } from '@shopify/polaris' +import { Button, LegacyCard, VerticalStack } from '@shopify/polaris' import React from 'react' import Dropdown from './layouts/Dropdown'; import {DeleteMinor} from "@shopify/polaris-icons" diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/TestRolesConditionsPicker.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/TestRolesConditionsPicker.jsx index ee5224e70d..c7d0e06b2f 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/TestRolesConditionsPicker.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/TestRolesConditionsPicker.jsx @@ -1,4 +1,4 @@ -import { Button, LegacyCard, VerticalStack, Box, HorizontalStack } from '@shopify/polaris' +import { Button, LegacyCard, VerticalStack } from '@shopify/polaris' import React from 'react' import ConditionComponent from './ConditionComponent'; import Dropdown from './layouts/Dropdown'; diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/SampleData.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/SampleData.js index 9e12cb7866..89371f0e66 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/SampleData.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/shared/SampleData.js @@ -202,7 +202,8 @@ function SampleData(props) { lightbulb: { enabled: false }, scrollbar:{ alwaysConsumeMouseWheel: false - } + }, + fixedOverflowWidgets: true } let instance = ""; if(editorLanguage.includes("custom")){ diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/GithubServerTable.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/GithubServerTable.js index 4fb755da9f..f8520f7086 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/GithubServerTable.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/GithubServerTable.js @@ -20,13 +20,23 @@ import tableFunc from './transform'; import useTable from './TableContext'; import { debounce } from 'lodash'; +import { useSearchParams } from 'react-router-dom'; + function GithubServerTable(props) { + const [searchParams, setSearchParams] = useSearchParams(); + + const updateQueryParams = (key, value) => { + const newSearchParams = new URLSearchParams(searchParams); + newSearchParams.set(key, value); + setSearchParams(newSearchParams); + }; + const filtersMap = PersistStore(state => state.filtersMap) const setFiltersMap = PersistStore(state => state.setFiltersMap) const tableInitialState = PersistStore(state => state.tableInitialState) const setTableInitialState = PersistStore(state => state.setTableInitialState) - const currentPageKey = props?.filterStateUrl || window.location.href + const currentPageKey = props?.filterStateUrl || (window.location.pathname + "/" + window.location.hash) const pageFiltersMap = filtersMap[currentPageKey] const handleRemoveAppliedFilter = (key) => { @@ -70,17 +80,28 @@ function GithubServerTable(props) { const handleSelectedTab = (x) => { const tableTabs = props.tableTabs ? props.tableTabs : props.tabs if(tableTabs){ - const primitivePath = window.location.origin + window.location.pathname + const primitivePath = window.location.origin + window.location.pathname + window.location?.search const newUrl = primitivePath + "#" + tableTabs[x].id window.history.replaceState(null, null, newUrl) } } useEffect(()=> { - setAppliedFilters(initialStateFilters) + let queryFilters + if (performance.getEntriesByType('navigation')[0].type === 'reload') { + queryFilters = [] + }else{ + queryFilters = tableFunc.getFiltersMapFromUrl(decodeURIComponent(searchParams.get("filters") || ""), props?.disambiguateLabel, handleRemoveAppliedFilter, currentPageKey) + } + const currentFilters = tableFunc.mergeFilters(queryFilters,initialStateFilters,props?.disambiguateLabel, handleRemoveAppliedFilter) + setAppliedFilters(currentFilters) setSortSelected(tableFunc.getInitialSortSelected(props.sortOptions, pageFiltersMap)) },[currentPageKey]) + useEffect(() => { + updateQueryParams("filters",tableFunc.getPrettifiedFilter(appliedFilters)) + },[appliedFilters]) + async function fetchData(searchVal) { let [sortKey, sortOrder] = sortSelected.length == 0 ? ["", ""] : sortSelected[0].split(" "); let filters = props.headers.reduce((map, e) => { map[e.filterKey || e.value] = []; return map }, {}) @@ -91,11 +112,12 @@ function GithubServerTable(props) { tempData ? setData([...tempData.value]) : setData([]) tempData ? setTotal(tempData.total) : setTotal(0) applyFilter(tempData.total) - - setTableInitialState({ - ...tableInitialState, - [currentPageKey]: tempData.total - }) + if(!performance.getEntriesByType('navigation')[0].type === 'reload'){ + setTableInitialState({ + ...tableInitialState, + [currentPageKey]: tempData.total + }) + } } useEffect(() => { @@ -108,6 +130,10 @@ function GithubServerTable(props) { setSortableColumns(tableFunc.getSortableChoices(props?.headers)) },[props?.headers]) + useEffect(() => { + fetchData(queryValue) + },[props?.callFromOutside]) + const handleSort = (col, dir) => { let tempSortSelected = props?.sortOptions.filter(x => x.columnIndex === (col + 1)) let sortVal = [tempSortSelected[0].value] @@ -275,12 +301,18 @@ function GithubServerTable(props) { setPage((page) => (page - 1)); } + const handleTabChange = (x) => { + props?.onSelect(x); + updateQueryParams("filters", tableFunc.getPrettifiedFilter([])) ; + handleSelectedTab(x) + } + let tableHeightClass = props.increasedHeight ? "control-row" : (props.condensedHeight ? "condensed-row" : '') let tableClass = props.useNewRow ? "new-table" : (props.selectable ? "removeHeaderColor" : "hideTableHead") return (
- {props.tabs && {props?.onSelect(x); handleSelectedTab(x)}}>} + {props.tabs && handleTabChange(x)}>} {props.tabs && props.tabs[props.selected].component ? props.tabs[props.selected].component :
@@ -306,7 +338,7 @@ function GithubServerTable(props) { setMode={setMode} loading={props.loading || false} selected={props?.selected} - onSelect={(x) => {props?.onSelect(x); handleSelectedTab(x)}} + onSelect={(x) => handleTabChange(x)} />
+ { headers?.filter((header) => { return header.itemOrder==0 @@ -138,7 +138,7 @@ function GithubCell(props){
: - + {item} diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/tableReducer.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/tableReducer.js index 4285be3e7a..fda4b41079 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/tableReducer.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/tableReducer.js @@ -1,6 +1,5 @@ import PersistStore from "../../../main/PersistStore"; -const tableInitialState = PersistStore.getState().tableInitialState[window.location.href] || 0 - +const tableInitialState = PersistStore.getState().tableInitialState[window.location.pathname + "/" + window.location.hash] || 0 export const initialState = { tabsInfo : tableInitialState } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/transform.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/transform.js index 604bbf27e2..cd336f54fd 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/transform.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/components/tables/transform.js @@ -1,4 +1,5 @@ import func from "@/util/func"; +import PersistStore from "../../../main/PersistStore"; const tableFunc = { fetchDataSync: function (sortKey, sortOrder, skip, limit, filters, filterOperators, queryValue, setFilters, props){ @@ -136,6 +137,55 @@ const tableFunc = { return [sortOptions[0].value] } return filtersMap.sort + }, + getPrettifiedFilter(filters){ + let filterStr = ""; + filters.forEach((filter) => { + if(filterStr.length !== 0){filterStr += "&"} + filterStr += filter.key + "__" + filter.value + }) + return filterStr + }, + + convertValue(value) { + const intValue = parseInt(value, 10); + if (!isNaN(intValue)) return intValue; + return value; + }, + + getFiltersMapFromUrl(searchString, labelFunc, handleRemoveAppliedFilter, pageKey){ + const result = []; + if(searchString.length === 0){ + return [] + } + const pairs = searchString.split('&'); + + pairs.forEach(pair => { + const [key, values] = pair.split('__'); + const valueArray = values.split(',').map(this.convertValue); + result.push({ + key, + value: valueArray, + label: labelFunc(key,valueArray), + onRemove: handleRemoveAppliedFilter + }); + }); + + const currentFilters = PersistStore.getState().filtersMap + const setPageFilters = PersistStore.getState().setFiltersMap + const currentPageFilters = currentFilters?.[pageKey]?.filters || [] + if(!func.deepComparison(currentPageFilters, result)){ + setPageFilters({ + ...currentFilters, + [pageKey]: { + sort: currentFilters?.[pageKey]?.sort || [], + 'filters':result + } + + }) + return result + } + return [] } } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/Dashboard.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/Dashboard.jsx index bc2742d198..f37581e846 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/Dashboard.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/Dashboard.jsx @@ -15,8 +15,6 @@ function Dashboard() { const location = useLocation(); history.location = location history.navigate = useNavigate(); - const navigate = useNavigate() - const setAllCollections = PersistStore(state => state.setAllCollections) const setCollectionsMap = PersistStore(state => state.setCollectionsMap) const setHostNameMap = PersistStore(state => state.setHostNameMap) @@ -46,16 +44,6 @@ function Dashboard() { if (!subCategoryMap || (Object.keys(subCategoryMap).length === 0)) { fetchMetadata(); } - if(location.hash?.length > 0){ - let newPath = location.pathname - if(location.hash.includes("Data")){ - newPath = '/dashboard/observe/sensitive' - } - else if(newPath.includes("settings")){ - newPath = newPath + "/" + location.hash.split("#")[1] - } - navigate(newPath) - } if(window.Beamer){ window.Beamer.init(); } 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 b497a769d7..3fd71cec1f 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 @@ -64,14 +64,19 @@ const headers = [ }, { value: 'collectionIds' - } + }, + { + text:"unread", + value:"unread", + itemOrder:2 + }, ] const sortOptions = [ { label: 'Discovered time', value: 'timestamp asc', directionLabel: 'Newest', sortKey: 'timestamp', columnIndex: 5 }, { label: 'Discovered time', value: 'timestamp desc', directionLabel: 'Oldest', sortKey: 'timestamp', columnIndex: 5 }, { label: 'Issue', value: 'categoryName asc', directionLabel: 'A-Z', sortKey: 'categoryName', columnIndex: 1 }, - { label: 'Issue', value: 'categoryName desc', directionLabel: 'Z-A', sortKey: 'categoryName', columnIndex: 1 }, + { label: 'Issue', value: 'categoryName desc', directionLabel: 'Z-A', sortKey: 'categoryName', columnIndex: 1 }, ]; let filtersOptions = [ diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/transform.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/transform.js index dd30a05342..35416733a4 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/transform.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/issues/transform.js @@ -66,6 +66,9 @@ const transform = { temp.categoryDescription=getCategoryDescription(issue.id) temp.testType=getTestType(issue.id.testErrorSource) temp.issueId=issue.id + if (issue.unread) { + temp.unread = ['Unread'] + } temp.issueStatus=issue.testRunIssueStatus if(temp.issueStatus=="IGNORED"){ temp.ignoreReason=issue.ignoreReason diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/GetPrettifyEndpoint.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/GetPrettifyEndpoint.jsx index 33cb2fab55..331d9fd9bb 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/GetPrettifyEndpoint.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/GetPrettifyEndpoint.jsx @@ -20,7 +20,7 @@ function GetPrettifyEndpoint({method,url, isNew}){ {observeFunc.getTruncatedUrl(url)} {copyActive ? -
{e.stopPropagation();func.copyToClipboard(url, ref, "URL copied");}}> +
{e.stopPropagation();func.copyToClipboard(method + " " + url, ref, "URL copied");}}> diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiDetails.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiDetails.jsx index deb1d458c3..56d607b86f 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiDetails.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiDetails.jsx @@ -183,7 +183,7 @@ function ApiDetails(props) { badgeClicked={badgeClicked} /> -
diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiEndpoints.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiEndpoints.jsx index 937f48acd4..39ba6489b6 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiEndpoints.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/ApiEndpoints.jsx @@ -1,5 +1,5 @@ import PageWithMultipleCards from "../../../components/layouts/PageWithMultipleCards" -import { Text, HorizontalStack, Button, Popover, Modal, IndexFiltersMode, VerticalStack, Box, Checkbox, Link, Tooltip } from "@shopify/polaris" +import { Text, HorizontalStack, Button, Popover, Modal, IndexFiltersMode, VerticalStack, Box, Checkbox } from "@shopify/polaris" import api from "../api" import { useEffect, useState } from "react" import func from "@/util/func" diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/component/ApiChangesTable.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/component/ApiChangesTable.jsx index d2a54ea533..3636ad4c92 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/component/ApiChangesTable.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/api_collections/component/ApiChangesTable.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useState } from 'react' import transform from '../../transform'; import apiChangesData from '../data/apiChanges'; import Store from '../../../../store'; @@ -8,53 +8,30 @@ import tableFunc from '../../../../components/tables/transform'; import api from '../../api'; import GithubServerTable from '../../../../components/tables/GithubServerTable'; import { IndexFiltersMode } from '@shopify/polaris'; +import useTable from '../../../../components/tables/TableContext'; function ApiChangesTable(props) { const { handleRowClick, tableLoading, startTimeStamp, endTimeStamp, newEndpoints, parametersCount, tab } = props ; - const [selectedTab, setSelectedTab] = useState("endpoints") ; + const [selectedTab, setSelectedTab] = useState("new_endpoints") ; const [selected, setSelected] = useState(0) ; const dataTypeNames = Store(state => state.dataTypeNames); const apiCollectionMap = PersistStore(state => state.collectionsMap) const [loading, setLoading] = useState(false); const [filters, setFilters] = useState([]) - useEffect(() => { - if (tab==1) { - setSelected(1); - setSelectedTab('param') - } - else if (tab==0) { - setSelected(0); - setSelectedTab('endpoints') - } - - }, [tab]); - - + const definedTableTabs = ['New endpoints', 'New params'] + const initialCount = [0 , parametersCount] - const tableTabs = [ - { - content: 'New endpoints', - index: 0, - badge: transform.formatNumberWithCommas(newEndpoints.length), - onAction: ()=> {setSelectedTab('endpoints')}, - id: 'endpoints', - }, - { - content: 'New parameters', - index: 1, - badge: transform.formatNumberWithCommas(parametersCount), - onAction: ()=> {setSelectedTab('param')}, - id: 'param', - }, - ] + const { tabsInfo } = useTable() + const tableCountObj = func.getTabsCount(definedTableTabs, newEndpoints, initialCount) + const tableTabs = func.getTableTabsContent(definedTableTabs, tableCountObj, setSelectedTab, selectedTab, tabsInfo) const tableDataObj = apiChangesData.getData(selectedTab); const handleRow = (data) => { let headers = [] - if(selectedTab === 'param'){ + if(selectedTab.includes('param')){ headers = transform.getParamHeaders() ; }else{ headers = transform.getDetailsHeaders() ; @@ -79,7 +56,7 @@ function ApiChangesTable(props) { }) function disambiguateLabel(key, value) { - if(selectedTab === 'param'){ + if(selectedTab.includes('param')){ switch (key) { case "apiCollectionId": return func.convertToDisambiguateLabelObj(value, apiCollectionMap, 3) @@ -100,7 +77,7 @@ function ApiChangesTable(props) { } const fetchTableData = async(sortKey, sortOrder, skip, limit, filters, filterOperators, queryValue) =>{ - if(selectedTab === 'param'){ + if(selectedTab.includes('param')){ setLoading(true); let ret = []; let total = 0; @@ -132,7 +109,7 @@ function ApiChangesTable(props) { loading={loading || tableLoading} onRowClick={(data) => handleRow(data)} fetchData={fetchTableData} - filters={selectedTab === 'param' ? paramFilters : filters} + filters={selectedTab.includes('param') ? paramFilters : filters} selected={selected} onSelect={handleSelectedTab} mode={IndexFiltersMode.Default} diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/data_types/DataTypes.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/data_types/DataTypes.jsx index b4df3350e7..8a061ba529 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/data_types/DataTypes.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/observe/data_types/DataTypes.jsx @@ -192,8 +192,9 @@ function DataTypes() { const handleChange = (obj) => { dispatchCurrState({type:"update", obj:obj}) -} + } + const errorMessage = func.nameValidationFunc(currState.name) const descriptionCard = ( @@ -201,6 +202,8 @@ function DataTypes() { handleChange({name: val})} : {}} + requiredIndicator={true} + {...errorMessage.length > 0 ? {error: errorMessage} : {}} /> {currState.dataType === 'Custom' ? + { Object.keys(severityInfo).length > 0 ? Object.keys(severityInfo).map((key,index)=>{ return( @@ -368,7 +368,7 @@ const transform = { prettifySubtypes(sensitiveTags, deactivated){ return( - + {sensitiveTags.map((item,index)=>{ return (index < 4 ?
diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js index f2d23f4994..c31c3a7601 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/api.js @@ -212,11 +212,11 @@ const settingRequests = { }) }, - addGithubSso(githubClientId, githubClientSecret) { + addGithubSso(githubClientId, githubClientSecret, githubUrl, githubApiUrl) { return request({ url: '/api/addGithubSso', method: 'post', - data: {githubClientId, githubClientSecret} + data: {githubClientId, githubClientSecret, githubUrl, githubApiUrl} }) }, diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/auth_types/AuthTypeDetails.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/auth_types/AuthTypeDetails.jsx index facd885b4f..b3baf1c0e8 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/auth_types/AuthTypeDetails.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/auth_types/AuthTypeDetails.jsx @@ -95,6 +95,8 @@ function AuthTypeDetails() { dispatchCurrState({type:"update", obj:obj}) } + const errorMessage = func.nameValidationFunc(currState.name || "", !isNew) + const descriptionCard = ( @@ -102,7 +104,10 @@ function AuthTypeDetails() { { (isNew || isEditMode) ? handleChange({ name: val }) : {} }} + placeholder='New auth type name' + {...isNew ? {onChange: (val) => handleChange({name: val})} : {}} + requiredIndicator={true} + {...errorMessage.length > 0 ? {error: errorMessage} : {}} /> {isNew ? null : { diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/integrations/GithubSso.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/integrations/GithubSso.jsx index 04332d40e3..a13631a2c4 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/integrations/GithubSso.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/integrations/GithubSso.jsx @@ -14,6 +14,8 @@ function GithubSso() { const [githubPresent, setGithubPresent] = useState("") const [componentType, setComponentType] = useState(0) ; const [nextButtonActive,setNextButtonActive] = useState(window.DASHBOARD_MODE === "ON_PREM"); + const [githubUrl, setGithubUrl] = useState("https://github.com") + const [githubApiUrl, setGithubApiUrl] = useState("https://api.github.com") const location = window.location ; const hostname = location.origin; @@ -51,12 +53,14 @@ function GithubSso() { async function fetchGithubSso() { try { - let {githubClientId} = await settingRequests.fetchGithubSso() + let {githubClientId, githubApiUrl, githubUrl} = await settingRequests.fetchGithubSso() if(githubClientId){ setComponentType(1); } setGithubPresent(!!githubClientId) setGithubClientId(githubClientId) + if (githubUrl) setGithubUrl(githubUrl) + if (githubApiUrl) setGithubApiUrl(githubApiUrl) } catch (error) { setNextButtonActive(false) } @@ -67,7 +71,7 @@ function GithubSso() { }, []) const handleAddGithubSso = async () => { - const response = await settingRequests.addGithubSso(githubClientId, githubClientSecret) + const response = await settingRequests.addGithubSso(githubClientId, githubClientSecret, githubUrl, githubApiUrl) if (response) { if (response.error) { func.setToast(true, true, response.error) @@ -96,6 +100,18 @@ function GithubSso() { value={githubPresent ? "********************************": githubClientSecret} onChange={(githubClientSecret) => setGithubClientSecret(githubClientSecret)} /> + + setGithubUrl(githubUrl)} + /> + + setGithubApiUrl(githubApiUrl)} + /> ) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/tags/TagDetails.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/tags/TagDetails.jsx index 20a13163e1..f4021a55aa 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/tags/TagDetails.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/settings/tags/TagDetails.jsx @@ -83,6 +83,8 @@ function TagDetails() { dispatchCurrState({type:"update", obj:obj}) } + const errorMessage = func.nameValidationFunc(currState.name || "", !isNew) + const descriptionCard = ( @@ -90,7 +92,10 @@ function TagDetails() { { isNew ? handleChange({ name: val }) : {} }} + placeholder='New tag name' + {...isNew ? {onChange: (val) => handleChange({name: val})} : {}} + requiredIndicator={true} + {...errorMessage.length > 0 ? {error: errorMessage} : {}} /> {isNew ? null : { let name = currState.name; - let isValidOrError = func.validateName(name); let keyConditionFromUsers = transform.preparePredicatesForApi(currState.keyConditions); if ((!keyConditionFromUsers || keyConditionFromUsers.length == 0)) { func.setToast(true, true, "Invalid url conditions"); - } else if (isValidOrError!==true){ - func.setToast(true, true, isValidOrError); + } else if (errorMessage.length ===0){ + func.setToast(true, true, errorMessage); } else { if (isNew) { tagsApi.saveTagConfig(name, currState.operator, keyConditionFromUsers, true, currState.active).then((res) => { diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css index f463943bad..ad55a091b6 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.css @@ -1,5 +1,6 @@ .editor-navbar .Polaris-Navigation__PrimaryNavigation{ flex: none !important; + overflow-x: hidden !important; } .editor-navbar .Polaris-HorizontalStack{ diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.jsx index 12dfff3ed7..5adc2689e7 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/TestEditor.jsx @@ -1,7 +1,7 @@ import { useEffect, useState } from "react" import { useNavigate } from "react-router-dom" -import { Badge, Button, Frame, HorizontalStack, Text, TopBar } from "@shopify/polaris" +import { Badge, Box, Button, Frame, HorizontalGrid, HorizontalStack, TopBar } from "@shopify/polaris" import { ExitMajor } from "@shopify/polaris-icons" import TestEditorFileExplorer from "./components/TestEditorFileExplorer" @@ -121,12 +121,12 @@ const TestEditor = () => { } navigation={ addCustomTest(e)}/> } > - -
- - -
- + + + + + + ) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx index de17dccc30..b9c34fca30 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/test_editor/components/SampleApi.jsx @@ -250,7 +250,7 @@ const SampleApi = () => {
- + {resultComponent} { return arr } return ( -
+
{ } return ( -
+
@@ -164,8 +164,9 @@ const YamlEditor = ({ fetchAllTests }) => { - -
+
+ + ) } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/ReRunModal.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/ReRunModal.jsx index 6f33591e1c..90ad71ac34 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/ReRunModal.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/SingleTestRunPage/ReRunModal.jsx @@ -3,7 +3,7 @@ import transform from '../transform'; import React, { useEffect, useState } from 'react' import TestingStore from '../testingStore'; -function ReRunModal({refreshSummaries, selectedTestRun}) { +function ReRunModal({refreshSummaries, selectedTestRun, shouldRefresh}) { const [localModal, setLocalModal] = useState(false) const rerunModal = TestingStore(state => state.rerunModal) const setRerunModal = TestingStore(state => state.setRerunModal) @@ -24,7 +24,7 @@ function ReRunModal({refreshSummaries, selectedTestRun}) { title={"Re-run test"} primaryAction={{ content: "Re-run test", - onAction: () => {transform.rerunTest(selectedTestRun.id, refreshSummaries) ; handleClose()} + onAction: () => {transform.rerunTest(selectedTestRun.id, refreshSummaries, shouldRefresh) ; handleClose()} }} secondaryActions={[ { 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 ecfae6bb5d..cc5abcf9e6 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 @@ -13,14 +13,16 @@ import { Popover, ActionList, Card, - ProgressBar + ProgressBar, + Tooltip } from '@shopify/polaris'; import { CircleInformationMajor, ArchiveMinor, PriceLookupMinor, - ReportMinor + ReportMinor, + RefreshMajor } from '@shopify/polaris-icons'; import api from "../api"; import func from '@/util/func'; @@ -199,22 +201,11 @@ function SingleTestRunPage() { } let cicd = testingRunType === "CI_CD"; localSelectedTestRun = transform.prepareTestRun(testingRun, testingRunResultSummaries[0], cicd, false); - if(localSelectedTestRun.orderPriority === 1){ - if(setData){ - setTimeout(() => { - refreshSummaries(); - }, 2000) - } - setTempLoading((prev) => { - prev.running = true; - return {...prev}; - }); - } if(setData){ setSelectedTestRun(localSelectedTestRun); } - if((localSelectedTestRun.testingRunResultSummaryHexId && testRunResults[selectedTab].length === 0) || !setData) { + if((localSelectedTestRun.testingRunResultSummaryHexId && testRunResults[selectedTab].length === 0) || setData) { await fetchTestingRunResultsData(localSelectedTestRun.testingRunResultSummaryHexId); } }) @@ -222,31 +213,6 @@ function SingleTestRunPage() { return localSelectedTestRun; } - const refreshSummaries = () => { - let intervalId = setInterval(async() => { - let localSelectedTestRun = await fetchData(false); - if(localSelectedTestRun.id){ - if(localSelectedTestRun.orderPriority !== 1){ - setSelectedTestRun(localSelectedTestRun); - setTempLoading((prev) => { - prev.running = false; - return prev; - }); - clearInterval(intervalId) - } else { - setSelectedTestRun((prev) => { - if(func.deepComparison(prev, localSelectedTestRun)){ - return prev; - } - return localSelectedTestRun; - }); - } - } else { - clearInterval(intervalId) - } - refreshId.current = intervalId; - },5000) - } useEffect(()=>{ async function loadData(){ @@ -358,7 +324,7 @@ const promotedBulkActions = (selectedDataHexIds) => { selected={selected} tableTabs={tableTabs} onSelect={handleSelectedTab} - filterStateUrl={"dashboard/testing/" + selectedTestRun?.id + "/" + selectedTab} + filterStateUrl={"/dashboard/testing/" + selectedTestRun?.id + "/#" + selectedTab} /> ) @@ -468,6 +434,7 @@ const promotedBulkActions = (selectedDataHexIds) => { )} + @@ -520,7 +487,7 @@ const promotedBulkActions = (selectedDataHexIds) => { secondaryActions={!workflowTest ? moreActionsComp: undefined} components={useComponents} /> - + ); } diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRoleSettings/TestRoleSettings.jsx b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRoleSettings/TestRoleSettings.jsx index 37b7b43e10..c0436484ad 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRoleSettings/TestRoleSettings.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRoleSettings/TestRoleSettings.jsx @@ -6,7 +6,7 @@ import func from "@/util/func"; import api from '../api'; import transform from '../transform'; import DetailsPage from '../../../components/DetailsPage'; -import {produce, current} from "immer" +import {produce} from "immer" import HardCoded from '../user_config/HardCoded'; import LoginStepBuilder from '../user_config/LoginStepBuilder'; import { ChevronRightMinor, ChevronDownMinor, InfoMinor } from '@shopify/polaris-icons'; @@ -186,6 +186,7 @@ function TestRoleSettings() { { }} + requiredIndicator /> 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 8956cba1ad..610e7432d6 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 @@ -81,6 +81,11 @@ function TestRunResultFlyout(props) { const navigateUrl = isIssuePage ? "/dashboard/issues" : window.location.pathname.split("result")[0] navigate(navigateUrl) } + + const openTest = () => { + const navUrl = window.location.origin + "/dashboard/test-editor/" + selectedTestRunResult.testCategoryId + window.open(navUrl, "_blank") + } function ActionsComp (){ const issuesActions = issueDetails?.testRunIssueStatus === "IGNORED" ? [...issues, ...reopen] : issues @@ -128,7 +133,9 @@ function TestRunResultFlyout(props) {
- {selectedTestRunResult?.name} + {severity.length > 0 ? {severity} : null}
diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunsPage/TestRunsPage.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunsPage/TestRunsPage.js index 59bd08a5ad..ead58e5628 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunsPage/TestRunsPage.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/TestRunsPage/TestRunsPage.js @@ -15,7 +15,6 @@ import {TestrunsBannerComponent} from "./TestrunsBannerComponent"; import useTable from "../../../components/tables/TableContext"; import PersistStore from "../../../../main/PersistStore"; import TitleWithInfo from "@/apps/dashboard/components/shared/TitleWithInfo"; - /* { text:"", // req. -> The text to be shown wherever the header is being shown @@ -141,26 +140,18 @@ const [subCategoryInfo, setSubCategoryInfo] = useState({}) const [collapsible, setCollapsible] = useState(true) const [hasUserInitiatedTestRuns, setHasUserInitiatedTestRuns] = useState(false) -const checkIsTestRunning = (testingRuns) => { - let val = false - testingRuns.forEach(element => { - if(element.orderPriority == 1){ - val = true - } - }); - return val ; -} const refreshSummaries = () =>{ setTimeout(() => { - setUpdateTable(!updateTable); + setUpdateTable(!updateTable) }, 5000) } function processData(testingRuns, latestTestingRunResultSummaries, cicd){ let testRuns = transform.prepareTestRuns(testingRuns, latestTestingRunResultSummaries, cicd, true); - if(checkIsTestRunning(testRuns)){ - refreshSummaries(); + const updatedRuns = testRuns.filter((test) => test.orderPriority !== 1) + if(updatedRuns.length !== testRuns.length){ + refreshSummaries() } return testRuns; } @@ -309,7 +300,7 @@ const SummaryCardComponent = () =>{ }, ]}; - const key = currentTab + startTimestamp + endTimestamp + updateTable; + const key = currentTab + startTimestamp + endTimestamp; const coreTable = ( ) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/transform.js b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/transform.js index bacc14e779..41fb32a125 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/transform.js +++ b/apps/dashboard/web/polaris_web/web/src/apps/dashboard/pages/testing/transform.js @@ -148,7 +148,7 @@ function minimizeTagList(items){ } function checkTestFailure(summaryState, testRunState) { - if (testRunState == 'COMPLETED' && summaryState != 'COMPLETED') { + if (testRunState === 'COMPLETED' && summaryState !== 'COMPLETED' && summaryState !== "STOPPED") { return true; } return false; @@ -280,8 +280,8 @@ const transform = { obj['severityStatus'] = func.getSeverityStatus(testingRunResultSummary.countIssues) obj['runTypeStatus'] = [obj['run_type']] obj['nextUrl'] = "/dashboard/testing/"+data.hexId - obj['testRunState'] = data.state - obj['summaryState'] = state + obj['testRunState'] = state + obj['summaryState'] = testingRunResultSummary.state obj['startTimestamp'] = testingRunResultSummary?.startTimestamp obj['endTimestamp'] = testingRunResultSummary?.endTimestamp obj['metadata'] = func.flattenObject(testingRunResultSummary?.metadata) @@ -331,6 +331,7 @@ const transform = { obj['cve'] = subCategoryMap[data.testSubType]?.cve ? subCategoryMap[data.testSubType]?.cve : [] obj['cveDisplay'] = minimizeTagList(obj['cve']) obj['errorsList'] = data.errorsList || [] + obj['testCategoryId'] = data.testSubType return obj; }, prepareTestRunResults : (hexId, testingRunResults, subCategoryMap, subCategoryFromSourceConfigMap) => { @@ -801,7 +802,7 @@ getPrettifiedTestRunResults(testRunResults){ ...obj, nameComp:
, severityComp: obj?.vulnerable === true ? {obj?.severity[0]} : -, - cweDisplayComp: obj?.cweDisplay?.length > 0 ? + cweDisplayComp: obj?.cweDisplay?.length > 0 ? {obj.cweDisplay.map((ele,index)=>{ return( {ele} @@ -914,12 +915,15 @@ stopTest(hexId){ }); }, -rerunTest(hexId, refreshSummaries){ +rerunTest(hexId, refreshSummaries, shouldRefresh){ api.rerunTest(hexId).then((resp) => { + window.location.reload() func.setToast(true, false, "Test re-run initiated") - setTimeout(() => { - refreshSummaries(); - }, 2000) + if(shouldRefresh){ + setTimeout(() => { + refreshSummaries(); + }, 2000) + } }).catch((resp) => { func.setToast(true, true, "Unable to re-run test") }); @@ -945,7 +949,7 @@ getActionsList(hexId){ content: 'Stop', icon: CircleCancelMajor, destructive:true, - onAction: () => {this.stopTest(hexId || "")}, + onAction: () => {this.stopTest(hexId || ""); window.location.reload();}, disabled: true, } ]}, @@ -953,17 +957,17 @@ getActions(item){ let arr = [] let section1 = {title: 'Actions', items:[]} let actionsList = this.getActionsList(item.id); + if(item.orderPriority === 1){ + actionsList[1].disabled = true + } if(item['run_type'] === 'One-time'){ section1.items.push(actionsList[1]) } if(item['run_type'] !== 'CI/CD'){ section1.items.push(actionsList[2]) } - - if(item['orderPriority'] === 1 || item['orderPriority'] === 2){ - actionsList[3].disabled = false - }else{ - actionsList[3].disabled = true + if(item.orderPriority < 3){ + actionsList[3].disabled = false } section1.items.push(actionsList[3]); arr.push(section1) diff --git a/apps/dashboard/web/polaris_web/web/src/apps/signup/components/SignUp.jsx b/apps/dashboard/web/polaris_web/web/src/apps/signup/components/SignUp.jsx index eee1bf7d69..5dfc578e7b 100644 --- a/apps/dashboard/web/polaris_web/web/src/apps/signup/components/SignUp.jsx +++ b/apps/dashboard/web/polaris_web/web/src/apps/signup/components/SignUp.jsx @@ -21,11 +21,12 @@ function SignUp() { const oktaUrl = window.OKTA_AUTH_URL const azureUrl = window.AZURE_REQUEST_URL const githubId = window.GITHUB_CLIENT_ID + const githubUrl = window.GITHUB_URL ? window.GITHUB_URL : "https://github.com" const githubAuthObj = { logo: '/public/github_icon.svg', text: 'Continue with Github SSO', - onClickFunc: () => { window.location.href = ("https://github.com/login/oauth/authorize?client_id=" + githubId); } + onClickFunc: () => { window.location.href = (githubUrl + "/login/oauth/authorize?client_id=" + githubId); } } const azureAuthObj = { diff --git a/apps/dashboard/web/polaris_web/web/src/util/func.js b/apps/dashboard/web/polaris_web/web/src/util/func.js index 821f1bdc8a..1ccffd739c 100644 --- a/apps/dashboard/web/polaris_web/web/src/util/func.js +++ b/apps/dashboard/web/polaris_web/web/src/util/func.js @@ -34,14 +34,18 @@ const func = { } return res }, - validateName(name) { - const regex = /^[a-z0-9_]+$/i; - if (name.length == 0) { - return "Name cannot be blank"; - } else if (!name.match(regex)) { - return "Only alphanumeric and underscore characters allowed in name" ; + nameValidationFunc(nameVal, initialCond){ + let error = "" + if(nameVal.length === 0 || initialCond){ + return error } - return true; + const regex = /^[A-Z_0-9 ]+$/; + if (!nameVal.toUpperCase().match(regex)){ + error = "Name can only contain alphabets, spaces, numbers and underscores" + } else if(nameVal.length > 25){ + error = "Name too long. Maximum limit allowed is 25" + } + return error; }, toDateStr(date, needYear) { let strArray = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; @@ -258,7 +262,8 @@ prettifyEpoch(epoch) { if(localItem.includes("HIGH")) return 'critical'; if(localItem.includes("MEDIUM")) return 'warning'; if(localItem.includes("LOW")) return 'neutral'; - if(localItem.includes("CWE") || localItem.startsWith("+")) return 'info'; + if(localItem.includes("CWE") || localItem.startsWith("+")) return 'info' + if(localItem.includes("UNREAD") || localItem.startsWith("+")) return 'attention'; return ""; }, getRunResultSubCategory(runResult, subCategoryFromSourceConfigMap, subCategoryMap, fieldName) { @@ -1436,12 +1441,11 @@ showConfirmationModal(modalContent, primaryActionContent, primaryAction) { }, getTabsCount(tableTabs, data, initialCountArr = []){ const currentState = PersistStore(state => state.tableInitialState) - const baseUrl = window.location.href.split('#')[0] - + const baseUrl = window.location.pathname + "/#" let finalCountObj = {} tableTabs.forEach((tab,ind) => { const tabId = this.getKeyFromName(tab) - const tabKey = baseUrl + '#' + tabId + const tabKey = baseUrl + tabId const count = currentState[tabKey] || data[tabId]?.length || initialCountArr[ind] || 0 finalCountObj[tabId] = count }) diff --git a/apps/testing/src/main/java/com/akto/crons/GetRunningTestsStatus.java b/apps/testing/src/main/java/com/akto/crons/GetRunningTestsStatus.java new file mode 100644 index 0000000000..99505761bc --- /dev/null +++ b/apps/testing/src/main/java/com/akto/crons/GetRunningTestsStatus.java @@ -0,0 +1,82 @@ +package com.akto.crons; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import org.bson.types.ObjectId; + +import com.akto.dao.context.Context; +import com.akto.dao.testing.TestingRunResultSummariesDao; +import com.akto.dto.Account; +import com.akto.dto.testing.TestingRun; +import com.akto.dto.testing.TestingRunResultSummary; +import com.akto.util.AccountTask; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; + +public class GetRunningTestsStatus { + private final ConcurrentHashMap currentRunningTestsMap = new ConcurrentHashMap<>(); + + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + private GetRunningTestsStatus () { + } + + private static final GetRunningTestsStatus getRunningTestsStatus = new GetRunningTestsStatus(); + + public static GetRunningTestsStatus getRunningTests() { + return getRunningTestsStatus; + } + + public void getStatusOfRunningTests(){ + scheduler.scheduleAtFixedRate(new Runnable() { + public void run(){ + AccountTask.instance.executeTask(new Consumer() { + @Override + public void accept(Account t) { + try { + int timeFilter = Context.now() - 30 * 60; + List currentRunningTests = TestingRunResultSummariesDao.instance.findAll( + Filters.gte(TestingRunResultSummary.START_TIMESTAMP, timeFilter), + Projections.include("_id", TestingRunResultSummary.STATE, TestingRunResultSummary.TESTING_RUN_ID) + ); + for(TestingRunResultSummary trrs : currentRunningTests){ + if(trrs.getState() == TestingRun.State.COMPLETED){ + currentRunningTestsMap.remove(trrs.getId()); + currentRunningTestsMap.remove(trrs.getTestingRunId()); + }else{ + currentRunningTestsMap.put(trrs.getId(), trrs.getState()); + currentRunningTestsMap.put(trrs.getTestingRunId(), trrs.getState()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + },"get-current-running-tests"); + } + }, 0 , 1, TimeUnit.MINUTES); + } + + public ConcurrentHashMap getCurrentRunningTestsMap() { + return currentRunningTestsMap; + } + + public boolean isTestRunning(ObjectId runId){ + if(currentRunningTestsMap == null || !currentRunningTestsMap.containsKey(runId) || currentRunningTestsMap.get(runId).equals(TestingRun.State.RUNNING)){ + return true; + }else{ + return false; + } + } + + public TestingRun.State getCurrentState(ObjectId runId){ + if(currentRunningTestsMap == null || !currentRunningTestsMap.containsKey(runId)){ + return null; + } + return currentRunningTestsMap.get(runId); + } +} \ No newline at end of file diff --git a/apps/testing/src/main/java/com/akto/testing/Main.java b/apps/testing/src/main/java/com/akto/testing/Main.java index 6b378b7012..05fef46af6 100644 --- a/apps/testing/src/main/java/com/akto/testing/Main.java +++ b/apps/testing/src/main/java/com/akto/testing/Main.java @@ -2,6 +2,7 @@ import com.akto.DaoInit; import com.akto.billing.UsageMetricUtils; +import com.akto.crons.GetRunningTestsStatus; import com.akto.dao.*; import com.akto.dao.billing.OrganizationsDao; import com.akto.dao.context.Context; @@ -225,8 +226,7 @@ public void run() { },"matrix-analyser-task"); } }, 0, 1, TimeUnit.MINUTES); - - + GetRunningTestsStatus.getRunningTests().getStatusOfRunningTests(); loggerMaker.infoAndAddToDb("sun.arch.data.model: " + System.getProperty("sun.arch.data.model"), LogDb.TESTING); loggerMaker.infoAndAddToDb("os.arch: " + System.getProperty("os.arch"), LogDb.TESTING); @@ -391,10 +391,11 @@ public void run() { Updates.set(TestingRun.SCHEDULE_TIMESTAMP, testingRun.getScheduleTimestamp() + testingRun.getPeriodInSeconds()) ); } - - TestingRunDao.instance.getMCollection().findOneAndUpdate( - Filters.eq("_id", testingRun.getId()), completedUpdate - ); + if(GetRunningTestsStatus.getRunningTests().isTestRunning(testingRun.getId())){ + TestingRunDao.instance.getMCollection().findOneAndUpdate( + Filters.eq("_id", testingRun.getId()), completedUpdate + ); + } if(summaryId != null && testingRun.getTestIdConfig() != 1){ TestExecutor.updateTestSummary(summaryId); diff --git a/apps/testing/src/main/java/com/akto/testing/TestExecutor.java b/apps/testing/src/main/java/com/akto/testing/TestExecutor.java index f972a1f46d..00ad037526 100644 --- a/apps/testing/src/main/java/com/akto/testing/TestExecutor.java +++ b/apps/testing/src/main/java/com/akto/testing/TestExecutor.java @@ -1,13 +1,12 @@ package com.akto.testing; +import com.akto.crons.GetRunningTestsStatus; import com.akto.dao.ActivitiesDao; import com.akto.dao.ApiInfoDao; import com.akto.dao.CustomAuthTypeDao; -import com.akto.dao.testing.TestRolesDao; import com.akto.dao.context.Context; import com.akto.dao.test_editor.YamlTemplateDao; -import com.akto.dao.testing.TestRolesDao; import com.akto.dao.testing.TestingRunResultDao; import com.akto.dao.testing.TestingRunResultSummariesDao; import com.akto.dao.testing.WorkflowTestResultsDao; @@ -36,6 +35,7 @@ import com.akto.test_editor.execution.VariableResolver; import com.akto.testing.yaml_tests.YamlTestTemplate; import com.akto.testing_issues.TestingIssuesHandler; +import com.akto.testing_utils.TestingUtils; import com.akto.usage.UsageMetricCalculator; import com.akto.util.Constants; import com.akto.util.JSONUtils; @@ -271,52 +271,21 @@ public void apiWiseInit(TestingRun testingRun, ObjectId summaryId, boolean debug public static void updateTestSummary(ObjectId summaryId){ loggerMaker.infoAndAddToDb("Finished updating results count", LogDb.TESTING); - Map totalCountIssues = new HashMap<>(); - totalCountIssues.put(Severity.HIGH.toString(), 0); - totalCountIssues.put(Severity.MEDIUM.toString(), 0); - totalCountIssues.put(Severity.LOW.toString(), 0); - - int skip = 0; - int limit = 1000; - boolean fetchMore = false; - do { - fetchMore = false; - List testingRunResults = TestingRunResultDao.instance - .fetchLatestTestingRunResult( - Filters.and( - Filters.eq(TestingRunResult.TEST_RUN_RESULT_SUMMARY_ID, summaryId), - Filters.eq(TestingRunResult.VULNERABLE, true)), - limit, - skip, - Projections.exclude("testResults.originalMessage", "testResults.nodeResultMap")); - - loggerMaker.infoAndAddToDb("Reading " + testingRunResults.size() + " vulnerable testingRunResults", - LogDb.TESTING); - - for (TestingRunResult testingRunResult : testingRunResults) { - String severity = getSeverityFromTestingRunResult(testingRunResult).toString(); - int initialCount = totalCountIssues.get(severity); - totalCountIssues.put(severity, initialCount + 1); - } - - if (testingRunResults.size() == limit) { - skip += limit; - fetchMore = true; - } - - } while (fetchMore); - FindOneAndUpdateOptions options = new FindOneAndUpdateOptions(); options.returnDocument(ReturnDocument.AFTER); + + State updatedState = GetRunningTestsStatus.getRunningTests().isTestRunning(summaryId) ? State.COMPLETED : GetRunningTestsStatus.getRunningTests().getCurrentState(summaryId); + TestingRunResultSummary testingRunResultSummary = TestingRunResultSummariesDao.instance.getMCollection().findOneAndUpdate( Filters.eq(Constants.ID, summaryId), Updates.combine( Updates.set(TestingRunResultSummary.END_TIMESTAMP, Context.now()), - Updates.set(TestingRunResultSummary.STATE, State.COMPLETED), - Updates.set(TestingRunResultSummary.COUNT_ISSUES, totalCountIssues)), + Updates.set(TestingRunResultSummary.STATE, updatedState)), options); GithubUtils.publishGithubComments(testingRunResultSummary); + Map totalCountIssues = testingRunResultSummary.getCountIssues(); + loggerMaker.infoAndAddToDb("Finished updating TestingRunResultSummariesDao", LogDb.TESTING); if(totalCountIssues.get(Severity.HIGH.toString()) > 0){ ActivitiesDao.instance.insertActivity("High Vulnerability detected", totalCountIssues.get(Severity.HIGH.toString()) + " HIGH vulnerabilites detected"); @@ -578,31 +547,36 @@ public void startTestNew(ApiInfo.ApiInfoKey apiInfoKey, ObjectId testRunId, int countSuccessfulTests = 0; for (String testSubCategory: testSubCategories) { - if (Context.now() - startTime > timeToKill) { - loggerMaker.infoAndAddToDb("Timed out in " + (Context.now()-startTime) + "seconds"); - return; - } - List testingRunResults = new ArrayList<>(); + if(GetRunningTestsStatus.getRunningTests().isTestRunning(testRunResultSummaryId)){ + if (Context.now() - startTime > timeToKill) { + loggerMaker.infoAndAddToDb("Timed out in " + (Context.now()-startTime) + "seconds"); + return; + } + List testingRunResults = new ArrayList<>(); + + TestConfig testConfig = testConfigMap.get(testSubCategory); + + if (testConfig == null) continue; + TestingRunResult testingRunResult = null; + if (!applyRunOnceCheck(apiInfoKey, testConfig, subCategoryEndpointMap, apiInfoKeyToHostMap, testSubCategory)) { + continue; + } + try { + testingRunResult = runTestNew(apiInfoKey,testRunId,testingUtil,testRunResultSummaryId, testConfig, testingRunConfig, debug, testLogs); + } catch (Exception e) { + loggerMaker.errorAndAddToDb("Error while running tests for " + testSubCategory + ": " + e.getMessage(), LogDb.TESTING); + e.printStackTrace(); + } + if (testingRunResult != null) { + testingRunResults.add(testingRunResult); + countSuccessfulTests++; + } - TestConfig testConfig = testConfigMap.get(testSubCategory); - - if (testConfig == null) continue; - TestingRunResult testingRunResult = null; - if (!applyRunOnceCheck(apiInfoKey, testConfig, subCategoryEndpointMap, apiInfoKeyToHostMap, testSubCategory)) { - continue; - } - try { - testingRunResult = runTestNew(apiInfoKey,testRunId,testingUtil,testRunResultSummaryId, testConfig, testingRunConfig, debug, testLogs); - } catch (Exception e) { - loggerMaker.errorAndAddToDb("Error while running tests for " + testSubCategory + ": " + e.getMessage(), LogDb.TESTING); - e.printStackTrace(); - } - if (testingRunResult != null) { - testingRunResults.add(testingRunResult); - countSuccessfulTests++; + insertResultsAndMakeIssues(testingRunResults, testRunResultSummaryId); + }else{ + logger.info("Test stopped for id: " + testRunId.toString()); + return; } - - insertResultsAndMakeIssues(testingRunResults, testRunResultSummaryId); } if(countSuccessfulTests > 0){ ApiInfoDao.instance.updateLastTestedField(apiInfoKey); @@ -769,20 +743,19 @@ public boolean filterGraphQlPayload(RawApi rawApi, ApiInfo.ApiInfoKey apiInfoKey } int index = 0; - List updatedObjList = new ArrayList<>(); + Object reqObj = null; for (int i = 0; i < objList.size(); i++) { Map mapValues = m.convertValue(objList.get(i), Map.class); if (mapValues.get("operationName").toString().equalsIgnoreCase(queryName)) { - updatedObjList.add(objList.get(i)); + reqObj = objList.get(i); index = i; break; } } - updatedBody = gson.toJson(updatedObjList); + updatedBody = gson.toJson(reqObj); - List updatedRespObjList = new ArrayList<>(); - updatedRespObjList.add(respObjList.get(index)); - updatedRespBody = gson.toJson(updatedRespObjList); + Object respObject = respObjList.get(index); + updatedRespBody = gson.toJson(respObject); Map json = gson.fromJson(rawApi.getOriginalMessage(), Map.class); json.put("requestPayload", updatedBody); diff --git a/apps/testing/src/main/java/com/akto/testing_issues/TestingIssuesHandler.java b/apps/testing/src/main/java/com/akto/testing_issues/TestingIssuesHandler.java index c0aec8488c..50804ddb53 100644 --- a/apps/testing/src/main/java/com/akto/testing_issues/TestingIssuesHandler.java +++ b/apps/testing/src/main/java/com/akto/testing_issues/TestingIssuesHandler.java @@ -1,26 +1,34 @@ package com.akto.testing_issues; import com.akto.dao.context.Context; +import com.akto.dao.testing.TestingRunResultDao; +import com.akto.dao.testing.TestingRunResultSummariesDao; import com.akto.dao.testing.sources.TestSourceConfigsDao; import com.akto.dao.testing_run_findings.TestingRunIssuesDao; import com.akto.dto.test_run_findings.TestingIssuesId; import com.akto.dto.test_run_findings.TestingRunIssues; import com.akto.dto.testing.TestingRunResult; +import com.akto.dto.testing.TestingRunResultSummary; import com.akto.dto.testing.sources.TestSourceConfig; import com.akto.log.LoggerMaker; import com.akto.log.LoggerMaker.LogDb; import com.akto.testing.TestExecutor; import com.akto.testing_utils.TestingUtils; import com.akto.util.enums.GlobalEnums; +import com.akto.util.enums.GlobalEnums.Severity; +import com.akto.util.enums.GlobalEnums.TestRunIssueStatus; import com.mongodb.bulk.BulkWriteResult; import com.mongodb.client.model.*; import org.bson.conversions.Bson; +import org.bson.types.ObjectId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import static com.akto.util.Constants.ID; import static com.akto.util.enums.GlobalEnums.*; @@ -101,31 +109,63 @@ private void insertVulnerableTestsIntoIssuesCollection(List testingIssuesIdsMap, List testingRunIssuesList) { int lastSeen = Context.now(); - testingIssuesIdsMap.forEach((testingIssuesId, runResult) -> { + ObjectId summaryId = null; + + Map countIssuesMap = new HashMap<>(); + countIssuesMap.put(Severity.HIGH.toString(), 0); + countIssuesMap.put(Severity.MEDIUM.toString(), 0); + countIssuesMap.put(Severity.LOW.toString(), 0); + + for(TestingIssuesId testingIssuesId : testingIssuesIdsMap.keySet()) { + TestingRunResult runResult = testingIssuesIdsMap.get(testingIssuesId); boolean doesExists = false; + if (summaryId == null) { + summaryId = runResult.getTestRunResultSummaryId(); + } + + if(!runResult.isVulnerable()){ + return; + } + + Severity severity = TestExecutor.getSeverityFromTestingRunResult(runResult); + int count = countIssuesMap.getOrDefault(severity.toString(), 0); + countIssuesMap.put(severity.toString(), count + 1); + for (TestingRunIssues testingRunIssues : testingRunIssuesList) { if (testingRunIssues.getId().equals(testingIssuesId)) { doesExists = true; break; } } - if (!doesExists && runResult.isVulnerable()) { + if (!doesExists) { // name = category String subCategory = runResult.getTestSubType(); if (subCategory.startsWith("http")) { TestSourceConfig config = TestSourceConfigsDao.instance.getTestSourceConfig(runResult.getTestSubType()); writeModelList.add(new InsertOneModel<>(new TestingRunIssues(testingIssuesId, config.getSeverity(), - TestRunIssueStatus.OPEN, lastSeen, lastSeen, runResult.getTestRunResultSummaryId(), null, lastSeen))); + TestRunIssueStatus.OPEN, lastSeen, lastSeen, runResult.getTestRunResultSummaryId(), null, lastSeen, true))); }else { - Severity severity = TestExecutor.getSeverityFromTestingRunResult(runResult); + writeModelList.add(new InsertOneModel<>(new TestingRunIssues(testingIssuesId, severity, - TestRunIssueStatus.OPEN, lastSeen, lastSeen, runResult.getTestRunResultSummaryId(),null, lastSeen))); // todo: take value from yaml + TestRunIssueStatus.OPEN, lastSeen, lastSeen, runResult.getTestRunResultSummaryId(),null, lastSeen, true))); // todo: take value from yaml } loggerMaker.infoAndAddToDb(String.format("Inserting the id %s , with summary Id as %s", testingIssuesId, runResult.getTestRunResultSummaryId()), LogDb.TESTING); } - }); + }; + + if(summaryId != null){ + TestingRunResultSummariesDao.instance.updateOneNoUpsert( + Filters.eq("_id", summaryId), + Updates.combine( + Updates.inc("countIssues.HIGH", countIssuesMap.get("HIGH")), + Updates.inc("countIssues.MEDIUM", countIssuesMap.get("MEDIUM")), + Updates.inc("countIssues.LOW", countIssuesMap.get("LOW")) + ) + ); + } + } public void handleIssuesCreationFromTestingRunResults(List testingRunResultList, boolean triggeredByTestEditor) { diff --git a/libs/dao/src/main/java/com/akto/dto/Config.java b/libs/dao/src/main/java/com/akto/dto/Config.java index d8f134b99b..f94a5460d4 100644 --- a/libs/dao/src/main/java/com/akto/dto/Config.java +++ b/libs/dao/src/main/java/com/akto/dto/Config.java @@ -302,6 +302,8 @@ public static class GithubConfig extends Config { private String clientId; private String clientSecret; + private String githubUrl; + private String githubApiUrl; public static final String CONFIG_ID = ConfigType.GITHUB.name() + CONFIG_SALT; public GithubConfig() { @@ -324,6 +326,22 @@ public String getClientSecret() { public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } + + public String getGithubUrl() { + return githubUrl; + } + + public void setGithubUrl(String githubUrl) { + this.githubUrl = githubUrl; + } + + public String getGithubApiUrl() { + return githubApiUrl; + } + + public void setGithubApiUrl(String githubApiUrl) { + this.githubApiUrl = githubApiUrl; + } } @BsonDiscriminator diff --git a/libs/dao/src/main/java/com/akto/dto/test_run_findings/TestingRunIssues.java b/libs/dao/src/main/java/com/akto/dto/test_run_findings/TestingRunIssues.java index 13cc258731..2676316c3a 100644 --- a/libs/dao/src/main/java/com/akto/dto/test_run_findings/TestingRunIssues.java +++ b/libs/dao/src/main/java/com/akto/dto/test_run_findings/TestingRunIssues.java @@ -25,11 +25,17 @@ public class TestingRunIssues { private String jiraIssueUrl; public static final String LAST_UPDATED = "lastUpdated"; private int lastUpdated; - + public static final String UNREAD = "unread"; + private boolean unread; private List collectionIds; public TestingRunIssues(TestingIssuesId id, GlobalEnums.Severity severity, GlobalEnums.TestRunIssueStatus status, int creationTime, int lastSeen, ObjectId latestTestingRunSummaryId, String jiraIssueUrl, int lastUpdated) { + this(id, severity, status, creationTime, lastSeen, latestTestingRunSummaryId, jiraIssueUrl, lastUpdated, false); + } + + public TestingRunIssues(TestingIssuesId id, GlobalEnums.Severity severity, GlobalEnums.TestRunIssueStatus status, + int creationTime, int lastSeen, ObjectId latestTestingRunSummaryId, String jiraIssueUrl, int lastUpdated, boolean unread) { this.creationTime = creationTime; this.lastSeen = lastSeen; this.id = id; @@ -41,6 +47,7 @@ public TestingRunIssues(TestingIssuesId id, GlobalEnums.Severity severity, Globa this.latestTestingRunSummaryId = latestTestingRunSummaryId; this.jiraIssueUrl = jiraIssueUrl; this.lastUpdated = lastUpdated; + this.unread = unread; } public TestingRunIssues() { @@ -144,4 +151,12 @@ public String toString() { ", collectionIds=" + collectionIds + '}'; } + + public boolean isUnread() { + return unread; + } + + public void setUnread(boolean unread) { + this.unread = unread; + } }