Skip to content

Commit 7fd6656

Browse files
rbjornstadandnorda
andcommitted
feat: add vulnerability summary and SBOM support to image queries and components
Co-authored-by: Andreas Nordahl <[email protected]>
1 parent 88d8c7b commit 7fd6656

File tree

12 files changed

+242
-333
lines changed

12 files changed

+242
-333
lines changed

src/lib/components/Image.svelte

-93
This file was deleted.

src/lib/components/WorkloadVulnerabilitySummary.svelte

+17-30
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
<script lang="ts">
22
import { docURL } from '$lib/doc';
3-
import SuccessIcon from '$lib/icons/SuccessIcon.svelte';
43
import WarningIcon from '$lib/icons/WarningIcon.svelte';
5-
import { BodyShort, Heading, Link } from '@nais/ds-svelte-community';
4+
import { BodyShort, Link } from '@nais/ds-svelte-community';
65
import VulnerabilityBadges from './VulnerabilityBadges.svelte';
76
87
interface Props {
8+
showReportLink?: boolean;
99
workload: {
10-
__typename: string;
10+
__typename: string | null;
1111
name: string;
1212
team: {
1313
slug: string;
1414
};
15-
teamEnvironmnet: {
15+
teamEnvironment: {
1616
environment: {
1717
name: string;
1818
};
@@ -26,48 +26,35 @@
2626
low: number;
2727
unassigned: number;
2828
riskScore: number;
29-
};
29+
} | null;
3030
};
3131
};
3232
}
3333
34-
const { workload }: Props = $props();
34+
const { workload, showReportLink = true }: Props = $props();
3535
3636
const { image } = workload;
3737
3838
const imageDetailsUrl = $derived(
39-
`/team/${workload.team.slug}/${workload.teamEnvironmnet.environment.name}/${workload.__typename === 'Application' ? 'app' : 'job'}/${workload.name}/vulnerability-report`
40-
);
41-
42-
const categories = ['critical', 'high', 'medium', 'low', 'unassigned'] as const;
43-
const hasFindings = categories.some(
44-
(severity) => (image.vulnerabilitySummary?.[severity] ?? 0) > 0
39+
`/team/${workload.team.slug}/${workload.teamEnvironment.environment.name}/${workload.__typename === 'Application' ? 'app' : 'job'}/${workload.name}/vulnerability-report`
4540
);
4641
</script>
4742

