From c3f339be4e2b03a466d648c58fda51ce0eec406c Mon Sep 17 00:00:00 2001 From: Mathieu Suen Date: Tue, 31 May 2022 12:08:43 +0200 Subject: [PATCH] SONAR-16376 Update Hotspot page to consume descriptions from the rule api --- .../components/HotspotViewer.tsx | 42 ++++++++++++++----- .../__tests__/HotspotViewer-test.tsx | 40 +++++++++++++++++- .../__snapshots__/HotspotViewer-test.tsx.snap | 5 +++ 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx index 14c648765fd..fc275159d78 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.tsx @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { getRuleDetails } from '../../../api/rules'; import { getSecurityHotspotDetails } from '../../../api/security-hotspots'; import { scrollToElement } from '../../../helpers/scrolling'; import { @@ -25,7 +26,7 @@ import { HotspotStatusFilter, HotspotStatusOption } from '../../../types/security-hotspots'; -import { Component } from '../../../types/types'; +import { Component, RuleDescriptionSections } from '../../../types/types'; import { getStatusFilterFromStatusOption } from '../utils'; import HotspotViewerRenderer from './HotspotViewerRenderer'; @@ -74,16 +75,37 @@ export default class HotspotViewer extends React.PureComponent { this.mounted = false; } - fetchHotspot = () => { + fetchHotspot = async () => { this.setState({ loading: true }); - return getSecurityHotspotDetails(this.props.hotspotKey) - .then(hotspot => { - if (this.mounted) { - this.setState({ hotspot, loading: false }); - } - return hotspot; - }) - .catch(() => this.mounted && this.setState({ loading: false })); + try { + const hotspot = await getSecurityHotspotDetails(this.props.hotspotKey); + const ruleDetails = await getRuleDetails({ key: hotspot.rule.key }).then(r => r.rule); + + if (this.mounted) { + hotspot.rule.riskDescription = + ruleDetails.descriptionSections?.find(section => + [RuleDescriptionSections.DEFAULT, RuleDescriptionSections.ROOT_CAUSE].includes( + section.key + ) + )?.content || hotspot.rule.riskDescription; + + hotspot.rule.fixRecommendations = + ruleDetails.descriptionSections?.find( + section => RuleDescriptionSections.HOW_TO_FIX === section.key + )?.content || hotspot.rule.fixRecommendations; + + hotspot.rule.vulnerabilityDescription = + ruleDetails.descriptionSections?.find( + section => RuleDescriptionSections.ASSESS_THE_PROBLEM === section.key + )?.content || hotspot.rule.vulnerabilityDescription; + + this.setState({ hotspot, loading: false }); + } + } catch (error) { + if (this.mounted) { + this.setState({ loading: false }); + } + } }; handleHotspotUpdate = async (statusUpdate = false, statusOption?: HotspotStatusOption) => { diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx index 264e81a5812..1ed1336d462 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/HotspotViewer-test.tsx @@ -20,18 +20,27 @@ import { shallow } from 'enzyme'; import { clone } from 'lodash'; import * as React from 'react'; +import { getRuleDetails } from '../../../../api/rules'; import { getSecurityHotspotDetails } from '../../../../api/security-hotspots'; import { mockComponent } from '../../../../helpers/mocks/component'; import { scrollToElement } from '../../../../helpers/scrolling'; +import { mockRuleDetails } from '../../../../helpers/testMocks'; import { waitAndUpdate } from '../../../../helpers/testUtils'; import { HotspotStatusOption } from '../../../../types/security-hotspots'; +import { RuleDescriptionSections } from '../../../../types/types'; import HotspotViewer from '../HotspotViewer'; import HotspotViewerRenderer from '../HotspotViewerRenderer'; const hotspotKey = 'hotspot-key'; jest.mock('../../../../api/security-hotspots', () => ({ - getSecurityHotspotDetails: jest.fn().mockResolvedValue({ id: `I am a detailled hotspot` }) + getSecurityHotspotDetails: jest + .fn() + .mockResolvedValue({ id: `I am a detailled hotspot`, rule: {} }) +})); + +jest.mock('../../../../api/rules', () => ({ + getRuleDetails: jest.fn().mockResolvedValue({ rule: { descriptionSections: [] } }) })); jest.mock('../../../../helpers/scrolling', () => ({ @@ -54,6 +63,35 @@ it('should render correctly', async () => { expect(getSecurityHotspotDetails).toHaveBeenCalledWith(newHotspotKey); }); +it('should render fetch rule details', async () => { + (getRuleDetails as jest.Mock).mockResolvedValueOnce({ + rule: mockRuleDetails({ + descriptionSections: [ + { + key: RuleDescriptionSections.ASSESS_THE_PROBLEM, + content: 'assess' + }, + { + key: RuleDescriptionSections.ROOT_CAUSE, + content: 'cause' + }, + { + key: RuleDescriptionSections.HOW_TO_FIX, + content: 'how' + } + ] + }) + }); + const wrapper = shallowRender(); + await waitAndUpdate(wrapper); + + expect(wrapper.state().hotspot?.rule).toStrictEqual({ + fixRecommendations: 'how', + riskDescription: 'cause', + vulnerabilityDescription: 'assess' + }); +}); + it('should refresh hotspot list on status update', () => { const onUpdateHotspot = jest.fn(); const wrapper = shallowRender({ onUpdateHotspot }); diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap index 0e615b87137..5b3e0ef3cc4 100644 --- a/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/security-hotspots/components/__tests__/__snapshots__/HotspotViewer-test.tsx.snap @@ -71,6 +71,11 @@ exports[`should render correctly 2`] = ` hotspot={ Object { "id": "I am a detailled hotspot", + "rule": Object { + "fixRecommendations": undefined, + "riskDescription": undefined, + "vulnerabilityDescription": undefined, + }, } } loading={false} -- 2.39.5