-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #500 from devtron-labs/feat/scanning-breakdown
feat: bifurcate image cards in imageScan codeScan and manifestScan
- Loading branch information
Showing
24 changed files
with
441 additions
and
166 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/Shared/Components/Security/SecurityDetailsCards/SecurityCard.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { SegmentedBarChart } from '@Common/SegmentedBarChart' | ||
import { ReactComponent as ICShieldWarning } from '@Icons/ic-shield-warning-outline.svg' | ||
import { ReactComponent as ICShieldSecure } from '@Icons/ic-shield-check.svg' | ||
import { ReactComponent as ICArrowRight } from '@Icons/ic-caret-down-small.svg' | ||
import { SecurityCardProps } from './types' | ||
import { SUB_CATEGORIES } from '../SecurityModal/types' | ||
import { SEVERITIES } from '../SecurityModal/constants' | ||
import './securityCard.scss' | ||
import { getTotalSeverities } from '../utils' | ||
import { SECURITY_CONFIG } from '../constants' | ||
|
||
const SecurityCard = ({ category, subCategory, severityCount = {}, handleCardClick }: SecurityCardProps) => { | ||
const totalCount = getTotalSeverities(severityCount) | ||
|
||
const hasThreats: boolean = !!totalCount | ||
|
||
const entities = Object.entries(SEVERITIES) | ||
.map(([key, severity]) => ({ | ||
...severity, | ||
value: severityCount[key], | ||
})) | ||
.filter((entity) => !!entity.value) | ||
|
||
const getTitleSubtitle = (): { title: string; subtitle?: string } => { | ||
switch (subCategory) { | ||
case SUB_CATEGORIES.EXPOSED_SECRETS: | ||
return hasThreats | ||
? { title: `${totalCount} exposed secrets` } | ||
: { | ||
title: 'No exposed secrets', | ||
subtitle: 'No exposed secrets like passwords, api keys, and tokens found', | ||
} | ||
case SUB_CATEGORIES.LICENSE: | ||
return hasThreats | ||
? { title: `${totalCount} license risks` } | ||
: { title: 'No license risks', subtitle: 'No license risks or compliance issues found' } | ||
case SUB_CATEGORIES.MISCONFIGURATIONS: | ||
return hasThreats | ||
? { title: `${totalCount} misconfigurations` } | ||
: { title: 'No misconfiguration', subtitle: 'No configuration issues detected in scanned files' } | ||
default: | ||
return hasThreats | ||
? { title: `${totalCount} vulnerabilities` } | ||
: { title: 'No vulnerabilities', subtitle: 'No vulnerabilities or potential threats found' } | ||
} | ||
} | ||
|
||
const { title, subtitle } = getTitleSubtitle() | ||
|
||
const onKeyDown = (event) => { | ||
if (event.key === 'Enter') { | ||
handleCardClick() | ||
} | ||
} | ||
|
||
return ( | ||
<div | ||
className={`w-100 bcn-0 p-20 flexbox-col dc__gap-16 br-8 dc__border security-card security-card${hasThreats ? '--threat' : '--secure'}`} | ||
role="button" | ||
tabIndex={0} | ||
onClick={handleCardClick} | ||
onKeyDown={onKeyDown} | ||
> | ||
<div className="flexbox dc__content-space"> | ||
<div className="flexbox-col"> | ||
<span className="fs-12 fw-4 lh-1-5 cn-7">{SECURITY_CONFIG[category].label}</span> | ||
<div className="fs-15 fw-6 lh-1-5 cn-9 flex"> | ||
<span className="security-card-title">{title}</span> | ||
<ICArrowRight className="icon-dim-20 dc__flip-270 scb-5 arrow-right" /> | ||
</div> | ||
</div> | ||
{hasThreats ? ( | ||
<ICShieldWarning className="icon-dim-24 scr-5 dc__no-shrink" /> | ||
) : ( | ||
<ICShieldSecure className="icon-dim-24 scg-5 dc__no-shrink" /> | ||
)} | ||
</div> | ||
<div className="flexbox-col dc__gap-12"> | ||
{hasThreats || severityCount.success ? ( | ||
<SegmentedBarChart | ||
entities={entities} | ||
labelClassName="fs-13 fw-4 lh-20 cn-9" | ||
countClassName="fs-13 fw-6 lh-20 cn-7" | ||
swapLegendAndBar | ||
/> | ||
) : ( | ||
<div className="bcn-1 br-4 h-8" /> | ||
)} | ||
{subtitle && <span className="cn-9 fs-13 lh-20">{subtitle}</span>} | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default SecurityCard |
117 changes: 117 additions & 0 deletions
117
src/Shared/Components/Security/SecurityDetailsCards/SecurityDetailsCards.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { ScannedByToolModal } from '@Shared/Components/ScannedByToolModal' | ||
import { EMPTY_STATE_STATUS, SCAN_TOOL_ID_CLAIR, SCAN_TOOL_ID_TRIVY } from '@Shared/constants' | ||
import { useState } from 'react' | ||
import { GenericEmptyState } from '@Common/index' | ||
import { ReactComponent as NoVulnerability } from '@Icons/ic-vulnerability-not-found.svg' | ||
import SecurityCard from './SecurityCard' | ||
import { CATEGORIES, SecurityModalStateType, SUB_CATEGORIES } from '../SecurityModal/types' | ||
import { SecurityCardProps, SecurityDetailsCardsProps } from './types' | ||
import { SecurityModal } from '../SecurityModal' | ||
import { DEFAULT_SECURITY_MODAL_IMAGE_STATE } from '../SecurityModal/constants' | ||
import { ScanCategories, ScanSubCategories } from '../types' | ||
import { getSecurityConfig, getCompiledSecurityThreats, getTotalSeverities } from '../utils' | ||
import './securityCard.scss' | ||
|
||
const SecurityDetailsCards = ({ scanResult, Sidebar }: SecurityDetailsCardsProps) => { | ||
const [showSecurityModal, setShowSecurityModal] = useState<boolean>(false) | ||
const [modalState, setModalState] = useState<SecurityModalStateType>(DEFAULT_SECURITY_MODAL_IMAGE_STATE) | ||
const { imageScan, codeScan, kubernetesManifest } = scanResult | ||
|
||
const scanThreats = getCompiledSecurityThreats(scanResult) | ||
const threatCount = getTotalSeverities(scanThreats) | ||
|
||
if (!threatCount) { | ||
return ( | ||
<GenericEmptyState | ||
SvgImage={NoVulnerability} | ||
title={EMPTY_STATE_STATUS.CI_DEATILS_NO_VULNERABILITY_FOUND.TITLE} | ||
subTitle={EMPTY_STATE_STATUS.CI_DEATILS_NO_VULNERABILITY_FOUND.SUBTITLE} | ||
/> | ||
) | ||
} | ||
|
||
const SECURITY_CONFIG = getSecurityConfig({ | ||
imageScan: !!imageScan, | ||
codeScan: !!codeScan, | ||
kubernetesManifest: !!kubernetesManifest, | ||
}) | ||
|
||
const getScanToolId = (category: string) => { | ||
switch (category) { | ||
case CATEGORIES.CODE_SCAN: | ||
return codeScan?.scanToolName === 'TRIVY' ? SCAN_TOOL_ID_TRIVY : SCAN_TOOL_ID_CLAIR | ||
case CATEGORIES.KUBERNETES_MANIFEST: | ||
return kubernetesManifest?.scanToolName === 'TRIVY' ? SCAN_TOOL_ID_TRIVY : SCAN_TOOL_ID_CLAIR | ||
case CATEGORIES.IMAGE_SCAN: | ||
return imageScan?.vulnerability?.list?.[0].scanToolName === 'TRIVY' | ||
? SCAN_TOOL_ID_TRIVY | ||
: SCAN_TOOL_ID_CLAIR | ||
default: | ||
return SCAN_TOOL_ID_TRIVY | ||
} | ||
} | ||
|
||
const handleOpenModal = ( | ||
category: SecurityCardProps['category'], | ||
subCategory: SecurityCardProps['subCategory'], | ||
) => { | ||
setShowSecurityModal(true) | ||
setModalState({ | ||
category, | ||
subCategory, | ||
detailViewData: null, | ||
}) | ||
} | ||
|
||
const handleCardClick = | ||
(category: SecurityCardProps['category'], subCategory: SecurityCardProps['subCategory']) => () => | ||
handleOpenModal(category, subCategory) | ||
|
||
const handleModalClose = () => { | ||
setShowSecurityModal(false) | ||
} | ||
|
||
return ( | ||
<> | ||
<div className="flexbox-col dc__gap-20 mw-600 dc__mxw-1200"> | ||
{Object.keys(SECURITY_CONFIG).map((category: ScanCategories) => ( | ||
<div className="flexbox-col dc__gap-12" key={category}> | ||
<div className="flexbox dc__content-space pb-8 dc__border-bottom-n1"> | ||
<span className="fs-13 fw-6 lh-1-5 cn-9">{SECURITY_CONFIG[category].label}</span> | ||
<ScannedByToolModal scanToolId={getScanToolId(category)} /> | ||
</div> | ||
<div className="dc__grid security-cards"> | ||
{SECURITY_CONFIG[category].subCategories.map((subCategory: ScanSubCategories) => { | ||
const severityCount = | ||
subCategory === SUB_CATEGORIES.MISCONFIGURATIONS | ||
? scanResult[category][subCategory]?.misConfSummary?.status | ||
: scanResult[category][subCategory]?.summary?.severities | ||
|
||
return ( | ||
<SecurityCard | ||
category={category} | ||
subCategory={subCategory} | ||
severityCount={severityCount} | ||
handleCardClick={handleCardClick(category, subCategory)} | ||
/> | ||
) | ||
})} | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
{showSecurityModal && ( | ||
<SecurityModal | ||
isLoading={false} | ||
error={null} | ||
responseData={scanResult} | ||
handleModalClose={handleModalClose} | ||
Sidebar={Sidebar} | ||
defaultState={modalState} | ||
/> | ||
)} | ||
</> | ||
) | ||
} | ||
|
||
export default SecurityDetailsCards |
2 changes: 2 additions & 0 deletions
2
src/Shared/Components/Security/SecurityDetailsCards/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { default as SecurityCard } from './SecurityCard' | ||
export { default as SecurityDetailsCards } from './SecurityDetailsCards' |
28 changes: 28 additions & 0 deletions
28
src/Shared/Components/Security/SecurityDetailsCards/securityCard.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
.security-card { | ||
&--threat { | ||
background: radial-gradient(25.91% 100% at 100% 0%, var(--R100) 0%, var(--N0) 100%); | ||
} | ||
&--secure { | ||
background: radial-gradient(25.91% 100% at 100% 0%, var(--G100) 0%, var(--N0) 100%); | ||
} | ||
|
||
.arrow-right { | ||
visibility: hidden; | ||
} | ||
|
||
&:hover { | ||
.arrow-right { | ||
visibility: visible; | ||
} | ||
|
||
.security-card-title { | ||
color: var(--B500); | ||
} | ||
} | ||
} | ||
|
||
.security-cards { | ||
grid-template-columns: 1fr 1fr; | ||
grid-row-gap: 12px; | ||
grid-column-gap: 12px; | ||
} |
13 changes: 13 additions & 0 deletions
13
src/Shared/Components/Security/SecurityDetailsCards/types.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { ScanResultDTO, SecurityModalPropsType, SeveritiesDTO } from '../SecurityModal/types' | ||
import { ScanCategories, ScanSubCategories } from '../types' | ||
|
||
export interface SecurityCardProps { | ||
category: ScanCategories | ||
subCategory: ScanSubCategories | ||
severityCount: Partial<Record<SeveritiesDTO, number>> | ||
handleCardClick: () => void | ||
} | ||
|
||
export interface SecurityDetailsCardsProps extends Pick<SecurityModalPropsType, 'Sidebar'> { | ||
scanResult: ScanResultDTO | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.