Move ssh out to org level

This commit is contained in:
Tuan Dang
2024-12-15 20:43:13 -08:00
214 changed files with 6277 additions and 2125 deletions
@@ -7,5 +7,6 @@ export const identityAuthToNameMap: { [I in IdentityAuthMethod]: string } = {
[IdentityAuthMethod.GCP_AUTH]: "GCP Auth",
[IdentityAuthMethod.AWS_AUTH]: "AWS Auth",
[IdentityAuthMethod.AZURE_AUTH]: "Azure Auth",
[IdentityAuthMethod.OIDC_AUTH]: "OIDC Auth"
[IdentityAuthMethod.OIDC_AUTH]: "OIDC Auth",
[IdentityAuthMethod.JWT_AUTH]: "JWT Auth"
};
+7 -1
View File
@@ -5,5 +5,11 @@ export enum IdentityAuthMethod {
GCP_AUTH = "gcp-auth",
AWS_AUTH = "aws-auth",
AZURE_AUTH = "azure-auth",
OIDC_AUTH = "oidc-auth"
OIDC_AUTH = "oidc-auth",
JWT_AUTH = "jwt-auth"
}
export enum IdentityJwtConfigurationType {
JWKS = "jwks",
STATIC = "static"
}
+8 -2
View File
@@ -4,6 +4,7 @@ export {
useAddIdentityAwsAuth,
useAddIdentityAzureAuth,
useAddIdentityGcpAuth,
useAddIdentityJwtAuth,
useAddIdentityKubernetesAuth,
useAddIdentityOidcAuth,
useAddIdentityTokenAuth,
@@ -15,6 +16,7 @@ export {
useDeleteIdentityAwsAuth,
useDeleteIdentityAzureAuth,
useDeleteIdentityGcpAuth,
useDeleteIdentityJwtAuth,
useDeleteIdentityKubernetesAuth,
useDeleteIdentityOidcAuth,
useDeleteIdentityTokenAuth,
@@ -25,20 +27,24 @@ export {
useUpdateIdentityAwsAuth,
useUpdateIdentityAzureAuth,
useUpdateIdentityGcpAuth,
useUpdateIdentityJwtAuth,
useUpdateIdentityKubernetesAuth,
useUpdateIdentityOidcAuth,
useUpdateIdentityTokenAuth,
useUpdateIdentityTokenAuthToken,
useUpdateIdentityUniversalAuth} from "./mutations";
useUpdateIdentityUniversalAuth
} from "./mutations";
export {
useGetIdentityAwsAuth,
useGetIdentityAzureAuth,
useGetIdentityById,
useGetIdentityGcpAuth,
useGetIdentityJwtAuth,
useGetIdentityKubernetesAuth,
useGetIdentityOidcAuth,
useGetIdentityProjectMemberships,
useGetIdentityTokenAuth,
useGetIdentityTokensTokenAuth,
useGetIdentityUniversalAuth,
useGetIdentityUniversalAuthClientSecrets} from "./queries";
useGetIdentityUniversalAuthClientSecrets
} from "./queries";
@@ -8,6 +8,7 @@ import {
AddIdentityAwsAuthDTO,
AddIdentityAzureAuthDTO,
AddIdentityGcpAuthDTO,
AddIdentityJwtAuthDTO,
AddIdentityKubernetesAuthDTO,
AddIdentityOidcAuthDTO,
AddIdentityTokenAuthDTO,
@@ -22,6 +23,7 @@ import {
DeleteIdentityAzureAuthDTO,
DeleteIdentityDTO,
DeleteIdentityGcpAuthDTO,
DeleteIdentityJwtAuthDTO,
DeleteIdentityKubernetesAuthDTO,
DeleteIdentityOidcAuthDTO,
DeleteIdentityTokenAuthDTO,
@@ -32,6 +34,7 @@ import {
IdentityAwsAuth,
IdentityAzureAuth,
IdentityGcpAuth,
IdentityJwtAuth,
IdentityKubernetesAuth,
IdentityOidcAuth,
IdentityTokenAuth,
@@ -42,6 +45,7 @@ import {
UpdateIdentityAzureAuthDTO,
UpdateIdentityDTO,
UpdateIdentityGcpAuthDTO,
UpdateIdentityJwtAuthDTO,
UpdateIdentityKubernetesAuthDTO,
UpdateIdentityOidcAuthDTO,
UpdateIdentityTokenAuthDTO,
@@ -518,6 +522,118 @@ export const useDeleteIdentityOidcAuth = () => {
}
});
};
export const useUpdateIdentityJwtAuth = () => {
const queryClient = useQueryClient();
return useMutation<IdentityJwtAuth, {}, UpdateIdentityJwtAuthDTO>({
mutationFn: async ({
identityId,
configurationType,
jwksUrl,
jwksCaCert,
publicKeys,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps,
boundIssuer,
boundAudiences,
boundClaims,
boundSubject
}) => {
const {
data: { identityJwtAuth }
} = await apiRequest.patch<{ identityJwtAuth: IdentityJwtAuth }>(
`/api/v1/auth/jwt-auth/identities/${identityId}`,
{
configurationType,
jwksUrl,
jwksCaCert,
publicKeys,
boundIssuer,
boundAudiences,
boundClaims,
boundSubject,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
}
);
return identityJwtAuth;
},
onSuccess: (_, { identityId, organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
queryClient.invalidateQueries(identitiesKeys.getIdentityById(identityId));
queryClient.invalidateQueries(identitiesKeys.getIdentityJwtAuth(identityId));
}
});
};
export const useAddIdentityJwtAuth = () => {
const queryClient = useQueryClient();
return useMutation<IdentityJwtAuth, {}, AddIdentityJwtAuthDTO>({
mutationFn: async ({
identityId,
configurationType,
jwksUrl,
jwksCaCert,
publicKeys,
boundIssuer,
boundAudiences,
boundClaims,
boundSubject,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
}) => {
const {
data: { identityJwtAuth }
} = await apiRequest.post<{ identityJwtAuth: IdentityJwtAuth }>(
`/api/v1/auth/jwt-auth/identities/${identityId}`,
{
configurationType,
jwksUrl,
jwksCaCert,
publicKeys,
boundIssuer,
boundAudiences,
boundClaims,
boundSubject,
accessTokenTTL,
accessTokenMaxTTL,
accessTokenNumUsesLimit,
accessTokenTrustedIps
}
);
return identityJwtAuth;
},
onSuccess: (_, { identityId, organizationId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
queryClient.invalidateQueries(identitiesKeys.getIdentityById(identityId));
queryClient.invalidateQueries(identitiesKeys.getIdentityJwtAuth(identityId));
}
});
};
export const useDeleteIdentityJwtAuth = () => {
const queryClient = useQueryClient();
return useMutation<IdentityTokenAuth, {}, DeleteIdentityJwtAuthDTO>({
mutationFn: async ({ identityId }) => {
const {
data: { identityJwtAuth }
} = await apiRequest.delete(`/api/v1/auth/jwt-auth/identities/${identityId}`);
return identityJwtAuth;
},
onSuccess: (_, { organizationId, identityId }) => {
queryClient.invalidateQueries(organizationKeys.getOrgIdentityMemberships(organizationId));
queryClient.invalidateQueries(identitiesKeys.getIdentityById(identityId));
queryClient.invalidateQueries(identitiesKeys.getIdentityJwtAuth(identityId));
}
});
};
export const useAddIdentityAzureAuth = () => {
const queryClient = useQueryClient();
@@ -8,6 +8,7 @@ import {
IdentityAwsAuth,
IdentityAzureAuth,
IdentityGcpAuth,
IdentityJwtAuth,
IdentityKubernetesAuth,
IdentityMembership,
IdentityMembershipOrg,
@@ -29,6 +30,7 @@ export const identitiesKeys = {
getIdentityAwsAuth: (identityId: string) => [{ identityId }, "identity-aws-auth"] as const,
getIdentityAzureAuth: (identityId: string) => [{ identityId }, "identity-azure-auth"] as const,
getIdentityTokenAuth: (identityId: string) => [{ identityId }, "identity-token-auth"] as const,
getIdentityJwtAuth: (identityId: string) => [{ identityId }, "identity-jwt-auth"] as const,
getIdentityTokensTokenAuth: (identityId: string) =>
[{ identityId }, "identity-tokens-token-auth"] as const,
getIdentityProjectMemberships: (identityId: string) =>
@@ -276,3 +278,30 @@ export const useGetIdentityOidcAuth = (
enabled: Boolean(identityId) && (options?.enabled ?? true)
});
};
export const useGetIdentityJwtAuth = (
identityId: string,
options?: UseQueryOptions<
IdentityJwtAuth,
unknown,
IdentityJwtAuth,
ReturnType<typeof identitiesKeys.getIdentityJwtAuth>
>
) => {
return useQuery({
queryKey: identitiesKeys.getIdentityJwtAuth(identityId),
queryFn: async () => {
const {
data: { identityJwtAuth }
} = await apiRequest.get<{ identityJwtAuth: IdentityJwtAuth }>(
`/api/v1/auth/jwt-auth/identities/${identityId}`
);
return identityJwtAuth;
},
staleTime: 0,
cacheTime: 0,
...options,
enabled: Boolean(identityId) && (options?.enabled ?? true)
});
};
+61 -2
View File
@@ -1,6 +1,6 @@
import { TOrgRole } from "../roles/types";
import { ProjectUserMembershipTemporaryMode, Workspace } from "../workspace/types";
import { IdentityAuthMethod } from "./enums";
import { IdentityAuthMethod, IdentityJwtConfigurationType } from "./enums";
export type IdentityTrustedIp = {
id: string;
@@ -47,7 +47,7 @@ export type IdentityMembershipOrg = {
export type IdentityMembership = {
id: string;
identity: Identity;
project: Pick<Workspace, "id" | "name">;
project: Pick<Workspace, "id" | "name" | "type">;
roles: Array<
{
id: string;
@@ -446,6 +446,65 @@ export type DeleteIdentityTokenAuthDTO = {
identityId: string;
};
export type IdentityJwtAuth = {
identityId: string;
configurationType: IdentityJwtConfigurationType;
jwksUrl: string;
jwksCaCert: string;
publicKeys: string[];
boundIssuer: string;
boundAudiences: string;
boundClaims: Record<string, string>;
boundSubject: string;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: IdentityTrustedIp[];
};
export type AddIdentityJwtAuthDTO = {
organizationId: string;
identityId: string;
configurationType: string;
jwksUrl?: string;
jwksCaCert: string;
publicKeys?: string[];
boundIssuer: string;
boundAudiences: string;
boundClaims: Record<string, string>;
boundSubject: string;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
accessTokenTrustedIps: {
ipAddress: string;
}[];
};
export type UpdateIdentityJwtAuthDTO = {
organizationId: string;
identityId: string;
configurationType?: string;
jwksUrl?: string;
jwksCaCert?: string;
publicKeys?: string[];
boundIssuer?: string;
boundAudiences?: string;
boundClaims?: Record<string, string>;
boundSubject?: string;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;
accessTokenTrustedIps?: {
ipAddress: string;
}[];
};
export type DeleteIdentityJwtAuthDTO = {
organizationId: string;
identityId: string;
};
export type CreateTokenIdentityTokenAuthDTO = {
identityId: string;
name: string;
@@ -3,6 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { workspaceKeys } from "../workspace";
import { ProjectType } from "../workspace/types";
export const useImportEnvKey = () => {
const queryClient = useQueryClient();
@@ -31,7 +32,7 @@ export const useImportEnvKey = () => {
}
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(ProjectType.SecretManager));
}
});
};
+2 -1
View File
@@ -1,6 +1,6 @@
import { MfaMethod } from "../auth/types";
import { UserWsKeyPair } from "../keys/types";
import { ProjectUserMembershipTemporaryMode } from "../workspace/types";
import { ProjectType, ProjectUserMembershipTemporaryMode } from "../workspace/types";
export enum AuthMethod {
EMAIL = "email",
@@ -95,6 +95,7 @@ export type TWorkspaceUser = {
project: {
id: string;
name: string;
type: ProjectType;
};
inviteEmail: string;
organization: string;
@@ -4,7 +4,7 @@ import { apiRequest } from "@app/config/request";
import { userKeys } from "../users/query-keys";
import { workspaceKeys } from "./query-keys";
import { TUpdateWorkspaceGroupRoleDTO } from "./types";
import { ProjectType, TUpdateWorkspaceGroupRoleDTO } from "./types";
export const useAddGroupToWorkspace = () => {
const queryClient = useQueryClient();
@@ -83,7 +83,7 @@ export const useLeaveProject = () => {
return apiRequest.delete(`/api/v1/workspace/${workspaceId}/leave`);
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace());
}
});
};
@@ -95,7 +95,7 @@ export const useMigrateProjectToV3 = () => {
return apiRequest.post(`/api/v1/workspace/${workspaceId}/migrate-v3`);
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(ProjectType.SecretManager));
}
});
};
+74 -56
View File
@@ -28,6 +28,7 @@ import {
DeleteWorkspaceDTO,
NameWorkspaceSecretsDTO,
ProjectIdentityOrderBy,
ProjectType,
TGetUpgradeProjectStatusDTO,
TListProjectIdentitiesDTO,
ToggleAutoCapitalizationDTO,
@@ -84,7 +85,7 @@ export const useUpgradeProject = () => {
});
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(ProjectType.SecretManager));
}
});
};
@@ -104,10 +105,11 @@ export const useGetUpgradeProjectStatus = ({
});
};
const fetchUserWorkspaces = async (includeRoles?: boolean) => {
const fetchUserWorkspaces = async (includeRoles?: boolean, type?: ProjectType | "all") => {
const { data } = await apiRequest.get<{ workspaces: Workspace[] }>("/api/v1/workspace", {
params: {
includeRoles
includeRoles,
type
}
});
return data.workspaces;
@@ -141,8 +143,16 @@ export const useGetWorkspaceById = (
});
};
export const useGetUserWorkspaces = (includeRoles?: boolean) =>
useQuery(workspaceKeys.getAllUserWorkspace, () => fetchUserWorkspaces(includeRoles));
export const useGetUserWorkspaces = ({
includeRoles,
type = "all"
}: {
includeRoles?: boolean;
type?: ProjectType | "all";
} = {}) =>
useQuery(workspaceKeys.getAllUserWorkspace(type || ""), () =>
fetchUserWorkspaces(includeRoles, type)
);
const fetchUserWorkspaceMemberships = async (orgId: string) => {
const { data } = await apiRequest.get<Record<string, Workspace[]>>(
@@ -208,33 +218,26 @@ export const useGetWorkspaceIntegrations = (workspaceId: string) =>
refetchInterval: 4000
});
export const createWorkspace = ({
projectName,
projectDescription,
kmsKeyId,
template
}: CreateWorkspaceDTO): Promise<{ data: { project: Workspace } }> => {
return apiRequest.post("/api/v2/workspace", {
projectName,
projectDescription,
kmsKeyId,
template
});
export const createWorkspace = (
dto: CreateWorkspaceDTO
): Promise<{ data: { project: Workspace } }> => {
return apiRequest.post("/api/v2/workspace", dto);
};
export const useCreateWorkspace = () => {
const queryClient = useQueryClient();
return useMutation<{ data: { project: Workspace } }, {}, CreateWorkspaceDTO>({
mutationFn: async ({ projectName, projectDescription, kmsKeyId, template }) =>
mutationFn: async ({ projectName, projectDescription, kmsKeyId, template, type }) =>
createWorkspace({
projectName,
projectDescription,
kmsKeyId,
template
template,
type
}),
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
onSuccess: (dto) => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(dto.data.project.type));
}
});
};
@@ -242,15 +245,19 @@ export const useCreateWorkspace = () => {
export const useUpdateProject = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, UpdateProjectDTO>({
mutationFn: ({ projectID, newProjectName, newProjectDescription }) => {
return apiRequest.patch(`/api/v1/workspace/${projectID}`, {
name: newProjectName,
description: newProjectDescription
});
return useMutation<Workspace, {}, UpdateProjectDTO>({
mutationFn: async ({ projectID, newProjectName, newProjectDescription }) => {
const { data } = await apiRequest.patch<{ workspace: Workspace }>(
`/api/v1/workspace/${projectID}`,
{
name: newProjectName,
description: newProjectDescription
}
);
return data.workspace;
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
onSuccess: (dto) => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(dto.type));
}
});
};
@@ -258,13 +265,18 @@ export const useUpdateProject = () => {
export const useToggleAutoCapitalization = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, ToggleAutoCapitalizationDTO>({
mutationFn: ({ workspaceID, state }) =>
apiRequest.post(`/api/v1/workspace/${workspaceID}/auto-capitalization`, {
autoCapitalization: state
}),
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
return useMutation<Workspace, {}, ToggleAutoCapitalizationDTO>({
mutationFn: async ({ workspaceID, state }) => {
const { data } = await apiRequest.post<{ workspace: Workspace }>(
`/api/v1/workspace/${workspaceID}/auto-capitalization`,
{
autoCapitalization: state
}
);
return data.workspace;
},
onSuccess: (dto) => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(dto.type));
}
});
};
@@ -272,14 +284,15 @@ export const useToggleAutoCapitalization = () => {
export const useUpdateWorkspaceVersionLimit = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, UpdatePitVersionLimitDTO>({
mutationFn: ({ projectSlug, pitVersionLimit }) => {
return apiRequest.put(`/api/v1/workspace/${projectSlug}/version-limit`, {
return useMutation<Workspace, {}, UpdatePitVersionLimitDTO>({
mutationFn: async ({ projectSlug, pitVersionLimit }) => {
const { data } = await apiRequest.put(`/api/v1/workspace/${projectSlug}/version-limit`, {
pitVersionLimit
});
return data.workspace;
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
onSuccess: (dto) => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(dto.type));
}
});
};
@@ -287,14 +300,18 @@ export const useUpdateWorkspaceVersionLimit = () => {
export const useUpdateWorkspaceAuditLogsRetention = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, UpdateAuditLogsRetentionDTO>({
mutationFn: ({ projectSlug, auditLogsRetentionDays }) => {
return apiRequest.put(`/api/v1/workspace/${projectSlug}/audit-logs-retention`, {
auditLogsRetentionDays
});
return useMutation<Workspace, {}, UpdateAuditLogsRetentionDTO>({
mutationFn: async ({ projectSlug, auditLogsRetentionDays }) => {
const { data } = await apiRequest.put(
`/api/v1/workspace/${projectSlug}/audit-logs-retention`,
{
auditLogsRetentionDays
}
);
return data.workspace;
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
onSuccess: (dto) => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(dto.type));
}
});
};
@@ -302,12 +319,13 @@ export const useUpdateWorkspaceAuditLogsRetention = () => {
export const useDeleteWorkspace = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, DeleteWorkspaceDTO>({
mutationFn: ({ workspaceID }) => {
return apiRequest.delete(`/api/v1/workspace/${workspaceID}`);
return useMutation<Workspace, {}, DeleteWorkspaceDTO>({
mutationFn: async ({ workspaceID }) => {
const { data } = await apiRequest.delete(`/api/v1/workspace/${workspaceID}`);
return data.workspace;
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
onSuccess: (dto) => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(dto.type));
queryClient.invalidateQueries(["org-admin-projects"]);
}
});
@@ -324,7 +342,7 @@ export const useCreateWsEnvironment = () => {
});
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(ProjectType.SecretManager));
}
});
};
@@ -341,7 +359,7 @@ export const useUpdateWsEnvironment = () => {
});
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(ProjectType.SecretManager));
}
});
};
@@ -354,7 +372,7 @@ export const useDeleteWsEnvironment = () => {
return apiRequest.delete(`/api/v1/workspace/${workspaceId}/environments/${id}`);
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace(ProjectType.SecretManager));
}
});
};
@@ -11,7 +11,8 @@ export const workspaceKeys = {
getWorkspaceMemberships: (orgId: string) => [{ orgId }, "workspace-memberships"],
getWorkspaceAuthorization: (workspaceId: string) => [{ workspaceId }, "workspace-authorizations"],
getWorkspaceIntegrations: (workspaceId: string) => [{ workspaceId }, "workspace-integrations"],
getAllUserWorkspace: ["workspaces"] as const,
getAllUserWorkspace: (type?: string) =>
type ? ["workspaces", { type }] : (["workspace"] as const),
getWorkspaceAuditLogs: (workspaceId: string) =>
[{ workspaceId }, "workspace-audit-logs"] as const,
getWorkspaceUsers: (workspaceId: string) => [{ workspaceId }, "workspace-users"] as const,
@@ -8,6 +8,13 @@ export enum ProjectVersion {
V3 = 3
}
export enum ProjectType {
SecretManager = "secret-manager",
CertificateManager = "cert-manager",
KMS = "kms",
SSH = "ssh"
}
export enum ProjectUserMembershipTemporaryMode {
Relative = "relative"
}
@@ -16,6 +23,7 @@ export type Workspace = {
__v: number;
id: string;
name: string;
type: ProjectType;
description?: string;
orgId: string;
version: ProjectVersion;
@@ -59,6 +67,7 @@ export type CreateWorkspaceDTO = {
projectDescription?: string;
kmsKeyId?: string;
template?: string;
type: ProjectType;
};
export type UpdateProjectDTO = {