Skip to content

Commit c296d5a

Browse files
authored
Merge pull request #1029 from devtron-labs/feat/dockerfile-hadolint-scan
feat: Dockerfile hadolint scan
2 parents f4e4b71 + 522e648 commit c296d5a

18 files changed

Lines changed: 219 additions & 191 deletions

File tree

package-lock.json

Lines changed: 2 additions & 122 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "1.23.4-pre-1",
3+
"version": "1.23.4-pre-2",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",
Lines changed: 12 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading

src/Assets/IconV2/ic-hadolint.svg

Lines changed: 14 additions & 0 deletions
Loading

src/Common/CIPipeline.Types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ export interface FormType {
275275
webhookConditionList: { selectorId: number; value: string }[]
276276
triggerType: string
277277
scanEnabled?: boolean
278+
dockerfileScanEnabled?: boolean
278279
beforeDockerBuildScripts?: {
279280
id: number
280281
name: string

src/Common/Constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ export const ROUTES = {
7979
DEPLOYMENT_TEMPLATE_LIST: 'app/template/list',
8080
INFRA_CONFIG_PROFILE: 'infra-config/profile',
8181
SCAN_RESULT: 'scan-result',
82+
SCAN_RESULT_RECOMMENDATIONS: 'security/scan/dockerfile/results',
8283
NOTIFIER: 'notification',
8384
TELEMETRY_EVENT: 'telemetry/event',
8485
SERVER_INFO_API: 'server',

src/Shared/Components/Icon/Icon.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import ICBgBuild from '@IconsV2/ic-bg-build.svg?react'
3939
import ICBgCluster from '@IconsV2/ic-bg-cluster.svg?react'
4040
import ICBgCpu from '@IconsV2/ic-bg-cpu.svg?react'
4141
import ICBgDeploy from '@IconsV2/ic-bg-deploy.svg?react'
42+
import ICBgDockerScanner from '@IconsV2/ic-bg-docker-scanner.svg?react'
4243
import ICBgEnvironment from '@IconsV2/ic-bg-environment.svg?react'
4344
import ICBgMemory from '@IconsV2/ic-bg-memory.svg?react'
4445
import ICBgPauseSchedule from '@IconsV2/ic-bg-pause-schedule.svg?react'
@@ -91,6 +92,7 @@ import ICCloudVms from '@IconsV2/ic-cloud-vms.svg?react'
9192
import ICCluster from '@IconsV2/ic-cluster.svg?react'
9293
import ICClusterIsolated from '@IconsV2/ic-cluster-isolated.svg?react'
9394
import ICCode from '@IconsV2/ic-code.svg?react'
95+
import ICCodeWrapped from '@IconsV2/ic-code-wrapped.svg?react'
9496
import ICCoins from '@IconsV2/ic-coins.svg?react'
9597
import ICCoinsColorAnimated from '@IconsV2/ic-coins-color-animated.svg?react'
9698
import ICComment from '@IconsV2/ic-comment.svg?react'
@@ -175,6 +177,7 @@ import ICGoogleGke from '@IconsV2/ic-google-gke.svg?react'
175177
import ICGridView from '@IconsV2/ic-grid-view.svg?react'
176178
import ICGroupFilter from '@IconsV2/ic-group-filter.svg?react'
177179
import ICGroupFilterApplied from '@IconsV2/ic-group-filter-applied.svg?react'
180+
import ICHadolint from '@IconsV2/ic-hadolint.svg?react'
178181
import ICHandPointing from '@IconsV2/ic-hand-pointing.svg?react'
179182
import ICHeartGreen from '@IconsV2/ic-heart-green.svg?react'
180183
import ICHeartRed from '@IconsV2/ic-heart-red.svg?react'
@@ -380,6 +383,7 @@ export const iconMap = {
380383
'ic-bg-cluster': ICBgCluster,
381384
'ic-bg-cpu': ICBgCpu,
382385
'ic-bg-deploy': ICBgDeploy,
386+
'ic-bg-docker-scanner': ICBgDockerScanner,
383387
'ic-bg-environment': ICBgEnvironment,
384388
'ic-bg-memory': ICBgMemory,
385389
'ic-bg-pause-schedule': ICBgPauseSchedule,
@@ -431,6 +435,7 @@ export const iconMap = {
431435
'ic-cloud-vms': ICCloudVms,
432436
'ic-cluster-isolated': ICClusterIsolated,
433437
'ic-cluster': ICCluster,
438+
'ic-code-wrapped': ICCodeWrapped,
434439
'ic-code': ICCode,
435440
'ic-coins-color-animated': ICCoinsColorAnimated,
436441
'ic-coins': ICCoins,
@@ -516,6 +521,7 @@ export const iconMap = {
516521
'ic-grid-view': ICGridView,
517522
'ic-group-filter-applied': ICGroupFilterApplied,
518523
'ic-group-filter': ICGroupFilter,
524+
'ic-hadolint': ICHadolint,
519525
'ic-hand-pointing': ICHandPointing,
520526
'ic-heart-green': ICHeartGreen,
521527
'ic-heart-red-animated': ICHeartRedAnimated,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Icon } from '@Shared/Components/Icon'
2+
3+
import { ReportTabEmptyStateProps } from './types'
4+
5+
export const ReportTabEmptyState = ({ title, subtitle, icon = 'ic-warning' }: ReportTabEmptyStateProps) => (
6+
<div className="flex dc__border br-8 fs-13 mw-600 dc__mxw-1000">
7+
<div className="flexbox-col dc__gap-12 dc__align-items-center p-20 w-300">
8+
<Icon name={icon} size={24} color="R500" />
9+
<div className="flex column dc__gap-4 dc__align-center">
10+
<div className="flex fw-6 cn-9 lh-20">{title}</div>
11+
<div className="flex cn-8">{subtitle}</div>
12+
</div>
13+
</div>
14+
</div>
15+
)

src/Shared/Components/Security/SecurityDetailsCards/SecurityDetailsCards.tsx

Lines changed: 86 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { DEFAULT_SECURITY_MODAL_IMAGE_STATE } from '../SecurityModal/constants'
2727
import { CATEGORIES, SecurityModalStateType, SUB_CATEGORIES } from '../SecurityModal/types'
2828
import { ScanCategories, ScanSubCategories } from '../types'
2929
import { getCompiledSecurityThreats, getSecurityConfig, getStatusForScanList, getTotalSeverities } from '../utils'
30+
import { ReportTabEmptyState } from './ReportTabEmptyState'
3031
import SecurityCard from './SecurityCard'
3132
import { SecurityCardProps, SecurityDetailsCardsProps } from './types'
3233

@@ -40,22 +41,6 @@ const SecurityDetailsCards = ({ scanResult, Sidebar }: SecurityDetailsCardsProps
4041
const scanThreats = getCompiledSecurityThreats(scanResult)
4142
const threatCount = getTotalSeverities(scanThreats)
4243

43-
if (!threatCount) {
44-
return (
45-
<GenericEmptyState
46-
SvgImage={NoVulnerability}
47-
title={EMPTY_STATE_STATUS.CI_DEATILS_NO_VULNERABILITY_FOUND.TITLE}
48-
subTitle={EMPTY_STATE_STATUS.CI_DEATILS_NO_VULNERABILITY_FOUND.SUBTITLE}
49-
/>
50-
)
51-
}
52-
53-
const SECURITY_CONFIG = getSecurityConfig({
54-
imageScan: !!imageScan,
55-
codeScan: !!codeScan,
56-
kubernetesManifest: !!kubernetesManifest,
57-
})
58-
5944
const getScanToolInfo = (category: string): { scanToolName: string; scanToolUrl: string } => {
6045
const image = imageScan?.vulnerability?.list?.[0]
6146
switch (category) {
@@ -71,6 +56,49 @@ const SecurityDetailsCards = ({ scanResult, Sidebar }: SecurityDetailsCardsProps
7156
}
7257
}
7358

59+
const renderScannedToolModal = (category: ScanCategories) => {
60+
const { scanToolName, scanToolUrl } = getScanToolInfo(category)
61+
return <ScannedByToolModal scanToolName={scanToolName} scanToolUrl={scanToolUrl} />
62+
}
63+
64+
const renderHeader = (category?: ScanCategories) => (
65+
<div className="flexbox dc__content-space pb-8 dc__border-bottom-n1">
66+
<span className="fs-13 fw-6 lh-1-5 cn-9">Security Scan</span>
67+
{category && renderScannedToolModal(category)}
68+
</div>
69+
)
70+
71+
if (!scanResult?.scanned) {
72+
return (
73+
<div className="flexbox-col dc__gap-16 mw-600 dc__mxw-1000">
74+
<ReportTabEmptyState
75+
title={EMPTY_STATE_STATUS.CI_DETAILS_IMAGE_NOT_SCANNED.TITLE}
76+
subtitle={EMPTY_STATE_STATUS.CI_DETAILS_IMAGE_NOT_SCANNED.SUBTITLE}
77+
/>
78+
</div>
79+
)
80+
}
81+
82+
if (!threatCount) {
83+
return (
84+
<div className="flexbox-col dc__gap-16 mw-600 dc__mxw-1000">
85+
<div className="flexbox-col en-2 bw-1 br-8 dc__gap-16 cn-9 p-16">
86+
<GenericEmptyState
87+
SvgImage={NoVulnerability}
88+
title={EMPTY_STATE_STATUS.CI_DEATILS_NO_VULNERABILITY_FOUND.TITLE}
89+
subTitle={EMPTY_STATE_STATUS.CI_DEATILS_NO_VULNERABILITY_FOUND.SUBTITLE}
90+
/>
91+
</div>
92+
</div>
93+
)
94+
}
95+
96+
const SECURITY_CONFIG = getSecurityConfig({
97+
imageScan: !!imageScan,
98+
codeScan: !!codeScan,
99+
kubernetesManifest: !!kubernetesManifest,
100+
})
101+
74102
const handleOpenModal = (
75103
category: SecurityCardProps['category'],
76104
subCategory: SecurityCardProps['subCategory'],
@@ -91,64 +119,57 @@ const SecurityDetailsCards = ({ scanResult, Sidebar }: SecurityDetailsCardsProps
91119
setShowSecurityModal(false)
92120
}
93121

122+
const renderSecurityCards = ({ category, categoryFailed }) =>
123+
categoryFailed ? (
124+
<div className="dc__border br-8">
125+
<GenericSectionErrorState
126+
title={category === CATEGORIES.CODE_SCAN ? 'Code scan failed' : 'Manifest scan failed'}
127+
subTitle=""
128+
description=""
129+
/>
130+
</div>
131+
) : (
132+
<div className="dc__grid security-cards">
133+
{SECURITY_CONFIG[category].subCategories.map((subCategory: ScanSubCategories) => {
134+
// Explicit handling if subcategory is null
135+
if (!scanResult[category][subCategory]) {
136+
return null
137+
}
138+
139+
const scanFailed: boolean =
140+
category === CATEGORIES.IMAGE_SCAN &&
141+
getStatusForScanList(scanResult[category][subCategory].list ?? []) === 'Failed'
142+
143+
const severities =
144+
subCategory === SUB_CATEGORIES.MISCONFIGURATIONS
145+
? scanResult[category][subCategory]?.misConfSummary?.status
146+
: scanResult[category][subCategory]?.summary?.severities
147+
148+
return (
149+
<SecurityCard
150+
category={category}
151+
subCategory={subCategory}
152+
severities={severities}
153+
handleCardClick={handleCardClick(category, subCategory)}
154+
scanFailed={scanFailed}
155+
/>
156+
)
157+
})}
158+
</div>
159+
)
160+
94161
return (
95162
<>
96-
<div className="flexbox-col dc__gap-20 mw-600 dc__mxw-1200">
163+
<div className="flexbox-col dc__gap-20">
97164
{Object.keys(SECURITY_CONFIG).map((category: ScanCategories) => {
98165
const categoryFailed: boolean =
99166
category !== CATEGORIES.IMAGE_SCAN &&
100167
(scanResult.codeScan?.status === 'Failed' || scanResult.kubernetesManifest?.status === 'Failed')
101168

102-
const { scanToolName, scanToolUrl } = getScanToolInfo(category)
103-
104169
return (
105170
<div className="flexbox-col dc__gap-12" key={category}>
106-
<div className="flexbox dc__content-space pb-8 dc__border-bottom-n1">
107-
<span className="fs-13 fw-6 lh-1-5 cn-9">{SECURITY_CONFIG[category].label}</span>
108-
<ScannedByToolModal scanToolName={scanToolName} scanToolUrl={scanToolUrl} />
109-
</div>
110-
{categoryFailed ? (
111-
<div className="dc__border br-8">
112-
<GenericSectionErrorState
113-
title={
114-
category === CATEGORIES.CODE_SCAN
115-
? 'Code scan failed'
116-
: 'Manifest scan failed'
117-
}
118-
subTitle=""
119-
description=""
120-
/>
121-
</div>
122-
) : (
123-
<div className="dc__grid security-cards">
124-
{SECURITY_CONFIG[category].subCategories.map((subCategory: ScanSubCategories) => {
125-
// Explicit handling if subcategory is null
126-
if (!scanResult[category][subCategory]) {
127-
return null
128-
}
129-
130-
const scanFailed: boolean =
131-
category === CATEGORIES.IMAGE_SCAN &&
132-
getStatusForScanList(scanResult[category][subCategory].list ?? []) ===
133-
'Failed'
134-
135-
const severities =
136-
subCategory === SUB_CATEGORIES.MISCONFIGURATIONS
137-
? scanResult[category][subCategory]?.misConfSummary?.status
138-
: scanResult[category][subCategory]?.summary?.severities
139-
140-
return (
141-
<SecurityCard
142-
category={category}
143-
subCategory={subCategory}
144-
severities={severities}
145-
handleCardClick={handleCardClick(category, subCategory)}
146-
scanFailed={scanFailed}
147-
/>
148-
)
149-
})}
150-
</div>
151-
)}
171+
{renderHeader(category)}
172+
{renderSecurityCards({ category, categoryFailed })}
152173
</div>
153174
)
154175
})}

0 commit comments

Comments
 (0)