Skip to content

Commit 76500be

Browse files
committed
chore: enable SBOM and containerd support in Docker builds
Added SBOM (Software Bill of Materials) generation during Docker build to enhance traceability. Refer to Docker documentation on SBOM: docs.docker.com/build/metadata/attestations/sbom Updated Docker build scripts to use BuildKit for provenance and SBOM support: docs.docker.com/build/metadata/attestations Configured Docker daemon to support the Containerd snapshotter feature to improve performance: docs.docker.com/engine/storage/containerd
1 parent 970d792 commit 76500be

File tree

13 files changed

+348
-328
lines changed

13 files changed

+348
-328
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ jobs:
259259
- name: Install Protoc
260260
run: |
261261
mkdir -p /tmp/proto
262-
build /tmp/proto
262+
pushd /tmp/proto
263263
curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v23.4/protoc-23.4-linux-x86_64.zip
264264
unzip protoc.zip
265265
cp -r ./bin/* /usr/local/bin

site/e2e/tests/auditLogs.spec.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
import { type Page, expect, test } from "@playwright/test";
2-
import { users } from "../constants";
3-
import {
4-
createTemplate,
5-
createWorkspace,
6-
currentUser,
7-
login,
8-
requiresLicense,
9-
} from "../helpers";
10-
import { beforeCoderTest } from "../hooks";
1+
import {expect, type Page, test} from "@playwright/test";
2+
import {users} from "../constants";
3+
import {createTemplate, createWorkspace, login, requiresLicense,} from "../helpers";
4+
import {beforeCoderTest} from "../hooks";
115

126
test.describe.configure({ mode: "parallel" });
137

@@ -35,7 +29,6 @@ test("logins are logged", async ({ page }) => {
3529
await page.goto("/audit");
3630
const username = users.auditor.username;
3731

38-
const user = currentUser(page);
3932
const loginMessage = `${username} logged in`;
4033
// Make sure those things we did all actually show up
4134
await resetSearch(page, username);

site/src/pages/GroupsPage/GroupsPage.tsx

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import GroupAdd from "@mui/icons-material/GroupAddOutlined";
2-
import { getErrorMessage } from "api/errors";
3-
import { groupsByOrganization } from "api/queries/groups";
4-
import { organizationsPermissions } from "api/queries/organizations";
5-
import { ErrorAlert } from "components/Alert/ErrorAlert";
6-
import { Button } from "components/Button/Button";
7-
import { EmptyState } from "components/EmptyState/EmptyState";
8-
import { displayError } from "components/GlobalSnackbar/utils";
9-
import { Loader } from "components/Loader/Loader";
10-
import { SettingsHeader } from "components/SettingsHeader/SettingsHeader";
11-
import { Stack } from "components/Stack/Stack";
12-
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
13-
import { type FC, useEffect } from "react";
14-
import { Helmet } from "react-helmet-async";
15-
import { useQuery } from "react-query";
16-
import { Link as RouterLink } from "react-router-dom";
17-
import { pageTitle } from "utils/page";
18-
import { useGroupsSettings } from "./GroupsPageProvider";
2+
import {getErrorMessage} from "api/errors";
3+
import {groupsByOrganization} from "api/queries/groups";
4+
import {organizationsPermissions} from "api/queries/organizations";
5+
import {Button} from "components/Button/Button";
6+
import {EmptyState} from "components/EmptyState/EmptyState";
7+
import {displayError} from "components/GlobalSnackbar/utils";
8+
import {Loader} from "components/Loader/Loader";
9+
import {SettingsHeader} from "components/SettingsHeader/SettingsHeader";
10+
import {Stack} from "components/Stack/Stack";
11+
import {useFeatureVisibility} from "modules/dashboard/useFeatureVisibility";
12+
import {RequirePermission} from "modules/permissions/RequirePermission";
13+
import {type FC, useEffect} from "react";
14+
import {Helmet} from "react-helmet-async";
15+
import {useQuery} from "react-query";
16+
import {Link as RouterLink} from "react-router-dom";
17+
import {pageTitle} from "utils/page";
18+
import {useGroupsSettings} from "./GroupsPageProvider";
1919
import GroupsPageView from "./GroupsPageView";
2020

2121
export const GroupsPage: FC = () => {
@@ -54,16 +54,26 @@ export const GroupsPage: FC = () => {
5454
return <Loader />;
5555
}
5656

57+
const helmet = (
58+
<Helmet>
59+
<title>{pageTitle("Groups")}</title>
60+
</Helmet>
61+
);
62+
5763
const permissions = permissionsQuery.data?.[organization.id];
58-
if (!permissions) {
59-
return <ErrorAlert error={permissionsQuery.error} />;
64+
65+
if (!permissions?.viewGroups) {
66+
return (
67+
<>
68+
{helmet}
69+
<RequirePermission isFeatureVisible={false} />
70+
</>
71+
);
6072
}
6173

6274
return (
6375
<>
64-
<Helmet>
65-
<title>{pageTitle("Groups")}</title>
66-
</Helmet>
76+
{helmet}
6777

6878
<Stack
6979
alignItems="baseline"

site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx

Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import { getErrorMessage } from "api/errors";
2-
import { deleteOrganizationRole, organizationRoles } from "api/queries/roles";
3-
import type { Role } from "api/typesGenerated";
4-
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog";
5-
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
6-
import { Loader } from "components/Loader/Loader";
7-
import { SettingsHeader } from "components/SettingsHeader/SettingsHeader";
8-
import { Stack } from "components/Stack/Stack";
9-
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
10-
import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout";
11-
import { RequirePermission } from "modules/permissions/RequirePermission";
12-
import { type FC, useEffect, useState } from "react";
13-
import { Helmet } from "react-helmet-async";
14-
import { useMutation, useQuery, useQueryClient } from "react-query";
15-
import { useParams } from "react-router-dom";
16-
import { pageTitle } from "utils/page";
1+
import {getErrorMessage} from "api/errors";
2+
import {deleteOrganizationRole, organizationRoles} from "api/queries/roles";
3+
import type {Role} from "api/typesGenerated";
4+
import {DeleteDialog} from "components/Dialogs/DeleteDialog/DeleteDialog";
5+
import {EmptyState} from "components/EmptyState/EmptyState";
6+
import {displayError, displaySuccess} from "components/GlobalSnackbar/utils";
7+
import {SettingsHeader} from "components/SettingsHeader/SettingsHeader";
8+
import {Stack} from "components/Stack/Stack";
9+
import {useFeatureVisibility} from "modules/dashboard/useFeatureVisibility";
10+
import {useOrganizationSettings} from "modules/management/OrganizationSettingsLayout";
11+
import {RequirePermission} from "modules/permissions/RequirePermission";
12+
import {type FC, useEffect, useState} from "react";
13+
import {Helmet} from "react-helmet-async";
14+
import {useMutation, useQuery, useQueryClient} from "react-query";
15+
import {useParams} from "react-router-dom";
16+
import {pageTitle} from "utils/page";
1717
import CustomRolesPageView from "./CustomRolesPageView";
1818

1919
export const CustomRolesPage: FC = () => {
@@ -22,7 +22,7 @@ export const CustomRolesPage: FC = () => {
2222
const { organization: organizationName } = useParams() as {
2323
organization: string;
2424
};
25-
const { organizationPermissions } = useOrganizationSettings();
25+
const { organization, organizationPermissions } = useOrganizationSettings();
2626

2727
const [roleToDelete, setRoleToDelete] = useState<Role>();
2828

@@ -49,65 +49,67 @@ export const CustomRolesPage: FC = () => {
4949
}
5050
}, [organizationRolesQuery.error]);
5151

52-
if (!organizationPermissions) {
53-
return <Loader />;
52+
if (!organization) {
53+
return <EmptyState message="Organization not found" />;
5454
}
5555

5656
return (
57-
<RequirePermission
58-
isFeatureVisible={
59-
organizationPermissions.assignOrgRoles ||
60-
organizationPermissions.createOrgRoles ||
61-
organizationPermissions.viewOrgRoles
62-
}
63-
>
57+
<>
6458
<Helmet>
65-
<title>{pageTitle("Custom Roles")}</title>
59+
<title>
60+
{pageTitle(
61+
"Custom Roles",
62+
organization.display_name || organization.name,
63+
)}
64+
</title>
6665
</Helmet>
67-
68-
<Stack
69-
alignItems="baseline"
70-
direction="row"
71-
justifyContent="space-between"
66+
<RequirePermission
67+
isFeatureVisible={organizationPermissions?.viewOrgRoles ?? false}
7268
>
73-
<SettingsHeader
74-
title="Roles"
75-
description="Manage roles for this organization."
76-
/>
77-
</Stack>
69+
<Stack
70+
alignItems="baseline"
71+
direction="row"
72+
justifyContent="space-between"
73+
>
74+
<SettingsHeader
75+
title="Roles"
76+
description="Manage roles for this organization."
77+
/>
78+
</Stack>
7879

79-
<CustomRolesPageView
80-
builtInRoles={builtInRoles}
81-
customRoles={customRoles}
82-
onDeleteRole={setRoleToDelete}
83-
canAssignOrgRole={organizationPermissions.assignOrgRoles}
84-
canCreateOrgRole={organizationPermissions.createOrgRoles}
85-
isCustomRolesEnabled={isCustomRolesEnabled}
86-
/>
80+
<CustomRolesPageView
81+
builtInRoles={builtInRoles}
82+
customRoles={customRoles}
83+
onDeleteRole={setRoleToDelete}
84+
canAssignOrgRole={organizationPermissions?.assignOrgRoles ?? false}
85+
canCreateOrgRole={organizationPermissions?.createOrgRoles ?? false}
86+
isCustomRolesEnabled={isCustomRolesEnabled}
87+
/>
8788

88-
<DeleteDialog
89-
key={roleToDelete?.name}
90-
isOpen={roleToDelete !== undefined}
91-
confirmLoading={deleteRoleMutation.isLoading}
92-
name={roleToDelete?.name ?? ""}
93-
entity="role"
94-
onCancel={() => setRoleToDelete(undefined)}
95-
onConfirm={async () => {
96-
try {
97-
if (roleToDelete) {
98-
await deleteRoleMutation.mutateAsync(roleToDelete.name);
89+
<DeleteDialog
90+
key={roleToDelete?.name}
91+
isOpen={roleToDelete !== undefined}
92+
confirmLoading={deleteRoleMutation.isLoading}
93+
name={roleToDelete?.name ?? ""}
94+
entity="role"
95+
onCancel={() => setRoleToDelete(undefined)}
96+
onConfirm={async () => {
97+
try {
98+
if (roleToDelete) {
99+
await deleteRoleMutation.mutateAsync(roleToDelete.name);
100+
}
101+
setRoleToDelete(undefined);
102+
await organizationRolesQuery.refetch();
103+
displaySuccess("Custom role deleted successfully!");
104+
} catch (error) {
105+
displayError(
106+
getErrorMessage(error, "Failed to delete custom role"),
107+
);
99108
}
100-
setRoleToDelete(undefined);
101-
await organizationRolesQuery.refetch();
102-
displaySuccess("Custom role deleted successfully!");
103-
} catch (error) {
104-
displayError(
105-
getErrorMessage(error, "Failed to delete custom role"),
106-
);
107-
}
108-
}}
109-
/>
110-
</RequirePermission>
109+
}}
110+
/>
111+
</RequirePermission>
112+
</>
111113
);
112114
};
113115

site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
1-
import { getErrorMessage } from "api/errors";
2-
import { groupsByOrganization } from "api/queries/groups";
1+
import {getErrorMessage} from "api/errors";
2+
import {groupsByOrganization} from "api/queries/groups";
33
import {
44
groupIdpSyncSettings,
55
organizationIdpSyncClaimFieldValues,
66
patchGroupSyncSettings,
77
patchRoleSyncSettings,
88
roleIdpSyncSettings,
99
} from "api/queries/organizations";
10-
import { organizationRoles } from "api/queries/roles";
11-
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
12-
import { EmptyState } from "components/EmptyState/EmptyState";
13-
import { displayError } from "components/GlobalSnackbar/utils";
14-
import { displaySuccess } from "components/GlobalSnackbar/utils";
15-
import { Link } from "components/Link/Link";
16-
import { Paywall } from "components/Paywall/Paywall";
17-
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
18-
import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout";
19-
import { type FC, useEffect, useState } from "react";
20-
import { Helmet } from "react-helmet-async";
21-
import { useMutation, useQueries, useQuery, useQueryClient } from "react-query";
22-
import { useParams, useSearchParams } from "react-router-dom";
23-
import { docs } from "utils/docs";
24-
import { pageTitle } from "utils/page";
10+
import {organizationRoles} from "api/queries/roles";
11+
import {ChooseOne, Cond} from "components/Conditionals/ChooseOne";
12+
import {EmptyState} from "components/EmptyState/EmptyState";
13+
import {displayError, displaySuccess} from "components/GlobalSnackbar/utils";
14+
import {Link} from "components/Link/Link";
15+
import {Paywall} from "components/Paywall/Paywall";
16+
import {useFeatureVisibility} from "modules/dashboard/useFeatureVisibility";
17+
import {useOrganizationSettings} from "modules/management/OrganizationSettingsLayout";
18+
import {RequirePermission} from "modules/permissions/RequirePermission";
19+
import {type FC, useEffect, useState} from "react";
20+
import {Helmet} from "react-helmet-async";
21+
import {useMutation, useQueries, useQuery, useQueryClient} from "react-query";
22+
import {useParams, useSearchParams} from "react-router-dom";
23+
import {docs} from "utils/docs";
24+
import {pageTitle} from "utils/page";
2525
import IdpSyncPageView from "./IdpSyncPageView";
2626

2727
export const IdpSyncPage: FC = () => {
@@ -31,8 +31,7 @@ export const IdpSyncPage: FC = () => {
3131
const { organization: organizationName } = useParams() as {
3232
organization: string;
3333
};
34-
const { organizations } = useOrganizationSettings();
35-
const organization = organizations?.find((o) => o.name === organizationName);
34+
const { organization, organizationPermissions } = useOrganizationSettings();
3635
const [groupField, setGroupField] = useState("");
3736
const [roleField, setRoleField] = useState("");
3837

@@ -80,6 +79,23 @@ export const IdpSyncPage: FC = () => {
8079
return <EmptyState message="Organization not found" />;
8180
}
8281

82+
const helmet = (
83+
<Helmet>
84+
<title>
85+
{pageTitle("IdP Sync", organization.display_name || organization.name)}
86+
</title>
87+
</Helmet>
88+
);
89+
90+
if (!organizationPermissions?.viewIdpSyncSettings) {
91+
return (
92+
<>
93+
{helmet}
94+
<RequirePermission isFeatureVisible={false} />
95+
</>
96+
);
97+
}
98+
8399
const patchGroupSyncSettingsMutation = useMutation(
84100
patchGroupSyncSettings(organizationName, queryClient),
85101
);
@@ -103,9 +119,7 @@ export const IdpSyncPage: FC = () => {
103119

104120
return (
105121
<>
106-
<Helmet>
107-
<title>{pageTitle("IdP Sync")}</title>
108-
</Helmet>
122+
{helmet}
109123

110124
<div className="flex flex-col gap-12">
111125
<header className="flex flex-row items-baseline justify-between">

0 commit comments

Comments
 (0)