Skip to content

Commit b3fb1be

Browse files
authored
WorkloadStatusVulnerable (#143)
* WIP * storybook complete * vulnerability report page and support vulnerable workload error * fix lint * wat
1 parent bf01739 commit b3fb1be

28 files changed

+295
-70
lines changed

src/lib/AppErrorTypeToMessage.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135
{/if}
136136
The threshold is determined by either having more than one critical vulnerability or a combined
137137
risk score of other severities exceeding 100. Please keep your dependencies up to date. See
138-
<a href="/team/{team}/{env}/app/{app}/image">image details</a> for more details.
138+
<a href="/team/{team}/{env}/app/{app}/vulnerability-report">image details</a> for more details.
139139
</Alert>
140140
{:else if type !== 'WorkloadStatusOutboundNetwork' && type !== 'WorkloadStatusInboundNetwork'}
141141
<Alert variant="error">Unkown error</Alert>

src/lib/components/Icon.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
case 'utilization':
7171
return LineGraphStackedIcon;
7272
case 'vulnerabilities':
73+
case 'vulnerability report':
7374
return VirusIcon;
7475
case 'members':
7576
return PersonGroupIcon;

src/lib/components/Menu.stories.svelte

+4-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@
5454
{ label: 'Status', href: '/team/devteam/dev/app/app-w-all-storage/status' }
5555
],
5656
[
57-
{ label: 'Image', href: '/team/devteam/dev/app/app-w-all-storage/image' },
57+
{
58+
label: 'Vulnerability Report',
59+
href: '/team/devteam/dev/app/app-w-all-storage/vulnerability-report'
60+
},
5861
{ label: 'Deployments', href: '/team/devteam/dev/app/app-w-all-storage/deploys' },
5962
{ label: 'Cost', href: '/team/devteam/dev/app/app-w-all-storage/cost' },
6063
{

src/lib/components/WorkloadsWithSBOM.svelte

+20-8
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@
141141
});
142142
};
143143
144-
const imageUrl = (workload: {
144+
const vulnerabilityReportUrl = (workload: {
145145
readonly __typename: string | null;
146146
readonly id: string;
147147
readonly name: string;
@@ -154,7 +154,7 @@
154154
readonly slug: string;
155155
};
156156
}) => {
157-
return `/team/${workload.team.slug}/${workload.teamEnvironment.environment.name}/${workload.__typename === 'Application' ? 'app' : 'job'}/${workload.name}/image`;
157+
return `/team/${workload.team.slug}/${workload.teamEnvironment.environment.name}/${workload.__typename === 'Application' ? 'app' : 'job'}/${workload.name}/vulnerability-report`;
158158
};
159159
160160
export function severityToColorWithHover(severity: string): string {
@@ -247,7 +247,10 @@
247247
<Tooltip content="critical">
248248
{#if workload.image.vulnerabilitySummary}
249249
{#if workload.image.vulnerabilitySummary.critical > 0}
250-
<a href={imageUrl(workload)} class="vulnerability-count CRITICAL">
250+
<a
251+
href={vulnerabilityReportUrl(workload)}
252+
class="vulnerability-count CRITICAL"
253+
>
251254
{workload.image.vulnerabilitySummary
252255
? workload.image.vulnerabilitySummary.critical
253256
: '-'}
@@ -268,7 +271,7 @@
268271
<Tooltip content="high">
269272
{#if workload.image.vulnerabilitySummary}
270273
{#if workload.image.vulnerabilitySummary.high > 0}
271-
<a href={imageUrl(workload)} class="vulnerability-count HIGH">
274+
<a href={vulnerabilityReportUrl(workload)} class="vulnerability-count HIGH">
272275
{workload.image.vulnerabilitySummary
273276
? workload.image.vulnerabilitySummary.high
274277
: '-'}
@@ -289,7 +292,10 @@
289292
<Tooltip content="medium">
290293
{#if workload.image.vulnerabilitySummary}
291294
{#if workload.image.vulnerabilitySummary.medium > 0}
292-
<a href={imageUrl(workload)} class="vulnerability-count MEDIUM">
295+
<a
296+
href={vulnerabilityReportUrl(workload)}
297+
class="vulnerability-count MEDIUM"
298+
>
293299
{workload.image.vulnerabilitySummary
294300
? workload.image.vulnerabilitySummary.medium
295301
: '-'}
@@ -310,7 +316,7 @@
310316
<Tooltip content="low">
311317
{#if workload.image.vulnerabilitySummary}
312318
{#if workload.image.vulnerabilitySummary.low > 0}
313-
<a href={imageUrl(workload)} class="vulnerability-count LOW">
319+
<a href={vulnerabilityReportUrl(workload)} class="vulnerability-count LOW">
314320
{workload.image.vulnerabilitySummary
315321
? workload.image.vulnerabilitySummary.low
316322
: '-'}
@@ -331,7 +337,10 @@
331337
<Tooltip content="unassigned">
332338
{#if workload.image.vulnerabilitySummary}
333339
{#if workload.image.vulnerabilitySummary.unassigned > 0}
334-
<a href={imageUrl(workload)} class="vulnerability-count UNASSIGNED">
340+
<a
341+
href={vulnerabilityReportUrl(workload)}
342+
class="vulnerability-count UNASSIGNED"
343+
>
335344
{workload.image.vulnerabilitySummary.unassigned}
336345
</a>
337346
{:else}
@@ -349,7 +358,10 @@
349358
<div class="vulnerability-summary">
350359
<Tooltip content="risk score">
351360
<BodyShort class="vulnerability-count">
352-
<a href={imageUrl(workload)} class="vulnerability-count RISK_SCORE">
361+
<a
362+
href={vulnerabilityReportUrl(workload)}
363+
class="vulnerability-count RISK_SCORE"
364+
>
353365
{workload.image.vulnerabilitySummary
354366
? workload.image.vulnerabilitySummary.riskScore
355367
: '-'}

src/lib/components/errors/DeprecatedImageRegistry.stories.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
registry: 'docker.pkg.github.com'
1919
}}
2020
workloadType="App"
21+
teamSlug="team-service-management"
22+
workloadName="ip-lookup-preprod"
23+
environment="dev-fss"
2124
/>
2225
</Story>
2326

src/lib/components/errors/ErrorMessage.svelte

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
<script module>
2+
export const supportedErrorTypes = [
3+
'WorkloadStatusInvalidNaisYaml',
4+
'WorkloadStatusSynchronizationFailing',
5+
'WorkloadStatusDeprecatedRegistry',
6+
'WorkloadStatusNoRunningInstances',
7+
'WorkloadStatusFailedRun',
8+
'WorkloadStatusVulnerable'
9+
] as const;
10+
</script>
11+
112
<script lang="ts">
213
import { WorkloadStatusErrorLevel, type ValueOf } from '$houdini';
314
import { Alert, BodyLong, Heading } from '@nais/ds-svelte-community';
@@ -6,9 +17,15 @@
617
error,
718
workloadType,
819
instances,
20+
teamSlug,
21+
workloadName,
22+
environment,
923
docURL
1024
}: {
1125
workloadType: 'App' | 'Job';
26+
teamSlug: string;
27+
workloadName: string;
28+
environment: string;
1229
instances?: {
1330
name: string;
1431
status: { message: string };
@@ -33,6 +50,11 @@
3350
name: string;
3451
detail: string;
3552
}
53+
| {
54+
__typename: 'WorkloadStatusVulnerable';
55+
riskScore: number;
56+
critical: number;
57+
}
3658
))
3759
| { __typename: "non-exhaustive; don't match this" };
3860
docURL: (path: string) => string;
@@ -55,7 +77,8 @@
5577
WorkloadStatusSynchronizationFailing: 'Rollout Failed - Synchronization Error',
5678
WorkloadStatusDeprecatedRegistry: 'Deprecated Image Registry',
5779
WorkloadStatusNoRunningInstances: 'No Running Instances',
58-
WorkloadStatusFailedRun: 'Job Failed'
80+
WorkloadStatusFailedRun: 'Job Failed',
81+
WorkloadStatusVulnerable: 'High Risk: Vulnerabilities Detected'
5982
};
6083
</script>
6184

@@ -139,6 +162,31 @@
139162
<BodyLong>
140163
Check logs if available. If you're unable to resolve the issue, contact the Nais team.
141164
</BodyLong>
165+
{:else if error.__typename === 'WorkloadStatusVulnerable'}
166+
<BodyLong>
167+
{#if error.riskScore > 100}
168+
<strong>Risk Score:</strong>
169+
{error.riskScore} (Exceeds threshold of 100)<br />
170+
{/if}
171+
{#if error.critical > 0}
172+
<strong>Critical Vulnerabilities:</strong>
173+
{error.critical}
174+
{/if}
175+
</BodyLong>
176+
<BodyLong>
177+
Workloads are flagged as vulnerable if their dependencies have a high risk score or
178+
critical vulnerabilities.
179+
</BodyLong>
180+
<BodyLong>
181+
Review detailed vulnerability information in the <a
182+
href="/team/{teamSlug}/{environment}/{workloadType === 'Job'
183+
? 'job'
184+
: 'app'}/{workloadName}/vulnerability-report">Vulnerability Report</a
185+
>, and update affected dependencies to their latest patched versions.
186+
</BodyLong>
187+
<BodyLong>
188+
Ignoring these vulnerabilities can expose your application to potential security breaches.
189+
</BodyLong>
142190
{/if}
143191
</div>
144192
</Alert>

src/lib/components/errors/FailedRun.stories.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
detail: 'Run failed after 7 attempts'
2020
}}
2121
workloadType="Job"
22+
teamSlug="team-service-management"
23+
workloadName="aareg-sync-konkurser-q4-29028365"
24+
environment="dev-fss"
2225
/>
2326
</Story>
2427

src/lib/components/errors/InvalidManifest.stories.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
'the domain "roger.com" cannot be used in cluster "dev-gcp"; use one of dev.nav.cloud.nais.io, external.dev.nav.cloud.nais.io, authenticated.dev.nav.cloud.nais.io, .intern.dev.nav.no, .dev-gcp.nav.cloud.nais.io, .ekstern.dev.nav.no, .ansatt.dev.nav.no, .very.intern.dev.nav.no'
2020
}}
2121
workloadType="App"
22+
teamSlug="team-service-management"
23+
workloadName="ip-lookup-preprod"
24+
environment="dev-fss"
2225
/>
2326
</Story>
2427

src/lib/components/errors/NoRunningInstances.stories.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
{ name: 'bidrag-sak-675cdddb5-vpc6m', status: { message: 'ImagePullBackOff' } }
2222
]}
2323
workloadType="App"
24+
teamSlug="team-service-management"
25+
workloadName="ip-lookup-preprod"
26+
environment="dev-fss"
2427
/>
2528
</Story>
2629

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<script module>
2+
import { defineMeta } from '@storybook/addon-svelte-csf';
3+
import ErrorMessage from './ErrorMessage.svelte';
4+
import TeamErrorMessage from './TeamErrorMessage.svelte';
5+
6+
const { Story } = defineMeta({
7+
title: 'Errors/Vulnerable Image',
8+
tags: ['autodocs']
9+
});
10+
</script>
11+
12+
<Story name="Risk Score - Workload">
13+
<ErrorMessage
14+
docURL={(p) => p}
15+
error={{
16+
__typename: 'WorkloadStatusVulnerable',
17+
level: 'WARNING',
18+
riskScore: 276,
19+
critical: 0
20+
}}
21+
teamSlug="team-service-management"
22+
workloadName="ip-lookup-preprod"
23+
environment="dev-fss"
24+
workloadType="App"
25+
/>
26+
</Story>
27+
28+
<Story name="Critical - Workload">
29+
<ErrorMessage
30+
docURL={(p) => p}
31+
error={{
32+
__typename: 'WorkloadStatusVulnerable',
33+
level: 'WARNING',
34+
riskScore: 70,
35+
critical: 7
36+
}}
37+
teamSlug="team-service-management"
38+
workloadName="ip-lookup-preprod"
39+
environment="dev-fss"
40+
workloadType="App"
41+
/>
42+
</Story>
43+
44+
<Story name="Both - Workload">
45+
<ErrorMessage
46+
docURL={(p) => p}
47+
error={{
48+
__typename: 'WorkloadStatusVulnerable',
49+
level: 'WARNING',
50+
riskScore: 276,
51+
critical: 1
52+
}}
53+
teamSlug="team-service-management"
54+
workloadName="ip-lookup-preprod"
55+
environment="dev-fss"
56+
workloadType="App"
57+
/>
58+
</Story>
59+
60+
<Story name="Team - Singular">
61+
<TeamErrorMessage
62+
teamSlug="team-service-management"
63+
error={{
64+
__typename: 'WorkloadStatusVulnerable',
65+
level: 'WARNING'
66+
}}
67+
workloads={[
68+
{
69+
__typename: 'App',
70+
name: 'ip-lookup-preprod',
71+
teamEnvironment: { environment: { name: 'dev-fss' } },
72+
team: { slug: 'team-service-management' }
73+
}
74+
]}
75+
/>
76+
</Story>
77+
78+
<Story name="Team - Multiple">
79+
<TeamErrorMessage
80+
teamSlug="team-service-management"
81+
error={{
82+
__typename: 'WorkloadStatusVulnerable',
83+
level: 'WARNING'
84+
}}
85+
workloads={[
86+
{
87+
__typename: 'App',
88+
name: 'ip-lookup-preprod',
89+
teamEnvironment: { environment: { name: 'dev-fss' } },
90+
team: { slug: 'team-service-management' }
91+
},
92+
{
93+
__typename: 'App',
94+
name: 'tsm-dustin-integration-preprod',
95+
teamEnvironment: { environment: { name: 'prod-fss' } },
96+
team: { slug: 'team-service-management' }
97+
},
98+
{
99+
__typename: 'App',
100+
name: 'tsm-dustin-integration-preprod',
101+
teamEnvironment: { environment: { name: 'prod-fss' } },
102+
team: { slug: 'team-service-management' }
103+
}
104+
]}
105+
/>
106+
</Story>

src/lib/components/errors/SynchronizationError.stories.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
'persisting SQLInstance to Kubernetes: validation error: refusing to overwrite manually edited resource; please add the correct ownerReference in order to continue'
2020
}}
2121
workloadType="Job"
22+
teamSlug="team-service-management"
23+
workloadName="ip-lookup-preprod"
24+
environment="dev-fss"
2225
/>
2326
</Story>
2427

0 commit comments

Comments
 (0)