4843
<div class="wrapper">
49-
<Heading level="3" size="small">Vulnerabilities</Heading>
50-
51-
{#if !image.hasSBOM && image.vulnerabilitySummary !== null}
52-
<BodyShort>
53-
<WarningIcon class="text-aligned-icon" /> Data was discovered, but the SBOM was not rendered. Refer
54-
to the <Link href={docURL('/services/vulnerabilities/')}>Nais documentation</Link> for further
55-
assistance.
56-
</BodyShort>
57-
{:else if image.vulnerabilitySummary === null}
58-
<BodyShort>
59-
<WarningIcon class="text-aligned-icon" /> No data found.
60-
<a href={docURL('/services/vulnerabilities/how-to/sbom/')} target="_blank">How to fix</a>
61-
</BodyShort>
62-
{:else if image.hasSBOM && image.vulnerabilitySummary && hasFindings}
44+
{#if image.hasSBOM && image.vulnerabilitySummary}
6345
<VulnerabilityBadges summary={image.vulnerabilitySummary} />
64-
{:else if image.hasSBOM}
46+
{#if showReportLink}
47+
<Link href={imageDetailsUrl}>View vulnerability report</Link>
48+
{/if}
49+
{:else}
6550
<BodyShort>
66-
<SuccessIcon class="text-aligned-icon" /> No vulnerabilities found. Good work!
51+
<WarningIcon class="text-aligned-icon" /> No vulnerability data available. Learn how to generate
52+
SBOMs and attestations for your workloads in the
53+
<a href={docURL('/services/vulnerabilities/how-to/sbom/')} target="_blank"
54+
>Nais documentation
55+
</a>.
6756
</BodyShort>
6857
{/if}
69-
70-
<Link href={imageDetailsUrl}>View vulnerability report</Link>
7158
</div>
7259

7360
<style>

src/lib/utils/image.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
export const parseImage = (image: string) => {
1+
export const parseImage = (image?: string) => {
2+
if (!image) {
3+
return {};
4+
}
25
const tag = image.split(':')[1];
36
const name = image.split(':')[0].split('/').pop();
47
const registry = image.split('/')[0];

src/routes/dataproduct/image/+page.gql

+6
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ query AllImages {
1515
name
1616
}
1717
}
18+
image {
19+
hasSBOM
20+
vulnerabilitySummary {
21+
riskScore
22+
}
23+
}
1824

1925
status {
2026
errors {

src/routes/team/[team]/[env]/app/[app]/+page.gql

+9-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ query App($app: String!, $team: Slug!, $env: String!) {
99
slug
1010
}
1111
image {
12-
tag
12+
hasSBOM
13+
vulnerabilitySummary {
14+
critical
15+
high
16+
medium
17+
low
18+
unassigned
19+
riskScore
20+
}
1321
}
1422
teamEnvironment {
1523
environment {
@@ -63,7 +71,6 @@ query App($app: String!, $team: Slug!, $env: String!) {
6371
...AppInstances
6472
...Persistence
6573
...WorkloadDeploy
66-
...WorkloadImage
6774
...NetworkPolicy
6875
...Manifest
6976
...Ingresses

src/routes/team/[team]/[env]/app/[app]/+page.svelte

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
import AggregatedCostForWorkload from '$lib/components/AggregatedCostForWorkload.svelte';
66
import Confirm from '$lib/components/Confirm.svelte';
77
import ErrorMessage, { supportedErrorTypes } from '$lib/components/errors/ErrorMessage.svelte';
8-
import Image from '$lib/components/Image.svelte';
98
import NetworkPolicy from '$lib/components/NetworkPolicy.svelte';
109
import Persistence from '$lib/components/persistence/Persistence.svelte';
1110
import Secrets from '$lib/components/Secrets.svelte';
1211
import WorkloadDeploy from '$lib/components/WorkloadDeploy.svelte';
12+
import WorkloadVulnerabilitySummary from '$lib/components/WorkloadVulnerabilitySummary.svelte';
1313
import { docURL } from '$lib/doc';
1414
import GraphErrors from '$lib/GraphErrors.svelte';
1515
import Time from '$lib/Time.svelte';
@@ -121,7 +121,11 @@
121121
</div>
122122
<div class="sidebar">
123123
<AggregatedCostForWorkload workload={app.name} {environment} {teamSlug} />
124-
<Image workload={app} />
124+
<div>
125+
<Heading level="2" size="small" spacing>Vulnerabilities</Heading>
126+
<WorkloadVulnerabilitySummary workload={app} />
127+
</div>
128+
125129
<WorkloadDeploy workload={app} />
126130
{#if viewerIsMember}
127131
<Secrets workload={app.name} {environment} {teamSlug} />

src/routes/team/[team]/[env]/app/[app]/vulnerability-report/+page.gql

+41-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,37 @@ query ApplicationImageDetails($team: Slug!, $env: String!, $app: String!)
33
team(slug: $team) {
44
slug
55
environment(name: $env) {
6-
name
6+
environment {
7+
name
8+
}
79
workload(name: $app) {
810
__typename
911
name
12+
team {
13+
slug
14+
}
15+
teamEnvironment {
16+
environment {
17+
name
18+
}
19+
}
20+
status {
21+
errors {
22+
__typename
23+
level
24+
... on WorkloadStatusVulnerable {
25+
summary {
26+
critical
27+
riskScore
28+
}
29+
}
30+
}
31+
}
1032
image {
33+
id
1134
name
1235
tag
1336
hasSBOM
14-
1537
vulnerabilitySummary {
1638
critical
1739
high
@@ -20,8 +42,23 @@ query ApplicationImageDetails($team: Slug!, $env: String!, $app: String!)
2042
unassigned
2143
riskScore
2244
}
23-
24-
...ImageWorkloadReferences
45+
workloadReferences {
46+
nodes {
47+
workload {
48+
id
49+
__typename
50+
team {
51+
slug
52+
}
53+
teamEnvironment {
54+
environment {
55+
name
56+
}
57+
}
58+
name
59+
}
60+
}
61+
}
2562
}
2663
}
2764
}

0 commit comments

Comments
 (0)