mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 23:28:45 +00:00
Revise PR based on review
This commit is contained in:
@@ -4,7 +4,7 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
|||||||
import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
|
import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
|
||||||
import { sanitizedSshHostGroup } from "@app/ee/services/ssh-host-group/ssh-host-group-schema";
|
import { sanitizedSshHostGroup } from "@app/ee/services/ssh-host-group/ssh-host-group-schema";
|
||||||
import { EHostGroupMembershipFilter } from "@app/ee/services/ssh-host-group/ssh-host-group-types";
|
import { EHostGroupMembershipFilter } from "@app/ee/services/ssh-host-group/ssh-host-group-types";
|
||||||
import { SSH_HOST_GROUPS } from "@app/lib/api-docs";
|
import { ApiDocsTags, SSH_HOST_GROUPS } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
@@ -18,6 +18,9 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
|
description: "Get SSH Host Group",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.GET.sshHostGroupId)
|
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.GET.sshHostGroupId)
|
||||||
}),
|
}),
|
||||||
@@ -60,6 +63,8 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
description: "Create SSH Host Group",
|
description: "Create SSH Host Group",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().describe(SSH_HOST_GROUPS.CREATE.projectId),
|
projectId: z.string().describe(SSH_HOST_GROUPS.CREATE.projectId),
|
||||||
@@ -107,6 +112,8 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
description: "Update SSH Host Group",
|
description: "Update SSH Host Group",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostGroupId: z.string().trim().describe(SSH_HOST_GROUPS.UPDATE.sshHostGroupId)
|
sshHostGroupId: z.string().trim().describe(SSH_HOST_GROUPS.UPDATE.sshHostGroupId)
|
||||||
@@ -155,6 +162,9 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
|
description: "Delete SSH Host Group",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.DELETE.sshHostGroupId)
|
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.DELETE.sshHostGroupId)
|
||||||
}),
|
}),
|
||||||
@@ -197,6 +207,9 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
|
description: "Get SSH Hosts in a Host Group",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.GET.sshHostGroupId)
|
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.GET.sshHostGroupId)
|
||||||
}),
|
}),
|
||||||
@@ -256,6 +269,9 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
|
description: "Add an SSH Host to a Host Group",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.ADD_HOST.sshHostGroupId),
|
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.ADD_HOST.sshHostGroupId),
|
||||||
hostId: z.string().describe(SSH_HOST_GROUPS.ADD_HOST.hostId)
|
hostId: z.string().describe(SSH_HOST_GROUPS.ADD_HOST.hostId)
|
||||||
@@ -301,6 +317,9 @@ export const registerSshHostGroupRouter = async (server: FastifyZodProvider) =>
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHostGroups],
|
||||||
|
description: "Remove an SSH Host from a Host Group",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.DELETE_HOST.sshHostGroupId),
|
sshHostGroupId: z.string().describe(SSH_HOST_GROUPS.DELETE_HOST.sshHostGroupId),
|
||||||
hostId: z.string().describe(SSH_HOST_GROUPS.DELETE_HOST.hostId)
|
hostId: z.string().describe(SSH_HOST_GROUPS.DELETE_HOST.hostId)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certif
|
|||||||
import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
|
import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema";
|
||||||
import { LoginMappingSource } from "@app/ee/services/ssh-host/ssh-host-types";
|
import { LoginMappingSource } from "@app/ee/services/ssh-host/ssh-host-types";
|
||||||
import { isValidHostname } from "@app/ee/services/ssh-host/ssh-host-validators";
|
import { isValidHostname } from "@app/ee/services/ssh-host/ssh-host-validators";
|
||||||
import { SSH_HOSTS } from "@app/lib/api-docs";
|
import { ApiDocsTags, SSH_HOSTS } from "@app/lib/api-docs";
|
||||||
import { ms } from "@app/lib/ms";
|
import { ms } from "@app/lib/ms";
|
||||||
import { publicSshCaLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { publicSshCaLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
@@ -22,6 +22,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
response: {
|
response: {
|
||||||
200: z.array(
|
200: z.array(
|
||||||
sanitizedSshHost.extend({
|
sanitizedSshHost.extend({
|
||||||
@@ -54,6 +56,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: readLimit
|
rateLimit: readLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().describe(SSH_HOSTS.GET.sshHostId)
|
sshHostId: z.string().describe(SSH_HOSTS.GET.sshHostId)
|
||||||
}),
|
}),
|
||||||
@@ -100,7 +104,9 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
description: "Add an SSH Host",
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
|
description: "Register SSH Host",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
projectId: z.string().describe(SSH_HOSTS.CREATE.projectId),
|
projectId: z.string().describe(SSH_HOSTS.CREATE.projectId),
|
||||||
hostname: z
|
hostname: z
|
||||||
@@ -176,6 +182,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
description: "Update SSH Host",
|
description: "Update SSH Host",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().trim().describe(SSH_HOSTS.UPDATE.sshHostId)
|
sshHostId: z.string().trim().describe(SSH_HOSTS.UPDATE.sshHostId)
|
||||||
@@ -252,6 +260,9 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: writeLimit
|
rateLimit: writeLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
|
description: "Delete SSH Host",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().describe(SSH_HOSTS.DELETE.sshHostId)
|
sshHostId: z.string().describe(SSH_HOSTS.DELETE.sshHostId)
|
||||||
}),
|
}),
|
||||||
@@ -299,6 +310,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
description: "Issue SSH certificate for user",
|
description: "Issue SSH certificate for user",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.sshHostId)
|
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_SSH_CREDENTIALS.sshHostId)
|
||||||
@@ -371,6 +384,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
description: "Issue SSH certificate for host",
|
description: "Issue SSH certificate for host",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.sshHostId)
|
sshHostId: z.string().describe(SSH_HOSTS.ISSUE_HOST_CERT.sshHostId)
|
||||||
@@ -435,6 +450,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: publicSshCaLimit
|
rateLimit: publicSshCaLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
description: "Get public key of the user SSH CA linked to the host",
|
description: "Get public key of the user SSH CA linked to the host",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
|
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
|
||||||
@@ -456,6 +473,8 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
|
|||||||
rateLimit: publicSshCaLimit
|
rateLimit: publicSshCaLimit
|
||||||
},
|
},
|
||||||
schema: {
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SshHosts],
|
||||||
description: "Get public key of the host SSH CA linked to the host",
|
description: "Get public key of the host SSH CA linked to the host",
|
||||||
params: z.object({
|
params: z.object({
|
||||||
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)
|
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)
|
||||||
|
|||||||
@@ -90,15 +90,19 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
|||||||
const { sshHostId, hostname, alias, userCertTtl, hostCertTtl, userSshCaId, hostSshCaId, projectId } =
|
const { sshHostId, hostname, alias, userCertTtl, hostCertTtl, userSshCaId, hostSshCaId, projectId } =
|
||||||
hostRows[0];
|
hostRows[0];
|
||||||
|
|
||||||
const loginMappingGrouped = groupBy(hostRows, (r) => `${r.loginUser}|${r.source}`);
|
const loginMappingGrouped = groupBy(hostRows, (r) => r.loginUser);
|
||||||
const loginMappings = Object.entries(loginMappingGrouped).map(([key]) => {
|
const loginMappings = Object.entries(loginMappingGrouped).map(([loginUser, mappings]) => {
|
||||||
const [loginUser, source] = key.split("|");
|
// Prefer HOST source over HOST_GROUP
|
||||||
|
const preferredMapping =
|
||||||
|
mappings.find((m) => m.source === LoginMappingSource.HOST) ||
|
||||||
|
mappings.find((m) => m.source === LoginMappingSource.HOST_GROUP);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loginUser,
|
loginUser,
|
||||||
allowedPrincipals: {
|
allowedPrincipals: {
|
||||||
usernames: [user.username]
|
usernames: [user.username]
|
||||||
},
|
},
|
||||||
source: source as LoginMappingSource
|
source: preferredMapping!.source
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ export enum ApiDocsTags {
|
|||||||
SshCertificates = "SSH Certificates",
|
SshCertificates = "SSH Certificates",
|
||||||
SshCertificateAuthorities = "SSH Certificate Authorities",
|
SshCertificateAuthorities = "SSH Certificate Authorities",
|
||||||
SshCertificateTemplates = "SSH Certificate Templates",
|
SshCertificateTemplates = "SSH Certificate Templates",
|
||||||
|
SshHosts = "SSH Hosts",
|
||||||
|
SshHostGroups = "SSH Host Groups",
|
||||||
KmsKeys = "KMS Keys",
|
KmsKeys = "KMS Keys",
|
||||||
KmsEncryption = "KMS Encryption",
|
KmsEncryption = "KMS Encryption",
|
||||||
KmsSigning = "KMS Signing"
|
KmsSigning = "KMS Signing"
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ export const useUpdateSshHostGroup = () => {
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
|
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
|
||||||
});
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: workspaceKeys.getWorkspaceSshHosts(projectId)
|
||||||
|
});
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId)
|
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId)
|
||||||
});
|
});
|
||||||
@@ -63,6 +66,9 @@ export const useDeleteSshHostGroup = () => {
|
|||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
|
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
|
||||||
});
|
});
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: workspaceKeys.getWorkspaceSshHosts(projectId)
|
||||||
|
});
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId)
|
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -95,7 +95,8 @@ const Page = () => {
|
|||||||
)}
|
)}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handlePopUpOpen("deleteSshHostGroup", {
|
handlePopUpOpen("deleteSshHostGroup", {
|
||||||
groupId: data.id
|
groupId: data.id,
|
||||||
|
name: data.name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
disabled={!isAllowed}
|
disabled={!isAllowed}
|
||||||
@@ -123,7 +124,9 @@ const Page = () => {
|
|||||||
<SshHostGroupModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
<SshHostGroupModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||||
<DeleteActionModal
|
<DeleteActionModal
|
||||||
isOpen={popUp.deleteSshHostGroup.isOpen}
|
isOpen={popUp.deleteSshHostGroup.isOpen}
|
||||||
title="Are you sure want to remove the SSH group from the project?"
|
title={`Are you sure want to remove the SSH group: ${
|
||||||
|
(popUp?.deleteSshHostGroup?.data as { name: string })?.name || ""
|
||||||
|
}?`}
|
||||||
onChange={(isOpen) => handlePopUpToggle("deleteSshHostGroup", isOpen)}
|
onChange={(isOpen) => handlePopUpToggle("deleteSshHostGroup", isOpen)}
|
||||||
deleteKey="confirm"
|
deleteKey="confirm"
|
||||||
onDeleteApproved={() =>
|
onDeleteApproved={() =>
|
||||||
|
|||||||
+7
-3
@@ -88,9 +88,13 @@ export const SshHostGroupHostsSection = ({ sshHostGroupId }: Props) => {
|
|||||||
<AddHostGroupMemberModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
<AddHostGroupMemberModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||||
<DeleteActionModal
|
<DeleteActionModal
|
||||||
isOpen={popUp.removeHostFromSshHostGroup.isOpen}
|
isOpen={popUp.removeHostFromSshHostGroup.isOpen}
|
||||||
title={`Are you sure want to remove the host ${
|
title={`Are you sure want to remove ${
|
||||||
(popUp?.removeHostFromSshHostGroup?.data as { hostname: string })?.hostname || ""
|
(popUp?.removeHostFromSshHostGroup?.data as { hostname: string; alias?: string })
|
||||||
} from this SSH group?`}
|
?.alias ||
|
||||||
|
(popUp?.removeHostFromSshHostGroup?.data as { hostname: string; alias?: string })
|
||||||
|
?.hostname ||
|
||||||
|
""
|
||||||
|
} from this host group?`}
|
||||||
onChange={(isOpen) => handlePopUpToggle("removeHostFromSshHostGroup", isOpen)}
|
onChange={(isOpen) => handlePopUpToggle("removeHostFromSshHostGroup", isOpen)}
|
||||||
deleteKey="confirm"
|
deleteKey="confirm"
|
||||||
onDeleteApproved={() =>
|
onDeleteApproved={() =>
|
||||||
|
|||||||
+3
-2
@@ -1,4 +1,4 @@
|
|||||||
import { faServer, faUserMinus } from "@fortawesome/free-solid-svg-icons";
|
import { faServer, faTrash } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
@@ -68,13 +68,14 @@ export const SshHostGroupHostsTable = ({ sshHostGroupId, handlePopUpOpen }: Prop
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
handlePopUpOpen("removeHostFromSshHostGroup", {
|
handlePopUpOpen("removeHostFromSshHostGroup", {
|
||||||
sshHostId: host.id,
|
sshHostId: host.id,
|
||||||
|
alias: host.alias,
|
||||||
hostname: host.hostname
|
hostname: host.hostname
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
variant="plain"
|
variant="plain"
|
||||||
colorSchema="danger"
|
colorSchema="danger"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faUserMinus} />
|
<FontAwesomeIcon icon={faTrash} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export const SshHostGroupsSection = () => {
|
|||||||
<SshHostGroupModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
<SshHostGroupModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||||
<DeleteActionModal
|
<DeleteActionModal
|
||||||
isOpen={popUp.deleteSshHostGroup.isOpen}
|
isOpen={popUp.deleteSshHostGroup.isOpen}
|
||||||
title="Are you sure you want to remove the SSH host group?"
|
title={`Are you sure you want to remove the SSH host group: ${popUp?.deleteSshHostGroup?.data?.name}?`}
|
||||||
onChange={(isOpen) => handlePopUpToggle("deleteSshHostGroup", isOpen)}
|
onChange={(isOpen) => handlePopUpToggle("deleteSshHostGroup", isOpen)}
|
||||||
deleteKey="confirm"
|
deleteKey="confirm"
|
||||||
onDeleteApproved={() =>
|
onDeleteApproved={() =>
|
||||||
|
|||||||
@@ -114,7 +114,33 @@ export const SshHostGroupsTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
disabled={!isAllowed}
|
disabled={!isAllowed}
|
||||||
icon={<FontAwesomeIcon icon={faPencil} />}
|
icon={<FontAwesomeIcon icon={faPencil} />}
|
||||||
>
|
>
|
||||||
Edit SSH host group
|
Edit Host Group
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
</ProjectPermissionCan>
|
||||||
|
<ProjectPermissionCan
|
||||||
|
I={ProjectPermissionActions.Edit}
|
||||||
|
a={ProjectPermissionSub.SshHostGroups}
|
||||||
|
>
|
||||||
|
{(isAllowed) => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
className={twMerge(
|
||||||
|
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
|
||||||
|
)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
navigate({
|
||||||
|
to: `/${ProjectType.SSH}/$projectId/ssh-host-groups/$sshHostGroupId` as const,
|
||||||
|
params: {
|
||||||
|
projectId: currentWorkspace.id,
|
||||||
|
sshHostGroupId: group.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
disabled={!isAllowed}
|
||||||
|
icon={<FontAwesomeIcon icon={faServer} />}
|
||||||
|
>
|
||||||
|
Manage Hosts
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</ProjectPermissionCan>
|
</ProjectPermissionCan>
|
||||||
@@ -130,13 +156,14 @@ export const SshHostGroupsTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
handlePopUpOpen("deleteSshHostGroup", {
|
handlePopUpOpen("deleteSshHostGroup", {
|
||||||
sshHostGroupId: group.id
|
sshHostGroupId: group.id,
|
||||||
|
name: group.name
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
disabled={!isAllowed}
|
disabled={!isAllowed}
|
||||||
icon={<FontAwesomeIcon icon={faTrash} />}
|
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||||
>
|
>
|
||||||
Delete SSH host group
|
Delete Host Group
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</ProjectPermissionCan>
|
</ProjectPermissionCan>
|
||||||
|
|||||||
@@ -362,7 +362,10 @@ export const SshHostModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
const newValue = e.target.value;
|
const newValue = e.target.value;
|
||||||
const loginMappings = getValues("loginMappings");
|
const loginMappings = getValues("loginMappings");
|
||||||
const isDuplicate = loginMappings.some(
|
const isDuplicate = loginMappings.some(
|
||||||
(mapping, index) => index !== i && mapping.loginUser === newValue
|
(mapping, index) =>
|
||||||
|
index !== i &&
|
||||||
|
mapping.loginUser === newValue &&
|
||||||
|
mapping.source === LoginMappingSource.HOST
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isDuplicate) {
|
if (isDuplicate) {
|
||||||
|
|||||||
@@ -91,7 +91,27 @@ export const SshHostsTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
{host.loginMappings.length === 0 ? (
|
{host.loginMappings.length === 0 ? (
|
||||||
<span className="italic text-mineshaft-400">None</span>
|
<span className="italic text-mineshaft-400">None</span>
|
||||||
) : (
|
) : (
|
||||||
host.loginMappings.map(({ loginUser, allowedPrincipals, source }) => (
|
Object.entries(
|
||||||
|
host.loginMappings.reduce(
|
||||||
|
(acc, mapping) => {
|
||||||
|
const { loginUser, source } = mapping;
|
||||||
|
const existing = acc[loginUser];
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
acc[loginUser] = mapping;
|
||||||
|
} else if (
|
||||||
|
existing.source === LoginMappingSource.HOST_GROUP &&
|
||||||
|
source === LoginMappingSource.HOST
|
||||||
|
) {
|
||||||
|
// Prefer HOST over HOST_GROUP
|
||||||
|
acc[loginUser] = mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, (typeof host.loginMappings)[number]>
|
||||||
|
)
|
||||||
|
).map(([loginUser, { allowedPrincipals, source }]) => (
|
||||||
<div key={`${host.id}-${loginUser}`} className="mb-2">
|
<div key={`${host.id}-${loginUser}`} className="mb-2">
|
||||||
<div className="text-mineshaft-200">
|
<div className="text-mineshaft-200">
|
||||||
{loginUser}
|
{loginUser}
|
||||||
@@ -147,7 +167,7 @@ export const SshHostsTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
disabled={!isAllowed}
|
disabled={!isAllowed}
|
||||||
icon={<FontAwesomeIcon icon={faPencil} />}
|
icon={<FontAwesomeIcon icon={faPencil} />}
|
||||||
>
|
>
|
||||||
Edit SSH host
|
Edit Host
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</ProjectPermissionCan>
|
</ProjectPermissionCan>
|
||||||
@@ -169,7 +189,7 @@ export const SshHostsTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
disabled={!isAllowed}
|
disabled={!isAllowed}
|
||||||
icon={<FontAwesomeIcon icon={faTrash} />}
|
icon={<FontAwesomeIcon icon={faTrash} />}
|
||||||
>
|
>
|
||||||
Delete SSH host
|
Delete Host
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</ProjectPermissionCan>
|
</ProjectPermissionCan>
|
||||||
|
|||||||
Reference in New Issue
Block a user