diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2019-04-30 09:21:47 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-05-07 09:54:29 +0200 |
commit | 444b67e5ffe6dc914d40ad1b157cb72aaa591643 (patch) | |
tree | 94751adede0868698246a801e3833f8997aff397 | |
parent | ecee829049b997c943b8c0f9060d940d1d88614c (diff) | |
download | sonarqube-444b67e5ffe6dc914d40ad1b157cb72aaa591643.tar.gz sonarqube-444b67e5ffe6dc914d40ad1b157cb72aaa591643.zip |
SONAR-11970 Remove security report code from sonar-web
15 files changed, 186 insertions, 3024 deletions
diff --git a/server/sonar-web/src/main/js/api/security-reports.ts b/server/sonar-web/src/main/js/api/security-reports.ts deleted file mode 100644 index d709b33ca7e..00000000000 --- a/server/sonar-web/src/main/js/api/security-reports.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import { getJSON } from '../helpers/request'; -import throwGlobalError from '../app/utils/throwGlobalError'; - -export function getSecurityHotspots(data: { - project: string; - standard: T.StandardType; - includeDistribution?: boolean; - branch?: string; -}): Promise<{ categories: T.SecurityHotspot[] }> { - return getJSON('/api/security_reports/show', data).catch(throwGlobalError); -} diff --git a/server/sonar-web/src/main/js/app/types.d.ts b/server/sonar-web/src/main/js/app/types.d.ts index d97e54174f3..5ec635aab23 100644 --- a/server/sonar-web/src/main/js/app/types.d.ts +++ b/server/sonar-web/src/main/js/app/types.d.ts @@ -331,19 +331,6 @@ declare namespace T { name: string; } - export interface SecurityHotspot { - activeRules: number; - category?: string; - cwe?: string; - distribution?: Array<SecurityHotspot>; - openSecurityHotspots: number; - toReviewSecurityHotspots: number; - totalRules: number; - vulnerabilities: number; - vulnerabilityRating?: number; - wontFixSecurityHotspots: number; - } - export interface Issue { actions: string[]; assignee?: string; diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx index 776fe74d0ce..64d954aed09 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -230,10 +230,6 @@ export default function startReactApp( )} /> <Route path="project/issues" component={Issues} /> - <Route - path="project/security_reports/:type" - component={lazyLoad(() => import('../../apps/securityReports/components/App'))} - /> <RouteWithChildRoutes path="project/quality_gate" childRoutes={projectQualityGateRoutes} diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx index 46482c38c93..51dde5811c3 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/StandardFacet.tsx @@ -19,23 +19,23 @@ */ import * as React from 'react'; import { sortBy, without, omit } from 'lodash'; -import { Query, STANDARDS, formatFacetStat, Facet } from '../utils'; +import DeferredSpinner from '../../../components/common/DeferredSpinner'; import FacetBox from '../../../components/facet/FacetBox'; import FacetHeader from '../../../components/facet/FacetHeader'; -import { translate } from '../../../helpers/l10n'; -import FacetItemsList from '../../../components/facet/FacetItemsList'; import FacetItem from '../../../components/facet/FacetItem'; +import FacetItemsList from '../../../components/facet/FacetItemsList'; +import ListStyleFacet from '../../../components/facet/ListStyleFacet'; +import MultipleSelectionHint from '../../../components/facet/MultipleSelectionHint'; +import { translate } from '../../../helpers/l10n'; +import { highlightTerm } from '../../../helpers/search'; import { + getStandards, + renderCWECategory, renderOwaspTop10Category, renderSansTop25Category, - renderCWECategory, renderSonarSourceSecurityCategory -} from '../../securityReports/utils'; -import DeferredSpinner from '../../../components/common/DeferredSpinner'; -import ListStyleFacet from '../../../components/facet/ListStyleFacet'; -import MultipleSelectionHint from '../../../components/facet/MultipleSelectionHint'; -import { highlightTerm } from '../../../helpers/search'; -import { getStandards } from '../../../helpers/security-standard'; +} from '../../../helpers/security-standard'; +import { Query, STANDARDS, formatFacetStat, Facet } from '../utils'; interface Props { cwe: string[]; diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx index 487b2d43349..0140d9d8c87 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/StandardFacet-test.tsx @@ -25,6 +25,7 @@ import { Query } from '../../utils'; import { getStandards } from '../../../../helpers/security-standard'; jest.mock('../../../../helpers/security-standard', () => ({ + ...require.requireActual('../../../../helpers/security-standard'), getStandards: jest.fn().mockResolvedValue({ owaspTop10: { a1: { diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/App.tsx b/server/sonar-web/src/main/js/apps/securityReports/components/App.tsx deleted file mode 100755 index 37c049a0c86..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/components/App.tsx +++ /dev/null @@ -1,195 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import Helmet from 'react-helmet'; -import { Link } from 'react-router'; -import VulnerabilityList from './VulnerabilityList'; -import A11ySkipTarget from '../../../app/components/a11y/A11ySkipTarget'; -import { Alert } from '../../../components/ui/Alert'; -import Checkbox from '../../../components/controls/Checkbox'; -import DeferredSpinner from '../../../components/common/DeferredSpinner'; -import DocTooltip from '../../../components/docs/DocTooltip'; -import NotFound from '../../../app/components/NotFound'; -import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; -import { withRouter, Location, Router } from '../../../components/hoc/withRouter'; -import { translate } from '../../../helpers/l10n'; -import { isLongLivingBranch } from '../../../helpers/branches'; -import { getSecurityHotspots } from '../../../api/security-reports'; -import { getType } from '../utils'; -import '../style.css'; - -interface Props { - branchLike?: T.BranchLike; - component: T.Component; - location: Pick<Location, 'pathname' | 'query'>; - params: { type: string }; - router: Pick<Router, 'push'>; -} - -interface State { - loading: boolean; - findings: T.SecurityHotspot[]; - hasVulnerabilities: boolean; - type: T.StandardType; - showCWE: boolean; -} - -export class App extends React.PureComponent<Props, State> { - mounted = false; - - constructor(props: Props) { - super(props); - this.state = { - loading: false, - findings: [], - hasVulnerabilities: false, - type: getType(props.params.type), - showCWE: props.location.query.showCWE === 'true' - }; - } - - componentDidMount() { - this.mounted = true; - this.fetchSecurityHotspots(); - } - - componentWillReceiveProps(newProps: Props) { - if (newProps.location.pathname !== this.props.location.pathname) { - const showCWE = newProps.location.query.showCWE === 'true'; - const type = getType(newProps.params.type); - this.setState({ type, showCWE }, this.fetchSecurityHotspots); - } - } - - componentWillUnmount() { - this.mounted = false; - } - - fetchSecurityHotspots = () => { - const { branchLike, component } = this.props; - this.setState({ loading: true }); - getSecurityHotspots({ - project: component.key, - standard: this.state.type, - includeDistribution: this.state.showCWE, - branch: isLongLivingBranch(branchLike) ? branchLike.name : undefined - }) - .then(results => { - if (this.mounted) { - const hasVulnerabilities = results.categories.some( - item => - item.vulnerabilities + - item.openSecurityHotspots + - item.toReviewSecurityHotspots + - item.wontFixSecurityHotspots > - 0 - ); - this.setState({ hasVulnerabilities, findings: results.categories, loading: false }); - } - }) - .catch(() => { - if (this.mounted) { - this.setState({ loading: false }); - } - }); - }; - - handleCheck = (checked: boolean) => { - this.props.router.push({ - pathname: this.props.location.pathname, - query: { id: this.props.component.key, showCWE: checked } - }); - this.setState({ showCWE: checked }, this.fetchSecurityHotspots); - }; - - renderAdditionalRulesMessage = () => { - const { findings } = this.state; - if (findings.length === 0) { - return null; - } - - const total = findings.map(f => f.totalRules).reduce((sum, count) => sum + count); - const active = findings.map(f => f.activeRules).reduce((sum, count) => sum + count); - if (active >= total) { - return null; - } - - return ( - <Alert className="spacer-top" display="inline" variant="info"> - {translate('security_reports.more_rules')} - </Alert> - ); - }; - - render() { - const { branchLike, component, params } = this.props; - const { loading, findings, showCWE, type } = this.state; - if (!['owasp_top_10', 'sans_top_25', 'sonarsource_security'].includes(params.type)) { - return <NotFound withContainer={false} />; - } - return ( - <div className="page page-limited" id="security-reports"> - <Suggestions suggestions="security_reports" /> - <Helmet title={translate('security_reports', type, 'page')} /> - <header className="page-header"> - <A11ySkipTarget anchor="security_main" /> - <h1 className="page-title">{translate('security_reports', type, 'page')}</h1> - <div className="page-description"> - {translate('security_reports', type, 'description')} - <Link - className="spacer-left" - target="_blank" - to={{ pathname: '/documentation/user-guide/security-reports/' }}> - {translate('learn_more')} - </Link> - {this.renderAdditionalRulesMessage()} - </div> - </header> - <div className="display-inline-flex-center"> - <Checkbox - checked={showCWE} - className="spacer-left spacer-right vertical-middle" - disabled={!this.state.hasVulnerabilities} - id={'showCWE'} - onCheck={this.handleCheck}> - <label className="little-spacer-left" htmlFor={'showCWE'}> - {translate('security_reports.cwe.show')} - <DocTooltip - className="spacer-left" - doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/security-reports/cwe.md')} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner loading={loading}> - <VulnerabilityList - branchLike={branchLike} - component={component} - findings={findings} - showCWE={showCWE} - type={type} - /> - </DeferredSpinner> - </div> - ); - } -} - -export default withRouter(App); diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx b/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx deleted file mode 100755 index 2179b89f73e..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/components/VulnerabilityList.tsx +++ /dev/null @@ -1,351 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import * as classNames from 'classnames'; -import { sortBy } from 'lodash'; -import { Link } from 'react-router'; -import { translate } from '../../../helpers/l10n'; -import Rating from '../../../components/ui/Rating'; -import { getComponentIssuesUrl, getRulesUrl } from '../../../helpers/urls'; -import { getBranchLikeQuery } from '../../../helpers/branches'; -import HelpTooltip from '../../../components/controls/HelpTooltip'; -import VulnerabilityIcon from '../../../components/icons-components/VulnerabilityIcon'; -import SecurityHotspotIcon from '../../../components/icons-components/SecurityHotspotIcon'; -import { - renderOwaspTop10Category, - renderSansTop25Category, - renderCWECategory, - renderSonarSourceSecurityCategory -} from '../utils'; -import DetachIcon from '../../../components/icons-components/DetachIcon'; -import Tooltip from '../../../components/controls/Tooltip'; -import { getRatingTooltip } from '../../../helpers/measures'; -import PlusCircleIcon from '../../../components/icons-components/PlusCircleIcon'; -import { isSonarCloud } from '../../../helpers/system'; -import * as theme from '../../../app/theme'; -import DeferredSpinner from '../../../components/common/DeferredSpinner'; - -interface Props { - branchLike?: T.BranchLike; - component: T.Component; - findings: T.SecurityHotspot[]; - showCWE: boolean; - type: T.StandardType; -} - -interface State { - loading: boolean; - standards: T.Standards; - standardKeys: string[]; -} - -const STANDARDS_TAGS = { - owaspTop10: 'owasp', - sansTop25: 'sans-top25', - cwe: 'cwe', - sonarsourceSecurity: 'sonarsourceSecurity' -}; - -export default class VulnerabilityList extends React.PureComponent<Props, State> { - mounted = false; - state: State = { - loading: false, - standards: { owaspTop10: {}, sansTop25: {}, cwe: {}, sonarsourceSecurity: {} }, - standardKeys: [] - }; - - componentDidMount() { - this.mounted = true; - this.loadStandards(); - } - - componentWillUnmount() { - this.mounted = false; - } - - loadStandards = () => { - this.setState({ loading: true }); - import('../../../helpers/standards.json') - .then(x => x.default) - .then( - ({ owaspTop10, sansTop25, cwe, sonarsourceSecurity }: T.Standards) => { - if (this.mounted) { - const standards = { owaspTop10, sansTop25, cwe, sonarsourceSecurity }; - this.setState({ - loading: false, - standards, - standardKeys: Object.keys(standards[this.props.type]) - }); - } - }, - () => {} - ); - }; - - getName(finding: T.SecurityHotspot, type: T.StandardType) { - const category = finding.category || finding.cwe || 'unknown'; - const renderers = { - owaspTop10: renderOwaspTop10Category, - sansTop25: renderSansTop25Category, - cwe: renderCWECategory, - sonarsourceSecurity: renderSonarSourceSecurityCategory - }; - return ( - <> - {renderers[type](this.state.standards, category)} - {this.state.standards[type][category] && - this.state.standards[type][category].description && ( - <HelpTooltip - className="spacer-left" - overlay={this.renderOverlay(this.state.standards[type][category].description)} - /> - )} - {finding.activeRules === 0 && - finding.totalRules > 0 && - category !== 'cwe' && - category !== 'unknown' && ( - <HelpTooltip - className="spacer-left" - overlay={this.renderMoreRulesOverlay(type, category)}> - <PlusCircleIcon className="vertical-middle" fill={theme.blue} size={12} /> - </HelpTooltip> - )} - </> - ); - } - - // We redirect the user to the rules page, using languages, types, keywords and tags filters - // to display the correct list of rules - renderMoreRulesOverlay = (type: T.StandardType, category: string) => { - const languages = this.props.component.qualityProfiles - ? this.props.component.qualityProfiles.map(qp => qp.language).join(',') - : ''; - const sansTopCategoryTags: T.Dict<string> = { - 'insecure-interaction': 'insecure', - 'porous-defenses': 'porous', - 'risky-resource': 'risky' - }; - const tags = `${STANDARDS_TAGS[type]}-${ - type === 'sansTop25' ? sansTopCategoryTags[category.toLowerCase()] : category.toLowerCase() - }`; - return ( - <> - <p>{translate('security_reports.activate_rules')}</p> - <hr className="spacer-top spacer-bottom" /> - <Link - className="spacer-left link-no-underline" - to={getRulesUrl( - { languages, tags, types: ['SECURITY_HOTSPOT', 'VULNERABILITY'].join() }, - isSonarCloud() ? this.props.component.organization : undefined - )}> - {translate('security_reports.activate_rules.link')} - </Link> - </> - ); - }; - - renderOverlay = (description: string | undefined) => { - return ( - <> - <p>{description}</p> - <hr className="spacer-top spacer-bottom" /> - {translate('learn_more')}: - <Link - className="spacer-left" - target="_blank" - to={{ pathname: '/documentation/user-guide/security-reports/' }}> - Security Reports - </Link> - <DetachIcon - className="little-spacer-left little-spacer-right vertical-baseline" - size={12} - /> - </> - ); - }; - - renderComponentIssuesLink = ( - activeRules: number, - query: T.Dict<string | undefined>, - value: number, - tooltip?: JSX.Element - ) => { - if (activeRules === 0) { - return '-'; - } - return value === 0 ? ( - <> - {value} - {tooltip} - </> - ) : ( - <> - <Link to={getComponentIssuesUrl(this.props.component.key, query)}>{value}</Link> - {tooltip} - </> - ); - }; - - renderFinding( - finding: T.SecurityHotspot, - isCWE?: boolean, - parent?: T.SecurityHotspot - ): React.ReactFragment { - const { branchLike, component, type } = this.props; - const params: T.Dict<string | undefined> = { - ...getBranchLikeQuery(branchLike), - types: 'SECURITY_HOTSPOT' - }; - if (isCWE && parent) { - params['cwe'] = finding.cwe; - params[type] = parent.category; - } else { - params[type] = finding.category; - } - - const subFindings = - this.props.showCWE && finding.distribution - ? finding.distribution.map(f => this.renderFinding(f, true, finding)) - : null; - - const title = getRatingTooltip('security_rating', finding.vulnerabilityRating || 1); - return ( - <React.Fragment key={finding.category || finding.cwe}> - <tr> - <td className={classNames({ 'cwe-title-cell': isCWE })}> - {this.getName(finding, isCWE ? 'cwe' : type)} - </td> - <td className="text-right"> - <div className="display-inline-flex-center"> - {this.renderComponentIssuesLink( - finding.activeRules, - { - ...params, - types: 'VULNERABILITY', - resolved: 'false' - }, - finding.vulnerabilities, - <Tooltip overlay={title}> - <Link - className="link-no-underline spacer-left" - to={getComponentIssuesUrl(component.key, { - ...params, - types: 'VULNERABILITY', - resolved: 'false' - })}> - <Rating value={finding.vulnerabilityRating || 1} /> - </Link> - </Tooltip> - )} - </div> - </td> - <td className="text-right security-column-separator"> - {this.renderComponentIssuesLink( - finding.activeRules, - { - ...params, - types: 'SECURITY_HOTSPOT', - resolved: 'false', - statuses: 'OPEN,REOPENED' - }, - finding.openSecurityHotspots - )} - </td> - <td className="text-right"> - {this.renderComponentIssuesLink( - finding.activeRules, - { - ...params, - types: 'SECURITY_HOTSPOT', - resolutions: 'FIXED', - statuses: 'RESOLVED' - }, - finding.toReviewSecurityHotspots - )} - </td> - <td className="text-right"> - {this.renderComponentIssuesLink( - finding.activeRules, - { - ...params, - types: 'SECURITY_HOTSPOT', - resolutions: 'WONTFIX', - statuses: 'RESOLVED' - }, - finding.wontFixSecurityHotspots - )} - </td> - </tr> - {subFindings} - </React.Fragment> - ); - } - - render() { - const { loading, standardKeys } = this.state; - const sortedFindings = sortBy(this.props.findings, ({ category }) => { - const index = category ? standardKeys.indexOf(category) : standardKeys.length; - return index < 0 ? standardKeys.length : index; - }); - - if (loading) { - return <DeferredSpinner />; - } - - return ( - <div className="boxed-group boxed-group-inner spacer-top"> - <table className="data zebra security-reports"> - <thead> - <tr> - <th className="security-category-column"> - {translate('security_reports.list.categories')} - </th> - <th className="security-result-column text-right"> - <div className="display-inline-flex-center"> - <VulnerabilityIcon className="spacer-right" /> - {translate('security_reports.list.vulnerabilities')} - </div> - </th> - <th className="text-right security-column-separator" colSpan={3}> - <div className="display-inline-flex-center"> - <SecurityHotspotIcon className="spacer-right" /> - {translate('security_reports.list.security_hotspots')} - </div> - </th> - </tr> - <tr className="subheader"> - <th colSpan={2} /> - <th className="text-right security-result-column security-column-separator"> - {translate('security_reports.line.open')} - </th> - <th className="text-right security-result-column"> - {translate('security_reports.line.in_review')} - </th> - <th className="text-right security-result-column"> - {translate('security_reports.line.wont_fix')} - </th> - </tr> - </thead> - <tbody>{sortedFindings.map(finding => this.renderFinding(finding))}</tbody> - </table> - </div> - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/App-test.tsx deleted file mode 100644 index 12bf3c5b428..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/App-test.tsx +++ /dev/null @@ -1,212 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/* eslint-disable import/first, import/order */ -jest.mock('../../../../api/security-reports', () => ({ - getSecurityHotspots: jest.fn(() => { - const distribution: any = [ - { - cwe: '477', - vulnerabilities: 1, - vulnerabiliyRating: 1, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0 - }, - { - cwe: '396', - vulnerabilities: 2, - vulnerabiliyRating: 2, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0 - } - ]; - return Promise.resolve({ - categories: [ - { - activeRules: 1, - totalRules: 1, - category: 'a1', - vulnerabilities: 2, - vulnerabiliyRating: 5, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0, - distribution - }, - { - activeRules: 1, - totalRules: 1, - category: 'a2', - vulnerabilities: 3, - vulnerabiliyRating: 3, - toReviewSecurityHotspots: 8, - openSecurityHotspots: 100, - wontFixSecurityHotspots: 10 - }, - { - activeRules: 0, - totalRules: 1, - category: 'a3', - vulnerabilities: 3, - vulnerabiliyRating: 3, - toReviewSecurityHotspots: 8, - openSecurityHotspots: 100, - wontFixSecurityHotspots: 10 - } - ] - }); - }) -})); - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import { App } from '../App'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; - -const getSecurityHotspots = require('../../../../api/security-reports') - .getSecurityHotspots as jest.Mock<any>; - -const component = { key: 'foo', name: 'Foo', qualifier: 'TRK' } as T.Component; -const location = { pathname: 'foo', query: {} }; -const locationWithCWE = { pathname: 'foo', query: { showCWE: 'true' } }; -const owaspParams = { type: 'owasp_top_10' }; -const sansParams = { type: 'sans_top_25' }; -const sonarParams = { type: 'sonarsource_security' }; -const wrongParams = { type: 'foo' }; - -beforeEach(() => { - getSecurityHotspots.mockClear(); -}); - -it('renders error on wrong type parameters', () => { - const wrapper = shallow( - <App - component={component} - location={location} - params={wrongParams} - router={{ push: jest.fn() }} - /> - ); - expect(wrapper).toMatchSnapshot(); -}); - -it('renders owaspTop10', async () => { - const wrapper = shallow( - <App - component={component} - location={location} - params={owaspParams} - router={{ push: jest.fn() }} - /> - ); - await waitAndUpdate(wrapper); - expect(getSecurityHotspots).toBeCalledWith({ - project: 'foo', - standard: 'owaspTop10', - includeDistribution: false, - branch: undefined - }); - expect(wrapper).toMatchSnapshot(); -}); - -it('renders with cwe', () => { - const wrapper = shallow( - <App - component={component} - location={locationWithCWE} - params={owaspParams} - router={{ push: jest.fn() }} - /> - ); - expect(getSecurityHotspots).toBeCalledWith({ - project: 'foo', - standard: 'owaspTop10', - includeDistribution: true, - branch: undefined - }); - expect(wrapper).toMatchSnapshot(); -}); - -it('handle checkbox for cwe display', async () => { - const wrapper = shallow( - <App - component={component} - location={location} - params={owaspParams} - router={{ push: jest.fn() }} - /> - ); - expect(getSecurityHotspots).toBeCalledWith({ - project: 'foo', - standard: 'owaspTop10', - includeDistribution: false, - branch: undefined - }); - expect(wrapper).toMatchSnapshot(); - - wrapper.find('Checkbox').prop<Function>('onCheck')(true); - await waitAndUpdate(wrapper); - - expect(getSecurityHotspots).toBeCalledWith({ - project: 'foo', - standard: 'owaspTop10', - includeDistribution: true, - branch: undefined - }); - expect(wrapper).toMatchSnapshot(); -}); - -it('renders sansTop25', () => { - const wrapper = shallow( - <App - component={component} - location={location} - params={sansParams} - router={{ push: jest.fn() }} - /> - ); - expect(getSecurityHotspots).toBeCalledWith({ - project: 'foo', - standard: 'sansTop25', - includeDistribution: false, - branch: undefined - }); - expect(wrapper).toMatchSnapshot(); -}); - -it('renders sonarsourceSecurity', async () => { - const wrapper = shallow( - <App - component={component} - location={location} - params={sonarParams} - router={{ push: jest.fn() }} - /> - ); - await waitAndUpdate(wrapper); - expect(getSecurityHotspots).toBeCalledWith({ - project: 'foo', - standard: 'sonarsourceSecurity', - includeDistribution: false, - branch: undefined - }); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/VulnerabilityList-test.tsx b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/VulnerabilityList-test.tsx deleted file mode 100644 index c5ab079ad23..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/VulnerabilityList-test.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import VulnerabilityList from '../VulnerabilityList'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; - -jest.mock('../../../../helpers/standards.json', () => ({ - default: { - owaspTop10: { a1: { title: 'a1 title' }, unknown: { title: 'Not OWAPS' } }, - sansTop25: { 'risky-resource': { title: 'Risky Resource Management' } }, - cwe: { 42: { title: 'cwe-42 title' }, unknown: { title: 'Unknown CWE' } } - } -})); - -const component = { key: 'foo', name: 'Foo', qualifier: 'TRK' } as T.Component; -const findings = [ - { - activeRules: 1, - totalRules: 1, - category: 'a1', - vulnerabilities: 2, - vulnerabilityRating: 5, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0, - distribution: [ - { - activeRules: 1, - totalRules: 1, - cwe: '42', - vulnerabilities: 1, - vulnerabilityRating: 1, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0 - } - ] - }, - { - activeRules: 1, - totalRules: 2, - category: 'a2', - vulnerabilities: 2, - vulnerabilityRating: 5, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0, - distribution: [ - { - activeRules: 1, - totalRules: 1, - cwe: '42', - vulnerabilities: 1, - vulnerabilityRating: 1, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0 - } - ] - }, - { - activeRules: 0, - totalRules: 1, - category: 'a3', - vulnerabilities: 2, - vulnerabilityRating: 5, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0, - distribution: [ - { - activeRules: 1, - totalRules: 1, - cwe: '42', - vulnerabilities: 1, - vulnerabilityRating: 1, - toReviewSecurityHotspots: 2, - openSecurityHotspots: 10, - wontFixSecurityHotspots: 0 - } - ] - }, - { - activeRules: 1, - totalRules: 1, - category: 'unknown', - vulnerabilities: 3, - vulnerabilityRating: 3, - toReviewSecurityHotspots: 8, - openSecurityHotspots: 100, - wontFixSecurityHotspots: 10 - } -]; - -it('renders', async () => { - const wrapper = shallow( - <VulnerabilityList - component={component} - findings={findings} - showCWE={false} - type="owaspTop10" - /> - ); - await waitAndUpdate(wrapper); - expect(wrapper.find('tr').length).toBe(6); - expect(wrapper).toMatchSnapshot(); -}); - -it('renders with cwe', async () => { - const wrapper = shallow( - <VulnerabilityList component={component} findings={findings} showCWE={true} type="owaspTop10" /> - ); - await waitAndUpdate(wrapper); - expect(wrapper.find('tr').length).toBe(9); - expect(wrapper).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap deleted file mode 100644 index b89aa9c57c4..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/App-test.tsx.snap +++ /dev/null @@ -1,697 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`handle checkbox for cwe display 1`] = ` -<div - className="page page-limited" - id="security-reports" -> - <Suggestions - suggestions="security_reports" - /> - <HelmetWrapper - defer={true} - encodeSpecialCharacters={true} - title="security_reports.owaspTop10.page" - /> - <header - className="page-header" - > - <A11ySkipTarget - anchor="security_main" - /> - <h1 - className="page-title" - > - security_reports.owaspTop10.page - </h1> - <div - className="page-description" - > - security_reports.owaspTop10.description - <Link - className="spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - target="_blank" - to={ - Object { - "pathname": "/documentation/user-guide/security-reports/", - } - } - > - learn_more - </Link> - </div> - </header> - <div - className="display-inline-flex-center" - > - <Checkbox - checked={false} - className="spacer-left spacer-right vertical-middle" - disabled={true} - id="showCWE" - onCheck={[Function]} - thirdState={false} - > - <label - className="little-spacer-left" - htmlFor="showCWE" - > - security_reports.cwe.show - <DocTooltip - className="spacer-left" - doc={Promise {}} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner - loading={true} - timeout={100} - > - <VulnerabilityList - component={ - Object { - "key": "foo", - "name": "Foo", - "qualifier": "TRK", - } - } - findings={Array []} - showCWE={false} - type="owaspTop10" - /> - </DeferredSpinner> -</div> -`; - -exports[`handle checkbox for cwe display 2`] = ` -<div - className="page page-limited" - id="security-reports" -> - <Suggestions - suggestions="security_reports" - /> - <HelmetWrapper - defer={true} - encodeSpecialCharacters={true} - title="security_reports.owaspTop10.page" - /> - <header - className="page-header" - > - <A11ySkipTarget - anchor="security_main" - /> - <h1 - className="page-title" - > - security_reports.owaspTop10.page - </h1> - <div - className="page-description" - > - security_reports.owaspTop10.description - <Link - className="spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - target="_blank" - to={ - Object { - "pathname": "/documentation/user-guide/security-reports/", - } - } - > - learn_more - </Link> - <Alert - className="spacer-top" - display="inline" - variant="info" - > - security_reports.more_rules - </Alert> - </div> - </header> - <div - className="display-inline-flex-center" - > - <Checkbox - checked={true} - className="spacer-left spacer-right vertical-middle" - disabled={false} - id="showCWE" - onCheck={[Function]} - thirdState={false} - > - <label - className="little-spacer-left" - htmlFor="showCWE" - > - security_reports.cwe.show - <DocTooltip - className="spacer-left" - doc={Promise {}} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner - loading={false} - timeout={100} - > - <VulnerabilityList - component={ - Object { - "key": "foo", - "name": "Foo", - "qualifier": "TRK", - } - } - findings={ - Array [ - Object { - "activeRules": 1, - "category": "a1", - "distribution": Array [ - Object { - "cwe": "477", - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "vulnerabilities": 1, - "vulnerabiliyRating": 1, - "wontFixSecurityHotspots": 0, - }, - Object { - "cwe": "396", - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "vulnerabilities": 2, - "vulnerabiliyRating": 2, - "wontFixSecurityHotspots": 0, - }, - ], - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "totalRules": 1, - "vulnerabilities": 2, - "vulnerabiliyRating": 5, - "wontFixSecurityHotspots": 0, - }, - Object { - "activeRules": 1, - "category": "a2", - "openSecurityHotspots": 100, - "toReviewSecurityHotspots": 8, - "totalRules": 1, - "vulnerabilities": 3, - "vulnerabiliyRating": 3, - "wontFixSecurityHotspots": 10, - }, - Object { - "activeRules": 0, - "category": "a3", - "openSecurityHotspots": 100, - "toReviewSecurityHotspots": 8, - "totalRules": 1, - "vulnerabilities": 3, - "vulnerabiliyRating": 3, - "wontFixSecurityHotspots": 10, - }, - ] - } - showCWE={true} - type="owaspTop10" - /> - </DeferredSpinner> -</div> -`; - -exports[`renders error on wrong type parameters 1`] = ` -<NotFound - withContainer={false} -/> -`; - -exports[`renders owaspTop10 1`] = ` -<div - className="page page-limited" - id="security-reports" -> - <Suggestions - suggestions="security_reports" - /> - <HelmetWrapper - defer={true} - encodeSpecialCharacters={true} - title="security_reports.owaspTop10.page" - /> - <header - className="page-header" - > - <A11ySkipTarget - anchor="security_main" - /> - <h1 - className="page-title" - > - security_reports.owaspTop10.page - </h1> - <div - className="page-description" - > - security_reports.owaspTop10.description - <Link - className="spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - target="_blank" - to={ - Object { - "pathname": "/documentation/user-guide/security-reports/", - } - } - > - learn_more - </Link> - <Alert - className="spacer-top" - display="inline" - variant="info" - > - security_reports.more_rules - </Alert> - </div> - </header> - <div - className="display-inline-flex-center" - > - <Checkbox - checked={false} - className="spacer-left spacer-right vertical-middle" - disabled={false} - id="showCWE" - onCheck={[Function]} - thirdState={false} - > - <label - className="little-spacer-left" - htmlFor="showCWE" - > - security_reports.cwe.show - <DocTooltip - className="spacer-left" - doc={Promise {}} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner - loading={false} - timeout={100} - > - <VulnerabilityList - component={ - Object { - "key": "foo", - "name": "Foo", - "qualifier": "TRK", - } - } - findings={ - Array [ - Object { - "activeRules": 1, - "category": "a1", - "distribution": Array [ - Object { - "cwe": "477", - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "vulnerabilities": 1, - "vulnerabiliyRating": 1, - "wontFixSecurityHotspots": 0, - }, - Object { - "cwe": "396", - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "vulnerabilities": 2, - "vulnerabiliyRating": 2, - "wontFixSecurityHotspots": 0, - }, - ], - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "totalRules": 1, - "vulnerabilities": 2, - "vulnerabiliyRating": 5, - "wontFixSecurityHotspots": 0, - }, - Object { - "activeRules": 1, - "category": "a2", - "openSecurityHotspots": 100, - "toReviewSecurityHotspots": 8, - "totalRules": 1, - "vulnerabilities": 3, - "vulnerabiliyRating": 3, - "wontFixSecurityHotspots": 10, - }, - Object { - "activeRules": 0, - "category": "a3", - "openSecurityHotspots": 100, - "toReviewSecurityHotspots": 8, - "totalRules": 1, - "vulnerabilities": 3, - "vulnerabiliyRating": 3, - "wontFixSecurityHotspots": 10, - }, - ] - } - showCWE={false} - type="owaspTop10" - /> - </DeferredSpinner> -</div> -`; - -exports[`renders sansTop25 1`] = ` -<div - className="page page-limited" - id="security-reports" -> - <Suggestions - suggestions="security_reports" - /> - <HelmetWrapper - defer={true} - encodeSpecialCharacters={true} - title="security_reports.sansTop25.page" - /> - <header - className="page-header" - > - <A11ySkipTarget - anchor="security_main" - /> - <h1 - className="page-title" - > - security_reports.sansTop25.page - </h1> - <div - className="page-description" - > - security_reports.sansTop25.description - <Link - className="spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - target="_blank" - to={ - Object { - "pathname": "/documentation/user-guide/security-reports/", - } - } - > - learn_more - </Link> - </div> - </header> - <div - className="display-inline-flex-center" - > - <Checkbox - checked={false} - className="spacer-left spacer-right vertical-middle" - disabled={true} - id="showCWE" - onCheck={[Function]} - thirdState={false} - > - <label - className="little-spacer-left" - htmlFor="showCWE" - > - security_reports.cwe.show - <DocTooltip - className="spacer-left" - doc={Promise {}} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner - loading={true} - timeout={100} - > - <VulnerabilityList - component={ - Object { - "key": "foo", - "name": "Foo", - "qualifier": "TRK", - } - } - findings={Array []} - showCWE={false} - type="sansTop25" - /> - </DeferredSpinner> -</div> -`; - -exports[`renders sonarsourceSecurity 1`] = ` -<div - className="page page-limited" - id="security-reports" -> - <Suggestions - suggestions="security_reports" - /> - <HelmetWrapper - defer={true} - encodeSpecialCharacters={true} - title="security_reports.sonarsourceSecurity.page" - /> - <header - className="page-header" - > - <A11ySkipTarget - anchor="security_main" - /> - <h1 - className="page-title" - > - security_reports.sonarsourceSecurity.page - </h1> - <div - className="page-description" - > - security_reports.sonarsourceSecurity.description - <Link - className="spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - target="_blank" - to={ - Object { - "pathname": "/documentation/user-guide/security-reports/", - } - } - > - learn_more - </Link> - <Alert - className="spacer-top" - display="inline" - variant="info" - > - security_reports.more_rules - </Alert> - </div> - </header> - <div - className="display-inline-flex-center" - > - <Checkbox - checked={false} - className="spacer-left spacer-right vertical-middle" - disabled={false} - id="showCWE" - onCheck={[Function]} - thirdState={false} - > - <label - className="little-spacer-left" - htmlFor="showCWE" - > - security_reports.cwe.show - <DocTooltip - className="spacer-left" - doc={Promise {}} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner - loading={false} - timeout={100} - > - <VulnerabilityList - component={ - Object { - "key": "foo", - "name": "Foo", - "qualifier": "TRK", - } - } - findings={ - Array [ - Object { - "activeRules": 1, - "category": "a1", - "distribution": Array [ - Object { - "cwe": "477", - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "vulnerabilities": 1, - "vulnerabiliyRating": 1, - "wontFixSecurityHotspots": 0, - }, - Object { - "cwe": "396", - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "vulnerabilities": 2, - "vulnerabiliyRating": 2, - "wontFixSecurityHotspots": 0, - }, - ], - "openSecurityHotspots": 10, - "toReviewSecurityHotspots": 2, - "totalRules": 1, - "vulnerabilities": 2, - "vulnerabiliyRating": 5, - "wontFixSecurityHotspots": 0, - }, - Object { - "activeRules": 1, - "category": "a2", - "openSecurityHotspots": 100, - "toReviewSecurityHotspots": 8, - "totalRules": 1, - "vulnerabilities": 3, - "vulnerabiliyRating": 3, - "wontFixSecurityHotspots": 10, - }, - Object { - "activeRules": 0, - "category": "a3", - "openSecurityHotspots": 100, - "toReviewSecurityHotspots": 8, - "totalRules": 1, - "vulnerabilities": 3, - "vulnerabiliyRating": 3, - "wontFixSecurityHotspots": 10, - }, - ] - } - showCWE={false} - type="sonarsourceSecurity" - /> - </DeferredSpinner> -</div> -`; - -exports[`renders with cwe 1`] = ` -<div - className="page page-limited" - id="security-reports" -> - <Suggestions - suggestions="security_reports" - /> - <HelmetWrapper - defer={true} - encodeSpecialCharacters={true} - title="security_reports.owaspTop10.page" - /> - <header - className="page-header" - > - <A11ySkipTarget - anchor="security_main" - /> - <h1 - className="page-title" - > - security_reports.owaspTop10.page - </h1> - <div - className="page-description" - > - security_reports.owaspTop10.description - <Link - className="spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - target="_blank" - to={ - Object { - "pathname": "/documentation/user-guide/security-reports/", - } - } - > - learn_more - </Link> - </div> - </header> - <div - className="display-inline-flex-center" - > - <Checkbox - checked={true} - className="spacer-left spacer-right vertical-middle" - disabled={true} - id="showCWE" - onCheck={[Function]} - thirdState={false} - > - <label - className="little-spacer-left" - htmlFor="showCWE" - > - security_reports.cwe.show - <DocTooltip - className="spacer-left" - doc={Promise {}} - /> - </label> - </Checkbox> - </div> - <DeferredSpinner - loading={true} - timeout={100} - > - <VulnerabilityList - component={ - Object { - "key": "foo", - "name": "Foo", - "qualifier": "TRK", - } - } - findings={Array []} - showCWE={true} - type="owaspTop10" - /> - </DeferredSpinner> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap b/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap deleted file mode 100644 index 2f6c25221bb..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/components/__tests__/__snapshots__/VulnerabilityList-test.tsx.snap +++ /dev/null @@ -1,1264 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders 1`] = ` -<div - className="boxed-group boxed-group-inner spacer-top" -> - <table - className="data zebra security-reports" - > - <thead> - <tr> - <th - className="security-category-column" - > - security_reports.list.categories - </th> - <th - className="security-result-column text-right" - > - <div - className="display-inline-flex-center" - > - <VulnerabilityIcon - className="spacer-right" - /> - security_reports.list.vulnerabilities - </div> - </th> - <th - className="text-right security-column-separator" - colSpan={3} - > - <div - className="display-inline-flex-center" - > - <SecurityHotspotIcon - className="spacer-right" - /> - security_reports.list.security_hotspots - </div> - </th> - </tr> - <tr - className="subheader" - > - <th - colSpan={2} - /> - <th - className="text-right security-result-column security-column-separator" - > - security_reports.line.open - </th> - <th - className="text-right security-result-column" - > - security_reports.line.in_review - </th> - <th - className="text-right security-result-column" - > - security_reports.line.wont_fix - </th> - </tr> - </thead> - <tbody> - <tr> - <td - className="" - > - A1 - a1 title - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 2 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.E" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={5} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - <tr> - <td - className="" - > - Not OWAPS - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 3 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.C" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={3} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 100 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 8 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolutions": "WONTFIX", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - </tr> - <tr> - <td - className="" - > - A2 - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 2 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.E" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={5} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - <tr> - <td - className="" - > - A3 - <HelpTooltip - className="spacer-left" - overlay={ - <React.Fragment> - <p> - security_reports.activate_rules - </p> - <hr - className="spacer-top spacer-bottom" - /> - <Link - className="spacer-left link-no-underline" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/coding_rules", - "query": Object { - "languages": "", - "tags": "owasp-a3", - "types": "SECURITY_HOTSPOT,VULNERABILITY", - }, - } - } - > - security_reports.activate_rules.link - </Link> - </React.Fragment> - } - > - <PlusCircleIcon - className="vertical-middle" - fill="#4b9fd5" - size={12} - /> - </HelpTooltip> - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - - - </div> - </td> - <td - className="text-right security-column-separator" - > - - - </td> - <td - className="text-right" - > - - - </td> - <td - className="text-right" - > - - - </td> - </tr> - </tbody> - </table> -</div> -`; - -exports[`renders with cwe 1`] = ` -<div - className="boxed-group boxed-group-inner spacer-top" -> - <table - className="data zebra security-reports" - > - <thead> - <tr> - <th - className="security-category-column" - > - security_reports.list.categories - </th> - <th - className="security-result-column text-right" - > - <div - className="display-inline-flex-center" - > - <VulnerabilityIcon - className="spacer-right" - /> - security_reports.list.vulnerabilities - </div> - </th> - <th - className="text-right security-column-separator" - colSpan={3} - > - <div - className="display-inline-flex-center" - > - <SecurityHotspotIcon - className="spacer-right" - /> - security_reports.list.security_hotspots - </div> - </th> - </tr> - <tr - className="subheader" - > - <th - colSpan={2} - /> - <th - className="text-right security-result-column security-column-separator" - > - security_reports.line.open - </th> - <th - className="text-right security-result-column" - > - security_reports.line.in_review - </th> - <th - className="text-right security-result-column" - > - security_reports.line.wont_fix - </th> - </tr> - </thead> - <tbody> - <tr> - <td - className="" - > - A1 - a1 title - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 2 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.E" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={5} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a1", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - <tr> - <td - className="cwe-title-cell" - > - CWE-42 - cwe-42 title - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 1 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.A" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={1} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a1", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a1", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - <tr> - <td - className="" - > - Not OWAPS - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 3 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.C" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={3} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 100 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 8 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "unknown", - "resolutions": "WONTFIX", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - </tr> - <tr> - <td - className="" - > - A2 - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 2 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.E" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={5} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "id": "foo", - "owaspTop10": "a2", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - <tr> - <td - className="cwe-title-cell" - > - CWE-42 - cwe-42 title - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 1 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.A" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={1} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a2", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a2", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - <tr> - <td - className="" - > - A3 - <HelpTooltip - className="spacer-left" - overlay={ - <React.Fragment> - <p> - security_reports.activate_rules - </p> - <hr - className="spacer-top spacer-bottom" - /> - <Link - className="spacer-left link-no-underline" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/coding_rules", - "query": Object { - "languages": "", - "tags": "owasp-a3", - "types": "SECURITY_HOTSPOT,VULNERABILITY", - }, - } - } - > - security_reports.activate_rules.link - </Link> - </React.Fragment> - } - > - <PlusCircleIcon - className="vertical-middle" - fill="#4b9fd5" - size={12} - /> - </HelpTooltip> - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - - - </div> - </td> - <td - className="text-right security-column-separator" - > - - - </td> - <td - className="text-right" - > - - - </td> - <td - className="text-right" - > - - - </td> - </tr> - <tr> - <td - className="cwe-title-cell" - > - CWE-42 - cwe-42 title - </td> - <td - className="text-right" - > - <div - className="display-inline-flex-center" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a3", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - 1 - </Link> - <Tooltip - overlay="metric.security_rating.tooltip.A" - > - <Link - className="link-no-underline spacer-left" - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a3", - "resolved": "false", - "types": "VULNERABILITY", - }, - } - } - > - <Rating - value={1} - /> - </Link> - </Tooltip> - </div> - </td> - <td - className="text-right security-column-separator" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a3", - "resolved": "false", - "statuses": "OPEN,REOPENED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 10 - </Link> - </td> - <td - className="text-right" - > - <Link - onlyActiveOnIndex={false} - style={Object {}} - to={ - Object { - "pathname": "/project/issues", - "query": Object { - "cwe": "42", - "id": "foo", - "owaspTop10": "a3", - "resolutions": "FIXED", - "statuses": "RESOLVED", - "types": "SECURITY_HOTSPOT", - }, - } - } - > - 2 - </Link> - </td> - <td - className="text-right" - > - 0 - </td> - </tr> - </tbody> - </table> -</div> -`; diff --git a/server/sonar-web/src/main/js/apps/securityReports/style.css b/server/sonar-web/src/main/js/apps/securityReports/style.css deleted file mode 100644 index 254f6047285..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/style.css +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -.security-column-separator { - border-left: 1px solid var(--barBorderColor); -} - -.security-category-column { - width: 52%; -} - -.security-result-column { - width: 12%; -} - -table.data.security-reports > thead:after { - content: none; -} - -.cwe-title-cell { - padding-left: 80px !important; -} diff --git a/server/sonar-web/src/main/js/apps/securityReports/utils.ts b/server/sonar-web/src/main/js/apps/securityReports/utils.ts deleted file mode 100755 index 8d378b80b90..00000000000 --- a/server/sonar-web/src/main/js/apps/securityReports/utils.ts +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -export function renderOwaspTop10Category( - standards: T.Standards, - category: string, - withPrefix = false -): string { - const record = standards.owaspTop10[category]; - if (!record) { - return addPrefix(category.toUpperCase(), 'OWASP', withPrefix); - } else if (category === 'unknown') { - return record.title; - } else { - return addPrefix(`${category.toUpperCase()} - ${record.title}`, 'OWASP', withPrefix); - } -} - -export function renderCWECategory(standards: T.Standards, category: string): string { - const record = standards.cwe[category]; - if (!record) { - return `CWE-${category}`; - } else if (category === 'unknown') { - return record.title; - } else { - return `CWE-${category} - ${record.title}`; - } -} - -export function renderSansTop25Category( - standards: T.Standards, - category: string, - withPrefix = false -): string { - const record = standards.sansTop25[category]; - return addPrefix(record ? record.title : category, 'SANS', withPrefix); -} - -export function renderSonarSourceSecurityCategory( - standards: T.Standards, - category: string, - withPrefix = false -): string { - const record = standards.sonarsourceSecurity[category]; - return addPrefix(record ? record.title : category, 'SONAR', withPrefix); -} - -function addPrefix(title: string, prefix: string, withPrefix: boolean) { - return withPrefix ? `${prefix} ${title}` : title; -} - -const TYPES_MAP: T.Dict<T.StandardType> = { - owasp_top_10: 'owaspTop10', - sans_top_25: 'sansTop25', - sonarsource_security: 'sonarsourceSecurity' -}; - -export function getType(type: string): T.StandardType { - return TYPES_MAP[type] || 'sonarsourceSecurity'; -} diff --git a/server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts new file mode 100644 index 00000000000..18d5e62ba4f --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/__tests__/security-standard-test.ts @@ -0,0 +1,123 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { + renderCWECategory, + renderOwaspTop10Category, + renderSansTop25Category, + renderSonarSourceSecurityCategory +} from '../security-standard'; + +describe('renderCWECategory', () => { + const standards: T.Standards = { + cwe: { + '1004': { + title: "Sensitive Cookie Without 'HttpOnly' Flag" + }, + unknown: { + title: 'No CWE associated' + } + }, + owaspTop10: {}, + sansTop25: {}, + sonarsourceSecurity: {} + }; + it('should render categories correctly', () => { + expect(renderCWECategory(standards, '1004')).toEqual( + "CWE-1004 - Sensitive Cookie Without 'HttpOnly' Flag" + ); + expect(renderCWECategory(standards, '124')).toEqual('CWE-124'); + expect(renderCWECategory(standards, 'unknown')).toEqual('No CWE associated'); + }); +}); + +describe('renderOwaspTop10Category', () => { + const standards: T.Standards = { + cwe: {}, + owaspTop10: { + a1: { + title: 'Injection' + }, + unknown: { + title: 'Not OWASP' + } + }, + sansTop25: {}, + sonarsourceSecurity: {} + }; + it('should render categories correctly', () => { + expect(renderOwaspTop10Category(standards, 'a1')).toEqual('A1 - Injection'); + expect(renderOwaspTop10Category(standards, 'a1', true)).toEqual('OWASP A1 - Injection'); + expect(renderOwaspTop10Category(standards, 'a2')).toEqual('A2'); + expect(renderOwaspTop10Category(standards, 'a2', true)).toEqual('OWASP A2'); + expect(renderOwaspTop10Category(standards, 'unknown')).toEqual('Not OWASP'); + expect(renderOwaspTop10Category(standards, 'unknown', true)).toEqual('Not OWASP'); + }); +}); + +describe('renderSansTop25Category', () => { + const standards: T.Standards = { + cwe: {}, + owaspTop10: {}, + sansTop25: { + 'insecure-interaction': { + title: 'Insecure Interaction Between Components' + } + }, + sonarsourceSecurity: {} + }; + it('should render categories correctly', () => { + expect(renderSansTop25Category(standards, 'insecure-interaction')).toEqual( + 'Insecure Interaction Between Components' + ); + expect(renderSansTop25Category(standards, 'insecure-interaction', true)).toEqual( + 'SANS Insecure Interaction Between Components' + ); + expect(renderSansTop25Category(standards, 'unknown')).toEqual('unknown'); + expect(renderSansTop25Category(standards, 'unknown', true)).toEqual('SANS unknown'); + }); +}); + +describe('renderSonarSourceSecurityCategory', () => { + const standards: T.Standards = { + cwe: {}, + owaspTop10: {}, + sansTop25: {}, + sonarsourceSecurity: { + xss: { + title: 'Cross-Site Scripting (XSS)' + }, + others: { + title: 'Others' + } + } + }; + it('should render categories correctly', () => { + expect(renderSonarSourceSecurityCategory(standards, 'xss')).toEqual( + 'Cross-Site Scripting (XSS)' + ); + expect(renderSonarSourceSecurityCategory(standards, 'xss', true)).toEqual( + 'SONAR Cross-Site Scripting (XSS)' + ); + expect(renderSonarSourceSecurityCategory(standards, 'unknown')).toEqual('unknown'); + expect(renderSonarSourceSecurityCategory(standards, 'unknown', true)).toEqual('SONAR unknown'); + expect(renderSonarSourceSecurityCategory(standards, 'others')).toEqual('Others'); + expect(renderSonarSourceSecurityCategory(standards, 'others', true)).toEqual('Others'); + }); +}); diff --git a/server/sonar-web/src/main/js/helpers/security-standard.ts b/server/sonar-web/src/main/js/helpers/security-standard.ts index 685c6ef4033..cc44d1b2226 100644 --- a/server/sonar-web/src/main/js/helpers/security-standard.ts +++ b/server/sonar-web/src/main/js/helpers/security-standard.ts @@ -20,3 +20,55 @@ export function getStandards(): Promise<T.Standards> { return import('./standards.json').then(x => x.default); } + +export function renderCWECategory(standards: T.Standards, category: string): string { + const record = standards.cwe[category]; + if (!record) { + return `CWE-${category}`; + } else if (category === 'unknown') { + return record.title; + } else { + return `CWE-${category} - ${record.title}`; + } +} + +export function renderOwaspTop10Category( + standards: T.Standards, + category: string, + withPrefix = false +): string { + const record = standards.owaspTop10[category]; + if (!record) { + return addPrefix(category.toUpperCase(), 'OWASP', withPrefix); + } else if (category === 'unknown') { + return record.title; + } else { + return addPrefix(`${category.toUpperCase()} - ${record.title}`, 'OWASP', withPrefix); + } +} + +export function renderSansTop25Category( + standards: T.Standards, + category: string, + withPrefix = false +): string { + const record = standards.sansTop25[category]; + return addPrefix(record ? record.title : category, 'SANS', withPrefix); +} + +export function renderSonarSourceSecurityCategory( + standards: T.Standards, + category: string, + withPrefix = false +): string { + const record = standards.sonarsourceSecurity[category]; + if (category === 'others') { + return record.title; + } else { + return addPrefix(record ? record.title : category, 'SONAR', withPrefix); + } +} + +function addPrefix(title: string, prefix: string, withPrefix: boolean) { + return withPrefix ? `${prefix} ${title}` : title; +} |