From 98a15a901ec17c38c9312ce0e5196b45524475ba Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Wed, 26 Jun 2024 22:45:14 +0800 Subject: [PATCH 001/117] feat: allowed toggling login options as admin --- ...0240626115035_admin-login-method-config.ts | 19 ++ backend/src/db/schemas/super-admin.ts | 3 +- backend/src/server/routes/v1/admin-router.ts | 10 +- .../services/super-admin/super-admin-types.ts | 10 + frontend/src/hooks/api/admin/types.ts | 11 + .../components/InitialStep/InitialStep.tsx | 321 ++++++++++-------- .../views/admin/DashboardPage/AuthPanel.tsx | 251 ++++++++++++++ .../admin/DashboardPage/DashboardPage.tsx | 9 +- 8 files changed, 488 insertions(+), 146 deletions(-) create mode 100644 backend/src/db/migrations/20240626115035_admin-login-method-config.ts create mode 100644 frontend/src/views/admin/DashboardPage/AuthPanel.tsx diff --git a/backend/src/db/migrations/20240626115035_admin-login-method-config.ts b/backend/src/db/migrations/20240626115035_admin-login-method-config.ts new file mode 100644 index 000000000..8748fe753 --- /dev/null +++ b/backend/src/db/migrations/20240626115035_admin-login-method-config.ts @@ -0,0 +1,19 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + if (!(await knex.schema.hasColumn(TableName.SuperAdmin, "enabledLoginMethods"))) { + await knex.schema.alterTable(TableName.SuperAdmin, (tb) => { + tb.specificType("enabledLoginMethods", "text[]"); + }); + } +} + +export async function down(knex: Knex): Promise { + if (await knex.schema.hasColumn(TableName.SuperAdmin, "enabledLoginMethods")) { + await knex.schema.alterTable(TableName.SuperAdmin, (t) => { + t.dropColumn("enabledLoginMethods"); + }); + } +} diff --git a/backend/src/db/schemas/super-admin.ts b/backend/src/db/schemas/super-admin.ts index 29e41c78e..b676b81a8 100644 --- a/backend/src/db/schemas/super-admin.ts +++ b/backend/src/db/schemas/super-admin.ts @@ -18,7 +18,8 @@ export const SuperAdminSchema = z.object({ trustSamlEmails: z.boolean().default(false).nullable().optional(), trustLdapEmails: z.boolean().default(false).nullable().optional(), trustOidcEmails: z.boolean().default(false).nullable().optional(), - defaultAuthOrgId: z.string().uuid().nullable().optional() + defaultAuthOrgId: z.string().uuid().nullable().optional(), + enabledLoginMethods: z.string().array().nullable().optional() }); export type TSuperAdmin = z.infer; diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index 24c7e2a6e..4557152bd 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -8,6 +8,7 @@ import { verifySuperAdmin } from "@app/server/plugins/auth/superAdmin"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; import { getServerCfg } from "@app/services/super-admin/super-admin-service"; +import { LoginMethod } from "@app/services/super-admin/super-admin-types"; import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types"; export const registerAdminRouter = async (server: FastifyZodProvider) => { @@ -54,7 +55,14 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { trustSamlEmails: z.boolean().optional(), trustLdapEmails: z.boolean().optional(), trustOidcEmails: z.boolean().optional(), - defaultAuthOrgId: z.string().optional().nullable() + defaultAuthOrgId: z.string().optional().nullable(), + enabledLoginMethods: z + .nativeEnum(LoginMethod) + .array() + .optional() + .refine((methods) => !methods || methods.length > 0, { + message: "At least one login method should be enabled." + }) }), response: { 200: z.object({ diff --git a/backend/src/services/super-admin/super-admin-types.ts b/backend/src/services/super-admin/super-admin-types.ts index e444c8843..f622c8f17 100644 --- a/backend/src/services/super-admin/super-admin-types.ts +++ b/backend/src/services/super-admin/super-admin-types.ts @@ -15,3 +15,13 @@ export type TAdminSignUpDTO = { ip: string; userAgent: string; }; + +export enum LoginMethod { + EMAIL = "email", + GOOGLE = "google", + GITHUB = "github", + GITLAB = "gitlab", + SAML = "saml", + LDAP = "ldap", + OIDC = "oidc" +} diff --git a/frontend/src/hooks/api/admin/types.ts b/frontend/src/hooks/api/admin/types.ts index 524bc6ace..4d5add1e0 100644 --- a/frontend/src/hooks/api/admin/types.ts +++ b/frontend/src/hooks/api/admin/types.ts @@ -1,3 +1,13 @@ +export enum LoginMethod { + EMAIL = "email", + GOOGLE = "google", + GITHUB = "github", + GITLAB = "gitlab", + SAML = "saml", + LDAP = "ldap", + OIDC = "oidc" +} + export type TServerConfig = { initialized: boolean; allowSignUp: boolean; @@ -9,6 +19,7 @@ export type TServerConfig = { isSecretScanningDisabled: boolean; defaultAuthOrgSlug: string | null; defaultAuthOrgId: string | null; + enabledLoginMethods: LoginMethod[]; }; export type TCreateAdminUserDTO = { diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx index 0616ee58d..83615ccf5 100644 --- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx +++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx @@ -15,6 +15,7 @@ import { CAPTCHA_SITE_KEY } from "@app/components/utilities/config"; import { Button, Input } from "@app/components/v2"; import { useServerConfig } from "@app/context"; import { useFetchServerStatus } from "@app/hooks/api"; +import { LoginMethod } from "@app/hooks/api/admin/types"; import { useNavigateToSelectOrganization } from "../../Login.utils"; @@ -162,154 +163,188 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }:

Login to Infisical

-
- -
-
- +
+ ))} + {!config.enabledLoginMethods || + (config.enabledLoginMethods.includes(LoginMethod.GITHUB) && ( +
+ -
-
- +
+ ))} + {!config.enabledLoginMethods || + (config.enabledLoginMethods.includes(LoginMethod.GITLAB) && ( +
+ -
-
- -
-
- -
-
- -
-
-
- or -
-
-
- setEmail(e.target.value)} - type="email" - placeholder="Enter your email..." - isRequired - autoComplete="username" - className="h-10" - /> -
-
- setPassword(e.target.value)} - type="password" - placeholder="Enter your password..." - isRequired - autoComplete="current-password" - id="current-password" - className="select:-webkit-autofill:focus h-10" - /> -
- {shouldShowCaptcha && ( -
- setCaptchaToken(token)} - ref={captchaRef} - /> -
- )} -
- -
+ window.close(); + }} + leftIcon={} + className="mx-0 h-10 w-full" + > + Continue with GitLab + +
+ ))} + {!config.enabledLoginMethods || + (config.enabledLoginMethods.includes(LoginMethod.SAML) && ( +
+ +
+ ))} + {!config.enabledLoginMethods || + (config.enabledLoginMethods.includes(LoginMethod.OIDC) && ( +
+ +
+ ))} + {!config.enabledLoginMethods || + (config.enabledLoginMethods.includes(LoginMethod.LDAP) && ( +
+ +
+ ))} + + {!config.enabledLoginMethods || + (config.enabledLoginMethods.length > 1 && + config.enabledLoginMethods.includes(LoginMethod.EMAIL) && ( +
+
+ or +
+
+ ))} + {!config.enabledLoginMethods || + (config.enabledLoginMethods.includes(LoginMethod.EMAIL) && ( + <> +
+ setEmail(e.target.value)} + type="email" + placeholder="Enter your email..." + isRequired + autoComplete="username" + className="h-10" + /> +
+
+ setPassword(e.target.value)} + type="password" + placeholder="Enter your password..." + isRequired + autoComplete="current-password" + id="current-password" + className="select:-webkit-autofill:focus h-10" + /> +
+ {shouldShowCaptcha && ( +
+ setCaptchaToken(token)} + ref={captchaRef} + /> +
+ )} +
+ +
+ + ))} {!isLoading && loginError && } {config.allowSignUp ? (
diff --git a/frontend/src/views/admin/DashboardPage/AuthPanel.tsx b/frontend/src/views/admin/DashboardPage/AuthPanel.tsx new file mode 100644 index 000000000..0060cb095 --- /dev/null +++ b/frontend/src/views/admin/DashboardPage/AuthPanel.tsx @@ -0,0 +1,251 @@ +import { Controller, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { createNotification } from "@app/components/notifications"; +import { Button, FormControl, Switch } from "@app/components/v2"; +import { useServerConfig } from "@app/context"; +import { useUpdateServerConfig } from "@app/hooks/api"; +import { LoginMethod } from "@app/hooks/api/admin/types"; + +const formSchema = z.object({ + isEmailEnabled: z.boolean(), + isGoogleEnabled: z.boolean(), + isGithubEnabled: z.boolean(), + isGitlabEnabled: z.boolean(), + isSamlEnabled: z.boolean(), + isLdapEnabled: z.boolean(), + isOidcEnabled: z.boolean() +}); + +type TAuthForm = z.infer; + +export const AuthPanel = () => { + const { config } = useServerConfig(); + const { enabledLoginMethods } = config; + const { mutateAsync: updateServerConfig } = useUpdateServerConfig(); + + const { + control, + handleSubmit, + formState: { isSubmitting, isDirty } + } = useForm({ + resolver: zodResolver(formSchema), + values: enabledLoginMethods + ? { + isEmailEnabled: enabledLoginMethods.includes(LoginMethod.EMAIL), + isGoogleEnabled: enabledLoginMethods.includes(LoginMethod.GOOGLE), + isGithubEnabled: enabledLoginMethods.includes(LoginMethod.GITHUB), + isGitlabEnabled: enabledLoginMethods.includes(LoginMethod.GITLAB), + isSamlEnabled: enabledLoginMethods.includes(LoginMethod.SAML), + isLdapEnabled: enabledLoginMethods.includes(LoginMethod.LDAP), + isOidcEnabled: enabledLoginMethods.includes(LoginMethod.OIDC) + } + : { + isEmailEnabled: true, + isGoogleEnabled: true, + isGithubEnabled: true, + isGitlabEnabled: true, + isSamlEnabled: true, + isLdapEnabled: true, + isOidcEnabled: true + } + }); + + const onAuthFormSubmit = async (formData: TAuthForm) => { + try { + const enabledMethods: LoginMethod[] = []; + if (formData.isEmailEnabled) { + enabledMethods.push(LoginMethod.EMAIL); + } + + if (formData.isGoogleEnabled) { + enabledMethods.push(LoginMethod.GOOGLE); + } + + if (formData.isGithubEnabled) { + enabledMethods.push(LoginMethod.GITHUB); + } + + if (formData.isGitlabEnabled) { + enabledMethods.push(LoginMethod.GITLAB); + } + + if (formData.isSamlEnabled) { + enabledMethods.push(LoginMethod.SAML); + } + + if (formData.isLdapEnabled) { + enabledMethods.push(LoginMethod.LDAP); + } + + if (formData.isOidcEnabled) { + enabledMethods.push(LoginMethod.OIDC); + } + + if (!enabledMethods.length) { + createNotification({ + type: "error", + text: "At least one login method should be enabled." + }); + return; + } + + await updateServerConfig({ + enabledLoginMethods: enabledMethods + }); + + createNotification({ + text: "Login methods have been successfully updated.", + type: "success" + }); + } catch (e) { + console.error(e); + createNotification({ + type: "error", + text: "Failed to update login methods." + }); + } + }; + + return ( +
+
+
Login Methods
+
+ Select the login methods available to users +
+ { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

Email

+
+
+ ); + }} + /> + { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

Google SSO

+
+
+ ); + }} + /> + { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

Github SSO

+
+
+ ); + }} + /> + { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

Gitlab SSO

+
+
+ ); + }} + /> + { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

SAML SSO

+
+
+ ); + }} + /> + { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

OIDC SSO

+
+
+ ); + }} + /> +
+ { + return ( + + field.onChange(value)} + isChecked={field.value} + > +

LDAP

+
+
+ ); + }} + /> + + + ); +}; diff --git a/frontend/src/views/admin/DashboardPage/DashboardPage.tsx b/frontend/src/views/admin/DashboardPage/DashboardPage.tsx index 134a67f8c..bf8a5a4a9 100644 --- a/frontend/src/views/admin/DashboardPage/DashboardPage.tsx +++ b/frontend/src/views/admin/DashboardPage/DashboardPage.tsx @@ -24,10 +24,12 @@ import { import { useOrganization, useServerConfig, useUser } from "@app/context"; import { useGetOrganizations, useUpdateServerConfig } from "@app/hooks/api"; +import { AuthPanel } from "./AuthPanel"; import { RateLimitPanel } from "./RateLimitPanel"; enum TabSections { Settings = "settings", + Auth = "auth", RateLimit = "rate-limit" } @@ -131,6 +133,7 @@ export const AdminDashboardPage = () => {
General + Auth Rate Limit
@@ -203,7 +206,8 @@ export const AdminDashboardPage = () => { Default organization
- Select the default organization you want to set for SAML/LDAP based logins. When selected, user logins will be automatically scoped to the selected organization. + Select the default organization you want to set for SAML/LDAP based logins. When + selected, user logins will be automatically scoped to the selected organization.
{ + + + From e1ed37c7135caf3e916bcbd9d56e182bdb44ab4d Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 01:07:28 +0800 Subject: [PATCH 002/117] misc: adjusted OrgSettingsPage and PersonalSettingsPage to include toggle --- .../components/OrgAuthTab/OrgAuthTab.tsx | 26 +++++++++++++++---- .../OrgAuthTab/OrgGeneralAuthSection.tsx | 2 +- .../components/OrgAuthTab/OrgLDAPSection.tsx | 2 +- .../components/OrgAuthTab/OrgOIDCSection.tsx | 2 +- .../components/OrgAuthTab/OrgSSOSection.tsx | 3 ++- .../AuthMethodSection/AuthMethodSection.tsx | 23 +++++++++++----- 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgAuthTab.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgAuthTab.tsx index 31d6987bd..b1a079922 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgAuthTab.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgAuthTab.tsx @@ -1,5 +1,8 @@ -import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; +import { useCallback } from "react"; + +import { OrgPermissionActions, OrgPermissionSubjects, useServerConfig } from "@app/context"; import { withPermission } from "@app/hoc"; +import { LoginMethod } from "@app/hooks/api/admin/types"; import { OrgGeneralAuthSection } from "./OrgGeneralAuthSection"; import { OrgLDAPSection } from "./OrgLDAPSection"; @@ -9,12 +12,25 @@ import { OrgSSOSection } from "./OrgSSOSection"; export const OrgAuthTab = withPermission( () => { + const { + config: { enabledLoginMethods } + } = useServerConfig(); + + const shouldDisplaySection = useCallback( + (method: LoginMethod) => !enabledLoginMethods || enabledLoginMethods.includes(method), + [enabledLoginMethods] + ); + return (
- - - - + {shouldDisplaySection(LoginMethod.SAML) && ( + <> + + + + )} + {shouldDisplaySection(LoginMethod.OIDC) && } + {shouldDisplaySection(LoginMethod.LDAP) && }
); diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgGeneralAuthSection.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgGeneralAuthSection.tsx index 7c3af9493..6e4eca456 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgGeneralAuthSection.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgGeneralAuthSection.tsx @@ -11,7 +11,6 @@ import { useLogoutUser, useUpdateOrg } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; export const OrgGeneralAuthSection = () => { - const { currentOrg } = useOrganization(); const { subscription } = useSubscription(); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["upgradePlan"] as const); @@ -88,6 +87,7 @@ export const OrgGeneralAuthSection = () => { Enforce members to authenticate via SAML to access this organization

+
handlePopUpToggle("upgradePlan", isOpen)} diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx index 87d0f28af..0d34fcefc 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx @@ -94,7 +94,6 @@ export const OrgLDAPSection = (): JSX.Element => { return ( <> -

LDAP

@@ -151,6 +150,7 @@ export const OrgLDAPSection = (): JSX.Element => {

)} +
{ return ( <> -

OIDC

@@ -103,6 +102,7 @@ export const OrgOIDCSection = (): JSX.Element => {

)} +
{ const { currentOrg } = useOrganization(); const { subscription } = useSubscription(); - + const { data, isLoading } = useGetSSOConfig(currentOrg?.id ?? ""); const { mutateAsync } = useUpdateSSOConfig(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ @@ -115,6 +115,7 @@ export const OrgSSOSection = (): JSX.Element => { Allow members to authenticate into Infisical with SAML

+
; export const AuthMethodSection = () => { - const { user } = useUser(); + const { config } = useServerConfig(); const { mutateAsync } = useUpdateUserAuthMethods(); const { reset, setValue, watch } = useForm({ @@ -102,6 +103,14 @@ export const AuthMethodSection = () => {
{user && authMethodOpts.map((authMethodOpt) => { + // only filter when enabledLoginMethods is explicitly configured by admin + if ( + config.enabledLoginMethods && + !config.enabledLoginMethods.includes(authMethodOpt.loginMethod) + ) { + return null; + } + return (
From 9daa5badec8657f8fd0b8e3f8f129824e30bcd65 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 01:15:50 +0800 Subject: [PATCH 003/117] misc: made reusable helper for login page --- .../components/InitialStep/InitialStep.tsx | 339 +++++++++--------- 1 file changed, 165 insertions(+), 174 deletions(-) diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx index 83615ccf5..d97126f67 100644 --- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx +++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx @@ -62,6 +62,12 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }: } }, []); + const shouldDisplayLoginMethod = useCallback( + (method: LoginMethod) => + !config.enabledLoginMethods || config.enabledLoginMethods.includes(method), + [config] + ); + const handleLogin = async (e: FormEvent) => { e.preventDefault(); try { @@ -163,188 +169,173 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }:

Login to Infisical

- {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.GOOGLE) && ( -
- -
- ))} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.GITHUB) && ( -
- +
+ )} + {shouldDisplayLoginMethod(LoginMethod.GITHUB) && ( +
+ -
- ))} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.GITLAB) && ( -
- +
+ )} + {shouldDisplayLoginMethod(LoginMethod.GITLAB) && ( +
+ -
- ))} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.SAML) && ( -
- -
- ))} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.OIDC) && ( -
- -
- ))} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.LDAP) && ( -
- -
- ))} + window.close(); + }} + leftIcon={} + className="mx-0 h-10 w-full" + > + Continue with GitLab + +
+ )} + {shouldDisplayLoginMethod(LoginMethod.SAML) && ( +
+ +
+ )} + {shouldDisplayLoginMethod(LoginMethod.OIDC) && ( +
+ +
+ )} + {shouldDisplayLoginMethod(LoginMethod.LDAP) && ( +
+ +
+ )} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.length > 1 && - config.enabledLoginMethods.includes(LoginMethod.EMAIL) && ( -
-
- or -
-
- ))} - {!config.enabledLoginMethods || - (config.enabledLoginMethods.includes(LoginMethod.EMAIL) && ( - <> -
- setEmail(e.target.value)} - type="email" - placeholder="Enter your email..." - isRequired - autoComplete="username" - className="h-10" + {shouldDisplayLoginMethod(LoginMethod.EMAIL) && config.enabledLoginMethods.length > 1 && ( +
+
+ or +
+
+ )} + {shouldDisplayLoginMethod(LoginMethod.EMAIL) && ( + <> +
+ setEmail(e.target.value)} + type="email" + placeholder="Enter your email..." + isRequired + autoComplete="username" + className="h-10" + /> +
+
+ setPassword(e.target.value)} + type="password" + placeholder="Enter your password..." + isRequired + autoComplete="current-password" + id="current-password" + className="select:-webkit-autofill:focus h-10" + /> +
+ {shouldShowCaptcha && ( +
+ setCaptchaToken(token)} + ref={captchaRef} />
-
- setPassword(e.target.value)} - type="password" - placeholder="Enter your password..." - isRequired - autoComplete="current-password" - id="current-password" - className="select:-webkit-autofill:focus h-10" - /> -
- {shouldShowCaptcha && ( -
- setCaptchaToken(token)} - ref={captchaRef} - /> -
- )} -
- -
- - ))} + )} +
+ +
+ + )} {!isLoading && loginError && } {config.allowSignUp ? (
From db39d03713403206725d1e2d0344020ab648074f Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 01:59:02 +0800 Subject: [PATCH 004/117] misc: added check to backend --- .../src/services/auth/auth-login-service.ts | 35 +++++++++++++++++++ .../components/InitialStep/InitialStep.tsx | 4 +-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index 8090b937a..8207e4bec 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -17,6 +17,7 @@ import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service"; import { TokenType } from "../auth-token/auth-token-types"; import { TOrgDALFactory } from "../org/org-dal"; import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; +import { LoginMethod } from "../super-admin/super-admin-types"; import { TUserDALFactory } from "../user/user-dal"; import { enforceUserLockStatus, validateProviderAuthToken } from "./auth-fns"; import { @@ -507,6 +508,40 @@ export const authLoginServiceFactory = ({ let user = await userDAL.findUserByUsername(email); const serverCfg = await getServerCfg(); + if (serverCfg.enabledLoginMethods) { + switch (authMethod) { + case AuthMethod.GITHUB: { + if (!serverCfg.enabledLoginMethods.includes(LoginMethod.GITHUB)) { + throw new BadRequestError({ + message: "Login with Github is disabled.", + name: "Oauth 2 login" + }); + } + break; + } + case AuthMethod.GOOGLE: { + if (!serverCfg.enabledLoginMethods.includes(LoginMethod.GOOGLE)) { + throw new BadRequestError({ + message: "Login with Google is disabled.", + name: "Oauth 2 login" + }); + } + break; + } + case AuthMethod.GITLAB: { + if (!serverCfg.enabledLoginMethods.includes(LoginMethod.GITLAB)) { + throw new BadRequestError({ + message: "Login with Gitlab is disabled.", + name: "Oauth 2 login" + }); + } + break; + } + default: + break; + } + } + const appCfg = getConfig(); if (!user) { diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx index d97126f67..99e80048a 100644 --- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx +++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx @@ -276,8 +276,8 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }:
)} - - {shouldDisplayLoginMethod(LoginMethod.EMAIL) && config.enabledLoginMethods.length > 1 && ( + {(!config.enabledLoginMethods || + (shouldDisplayLoginMethod(LoginMethod.EMAIL) && config.enabledLoginMethods.length > 1)) && (
or From c460f226650313ad1ff271d2113829d9cc14966f Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 12:40:56 +0800 Subject: [PATCH 005/117] misc: added backend disable checks --- .../ee/services/ldap-config/ldap-config-service.ts | 8 ++++++++ backend/src/ee/services/oidc/oidc-config-service.ts | 8 ++++++++ .../ee/services/saml-config/saml-config-service.ts | 8 ++++++++ backend/src/services/auth/auth-login-service.ts | 13 +++++++++++++ 4 files changed, 37 insertions(+) diff --git a/backend/src/ee/services/ldap-config/ldap-config-service.ts b/backend/src/ee/services/ldap-config/ldap-config-service.ts index 63565d94c..7434862fc 100644 --- a/backend/src/ee/services/ldap-config/ldap-config-service.ts +++ b/backend/src/ee/services/ldap-config/ldap-config-service.ts @@ -34,6 +34,7 @@ import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal import { TProjectKeyDALFactory } from "@app/services/project-key/project-key-dal"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { getServerCfg } from "@app/services/super-admin/super-admin-service"; +import { LoginMethod } from "@app/services/super-admin/super-admin-types"; import { TUserDALFactory } from "@app/services/user/user-dal"; import { normalizeUsername } from "@app/services/user/user-fns"; import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal"; @@ -411,6 +412,13 @@ export const ldapConfigServiceFactory = ({ }: TLdapLoginDTO) => { const appCfg = getConfig(); const serverCfg = await getServerCfg(); + + if (serverCfg.enabledLoginMethods && !serverCfg.enabledLoginMethods.includes(LoginMethod.LDAP)) { + throw new BadRequestError({ + message: "Login with LDAP is disabled." + }); + } + let userAlias = await userAliasDAL.findOne({ externalId, orgId, diff --git a/backend/src/ee/services/oidc/oidc-config-service.ts b/backend/src/ee/services/oidc/oidc-config-service.ts index b983492bc..58b098522 100644 --- a/backend/src/ee/services/oidc/oidc-config-service.ts +++ b/backend/src/ee/services/oidc/oidc-config-service.ts @@ -26,6 +26,7 @@ import { TOrgDALFactory } from "@app/services/org/org-dal"; import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { getServerCfg } from "@app/services/super-admin/super-admin-service"; +import { LoginMethod } from "@app/services/super-admin/super-admin-types"; import { TUserDALFactory } from "@app/services/user/user-dal"; import { normalizeUsername } from "@app/services/user/user-fns"; import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal"; @@ -157,6 +158,13 @@ export const oidcConfigServiceFactory = ({ const oidcLogin = async ({ externalId, email, firstName, lastName, orgId, callbackPort }: TOidcLoginDTO) => { const serverCfg = await getServerCfg(); + + if (serverCfg.enabledLoginMethods && !serverCfg.enabledLoginMethods.includes(LoginMethod.OIDC)) { + throw new BadRequestError({ + message: "Login with OIDC is disabled." + }); + } + const appCfg = getConfig(); const userAlias = await userAliasDAL.findOne({ externalId, diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index 3cc51e1c2..286a85746 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -28,6 +28,7 @@ import { TOrgDALFactory } from "@app/services/org/org-dal"; import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { getServerCfg } from "@app/services/super-admin/super-admin-service"; +import { LoginMethod } from "@app/services/super-admin/super-admin-types"; import { TUserDALFactory } from "@app/services/user/user-dal"; import { normalizeUsername } from "@app/services/user/user-fns"; import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal"; @@ -335,6 +336,13 @@ export const samlConfigServiceFactory = ({ }: TSamlLoginDTO) => { const appCfg = getConfig(); const serverCfg = await getServerCfg(); + + if (serverCfg.enabledLoginMethods && !serverCfg.enabledLoginMethods.includes(LoginMethod.SAML)) { + throw new BadRequestError({ + message: "Login with SAML is disabled." + }); + } + const userAlias = await userAliasDAL.findOne({ externalId, orgId, diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index 8207e4bec..24ae087b7 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -159,9 +159,22 @@ export const authLoginServiceFactory = ({ const userEnc = await userDAL.findUserEncKeyByUsername({ username: email }); + const serverCfg = await getServerCfg(); + + if ( + serverCfg.enabledLoginMethods && + !serverCfg.enabledLoginMethods.includes(LoginMethod.EMAIL) && + !providerAuthToken + ) { + throw new BadRequestError({ + message: "Login with email is disabled." + }); + } + if (!userEnc || (userEnc && !userEnc.isAccepted)) { throw new Error("Failed to find user"); } + if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) { validateProviderAuthToken(providerAuthToken as string, email); } From b3463e0d0fe563ccc8f5c4a744aaf618d1c0020f Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 12:55:39 +0800 Subject: [PATCH 006/117] misc: added explicit comment of intent --- frontend/src/views/admin/DashboardPage/AuthPanel.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/views/admin/DashboardPage/AuthPanel.tsx b/frontend/src/views/admin/DashboardPage/AuthPanel.tsx index 0060cb095..f2fab83ec 100644 --- a/frontend/src/views/admin/DashboardPage/AuthPanel.tsx +++ b/frontend/src/views/admin/DashboardPage/AuthPanel.tsx @@ -31,6 +31,7 @@ export const AuthPanel = () => { formState: { isSubmitting, isDirty } } = useForm({ resolver: zodResolver(formSchema), + // if not yet explicitly defined by the admin, all login methods should be enabled by default values: enabledLoginMethods ? { isEmailEnabled: enabledLoginMethods.includes(LoginMethod.EMAIL), From 92a663a17d3f1f3879ea45e3c80d1778148c041c Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 13:24:26 +0800 Subject: [PATCH 007/117] misc: design change to finalize scim section in org settings --- .../OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx index 601643db8..ffec3f355 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx @@ -13,7 +13,6 @@ import { usePopUp } from "@app/hooks/usePopUp"; import { ScimTokenModal } from "./ScimTokenModal"; export const OrgScimSection = () => { - const { currentOrg } = useOrganization(); const { subscription } = useSubscription(); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([ @@ -59,7 +58,6 @@ export const OrgScimSection = () => { return ( <> -

SCIM

From d6881e2e6831429ded24526e21ff210812e71af9 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Thu, 27 Jun 2024 13:53:12 +0800 Subject: [PATCH 008/117] misc: added signup option filtering --- .../components/signup/InitialSignupStep.tsx | 129 ++++++++++-------- 1 file changed, 74 insertions(+), 55 deletions(-) diff --git a/frontend/src/components/signup/InitialSignupStep.tsx b/frontend/src/components/signup/InitialSignupStep.tsx index e5c23f333..8df675913 100644 --- a/frontend/src/components/signup/InitialSignupStep.tsx +++ b/frontend/src/components/signup/InitialSignupStep.tsx @@ -1,9 +1,13 @@ +import { useCallback } from "react"; import { useTranslation } from "react-i18next"; import Link from "next/link"; import { faGithub, faGitlab, faGoogle } from "@fortawesome/free-brands-svg-icons"; import { faEnvelope } from "@fortawesome/free-regular-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useServerConfig } from "@app/context"; +import { LoginMethod } from "@app/hooks/api/admin/types"; + import { Button } from "../v2"; export default function InitialSignupStep({ @@ -12,67 +16,82 @@ export default function InitialSignupStep({ setIsSignupWithEmail: (value: boolean) => void; }) { const { t } = useTranslation(); + const { config } = useServerConfig(); + + const shouldDisplaySignupMethod = useCallback( + (method: LoginMethod) => + !config.enabledLoginMethods || config.enabledLoginMethods.includes(method), + [config] + ); return (

{t("signup.initial-title")}

-
- -
-
- -
-
- -
-
- -
+ {shouldDisplaySignupMethod(LoginMethod.GOOGLE) && ( +
+ +
+ )} + {shouldDisplaySignupMethod(LoginMethod.GITHUB) && ( +
+ +
+ )} + {shouldDisplaySignupMethod(LoginMethod.GITLAB) && ( +
+ +
+ )} + {shouldDisplaySignupMethod(LoginMethod.EMAIL) && ( +
+ +
+ )}
{t("signup.create-policy")}
From 59fc34412dde33add0068a73d2e93af344e3bdbe Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Thu, 27 Jun 2024 20:35:15 -0400 Subject: [PATCH 009/117] small nits for admin login toggle pr --- .../src/ee/services/ldap-config/ldap-config-service.ts | 2 +- backend/src/ee/services/oidc/oidc-config-service.ts | 2 +- .../src/ee/services/saml-config/saml-config-service.ts | 2 +- backend/src/services/auth/auth-login-service.ts | 8 ++++---- frontend/src/views/admin/DashboardPage/AuthPanel.tsx | 2 +- frontend/src/views/admin/DashboardPage/DashboardPage.tsx | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/backend/src/ee/services/ldap-config/ldap-config-service.ts b/backend/src/ee/services/ldap-config/ldap-config-service.ts index 7434862fc..55129ca02 100644 --- a/backend/src/ee/services/ldap-config/ldap-config-service.ts +++ b/backend/src/ee/services/ldap-config/ldap-config-service.ts @@ -415,7 +415,7 @@ export const ldapConfigServiceFactory = ({ if (serverCfg.enabledLoginMethods && !serverCfg.enabledLoginMethods.includes(LoginMethod.LDAP)) { throw new BadRequestError({ - message: "Login with LDAP is disabled." + message: "Login with LDAP is disabled by administrator." }); } diff --git a/backend/src/ee/services/oidc/oidc-config-service.ts b/backend/src/ee/services/oidc/oidc-config-service.ts index 58b098522..55c929b9a 100644 --- a/backend/src/ee/services/oidc/oidc-config-service.ts +++ b/backend/src/ee/services/oidc/oidc-config-service.ts @@ -161,7 +161,7 @@ export const oidcConfigServiceFactory = ({ if (serverCfg.enabledLoginMethods && !serverCfg.enabledLoginMethods.includes(LoginMethod.OIDC)) { throw new BadRequestError({ - message: "Login with OIDC is disabled." + message: "Login with OIDC is disabled by administrator." }); } diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index 286a85746..9ac6c9c5e 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -339,7 +339,7 @@ export const samlConfigServiceFactory = ({ if (serverCfg.enabledLoginMethods && !serverCfg.enabledLoginMethods.includes(LoginMethod.SAML)) { throw new BadRequestError({ - message: "Login with SAML is disabled." + message: "Login with SAML is disabled by administrator." }); } diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index 24ae087b7..2ce900b47 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -167,7 +167,7 @@ export const authLoginServiceFactory = ({ !providerAuthToken ) { throw new BadRequestError({ - message: "Login with email is disabled." + message: "Login with email is disabled by administrator." }); } @@ -526,7 +526,7 @@ export const authLoginServiceFactory = ({ case AuthMethod.GITHUB: { if (!serverCfg.enabledLoginMethods.includes(LoginMethod.GITHUB)) { throw new BadRequestError({ - message: "Login with Github is disabled.", + message: "Login with Github is disabled by administrator.", name: "Oauth 2 login" }); } @@ -535,7 +535,7 @@ export const authLoginServiceFactory = ({ case AuthMethod.GOOGLE: { if (!serverCfg.enabledLoginMethods.includes(LoginMethod.GOOGLE)) { throw new BadRequestError({ - message: "Login with Google is disabled.", + message: "Login with Google is disabled by administrator.", name: "Oauth 2 login" }); } @@ -544,7 +544,7 @@ export const authLoginServiceFactory = ({ case AuthMethod.GITLAB: { if (!serverCfg.enabledLoginMethods.includes(LoginMethod.GITLAB)) { throw new BadRequestError({ - message: "Login with Gitlab is disabled.", + message: "Login with Gitlab is disabled by administrator.", name: "Oauth 2 login" }); } diff --git a/frontend/src/views/admin/DashboardPage/AuthPanel.tsx b/frontend/src/views/admin/DashboardPage/AuthPanel.tsx index f2fab83ec..84e48ea0f 100644 --- a/frontend/src/views/admin/DashboardPage/AuthPanel.tsx +++ b/frontend/src/views/admin/DashboardPage/AuthPanel.tsx @@ -117,7 +117,7 @@ export const AuthPanel = () => {
Login Methods
- Select the login methods available to users + Select the login methods you wish to allow for all users of this instance.
{

Admin Dashboard

-

Manage your Infisical instance.

+

Manage your instance level configurations.

{isUserLoading || isNotAllowed ? ( @@ -133,7 +133,7 @@ export const AdminDashboardPage = () => {
General - Auth + Authentication Rate Limit
From 04f54479cd6a968f2fd1e6e5bcc5459ddfa98fbd Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Sat, 29 Jun 2024 01:58:27 +0800 Subject: [PATCH 010/117] misc: implemented review comments --- backend/src/server/routes/v1/admin-router.ts | 2 +- .../super-admin/super-admin-service.ts | 37 +++++++++++++++++-- .../components/InitialStep/InitialStep.tsx | 6 ++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index 4557152bd..73d6cc7e7 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -78,7 +78,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { }); }, handler: async (req) => { - const config = await server.services.superAdmin.updateServerCfg(req.body); + const config = await server.services.superAdmin.updateServerCfg(req.body, req.permission.id); return { config }; } }); diff --git a/backend/src/services/super-admin/super-admin-service.ts b/backend/src/services/super-admin/super-admin-service.ts index 41b97efa4..a51282db6 100644 --- a/backend/src/services/super-admin/super-admin-service.ts +++ b/backend/src/services/super-admin/super-admin-service.ts @@ -12,7 +12,7 @@ import { AuthMethod } from "../auth/auth-type"; import { TOrgServiceFactory } from "../org/org-service"; import { TUserDALFactory } from "../user/user-dal"; import { TSuperAdminDALFactory } from "./super-admin-dal"; -import { TAdminSignUpDTO } from "./super-admin-types"; +import { LoginMethod, TAdminSignUpDTO } from "./super-admin-types"; type TSuperAdminServiceFactoryDep = { serverCfgDAL: TSuperAdminDALFactory; @@ -79,7 +79,38 @@ export const superAdminServiceFactory = ({ return newCfg; }; - const updateServerCfg = async (data: TSuperAdminUpdate) => { + const updateServerCfg = async (data: TSuperAdminUpdate, userId: string) => { + if (data.enabledLoginMethods) { + const superAdminUser = await userDAL.findById(userId); + const loginMethodToAuthMethod = { + [LoginMethod.EMAIL]: [AuthMethod.EMAIL], + [LoginMethod.GOOGLE]: [AuthMethod.GOOGLE], + [LoginMethod.GITLAB]: [AuthMethod.GITLAB], + [LoginMethod.GITHUB]: [AuthMethod.GITHUB], + [LoginMethod.LDAP]: [AuthMethod.LDAP], + [LoginMethod.OIDC]: [AuthMethod.OIDC], + [LoginMethod.SAML]: [ + AuthMethod.AZURE_SAML, + AuthMethod.GOOGLE_SAML, + AuthMethod.JUMPCLOUD_SAML, + AuthMethod.KEYCLOAK_SAML, + AuthMethod.OKTA_SAML + ] + }; + + if ( + !data.enabledLoginMethods.some((loginMethod) => + loginMethodToAuthMethod[loginMethod as LoginMethod].some( + (authMethod) => superAdminUser.authMethods?.includes(authMethod) + ) + ) + ) { + throw new BadRequestError({ + message: + "Admin has insufficient authentication methods for update operation to complete without getting locked out." + }); + } + } const updatedServerCfg = await serverCfgDAL.updateById(ADMIN_CONFIG_DB_UUID, data); await keyStore.setItemWithExpiry(ADMIN_CONFIG_KEY, ADMIN_CONFIG_KEY_EXP, JSON.stringify(updatedServerCfg)); @@ -167,7 +198,7 @@ export const superAdminServiceFactory = ({ orgName: initialOrganizationName }); - await updateServerCfg({ initialized: true }); + await updateServerCfg({ initialized: true }, userInfo.user.id); const token = await authService.generateUserTokens({ user: userInfo.user, authMethod: AuthMethod.EMAIL, diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx index 99e80048a..69a418827 100644 --- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx +++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx @@ -337,7 +337,11 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }: )} {!isLoading && loginError && } - {config.allowSignUp ? ( + {config.allowSignUp && + (shouldDisplayLoginMethod(LoginMethod.EMAIL) || + shouldDisplayLoginMethod(LoginMethod.GOOGLE) || + shouldDisplayLoginMethod(LoginMethod.GITHUB) || + shouldDisplayLoginMethod(LoginMethod.GITLAB)) ? (
From 5a1e43be4448fe2d1b069a9338a701414ae521c4 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Sat, 29 Jun 2024 02:12:09 +0800 Subject: [PATCH 011/117] misc: only display recover when email login is enabled --- .../Login/components/InitialStep/InitialStep.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx index 69a418827..06c4df835 100644 --- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx +++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx @@ -352,13 +352,15 @@ export const InitialStep = ({ setStep, email, setEmail, password, setPassword }: ) : (
)} -
- - - Forgot password? Recover your account - - -
+ {shouldDisplayLoginMethod(LoginMethod.EMAIL) && ( +
+ + + Forgot password? Recover your account + + +
+ )} ); }; From ae953add3d9d8925d837cc5edf500e7acd2140ba Mon Sep 17 00:00:00 2001 From: = Date: Tue, 2 Jul 2024 00:12:38 +0530 Subject: [PATCH 012/117] feat: dynamic secret for mssql completed --- backend/package-lock.json | 512 ++++++++++++++++++ backend/package.json | 1 + .../dynamic-secret/providers/models.ts | 3 +- frontend/src/hooks/api/dynamicSecret/types.ts | 3 +- .../SqlDatabaseInputForm.tsx | 37 +- .../EditDynamicSecretSqlProviderForm.tsx | 1 + 6 files changed, 550 insertions(+), 7 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 220d4305c..20a5f7c21 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -73,6 +73,7 @@ "posthog-node": "^3.6.2", "probot": "^13.0.0", "smee-client": "^2.0.0", + "tedious": "^18.2.1", "tweetnacl": "^1.0.3", "tweetnacl-util": "^0.15.1", "uuid": "^9.0.1", @@ -2910,6 +2911,351 @@ "tslib": "^2.3.1" } }, + "node_modules/@azure/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz", + "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-client": "^1.3.0", + "@azure/core-rest-pipeline": "^1.3.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", + "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.1.tgz", + "integrity": "sha512-ExPSbgjwCoht6kB7B4MeZoBAxcQSIl29r/bPeazZJx50ej4JJCByimLOrZoIsurISNyJQQHf30b3JfqC3Hb88A==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.9.0", + "@azure/logger": "^1.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@azure/core-tracing": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", + "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", + "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.3.0.tgz", + "integrity": "sha512-LHZ58/RsIpIWa4hrrE2YuJ/vzG1Jv9f774RfTTAVDZDriubvJ0/S5u4pnw4akJDlS0TiJb6VMphmVUFsWmgodQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.11.1", + "@azure/msal-node": "^2.9.2", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@azure/identity/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@azure/keyvault-keys": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.8.0.tgz", + "integrity": "sha512-jkuYxgkw0aaRfk40OQhFqDIupqblIOIlYESWB6DKCVDxQet1pyv86Tfk9M+5uFM0+mCs6+MUHU+Hxh3joiUn4Q==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.5.0", + "@azure/core-http-compat": "^2.0.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.8.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.0.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.2.tgz", + "integrity": "sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.17.0.tgz", + "integrity": "sha512-csccKXmW2z7EkZ0I3yAoW/offQt+JECdTIV/KrnRoZyM7wCSsQWODpwod8ZhYy7iOyamcHApR9uCh0oD1M+0/A==", + "dependencies": { + "@azure/msal-common": "14.12.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.12.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.12.0.tgz", + "integrity": "sha512-IDDXmzfdwmDkv4SSmMEyAniJf6fDu3FJ7ncOjlxkDuT85uSnLEhZi3fGZpoR7T4XZpOMx9teM9GXBgrfJgyeBw==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.9.2.tgz", + "integrity": "sha512-8tvi6Cos3m+0KmRbPjgkySXi+UQU/QiuVRFnrxIwt5xZlEEFa69O04RTaNESGgImyBBlYbo2mfE8/U8Bbdk1WQ==", + "dependencies": { + "@azure/msal-common": "14.12.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@azure/msal-node/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@casl/ability": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@casl/ability/-/ability-6.5.0.tgz", @@ -3733,6 +4079,11 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@js-joda/core": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.6.3.tgz", + "integrity": "sha512-T1rRxzdqkEXcou0ZprN1q9yDRlvzCPLqmlNt5IIsGBzoEVgLCCYrKEwc84+TvsXuAc95VAZwtWD2zVsKPY4bcA==" + }, "node_modules/@ldapjs/asn1": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-2.0.0.tgz", @@ -6194,6 +6545,20 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, + "node_modules/@types/readable-stream": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.14.tgz", + "integrity": "sha512-xZn/AuUbCMShGsqH/ehZtGDwQtbx00M9rZ2ENLe4tOjFZ/JFeWMhEZkk2fEe1jAUqqEAURIkFJ7Az/go8mM1/w==", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/@types/resolve": { "version": "1.20.6", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", @@ -8015,6 +8380,14 @@ "node": ">= 0.4" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -10145,6 +10518,50 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -10464,6 +10881,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -10686,6 +11117,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -10740,6 +11182,11 @@ "node": ">=10" } }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -11665,6 +12112,11 @@ "node": "^18 || >=20" } }, + "node_modules/native-duplexpair": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", + "integrity": "sha512-E7QQoM+3jvNtlmyfqRZ0/U75VFgCls+fSkbml2MpgWkWyz3ox8Y58gNhfuziuQYGNNQAbFZJQck55LHCnCK6CA==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -12046,6 +12498,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openapi-types": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", @@ -13823,6 +14291,11 @@ "node": ">= 10.x" } }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, "node_modules/sqlstring": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", @@ -13870,6 +14343,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", @@ -14192,6 +14674,36 @@ "node": ">=8.0.0" } }, + "node_modules/tedious": { + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-18.2.1.tgz", + "integrity": "sha512-DKsTgGBC0ZeZexAd5OObfeKd0Tlx3jx3kNoKImsxfBKdRuV216u9n6Sr+4w6vzn+S4r43XmWAXQwM7UkDkbIEg==", + "dependencies": { + "@azure/identity": "^4.2.1", + "@azure/keyvault-keys": "^4.4.0", + "@js-joda/core": "^5.6.1", + "@types/node": ">=18", + "bl": "^6.0.11", + "iconv-lite": "^0.6.3", + "js-md4": "^0.3.2", + "native-duplexpair": "^1.0.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tedious/node_modules/bl": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.13.tgz", + "integrity": "sha512-tMncAcpsyjZgAVbVFupVIaB2xud13xxT59fdHkuszY2jdZkqIWfpQdmII1fOe3kOGAz0mNLTIHEm+KxpYsQKKg==", + "dependencies": { + "@types/readable-stream": "^4.0.0", + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^4.2.0" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/backend/package.json b/backend/package.json index 6ef9add0d..b278be571 100644 --- a/backend/package.json +++ b/backend/package.json @@ -134,6 +134,7 @@ "posthog-node": "^3.6.2", "probot": "^13.0.0", "smee-client": "^2.0.0", + "tedious": "^18.2.1", "tweetnacl": "^1.0.3", "tweetnacl-util": "^0.15.1", "uuid": "^9.0.1", diff --git a/backend/src/ee/services/dynamic-secret/providers/models.ts b/backend/src/ee/services/dynamic-secret/providers/models.ts index c11f6ddfb..14b79eeea 100644 --- a/backend/src/ee/services/dynamic-secret/providers/models.ts +++ b/backend/src/ee/services/dynamic-secret/providers/models.ts @@ -3,7 +3,8 @@ import { z } from "zod"; export enum SqlProviders { Postgres = "postgres", MySQL = "mysql2", - Oracle = "oracledb" + Oracle = "oracledb", + MsSQL = "mssql" } export const DynamicSecretSqlDBSchema = z.object({ diff --git a/frontend/src/hooks/api/dynamicSecret/types.ts b/frontend/src/hooks/api/dynamicSecret/types.ts index a9aab8318..b987e94cc 100644 --- a/frontend/src/hooks/api/dynamicSecret/types.ts +++ b/frontend/src/hooks/api/dynamicSecret/types.ts @@ -24,7 +24,8 @@ export enum DynamicSecretProviders { export enum SqlProviders { Postgres = "postgres", MySql = "mysql2", - Oracle = "oracledb" + Oracle = "oracledb", + MsSQL = "mssql" } export type TDynamicSecretProvider = diff --git a/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx index 0910e137e..6d92641c6 100644 --- a/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx +++ b/frontend/src/views/SecretMainPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx @@ -86,6 +86,14 @@ const getSqlStatements = (provider: SqlProviders) => { 'REVOKE CONNECT FROM "{{username}}";\nREVOKE CREATE SESSION FROM "{{username}}";\nDROP USER "{{username}}";' }; } + if (provider === SqlProviders.MsSQL) { + return { + creationStatement: + "CREATE LOGIN [{{username}}] WITH PASSWORD = '{{password}}';\nCREATE USER [{{username}}] FOR LOGIN [{{username}}];\nGRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [{{username}}];", + renewStatement: "", + revocationStatement: "DROP USER [{{username}}];\nDROP LOGIN [{{username}}];" + }; + } return { creationStatement: @@ -96,6 +104,19 @@ const getSqlStatements = (provider: SqlProviders) => { }; }; +const getDefaultPort = (provider: SqlProviders) => { + switch (provider) { + case SqlProviders.MySql: + return 3306; + case SqlProviders.Oracle: + return 1521; + case SqlProviders.MsSQL: + return 1433; + default: + return 5432; + } +}; + export const SqlDatabaseInputForm = ({ onCompleted, onCancel, @@ -139,6 +160,14 @@ export const SqlDatabaseInputForm = ({ } }; + const handleDatabaseChange = (type: SqlProviders) => { + const sqlStatment = getSqlStatements(type); + setValue("provider.creationStatement", sqlStatment.creationStatement); + setValue("provider.renewStatement", sqlStatment.renewStatement); + setValue("provider.revocationStatement", sqlStatment.revocationStatement); + setValue("provider.port", getDefaultPort(type)); + }; + return (
@@ -155,7 +184,7 @@ export const SqlDatabaseInputForm = ({ isError={Boolean(error)} errorText={error?.message} > - + )} /> @@ -209,16 +238,14 @@ export const SqlDatabaseInputForm = ({ value={value} onValueChange={(val) => { onChange(val); - const sqlStatment = getSqlStatements(val as SqlProviders); - setValue("provider.creationStatement", sqlStatment.creationStatement); - setValue("provider.renewStatement", sqlStatment.renewStatement); - setValue("provider.revocationStatement", sqlStatment.revocationStatement); + handleDatabaseChange(val as SqlProviders); }} className="w-full border border-mineshaft-500" > PostgreSQL MySQL Oracle + MS SQL )} diff --git a/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx b/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx index 5f8ae6ccd..2094e24ed 100644 --- a/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx +++ b/frontend/src/views/SecretMainPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx @@ -194,6 +194,7 @@ export const EditDynamicSecretSqlProviderForm = ({ PostgreSQL MySQL Oracle + MS SQL )} From 0b4d4c008ab70e5b3287dc6e8efaca04c17a2cf4 Mon Sep 17 00:00:00 2001 From: = Date: Tue, 2 Jul 2024 00:13:30 +0530 Subject: [PATCH 013/117] docs: dynamic secret mssql --- .../platform/dynamic-secrets/mssql.mdx | 118 ++++++++++++++++++ .../dynamic-secret-setup-modal-mssql.png | Bin 0 -> 159348 bytes .../modify-sql-statements-mssql.png | Bin 0 -> 155399 bytes docs/mint.json | 1 + 4 files changed, 119 insertions(+) create mode 100644 docs/documentation/platform/dynamic-secrets/mssql.mdx create mode 100644 docs/images/platform/dynamic-secrets/dynamic-secret-setup-modal-mssql.png create mode 100644 docs/images/platform/dynamic-secrets/modify-sql-statements-mssql.png diff --git a/docs/documentation/platform/dynamic-secrets/mssql.mdx b/docs/documentation/platform/dynamic-secrets/mssql.mdx new file mode 100644 index 000000000..8dae71399 --- /dev/null +++ b/docs/documentation/platform/dynamic-secrets/mssql.mdx @@ -0,0 +1,118 @@ +--- +title: "MS SQL" +description: "How to dynamically generate MS SQL database users." +--- + +The Infisical MS SQL dynamic secret allows you to generate Microsoft SQL server database credentials on demand based on configured role. + +## Prerequisite + +Create a user with the required permission in your SQL instance. This user will be used to create new accounts on-demand. + + +## Set up Dynamic Secrets with MS SQL + + + + Open the Secret Overview dashboard and select the environment in which you would like to add a dynamic secret. + + + ![Add Dynamic Secret Button](../../../images/platform/dynamic-secrets/add-dynamic-secret-button.png) + + + ![Dynamic Secret Modal](../../../images/platform/dynamic-secrets/dynamic-secret-modal.png) + + + + Name by which you want the secret to be referenced + + + + Default time-to-live for a generated secret (it is possible to modify this value when a secret is generate) + + + + Maximum time-to-live for a generated secret + + + + Choose the service you want to generate dynamic secrets for. This must be selected as **MS SQL**. + + + + Database host + + + + Database port + + + + Username that will be used to create dynamic secrets + + + + Password that will be used to create dynamic secrets + + + + Name of the database for which you want to create dynamic secrets + + + + A CA may be required if your DB requires it for incoming connections. AWS RDS instances with default settings will requires a CA which can be downloaded [here](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesAllRegions). + + + ![Dynamic Secret Setup Modal](../../../images/platform/dynamic-secrets/dynamic-secret-setup-modal-mssql.png) + + + + If you want to provide specific privileges for the generated dynamic credentials, you can modify the SQL statement to your needs. This is useful if you want to only give access to a specific table(s). + + ![Modify SQL Statements Modal](../../../images/platform/dynamic-secrets/modify-sql-statements-mssql.png) + + + After submitting the form, you will see a dynamic secret created in the dashboard. + + + If this step fails, you may have to add the CA certficate. + + + ![Dynamic Secret](../../../images/platform/dynamic-secrets/dynamic-secret.png) + + + Once you've successfully configured the dynamic secret, you're ready to generate on-demand credentials. + To do this, simply click on the 'Generate' button which appears when hovering over the dynamic secret item. + Alternatively, you can initiate the creation of a new lease by selecting 'New Lease' from the dynamic secret lease list section. + + ![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-generate.png) + ![Dynamic Secret](/images/platform/dynamic-secrets/dynamic-secret-lease-empty.png) + + When generating these secrets, it's important to specify a Time-to-Live (TTL) duration. This will dictate how long the credentials are valid for. + + ![Provision Lease](/images/platform/dynamic-secrets/provision-lease.png) + + + Ensure that the TTL for the lease fall within the maximum TTL defined when configuring the dynamic secret. + + + + Once you click the `Submit` button, a new secret lease will be generated and the credentials for it will be shown to you. + + ![Provision Lease](/images/platform/dynamic-secrets/lease-values.png) + + + +## Audit or Revoke Leases +Once you have created one or more leases, you will be able to access them by clicking on the respective dynamic secret item on the dashboard. +This will allow you see the expiration time of the lease or delete the lease before it's set time to live. + +![Provision Lease](/images/platform/dynamic-secrets/lease-data.png) + +## Renew Leases +To extend the life of the generated dynamic secret leases past its initial time to live, simply click on the **Renew** as illustrated below. +![Provision Lease](/images/platform/dynamic-secrets/dynamic-secret-lease-renew.png) + + + Lease renewals cannot exceed the maximum TTL set when configuring the dynamic secret + diff --git a/docs/images/platform/dynamic-secrets/dynamic-secret-setup-modal-mssql.png b/docs/images/platform/dynamic-secrets/dynamic-secret-setup-modal-mssql.png new file mode 100644 index 0000000000000000000000000000000000000000..7f296a4414e72c67a154d8ae88602fc274af6e4c GIT binary patch literal 159348 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%0A=*t|DlAwOZrydDTV>6=6~YZ0gz@hKGcI3 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

45{$(sbUixx?nhW%#0u!^c zcF=XJWe6<>Fsu8L|6G##seq$EJ>~K_Si$pa%X}AN6)eH(56=mIk{Q#RONQvL% z;2ks!{G!&NWwtLC2b+O&qlj6v+GOu}WiVhJJot1zoeR+sju^U{hhYGkX@mnh8<86I zSXx}GQQ5=gZ^X&71OYVJdAQgFXFq^s1Xf3+hU|@_S55`!c@Aj<7q&elKl8|rf(?!W zgmYsBBCf-^#Dx@(xCQ9PlBYg7Kh9rMzxS;KYeajwBirH7d$BjxoVMN_JA_;TW}|yP z@M>!@L`cPY_bJK3x9*$064-EZb&XEmF0KcESz1Vdx8`>OlzG{gmA2` z@HT%`$bhR10L&gahPP-MpMi!uMCF*kK^=?7adBTcKxw}=Pi=2}JIhZGu}-?M;WWO` zlj1nErM0R`m7bp!Xp%9Oto~&Q@od<{OzoTC9O@Y=UpM+pe|3X7{g+WzFF4^{)YAg} z40nM4jt43POCMs;A+R#Ag1KDBeYXv3PFvJ_+2_kTGWA^Z{SDkoT?TYc+k*;HTGn*9 zvY)@wxO-%P6Ay>G4pzp274v7$=xV5;t(qTOc-mL?^LlB zSFyl+`i`&+R0|+PGtriV89aqYV49cnQ`QJ8#dj#fxoefypM+~UD@w}iJJaJo4dpcT zbMhSaTeAeE5FVV{fbqEd~sH5E`Wr~&w%Zx0|_>v*gkmiT{Hi}C9QK2 zXBb{vYT{IlB{CRdd~D7MsvK`Z?hd0@j=0ha(t|pe1f@nJzkFq-HHnC_ux>Noa8hQC zW3`~?SOnTMW6!7_WzXzJK2ozyKI6l3jyKxxId{Nxcp)*uwY;%*+D9sey5-L85ACCq z@+0A&{gSI=Sbnz@KlA~IEWkTGpk#$T-h&~LGXB^Q|5nnWR@|wnN(1rOxi+sx-Mh$- zF7~;0I?ek?^{jWD9=7kECK%k94*bT6vGJL)sr;bmE-YiYMDo%T%(6NdfCvk{dz z#n@i(#xW{cJ`}5CPIgovsC5oiMHU^q8m?fM+DBs7$ae!PbHr2Ld_L%8T-i zw`Y&7hqkRpdFAW#5N3sf; z`f!#G+EH_PtX%xA!j0N|qxVP2Qj>~k^O4t%CDPPIe3qSybLEy+hCh-!BChesE=P)n zn@fMCZZHGflcA75RpV*~VeURYO4@3eif?Lbf7B5$Rp~N81zD*4=$`2lH{)te3>rfH z7_Rk?N^!?EgjJ47tc1WF8JCT%7d=!=%dNQ3<=S>8g@@mn^;y!wL@t}^3kxzBTWZ(e zSv*yI0EKW!cUsz6(7`{Pt^~r!pM{Rh!v*JCToe2`3Fa$_hA1TMXMvngF zF4M&AUe|AYWt=@gbsX)kj%p~(lmXPKUw$yJUtWboC)X7(%^gejDKgib7+6hAWXr*! zhgd*r;VnvpDP|>qa^d)DUXs;{mAbHJq6mn?dOe|(K=j_D;f_^R_}F|nT%PSfn6UNd zjXfBun~HOl22Yc?xM0jP`0p&7uoORu>47iHofp_&Enm64s!D&VY~QTrdb#`d*~d~1 zQ%5D^03{bY^sfJvTw9it%6nsWhHvuwO2)r178#eH)5Fr54e`JhT3KtZ4(g?!sg}Yl z*Ul%9LCznUsKbHzgL`8+o>bsEP_&KRay-3OnpiO%cJ*Fai@-gH;%TFnq%M} z;`nVc3K?OtO`EZs7V@7<-AATqec*LEySROmM%6;vIHBW8Lm*b*Bm+^-tVp}8`;=39 z$lfC}lU=)d{*Y+hiVvH0cEjc;6eS&dqIPcvH zGgjI$d6k?G4QFfMgQ6qanmgea$VGE76Q`m1xPnBgv(0^XT;C8@Oeo-w110D61+7{q zO!pP)HMr7i5EYDaK`aq}By0Fy z+gr+ks8_AhD@K&Hcy)bjf9_)Gj;wijayFkmXvg2jvL(k&{uU~x1*o= zpc~VME!pqx%?1KHth2B5kW16C0kg4&+T65(fG(L?uJe3f(xrU@r|uPHux2?~?4+Ts z;KTs|WD@3^neDqA<+tD?mY3aB>D!$4WRnJY=eCVkfYomSNto*T2?j3Mj*N8LO<%N7 z5z!t!`85H!z#zr|AH`guV^+T9Y_;77?{BWuTJYaDIkMAk+=IlP42U@he9wLB$vnG% zsd;pm2C9C(5%x(9qn34C-4#-1cQENeMsOn==Hnt~zEL0V-33h$7a5~`{qu=JLMKcN zVb1dWKVM`$X)#*&0HONvAgT|DhoRWXxoj(GB7@cCWMrcOc z2n&7`s6p!o#Qt(>O{N43Ade{FWnf*;Epl!&AKr&PmMX<=&9OJ{tHDgK9oHR&sX<>& zF3#HgOg*IEB8>H;9lI_(j2HSTLQCV$00ICr*IgFEp0;eB)DiAGw*#-5Co z;gA}UP$Nxlivz%U*(G`5TbXsckMA;a^BW%934m@VNSMMMgw%=-ZI9L?skxgi4j!}n ztYBIWnTnT=n-4?S7z4CEf9v-^hhWaC_{80Vo)JZ?eJM2G4#YPS_HLbBP`1F?QBHI- zNr4-DDgO2&;B1M?&3#^N7nRQf0d57Q09Rn^G8~(HC}^5wSymIPvdthpw3|rHV`f=$ zt}ztY#}j=#V-%2^X2VJr6lgxx3}-RAZ>+aT!>w{lD=uf^z-QL`Pi%DG2&7kF z2_v6SJ2xPHqym6UkASU<7HGv0gBENkpnsd9^14=6)(A^8BA8(hSZY{7Di+?n6uNqq z9OA28zW&fWZ^|Zr%%_V>pN(QK9=k>pRw*oa4Kfsa!Stv^C8lgr)c-4p@uzh}-YCGw z>-{`lt5GEH#zTXa%%A=Mzd3bYjK;TpDhO^o8;4~`a9Kpfq9Ser-o+>4tzVEO^9z;zt&F`O>9WP&)HRm6^z}E0cV=Jx6JyNC#6FAT|sg=p$Gu6`)67A zT_Yv!7z#t;>u-a&in^{PRL7mtVhZrN;|;9&8KCtjQ&au(Hg$Ts;C#B`$VI@7Lg7x^ zi(9W(%Vo_#AtnRd_m6DR-e@3SX!9QsPNC_T9>9jyg&~_;%wQ)B%6ZEyJw{6qvWcr( zjUU4b2C?vzGVXZL!m5(5MLBL2brbNI47$xzn@`Sf)E&$bmahktYEY6Yb4pSr^&Cpp zc*qDO9fa?M08a(4`J1`T%B-DBZqz1y5EMc1D&9X30FaTVk zfj?;Oz)+{Vgsu*JZvgw~KY@YzCq#n1LEw7L=u{~k&#<{p24FFeysmLeX1gIc-6DxC2SMlxsyJy>wSDm?-ci1-e zk&zb^p6^!}mYUzSKxk^vKEsJUbBu~)5Ro3f^v4Ic24{Tuz(&9{F>i>mKt zg%wO-gQUXCz(W)GDet~rY*g>JrJoLI)|w?BIlEa>-0NpMv z#xnHu0P%{_zMU#w>{h7#ET;&73P4W#ysHqU?d0})d zpoTq0ra(J?+>lAiS5Cmotfb2ec7$nAeLnNam_>0}wYXpJ4OmSJIBFGehsbgE=LMeM zg{@HGKTZr+P?Sz&!$W9gO-I=F-dalT>Y z2$y>@Ko4~CGmy$bX|zHZfs_M??Hen6HjAP{!3>6&-7^2S)(Whh&J9W=gWLIlt~zMU zxN$KQ*uXlKX`+%yIR_iy93-a&YEL&nRJkcAxi271`k;|??_N2F))%w`4H15p=PlzoFVzxG3g=~!B8NPQk;aVPR zCA1c>)xn>$7^=#W99pxz?C_mdG4E4--*p}mS6YAgAO)P|#O}AxA%jmShVJK!;HpDE zs1f!ChJDJOT-w-Iu%DPQbIpA$?7fpVbS7cMzS4F|V&ly}dzb#8u3^5hTc_qd4bvG| z<*jwS3A(tX^$&-6tf;clLX+Rvi0-*_wAAMc2(_xbvM)i(7j(akr&j+1vf_BN^0hZR z``*ZlMIX7qQhPsS#|g#3%=;~5;X^9OihJD*9cpkeyTF0Cx9%Cuy}PqT3D5AWJYZmn z?ezHw{hsNQ{U$S4+krc1Z^1Jdi|=f|iU{)#6Q+pY(a zb$)e=dH&;!`SkZoF0E;cHnK=xBRD?%R&;9plepbanC}ZKU9`zi@jdW4kS1+S>=5jm~W}=kdGONt8mHYev`av=5O92Om&Ys?=oyDe@Wh9;M6^{sNL>& z?c%oqAO%Z8ZTG2Qa|#%^n4OhZC82OCuzbEwG`{hX} z)e-=n1LwVPcp%KTgEThNT{>HI=R9e#%xX{!0O@1gWeOI{x>IEPmQ>7!n3BrA8fbIU z%2IZTBC}MY7}$?SE^#y;@4F@ou2|`q-G2(C@eC0=NNn?X8kjYq+3uW6YtE*rLIy{q z`%wYsAH_>&8xxHnWstGL>?AM%gJ6K0==3-)AMFU^zcjLZ<=$-wybE}-rB8*lP0Jr4 zQX-G&70qFAhIXhO*L`O$VB&$7p}X2HFVL6w5;dF<`1|(J@TVt^X4$wV>!UY(T2tcs zd}3zkxsruI-2eqVy3zeePIvZGCM*o;k(Ohp&*fcMBBL}KqC!Cs{b}<8g;+L#jeUUw z;-xA6Twv#en(md)UqKs-D_y{}%q4#^kCNF%zm4hErCXMb;>JduO3M~c%@bmfw2B-B z;1^9}Qa;wEpC9O113>Bf(*Zl2Tli64+O%sA-u+~ElVtf+eBENhm}oH?QNaOY3?^Be zcM1v>m4WAlQ_s3+^EN~8pl3Y~(B7$fVaWpeLZe>2!=drzBPtmn!UV7(!!G^^MV#u@OB+sBB9x+!+eG!;Q{Q0dOLq1V zdti7%z54RR`BP9krUD^{p|6o?r<@Ibb8kO1C=iqV8K1}2Am`OO=)8qk^rH}Tx^G=1L(Sxew#c0 zbf1SupAdlOaX8k`ZqlURnHAbe$9n5$1!3-Hp8w^~0Dk2)BSH;aHV)Sj-*BiUS(aw) zi_BN4b}>0G2p`mx9riI(-T$^yd>x&tXLf^C$VJ!(;Gy?f)#_#{3G8P*;R2dV0+@nA zfXaihD>JR&v6svEP^6bY+pnV>xHZh6wG9Q7dw^&jxxLs2d3mL=Ae-i#?^{`a+*F}j z0tVPYc1gjnbU^pCi4SY)VU{jitToE)5wNmx$J*QzCi?;8 zOu|R4cECiu-B~7G^3UL+ZHi_W#Z^`?1WU(6y*}vB4;{>5JThp>=`%UB7^Q88zZpqD zatD{%l(02()&a|;KSgo}{Rqj;MrwsxMDQ8o0!{`n2y9_K-=Ls&s}$7kbupKm*OMWW zL_eRJD$Aw(kB!3b;Pxmz1ob)T9FrT&@F*cUW$6&Jv78po*8VaOqVw>%*Yh^30&&2I zEQqsMvZjPWF=j9-h9}ikIVDSi=*sfpBj*Nlm^pHy2z5Jap~^t^Oie0%d+cA1@6^!Y zCspL#91TcZoPtkj7On=}_@wKRi|+u`&X{X*WsJ8c+YWa7CEX=oZ>x@mJUP)A#&C7k z`>QZaVOQVtYhkL+l!$;I@K*nB45oO#|Npg98=2MU>XN#{sAzP&y}_uV@{Hw4mtWeQT&@|bLH+Meij3J)3& zeNuS=2)H|cLE44GaY0?vtuj-W9EZ0Hm3P?UvVEg|kY4SXE}^Y}?n>aR2j8 z_kgFx){T5}Jh5{3%IdmCqBbyvIRZ@Q66dTGo*6`6l6c~z$OD9IlI!dA-IX~=9Ukw& z9k&%%9^&_1#oPbvDW?2Y*w~^Otmv0L`-%jEIODKS&COqbviVR}F%JSJ%ioFq}*+qu#9`{g?ozk#ADEjXP>;^Xx0!>Lsry)6*)rxgm71 z${{+<`T3TM(QkhTA%KtaVZVhLu+>XdbXJeM%tf!XPJeccap#O5k651BWzqZ-9Zu&8 zX@D2`R$TZ*dxFE5@{Qa&{~4US*BmE2RPe`1(VxZ1(j=#Nr||H_{I2*Xuk<5Y-rFI& zr(5s#0NZnN!d(YG0EdSerMY{h{|)t16%J2eFU!fHNL98;NJHXB;1ej*5*>M_AvYkv zexu~tuW5dqxE=nf4ttQ8;qS?cYNlm)j?A3%=AHD~5p)qc9(balO( zuBccD0Y7PR@S{QBt6|A@gC!hg9JY>hhChCE^Mu5?!r{GZFCU4@pQ29BmNKLTq6GeJ zbFxb*fS@NIlMd~b&+44}y|i#nH8UtY2arr>l*7GiS~;v|kf}&e-OqhA%)iH76uGfdl~v|eer!Ax zRY01iLSaHHir;%RJY?nJQP0deF%~K{wDQ>De4$WyHER|lTh4E%a2x@H7SqlIR0=99$Ebcg1^nbXllIfs z3}mUD-GQHc{4LvjoiqoaslnFV zA7AS7{j#WO8#3~|(=9;cm|&fsY)`DHU+G!bz%Z%-E{ukvrQNQ`7$u?Pg?y$}9cFZu zJ+AM>Ut0CUrD)}!_MMI|(1WPgyDsh(tM_a^HhKR1V)$!j8{)vTl9)^CneHbBr$Xl% z4S-f7X}~$|bu^5uS9pv!wC+@rbN-v&OO>@~dJpQPN=ciCRa0}vv2zlLEveTG;{KR~ zcvW8nrVgHmOTl=K1GWPI?K7o>^}v-;r$bX@9hBYp{*oaAOC*|FUTGR-zt3mg04&n6 z{NtFDLnXkIflP}6q`wFz| z<%pOuN=B&OJ(*iW`VnjkG>QF!AmRgs71sX!`hOq(e;KjN{}V*7<1oN;t*)xugVf9O z>9(-&`#wyq46rZw*yVN!1iVnL12ov_Ac00O1?*82U`!uAyM?*;NBGtW4o{-E&)Bo= zvJ|YHLwBm%A%W+d8)x+p7ZpPg=rsWqP!UiOM0ybdQUyYXAfZU_C4}Bv=$(|i;y(N6KF9wU z?>p|7JMP_I9E=ddFKf*;%QK(#Og?jAk0GX1FjQ#u85acBJh;_BU!OzZGsG|0*9)WE z_N7_^HmxW6K;Gcjc$nRGUldk-c3qhV|JKrO$TD__LXWA>--JNYRM!0tl4B6f!$JHCM1INx*g zOq+20jz`BMsl=0md%HQ2eg}`baJ=wEa2ypr@$yjT0Bo}5_Rlbo-)|&rn%EjA(RZA) zd$-fG4;szt{QaqZ^pN98nr zU4{N~uJb^xaY!XAl*QhA8!o{jTw1Q1!DR@>&-RU8p~O&$H*P7i7x~O_q#B}NqRqYF z4scK##5N8#e@tvY#$)>Z&79CuO%1n@Z2UR|Hgd^llW9AzuU;3nPcZvdP2+i7xvJ~= z3#k(#WCKY(`_n*>!$!g`epK#v!so9H7O>?vkDe*q?7D4IXoIoXDp;Doa$@|A$$)i996wWV??K zFVed2ZCXn{*U@Pv`gpDD9=prtcZA8}1uoEnw8$GTZc-l{`au!^5FC9(Cv3JBaXB8%h-}=Y;4odk6K!?*%S-`r2oEs{#AKO+H*ewtUt)m z|2m_{K_g*vBP#dC4�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 WzWt&=nfhnob@r6~ccmvifA}ZKHvc~W literal 0 HcmV?d00001 diff --git a/docs/mint.json b/docs/mint.json index 465759875..cb08aab32 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -148,6 +148,7 @@ "documentation/platform/dynamic-secrets/overview", "documentation/platform/dynamic-secrets/postgresql", "documentation/platform/dynamic-secrets/mysql", + "documentation/platform/dynamic-secrets/mssql", "documentation/platform/dynamic-secrets/oracle", "documentation/platform/dynamic-secrets/cassandra", "documentation/platform/dynamic-secrets/aws-iam" From ed5a7d72ab7a3b9f8ac127035bbd93ff5b7ccd3c Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Tue, 2 Jul 2024 19:57:58 +0800 Subject: [PATCH 014/117] feat: added native slack webhook type --- ...0240702055253_add-encrypted-webhook-url.ts | 49 +++++++ backend/src/db/schemas/webhooks.ts | 6 +- .../src/server/routes/v1/webhook-router.ts | 31 +++-- backend/src/services/webhook/webhook-fns.ts | 127 ++++++++++++++---- .../src/services/webhook/webhook-service.ts | 45 +++++-- backend/src/services/webhook/webhook-types.ts | 6 + .../components/WebhooksTab/AddWebhookForm.tsx | 95 ++++++++++--- 7 files changed, 290 insertions(+), 69 deletions(-) create mode 100644 backend/src/db/migrations/20240702055253_add-encrypted-webhook-url.ts diff --git a/backend/src/db/migrations/20240702055253_add-encrypted-webhook-url.ts b/backend/src/db/migrations/20240702055253_add-encrypted-webhook-url.ts new file mode 100644 index 000000000..c2ca86d34 --- /dev/null +++ b/backend/src/db/migrations/20240702055253_add-encrypted-webhook-url.ts @@ -0,0 +1,49 @@ +import { Knex } from "knex"; + +import { WebhookType } from "@app/services/webhook/webhook-types"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasEncryptedURL = await knex.schema.hasColumn(TableName.Webhook, "encryptedUrl"); + const hasUrlIV = await knex.schema.hasColumn(TableName.Webhook, "urlIV"); + const hasUrlTag = await knex.schema.hasColumn(TableName.Webhook, "urlTag"); + const hasType = await knex.schema.hasColumn(TableName.Webhook, "type"); + + await knex.schema.alterTable(TableName.Webhook, (tb) => { + if (!hasEncryptedURL) { + tb.text("encryptedUrl"); + } + if (!hasUrlIV) { + tb.string("urlIV"); + } + if (!hasUrlTag) { + tb.string("urlTag"); + } + if (!hasType) { + tb.string("type").defaultTo(WebhookType.GENERAL); + } + }); +} + +export async function down(knex: Knex): Promise { + const hasEncryptedURL = await knex.schema.hasColumn(TableName.Webhook, "encryptedUrl"); + const hasUrlIV = await knex.schema.hasColumn(TableName.Webhook, "urlIV"); + const hasUrlTag = await knex.schema.hasColumn(TableName.Webhook, "urlTag"); + const hasType = await knex.schema.hasColumn(TableName.Webhook, "type"); + + await knex.schema.alterTable(TableName.Webhook, (t) => { + if (hasEncryptedURL) { + t.dropColumn("encryptedUrl"); + } + if (hasUrlIV) { + t.dropColumn("urlIV"); + } + if (hasUrlTag) { + t.dropColumn("urlTag"); + } + if (hasType) { + t.dropColumn("type"); + } + }); +} diff --git a/backend/src/db/schemas/webhooks.ts b/backend/src/db/schemas/webhooks.ts index 44aa8c5da..49b64662c 100644 --- a/backend/src/db/schemas/webhooks.ts +++ b/backend/src/db/schemas/webhooks.ts @@ -21,7 +21,11 @@ export const WebhooksSchema = z.object({ keyEncoding: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), - envId: z.string().uuid() + envId: z.string().uuid(), + encryptedUrl: z.string().nullable().optional(), + urlIV: z.string().nullable().optional(), + urlTag: z.string().nullable().optional(), + type: z.string().default("general").nullable().optional() }); export type TWebhooks = z.infer; diff --git a/backend/src/server/routes/v1/webhook-router.ts b/backend/src/server/routes/v1/webhook-router.ts index 1698c0c4b..4124d9150 100644 --- a/backend/src/server/routes/v1/webhook-router.ts +++ b/backend/src/server/routes/v1/webhook-router.ts @@ -6,13 +6,17 @@ import { removeTrailingSlash } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; +import { WebhookType } from "@app/services/webhook/webhook-types"; export const sanitizedWebhookSchema = WebhooksSchema.omit({ encryptedSecretKey: true, iv: true, tag: true, algorithm: true, - keyEncoding: true + keyEncoding: true, + encryptedUrl: true, + urlIV: true, + urlTag: true }).merge( z.object({ projectId: z.string(), @@ -33,13 +37,24 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), schema: { - body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - webhookUrl: z.string().url().trim(), - webhookSecretKey: z.string().trim().optional(), - secretPath: z.string().trim().default("/").transform(removeTrailingSlash) - }), + body: z + .object({ + type: z.nativeEnum(WebhookType).default(WebhookType.GENERAL), + workspaceId: z.string().trim(), + environment: z.string().trim(), + webhookUrl: z.string().url().trim(), + webhookSecretKey: z.string().trim().optional(), + secretPath: z.string().trim().default("/").transform(removeTrailingSlash) + }) + .superRefine((data, ctx) => { + if (data.type === WebhookType.SLACK && !data.webhookUrl.includes("hooks.slack.com")) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Incoming Webhook URL is invalid.", + path: ["webhookUrl"] + }); + } + }), response: { 200: z.object({ message: z.string(), diff --git a/backend/src/services/webhook/webhook-fns.ts b/backend/src/services/webhook/webhook-fns.ts index 35d2ba7fc..391d1b3b7 100644 --- a/backend/src/services/webhook/webhook-fns.ts +++ b/backend/src/services/webhook/webhook-fns.ts @@ -12,47 +12,82 @@ import { logger } from "@app/lib/logger"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TWebhookDALFactory } from "./webhook-dal"; +import { WebhookType } from "./webhook-types"; const WEBHOOK_TRIGGER_TIMEOUT = 15 * 1000; -export const triggerWebhookRequest = async ( - { url, encryptedSecretKey, iv, tag, keyEncoding }: TWebhooks, - data: Record -) => { - const headers: Record = {}; - const payload = { ...data, timestamp: Date.now() }; - const appCfg = getConfig(); - if (encryptedSecretKey) { - const encryptionKey = appCfg.ENCRYPTION_KEY; - const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY; - let secretKey; - if (rootEncryptionKey && keyEncoding === SecretKeyEncoding.BASE64) { - // case: encoding scheme is base64 - secretKey = decryptSymmetric({ +export const decryptWebhookDetails = (webhook: TWebhooks) => { + const appCfg = getConfig(); + const { keyEncoding, iv, encryptedSecretKey, tag, encryptedUrl, urlIV, urlTag, url } = webhook; + + const encryptionKey = appCfg.ENCRYPTION_KEY; + const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY; + + let decryptedSecretKey = ""; + let decryptedUrl = url; + + if (rootEncryptionKey && keyEncoding === SecretKeyEncoding.BASE64) { + // case: encoding scheme is base64 + if (encryptedSecretKey) { + decryptedSecretKey = decryptSymmetric({ ciphertext: encryptedSecretKey, iv: iv as string, tag: tag as string, key: rootEncryptionKey }); - } else if (encryptionKey && keyEncoding === SecretKeyEncoding.UTF8) { - // case: encoding scheme is utf8 - secretKey = decryptSymmetric128BitHexKeyUTF8({ + } + + if (encryptedUrl) { + decryptedUrl = decryptSymmetric({ + ciphertext: encryptedUrl, + iv: urlIV as string, + tag: urlTag as string, + key: rootEncryptionKey + }); + } + } else if (encryptionKey && keyEncoding === SecretKeyEncoding.UTF8) { + // case: encoding scheme is utf8 + if (encryptedSecretKey) { + decryptedSecretKey = decryptSymmetric128BitHexKeyUTF8({ ciphertext: encryptedSecretKey, iv: iv as string, tag: tag as string, key: encryptionKey }); } - if (secretKey) { - const webhookSign = crypto.createHmac("sha256", secretKey).update(JSON.stringify(payload)).digest("hex"); - headers["x-infisical-signature"] = `t=${payload.timestamp};${webhookSign}`; + + if (encryptedUrl) { + decryptedUrl = decryptSymmetric128BitHexKeyUTF8({ + ciphertext: encryptedUrl, + iv: urlIV as string, + tag: urlTag as string, + key: encryptionKey + }); } } + + return { + secretKey: decryptedSecretKey, + url: decryptedUrl + }; +}; + +export const triggerWebhookRequest = async (webhook: TWebhooks, data: Record) => { + const headers: Record = {}; + const payload = { ...data, timestamp: Date.now() }; + const { secretKey, url } = decryptWebhookDetails(webhook); + + if (secretKey) { + const webhookSign = crypto.createHmac("sha256", secretKey).update(JSON.stringify(payload)).digest("hex"); + headers["x-infisical-signature"] = `t=${payload.timestamp};${webhookSign}`; + } + const req = await request.post(url, payload, { headers, timeout: WEBHOOK_TRIGGER_TIMEOUT, signal: AbortSignal.timeout(WEBHOOK_TRIGGER_TIMEOUT) }); + return req; }; @@ -60,15 +95,48 @@ export const getWebhookPayload = ( eventName: string, workspaceId: string, environment: string, - secretPath?: string -) => ({ - event: eventName, - project: { - workspaceId, - environment, - secretPath + secretPath?: string, + type?: string | null +) => { + switch (type) { + case WebhookType.SLACK: + return { + text: "A secret value has been updated", + attachments: [ + { + color: "#E7F256", + fields: [ + { + title: "Workspace ID", + value: workspaceId, + short: true + }, + { + title: "Environment", + value: environment, + short: true + }, + { + title: "Secret Path", + value: secretPath, + short: true + } + ] + } + ] + }; + case WebhookType.GENERAL: + default: + return { + event: eventName, + project: { + workspaceId, + environment, + secretPath + } + }; } -}); +}; export type TFnTriggerWebhookDTO = { projectId: string; @@ -95,9 +163,10 @@ export const fnTriggerWebhook = async ({ logger.info("Secret webhook job started", { environment, secretPath, projectId }); const webhooksTriggered = await Promise.allSettled( toBeTriggeredHooks.map((hook) => - triggerWebhookRequest(hook, getWebhookPayload("secrets.modified", projectId, environment, secretPath)) + triggerWebhookRequest(hook, getWebhookPayload("secrets.modified", projectId, environment, secretPath, hook.type)) ) ); + // filter hooks by status const successWebhooks = webhooksTriggered .filter(({ status }) => status === "fulfilled") diff --git a/backend/src/services/webhook/webhook-service.ts b/backend/src/services/webhook/webhook-service.ts index 4a05ad219..acf4e2d75 100644 --- a/backend/src/services/webhook/webhook-service.ts +++ b/backend/src/services/webhook/webhook-service.ts @@ -9,7 +9,7 @@ import { BadRequestError } from "@app/lib/errors"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TWebhookDALFactory } from "./webhook-dal"; -import { getWebhookPayload, triggerWebhookRequest } from "./webhook-fns"; +import { decryptWebhookDetails, getWebhookPayload, triggerWebhookRequest } from "./webhook-fns"; import { TCreateWebhookDTO, TDeleteWebhookDTO, @@ -36,8 +36,13 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer webhookUrl, environment, secretPath, - webhookSecretKey + webhookSecretKey, + type }: TCreateWebhookDTO) => { + const appCfg = getConfig(); + const encryptionKey = appCfg.ENCRYPTION_KEY; + const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY; + const { permission } = await permissionService.getProjectPermission( actor, actorId, @@ -50,15 +55,14 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer if (!env) throw new BadRequestError({ message: "Env not found" }); const insertDoc: TWebhooksInsert = { - url: webhookUrl, + url: "", // deprecated - we are moving away from plaintext URLs envId: env.id, isDisabled: false, - secretPath: secretPath || "/" + secretPath: secretPath || "/", + type }; + if (webhookSecretKey) { - const appCfg = getConfig(); - const encryptionKey = appCfg.ENCRYPTION_KEY; - const rootEncryptionKey = appCfg.ROOT_ENCRYPTION_KEY; if (rootEncryptionKey) { const { ciphertext, iv, tag } = encryptSymmetric(webhookSecretKey, rootEncryptionKey); insertDoc.encryptedSecretKey = ciphertext; @@ -76,6 +80,22 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer } } + if (rootEncryptionKey) { + const { ciphertext, iv, tag } = encryptSymmetric(webhookUrl, rootEncryptionKey); + insertDoc.encryptedUrl = ciphertext; + insertDoc.urlIV = iv; + insertDoc.urlTag = tag; + insertDoc.algorithm = SecretEncryptionAlgo.AES_256_GCM; + insertDoc.keyEncoding = SecretKeyEncoding.BASE64; + } else if (encryptionKey) { + const { ciphertext, iv, tag } = encryptSymmetric128BitHexKeyUTF8(webhookUrl, encryptionKey); + insertDoc.encryptedUrl = ciphertext; + insertDoc.urlIV = iv; + insertDoc.urlTag = tag; + insertDoc.algorithm = SecretEncryptionAlgo.AES_256_GCM; + insertDoc.keyEncoding = SecretKeyEncoding.UTF8; + } + const webhook = await webhookDAL.create(insertDoc); return { ...webhook, projectId, environment: env }; }; @@ -131,7 +151,7 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer try { await triggerWebhookRequest( webhook, - getWebhookPayload("test", webhook.projectId, webhook.environment.slug, webhook.secretPath) + getWebhookPayload("test", webhook.projectId, webhook.environment.slug, webhook.secretPath, webhook.type) ); } catch (err) { webhookError = (err as Error).message; @@ -162,7 +182,14 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer ); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks); - return webhookDAL.findAllWebhooks(projectId, environment, secretPath); + const webhooks = await webhookDAL.findAllWebhooks(projectId, environment, secretPath); + return webhooks.map((w) => { + const { url } = decryptWebhookDetails(w); + return { + ...w, + url + }; + }); }; return { diff --git a/backend/src/services/webhook/webhook-types.ts b/backend/src/services/webhook/webhook-types.ts index 7a6e92c80..40dacb42a 100644 --- a/backend/src/services/webhook/webhook-types.ts +++ b/backend/src/services/webhook/webhook-types.ts @@ -5,6 +5,7 @@ export type TCreateWebhookDTO = { secretPath?: string; webhookUrl: string; webhookSecretKey?: string; + type: string; } & TProjectPermission; export type TUpdateWebhookDTO = { @@ -24,3 +25,8 @@ export type TListWebhookDTO = { environment?: string; secretPath?: string; } & TProjectPermission; + +export enum WebhookType { + GENERAL = "general", + SLACK = "slack" +} diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx index bf60372ef..5c756bfc2 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx @@ -1,7 +1,7 @@ import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; -import { yupResolver } from "@hookform/resolvers/yup"; -import * as yup from "yup"; +import { zodResolver } from "@hookform/resolvers/zod"; +import z from "zod"; import GlobPatternExamples from "@app/components/basic/popups/GlobPatternExamples"; import { @@ -15,14 +15,30 @@ import { SelectItem } from "@app/components/v2"; -const formSchema = yup.object({ - environment: yup.string().required().trim().label("Environment"), - webhookUrl: yup.string().url().required().trim().label("Webhook URL"), - webhookSecretKey: yup.string().trim().label("Secret Key"), - secretPath: yup.string().required().trim().label("Secret Path") -}); +enum WebhookType { + GENERAL = "general", + SLACK = "slack" +} -export type TFormSchema = yup.InferType; +const formSchema = z + .object({ + environment: z.string().trim().describe("Environment"), + webhookUrl: z.string().url().trim().describe("Webhook URL"), + webhookSecretKey: z.string().trim().optional().describe("Secret Key"), + secretPath: z.string().trim().describe("Secret Path"), + type: z.nativeEnum(WebhookType).describe("Type").default(WebhookType.GENERAL) + }) + .superRefine((data, ctx) => { + if (data.type === WebhookType.SLACK && !data.webhookUrl.includes("hooks.slack.com")) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Incoming Webhook URL is invalid.", + path: ["webhookUrl"] + }); + } + }); + +type TFormSchema = z.infer; type Props = { isOpen: boolean; @@ -42,11 +58,17 @@ export const AddWebhookForm = ({ handleSubmit, register, reset, + watch, formState: { errors, isSubmitting } } = useForm({ - resolver: yupResolver(formSchema) + resolver: zodResolver(formSchema), + defaultValues: { + type: WebhookType.GENERAL + } }); + const webhookType = watch("type"); + useEffect(() => { if (!isOpen) { reset(); @@ -58,6 +80,33 @@ export const AddWebhookForm = ({

+ ( + + + + )} + /> + {webhookType === WebhookType.GENERAL && ( + + + + )} - - - Date: Tue, 2 Jul 2024 20:04:55 +0800 Subject: [PATCH 015/117] misc: added placeholder for incoming webhook url --- .../components/WebhooksTab/AddWebhookForm.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx index 5c756bfc2..fa581fae1 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx @@ -165,7 +165,12 @@ export const AddWebhookForm = ({ isError={Boolean(errors?.webhookUrl)} errorText={errors?.webhookUrl?.message} > - +
From 398a8f363d404cff9bf255bd841ebe3c541a1ada Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Tue, 2 Jul 2024 20:20:25 +0800 Subject: [PATCH 016/117] misc: cleanup of form display structure --- .../components/WebhooksTab/AddWebhookForm.tsx | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx index fa581fae1..5d5bf164d 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/WebhooksTab/AddWebhookForm.tsx @@ -69,6 +69,38 @@ export const AddWebhookForm = ({ const webhookType = watch("type"); + const generalFormFields = ( + <> + + + + + + + + ); + + const slackFormFields = ( + + + + ); + useEffect(() => { if (!isOpen) { reset(); @@ -146,32 +178,7 @@ export const AddWebhookForm = ({ {...register("secretPath")} /> - {webhookType === WebhookType.GENERAL && ( - - - - )} - - - + {webhookType === WebhookType.SLACK ? slackFormFields : generalFormFields}
)} diff --git a/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx b/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx index 3726f3057..6d45d3da0 100644 --- a/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx +++ b/frontend/src/views/SecretMainPage/components/SecretListView/SecretItem.tsx @@ -250,7 +250,7 @@ export const SecretItem = memo( />
@@ -498,7 +498,7 @@ export const SecretItem = memo( {!isDirty ? ( { }); } } - const query: Record = { ...router.query, env: slug }; + + const query: Record = { ...router.query, env: slug, searchFilter }; const envIndex = visibleEnvs.findIndex((el) => slug === el.slug); if (envIndex !== -1) { router.push({ From b6a9dc7f53f3d290314f2bcf8ffe65c225aeca30 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 3 Jul 2024 20:03:21 +0530 Subject: [PATCH 024/117] feat: completed migration for secret approval group --- .../20240702131735_secret-approval-groups.ts | 188 ++++++++++++++++++ .../secret-approval-policies-approvers.ts | 4 +- .../secret-approval-requests-reviewers.ts | 4 +- .../db/schemas/secret-approval-requests.ts | 6 +- 4 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 backend/src/db/migrations/20240702131735_secret-approval-groups.ts diff --git a/backend/src/db/migrations/20240702131735_secret-approval-groups.ts b/backend/src/db/migrations/20240702131735_secret-approval-groups.ts new file mode 100644 index 000000000..537230b47 --- /dev/null +++ b/backend/src/db/migrations/20240702131735_secret-approval-groups.ts @@ -0,0 +1,188 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + // migrate secret approval policy approvers to user id + const hasApproverUserId = await knex.schema.hasColumn(TableName.SecretApprovalPolicyApprover, "approverUserId"); + const hasApproverId = await knex.schema.hasColumn(TableName.SecretApprovalPolicyApprover, "approverId"); + if (!hasApproverUserId) { + // add the new fields + await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => { + // if (hasApproverId) tb.setNullable("approverId"); + tb.uuid("approverUserId"); + tb.foreign("approverUserId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + }); + + // convert project membership id => user id + await knex(TableName.SecretApprovalPolicyApprover).update({ + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + approverUserId: knex(TableName.ProjectMembership) + .select("userId") + .where("id", knex.raw("??", [`${TableName.SecretApprovalPolicyApprover}.approverId`])) + }); + // drop the old field + await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => { + if (hasApproverId) tb.dropColumn("approverId"); + tb.uuid("approverUserId").notNullable().alter(); + }); + } + + // migrate secret approval request committer and statusChangeBy to user id + const hasSecretApprovalRequestTable = await knex.schema.hasTable(TableName.SecretApprovalRequest); + const hasCommitterUserId = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "committerUserId"); + const hasCommitterId = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "committerId"); + const hasStatusChangeBy = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "statusChangeBy"); + const hasStatusChangedByUserId = await knex.schema.hasColumn( + TableName.SecretApprovalRequest, + "statusChangedByUserId" + ); + if (hasSecretApprovalRequestTable) { + // new fields + await knex.schema.alterTable(TableName.SecretApprovalRequest, (tb) => { + // if (hasCommitterId) tb.setNullable("committerId"); + if (!hasCommitterUserId) { + tb.uuid("committerUserId"); + tb.foreign("committerUserId").references("id").inTable(TableName.Users).onDelete("SET NULL"); + } + if (!hasStatusChangedByUserId) { + tb.uuid("statusChangedByUserId"); + tb.foreign("statusChangedByUserId").references("id").inTable(TableName.Users).onDelete("SET NULL"); + } + }); + + // copy the assigned project membership => user id to new fields + await knex(TableName.SecretApprovalRequest).update({ + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + committerUserId: knex(TableName.ProjectMembership) + .select("userId") + .where("id", knex.raw("??", [`${TableName.SecretApprovalRequest}.committerId`])), + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + statusChangedByUserId: knex(TableName.ProjectMembership) + .select("userId") + .where("id", knex.raw("??", [`${TableName.SecretApprovalRequest}.statusChangeBy`])) + }); + // drop old fields + await knex.schema.alterTable(TableName.SecretApprovalRequest, (tb) => { + if (hasStatusChangeBy) tb.dropColumn("statusChangeBy"); + if (hasCommitterId) tb.dropColumn("committerId"); + tb.uuid("committerUserId").notNullable().alter(); + }); + } + + // migrate secret approval request reviewer to user id + const hasMemberId = await knex.schema.hasColumn(TableName.SecretApprovalRequestReviewer, "member"); + const hasReviewerUserId = await knex.schema.hasColumn(TableName.SecretApprovalRequestReviewer, "reviewerUserId"); + if (!hasReviewerUserId) { + // new fields + await knex.schema.alterTable(TableName.SecretApprovalRequestReviewer, (tb) => { + // if (hasMemberId) tb.setNullable("member"); + tb.uuid("reviewerUserId"); + tb.foreign("reviewerUserId").references("id").inTable(TableName.Users).onDelete("SET NULL"); + }); + // copy project membership => user id to new fields + await knex(TableName.SecretApprovalRequestReviewer).update({ + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + reviewerUserId: knex(TableName.ProjectMembership) + .select("userId") + .where("id", knex.raw("??", [`${TableName.SecretApprovalRequestReviewer}.member`])) + }); + // drop table + await knex.schema.alterTable(TableName.SecretApprovalRequestReviewer, (tb) => { + if (hasMemberId) tb.dropColumn("member"); + tb.uuid("reviewerUserId").notNullable().alter(); + }); + } +} + +export async function down(knex: Knex): Promise { + const hasApproverUserId = await knex.schema.hasColumn(TableName.SecretApprovalPolicyApprover, "approverUserId"); + const hasApproverId = await knex.schema.hasColumn(TableName.SecretApprovalPolicyApprover, "approverId"); + if (hasApproverUserId) { + await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => { + if (!hasApproverId) { + tb.uuid("approverId"); + tb.foreign("approverId").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE"); + } + }); + + if (!hasApproverId) { + await knex(TableName.SecretApprovalPolicyApprover).update({ + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + approverId: knex(TableName.ProjectMembership) + .select("id") + .where("userId", knex.raw("??", [`${TableName.SecretApprovalPolicyApprover}.approverUserId`])) + }); + await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => { + tb.dropColumn("approverUserId"); + tb.uuid("approverId").notNullable().alter(); + }); + } + } + + const hasSecretApprovalRequestTable = await knex.schema.hasTable(TableName.SecretApprovalRequest); + const hasCommitterUserId = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "committerUserId"); + const hasCommitterId = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "committerId"); + const hasStatusChangeBy = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "statusChangeBy"); + const hasStatusChangedByUser = await knex.schema.hasColumn(TableName.SecretApprovalRequest, "statusChangedByUserId"); + if (hasSecretApprovalRequestTable) { + await knex.schema.alterTable(TableName.SecretApprovalRequest, (tb) => { + // if (hasCommitterId) tb.uuid("committerId").notNullable().alter(); + if (!hasCommitterId) { + tb.uuid("committerId"); + tb.foreign("committerId").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE"); + } + if (!hasStatusChangeBy) { + tb.uuid("statusChangeBy"); + tb.foreign("statusChangeBy").references("id").inTable(TableName.ProjectMembership).onDelete("SET NULL"); + } + }); + + await knex(TableName.SecretApprovalRequest).update({ + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + committerId: knex(TableName.ProjectMembership) + .select("id") + .where("userId", knex.raw("??", [`${TableName.SecretApprovalRequest}.committerUserId`])), + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + statusChangeBy: knex(TableName.ProjectMembership) + .select("id") + .where("userId", knex.raw("??", [`${TableName.SecretApprovalRequest}.statusChangedByUserId`])) + }); + + await knex.schema.alterTable(TableName.SecretApprovalRequest, (tb) => { + if (hasCommitterUserId) tb.dropColumn("committerUserId"); + if (hasStatusChangedByUser) tb.dropColumn("statusChangedByUserId"); + if (hasCommitterId) tb.uuid("committerId").notNullable().alter(); + }); + } + + const hasMemberId = await knex.schema.hasColumn(TableName.SecretApprovalRequestReviewer, "member"); + const hasReviewerUserId = await knex.schema.hasColumn(TableName.SecretApprovalRequestReviewer, "reviewerUserId"); + if (hasReviewerUserId) { + if (!hasMemberId) { + await knex.schema.alterTable(TableName.SecretApprovalRequestReviewer, (tb) => { + // if (hasMemberId) tb.uuid("member").notNullable().alter(); + tb.uuid("member"); + tb.foreign("member").references("id").inTable(TableName.ProjectMembership).onDelete("CASCADE"); + }); + } + await knex(TableName.SecretApprovalRequestReviewer).update({ + // eslint-disable-next-line + // @ts-ignore because generate schema happens after this + member: knex(TableName.ProjectMembership) + .select("id") + .where("userId", knex.raw("??", [`${TableName.SecretApprovalRequestReviewer}.reviewerUserId`])) + }); + await knex.schema.alterTable(TableName.SecretApprovalRequestReviewer, (tb) => { + tb.uuid("member").notNullable().alter(); + tb.dropColumn("reviewerUserId"); + }); + } +} diff --git a/backend/src/db/schemas/secret-approval-policies-approvers.ts b/backend/src/db/schemas/secret-approval-policies-approvers.ts index 12a3119e6..3af5614f4 100644 --- a/backend/src/db/schemas/secret-approval-policies-approvers.ts +++ b/backend/src/db/schemas/secret-approval-policies-approvers.ts @@ -9,10 +9,10 @@ import { TImmutableDBKeys } from "./models"; export const SecretApprovalPoliciesApproversSchema = z.object({ id: z.string().uuid(), - approverId: z.string().uuid(), policyId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date() + updatedAt: z.date(), + approverUserId: z.string().uuid() }); export type TSecretApprovalPoliciesApprovers = z.infer; diff --git a/backend/src/db/schemas/secret-approval-requests-reviewers.ts b/backend/src/db/schemas/secret-approval-requests-reviewers.ts index f3ff88047..a5c445587 100644 --- a/backend/src/db/schemas/secret-approval-requests-reviewers.ts +++ b/backend/src/db/schemas/secret-approval-requests-reviewers.ts @@ -9,11 +9,11 @@ import { TImmutableDBKeys } from "./models"; export const SecretApprovalRequestsReviewersSchema = z.object({ id: z.string().uuid(), - member: z.string().uuid(), status: z.string(), requestId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date() + updatedAt: z.date(), + reviewerUserId: z.string().uuid() }); export type TSecretApprovalRequestsReviewers = z.infer; diff --git a/backend/src/db/schemas/secret-approval-requests.ts b/backend/src/db/schemas/secret-approval-requests.ts index 77ad370b7..aa6896d10 100644 --- a/backend/src/db/schemas/secret-approval-requests.ts +++ b/backend/src/db/schemas/secret-approval-requests.ts @@ -15,11 +15,11 @@ export const SecretApprovalRequestsSchema = z.object({ conflicts: z.unknown().nullable().optional(), slug: z.string(), folderId: z.string().uuid(), - statusChangeBy: z.string().uuid().nullable().optional(), - committerId: z.string().uuid(), createdAt: z.date(), updatedAt: z.date(), - isReplicated: z.boolean().nullable().optional() + isReplicated: z.boolean().nullable().optional(), + committerUserId: z.string().uuid(), + statusChangedByUserId: z.string().uuid().nullable().optional() }); export type TSecretApprovalRequests = z.infer; From 612cf4f9685f74e75879438f188998deca5a052b Mon Sep 17 00:00:00 2001 From: = Date: Wed, 3 Jul 2024 20:09:17 +0530 Subject: [PATCH 025/117] feat: server logic for secret approval group --- .../v1/secret-approval-policy-router.ts | 24 +++- .../v1/secret-approval-request-router.ts | 25 +++- .../secret-approval-policy-dal.ts | 79 ++++++---- .../secret-approval-policy-service.ts | 39 ++--- .../secret-approval-policy-types.ts | 4 +- .../secret-approval-request-dal.ts | 136 +++++++++++++++--- .../secret-approval-request-service.ts | 54 ++++--- .../secret-replication-service.ts | 11 +- backend/src/server/routes/index.ts | 2 - backend/src/server/routes/v3/secret-router.ts | 12 +- 10 files changed, 242 insertions(+), 144 deletions(-) diff --git a/backend/src/ee/routes/v1/secret-approval-policy-router.ts b/backend/src/ee/routes/v1/secret-approval-policy-router.ts index b09b58e26..ee10131dd 100644 --- a/backend/src/ee/routes/v1/secret-approval-policy-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-policy-router.ts @@ -25,10 +25,10 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi .optional() .nullable() .transform((val) => (val ? removeTrailingSlash(val) : val)), - approvers: z.string().array().min(1), + approverUserIds: z.string().array().min(1), approvals: z.number().min(1).default(1) }) - .refine((data) => data.approvals <= data.approvers.length, { + .refine((data) => data.approvals <= data.approverUserIds.length, { path: ["approvals"], message: "The number of approvals should be lower than the number of approvers." }), @@ -66,7 +66,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi body: z .object({ name: z.string().optional(), - approvers: z.string().array().min(1), + approverUserIds: z.string().array().min(1), approvals: z.number().min(1).default(1), secretPath: z .string() @@ -74,7 +74,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi .nullable() .transform((val) => (val ? removeTrailingSlash(val) : val)) }) - .refine((data) => data.approvals <= data.approvers.length, { + .refine((data) => data.approvals <= data.approverUserIds.length, { path: ["approvals"], message: "The number of approvals should be lower than the number of approvers." }), @@ -139,7 +139,15 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }), response: { 200: z.object({ - approvals: sapPubSchema.merge(z.object({ approvers: z.string().array() })).array() + approvals: sapPubSchema + .extend({ + userApprovers: z + .object({ + userId: z.string() + }) + .array() + }) + .array() }) } }, @@ -170,7 +178,11 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }), response: { 200: z.object({ - policy: sapPubSchema.merge(z.object({ approvers: z.string().array() })).optional() + policy: sapPubSchema + .extend({ + userApprovers: z.object({ userId: z.string() }).array() + }) + .optional() }) } }, diff --git a/backend/src/ee/routes/v1/secret-approval-request-router.ts b/backend/src/ee/routes/v1/secret-approval-request-router.ts index b7204f72e..8e72597bd 100644 --- a/backend/src/ee/routes/v1/secret-approval-request-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-request-router.ts @@ -6,7 +6,8 @@ import { SecretApprovalRequestsSecretsSchema, SecretsSchema, SecretTagsSchema, - SecretVersionsSchema + SecretVersionsSchema, + UsersSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { ApprovalStatus, RequestState } from "@app/ee/services/secret-approval-request/secret-approval-request-types"; @@ -14,6 +15,15 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; +const approvalRequestUser = z.object({ userId: z.string() }).merge( + UsersSchema.pick({ + email: true, + firstName: true, + lastName: true, + username: true + }) +); + export const registerSecretApprovalRequestRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", @@ -41,9 +51,10 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv approvers: z.string().array(), secretPath: z.string().optional().nullable() }), + committerUser: approvalRequestUser, commits: z.object({ op: z.string(), secretId: z.string().nullable().optional() }).array(), environment: z.string(), - reviewers: z.object({ member: z.string(), status: z.string() }).array(), + reviewers: z.object({ userId: z.string(), status: z.string() }).array(), approvers: z.string().array() }).array() }) @@ -195,7 +206,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED, // eslint-disable-next-line metadata: { - [isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangeBy as string, + [isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangedByUserId as string, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug // eslint-disable-next-line @@ -216,6 +227,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv }) .array() .optional(); + server.route({ method: "GET", url: "/:id", @@ -235,12 +247,13 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv id: z.string(), name: z.string(), approvals: z.number(), - approvers: z.string().array(), + approvers: approvalRequestUser.array(), secretPath: z.string().optional().nullable() }), environment: z.string(), - reviewers: z.object({ member: z.string(), status: z.string() }).array(), - approvers: z.string().array(), + statusChangedByUser: approvalRequestUser.optional(), + committerUser: approvalRequestUser, + reviewers: approvalRequestUser.extend({ status: z.string() }).array(), secretPath: z.string(), commits: SecretApprovalRequestsSecretsSchema.omit({ secretBlindIndex: true }) .merge( diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts index 883e63747..daf6d0bd8 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts @@ -1,49 +1,59 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName, TSecretApprovalPolicies } from "@app/db/schemas"; +import { SecretApprovalPoliciesSchema, TableName, TSecretApprovalPolicies } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; -import { buildFindFilter, mergeOneToManyRelation, ormify, selectAllTableCols, TFindFilter } from "@app/lib/knex"; +import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter } from "@app/lib/knex"; export type TSecretApprovalPolicyDALFactory = ReturnType; export const secretApprovalPolicyDALFactory = (db: TDbClient) => { const secretApprovalPolicyOrm = ormify(db, TableName.SecretApprovalPolicy); - const sapFindQuery = (tx: Knex, filter: TFindFilter) => + const secretApprovalPolicyFindQuery = (tx: Knex, filter: TFindFilter) => tx(TableName.SecretApprovalPolicy) // eslint-disable-next-line .where(buildFindFilter(filter)) .join(TableName.Environment, `${TableName.SecretApprovalPolicy}.envId`, `${TableName.Environment}.id`) - .join( + .leftJoin( TableName.SecretApprovalPolicyApprover, `${TableName.SecretApprovalPolicy}.id`, `${TableName.SecretApprovalPolicyApprover}.policyId` ) - .select(tx.ref("approverId").withSchema(TableName.SecretApprovalPolicyApprover)) - .select(tx.ref("name").withSchema(TableName.Environment).as("envName")) - .select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug")) - .select(tx.ref("id").withSchema(TableName.Environment).as("envId")) - .select(tx.ref("projectId").withSchema(TableName.Environment)) + .select(tx.ref("approverUserId").withSchema(TableName.SecretApprovalPolicyApprover)) + .select( + tx.ref("name").withSchema(TableName.Environment).as("envName"), + tx.ref("slug").withSchema(TableName.Environment).as("envSlug"), + tx.ref("id").withSchema(TableName.Environment).as("envId"), + tx.ref("projectId").withSchema(TableName.Environment) + ) .select(selectAllTableCols(TableName.SecretApprovalPolicy)) .orderBy("createdAt", "asc"); const findById = async (id: string, tx?: Knex) => { try { - const doc = await sapFindQuery(tx || db.replicaNode(), { + const doc = await secretApprovalPolicyFindQuery(tx || db.replicaNode(), { [`${TableName.SecretApprovalPolicy}.id` as "id"]: id }); - const formatedDoc = mergeOneToManyRelation( - doc, - "id", - ({ approverId, envId, envName: name, envSlug: slug, ...el }) => ({ - ...el, - envId, - environment: { id: envId, name, slug } + const formatedDoc = sqlNestRelationships({ + data: doc, + key: "id", + parentMapper: (data) => ({ + environment: { id: data.envId, name: data.envName, slug: data.envSlug }, + projectId: data.projectId, + ...SecretApprovalPoliciesSchema.parse(data) }), - ({ approverId }) => approverId, - "approvers" - ); + childrenMapper: [ + { + key: "approverUserId", + label: "userApprovers" as const, + mapper: ({ approverUserId }) => ({ + userId: approverUserId + }) + } + ] + }); + return formatedDoc?.[0]; } catch (error) { throw new DatabaseError({ error, name: "FindById" }); @@ -52,18 +62,25 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => { const find = async (filter: TFindFilter, tx?: Knex) => { try { - const docs = await sapFindQuery(tx || db.replicaNode(), filter); - const formatedDoc = mergeOneToManyRelation( - docs, - "id", - ({ approverId, envId, envName: name, envSlug: slug, ...el }) => ({ - ...el, - envId, - environment: { id: envId, name, slug } + const docs = await secretApprovalPolicyFindQuery(tx || db.replicaNode(), filter); + const formatedDoc = sqlNestRelationships({ + data: docs, + key: "id", + parentMapper: (data) => ({ + environment: { id: data.envId, name: data.envName, slug: data.envSlug }, + projectId: data.projectId, + ...SecretApprovalPoliciesSchema.parse(data) }), - ({ approverId }) => approverId, - "approvers" - ); + childrenMapper: [ + { + key: "approverUserId", + label: "userApprovers" as const, + mapper: ({ approverUserId }) => ({ + userId: approverUserId + }) + } + ] + }); return formatedDoc; } catch (error) { throw new DatabaseError({ error, name: "Find" }); diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts index f99384de6..2db825c88 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts @@ -7,7 +7,6 @@ import { BadRequestError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { containsGlobPatterns } from "@app/lib/picomatch"; import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal"; -import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal"; import { TSecretApprovalPolicyApproverDALFactory } from "./secret-approval-policy-approver-dal"; import { TSecretApprovalPolicyDALFactory } from "./secret-approval-policy-dal"; @@ -29,7 +28,6 @@ type TSecretApprovalPolicyServiceFactoryDep = { secretApprovalPolicyDAL: TSecretApprovalPolicyDALFactory; projectEnvDAL: Pick; secretApprovalPolicyApproverDAL: TSecretApprovalPolicyApproverDALFactory; - projectMembershipDAL: Pick; }; export type TSecretApprovalPolicyServiceFactory = ReturnType; @@ -38,8 +36,7 @@ export const secretApprovalPolicyServiceFactory = ({ secretApprovalPolicyDAL, permissionService, secretApprovalPolicyApproverDAL, - projectEnvDAL, - projectMembershipDAL + projectEnvDAL }: TSecretApprovalPolicyServiceFactoryDep) => { const createSecretApprovalPolicy = async ({ name, @@ -48,12 +45,12 @@ export const secretApprovalPolicyServiceFactory = ({ actorOrgId, actorAuthMethod, approvals, - approvers, + approverUserIds, projectId, secretPath, environment }: TCreateSapDTO) => { - if (approvals > approvers.length) + if (approvals > approverUserIds.length) throw new BadRequestError({ message: "Approvals cannot be greater than approvers" }); const { permission } = await permissionService.getProjectPermission( @@ -70,13 +67,6 @@ export const secretApprovalPolicyServiceFactory = ({ const env = await projectEnvDAL.findOne({ slug: environment, projectId }); if (!env) throw new BadRequestError({ message: "Environment not found" }); - const secretApprovers = await projectMembershipDAL.find({ - projectId, - $in: { id: approvers } - }); - if (secretApprovers.length !== approvers.length) - throw new BadRequestError({ message: "Approver not found in project" }); - const secretApproval = await secretApprovalPolicyDAL.transaction(async (tx) => { const doc = await secretApprovalPolicyDAL.create( { @@ -88,8 +78,8 @@ export const secretApprovalPolicyServiceFactory = ({ tx ); await secretApprovalPolicyApproverDAL.insertMany( - secretApprovers.map(({ id }) => ({ - approverId: id, + approverUserIds.map((approverUserId) => ({ + approverUserId, policyId: doc.id })), tx @@ -100,7 +90,7 @@ export const secretApprovalPolicyServiceFactory = ({ }; const updateSecretApprovalPolicy = async ({ - approvers, + approverUserIds, secretPath, name, actorId, @@ -132,22 +122,11 @@ export const secretApprovalPolicyServiceFactory = ({ }, tx ); - if (approvers) { - const secretApprovers = await projectMembershipDAL.find( - { - projectId: secretApprovalPolicy.projectId, - $in: { id: approvers } - }, - { tx } - ); - if (secretApprovers.length !== approvers.length) - throw new BadRequestError({ message: "Approver not found in project" }); - if (doc.approvals > secretApprovers.length) - throw new BadRequestError({ message: "Approvals cannot be greater than approvers" }); + if (approverUserIds) { await secretApprovalPolicyApproverDAL.delete({ policyId: doc.id }, tx); await secretApprovalPolicyApproverDAL.insertMany( - secretApprovers.map(({ id }) => ({ - approverId: id, + approverUserIds.map((approverUserId) => ({ + approverUserId, policyId: doc.id })), tx diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-types.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-types.ts index 2ddd9b51b..1a527289c 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-types.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-types.ts @@ -4,7 +4,7 @@ export type TCreateSapDTO = { approvals: number; secretPath?: string | null; environment: string; - approvers: string[]; + approverUserIds: string[]; projectId: string; name: string; } & Omit; @@ -13,7 +13,7 @@ export type TUpdateSapDTO = { secretPolicyId: string; approvals?: number; secretPath?: string | null; - approvers: string[]; + approverUserIds: string[]; name?: string; } & Omit; diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts index 4eda64f8f..06c48ac8b 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts @@ -5,7 +5,8 @@ import { SecretApprovalRequestsSchema, TableName, TSecretApprovalRequests, - TSecretApprovalRequestsSecrets + TSecretApprovalRequestsSecrets, + TUsers } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols, sqlNestRelationships, stripUndefinedInWhere, TFindFilter } from "@app/lib/knex"; @@ -16,7 +17,7 @@ export type TSecretApprovalRequestDALFactory = ReturnType { `${TableName.SecretApprovalRequest}.policyId`, `${TableName.SecretApprovalPolicy}.id` ) + .leftJoin( + db(TableName.Users).as("statusChangedByUser"), + `${TableName.SecretApprovalRequest}.statusChangedByUserId`, + `statusChangedByUser.id` + ) + .join( + db(TableName.Users).as("committerUser"), + `${TableName.SecretApprovalRequest}.committerUserId`, + `committerUser.id` + ) .join( TableName.SecretApprovalPolicyApprover, `${TableName.SecretApprovalPolicy}.id`, `${TableName.SecretApprovalPolicyApprover}.policyId` ) + .join( + db(TableName.Users).as("secretApprovalPolicyApproverUser"), + `${TableName.SecretApprovalPolicyApprover}.approverUserId`, + "secretApprovalPolicyApproverUser.id" + ) .leftJoin( TableName.SecretApprovalRequestReviewer, `${TableName.SecretApprovalRequest}.id`, `${TableName.SecretApprovalRequestReviewer}.requestId` ) + .leftJoin( + db(TableName.Users).as("secretApprovalReviewerUser"), + `${TableName.SecretApprovalRequestReviewer}.reviewerUserId`, + `secretApprovalReviewerUser.id` + ) .select(selectAllTableCols(TableName.SecretApprovalRequest)) .select( - tx.ref("member").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerMemberId"), + tx.ref("approverUserId").withSchema(TableName.SecretApprovalPolicyApprover), + tx.ref("email").withSchema("secretApprovalPolicyApproverUser").as("approverEmail"), + tx.ref("username").withSchema("secretApprovalPolicyApproverUser").as("approverUsername"), + tx.ref("firstName").withSchema("secretApprovalPolicyApproverUser").as("approverFirstName"), + tx.ref("lastName").withSchema("secretApprovalPolicyApproverUser").as("approverLastName"), + tx.ref("email").withSchema("statusChangedByUser").as("statusChangedByUserEmail"), + tx.ref("username").withSchema("statusChangedByUser").as("statusChangedByUserUsername"), + tx.ref("firstName").withSchema("statusChangedByUser").as("statusChangedByUserFirstName"), + tx.ref("lastName").withSchema("statusChangedByUser").as("statusChangedByUserLastName"), + tx.ref("email").withSchema("committerUser").as("committerUserEmail"), + tx.ref("username").withSchema("committerUser").as("committerUserUsername"), + tx.ref("firstName").withSchema("committerUser").as("committerUserFirstName"), + tx.ref("lastName").withSchema("committerUser").as("committerUserLastName"), + tx.ref("reviewerUserId").withSchema(TableName.SecretApprovalRequestReviewer), tx.ref("status").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerStatus"), + tx.ref("email").withSchema("secretApprovalReviewerUser").as("reviewerEmail"), + tx.ref("username").withSchema("secretApprovalReviewerUser").as("reviewerUsername"), + tx.ref("firstName").withSchema("secretApprovalReviewerUser").as("reviewerFirstName"), + tx.ref("lastName").withSchema("secretApprovalReviewerUser").as("reviewerLastName"), tx.ref("id").withSchema(TableName.SecretApprovalPolicy).as("policyId"), tx.ref("name").withSchema(TableName.SecretApprovalPolicy).as("policyName"), tx.ref("projectId").withSchema(TableName.Environment), tx.ref("slug").withSchema(TableName.Environment).as("environment"), tx.ref("secretPath").withSchema(TableName.SecretApprovalPolicy).as("policySecretPath"), - tx.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals"), - tx.ref("approverId").withSchema(TableName.SecretApprovalPolicyApprover) + tx.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals") ); const findById = async (id: string, tx?: Knex) => { @@ -71,6 +108,22 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { ...SecretApprovalRequestsSchema.parse(el), projectId: el.projectId, environment: el.environment, + statusChangedByUser: el.statusChangedByUserId + ? { + userId: el.statusChangedByUserId, + email: el.statusChangedByUserEmail, + firstName: el.statusChangedByUserFirstName, + lastName: el.statusChangedByUserLastName, + username: el.statusChangedByUserUsername + } + : undefined, + committerUser: { + userId: el.committerUserId, + email: el.committerUserEmail, + firstName: el.committerUserFirstName, + lastName: el.committerUserLastName, + username: el.committerUserUsername + }, policy: { id: el.policyId, name: el.policyName, @@ -80,11 +133,34 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { }), childrenMapper: [ { - key: "reviewerMemberId", + key: "reviewerUserId", label: "reviewers" as const, - mapper: ({ reviewerMemberId: member, reviewerStatus: status }) => (member ? { member, status } : undefined) + mapper: ({ + reviewerUserId: userId, + reviewerStatus: status, + reviewerEmail: email, + reviewerLastName: lastName, + reviewerUsername: username, + reviewerFirstName: firstName + }) => (userId ? { userId, status, email, firstName, lastName, username } : undefined) }, - { key: "approverId", label: "approvers" as const, mapper: ({ approverId }) => approverId } + { + key: "approverUserId", + label: "approvers" as const, + mapper: ({ + approverUserId, + approverEmail: email, + approverUsername: username, + approverLastName: lastName, + approverFirstName: firstName + }) => ({ + userId: approverUserId, + email, + firstName, + lastName, + username + }) + } ] }); if (!formatedDoc?.[0]) return; @@ -97,7 +173,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { } }; - const findProjectRequestCount = async (projectId: string, membershipId: string, tx?: Knex) => { + const findProjectRequestCount = async (projectId: string, userId: string, tx?: Knex) => { try { const docs = await (tx || db) .with( @@ -114,8 +190,8 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { .andWhere( (bd) => void bd - .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) - .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) + .where(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, userId) + .orWhere(`${TableName.SecretApprovalRequest}.committerUserId`, userId) ) .select("status", `${TableName.SecretApprovalRequest}.id`) .groupBy(`${TableName.SecretApprovalRequest}.id`, "status") @@ -142,7 +218,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { }; const findByProjectId = async ( - { status, limit = 20, offset = 0, projectId, committer, environment, membershipId }: TFindQueryFilter, + { status, limit = 20, offset = 0, projectId, committer, environment, userId }: TFindQueryFilter, tx?: Knex ) => { try { @@ -161,6 +237,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { `${TableName.SecretApprovalPolicy}.id`, `${TableName.SecretApprovalPolicyApprover}.policyId` ) + .join( + db(TableName.Users).as("committerUser"), + `${TableName.SecretApprovalRequest}.committerUserId`, + `committerUser.id` + ) .leftJoin( TableName.SecretApprovalRequestReviewer, `${TableName.SecretApprovalRequest}.id`, @@ -176,20 +257,21 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { projectId, [`${TableName.Environment}.slug` as "slug"]: environment, [`${TableName.SecretApprovalRequest}.status`]: status, - committerId: committer + committerUserId: committer }) ) .andWhere( (bd) => void bd - .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) - .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) + .where(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, userId) + .orWhere(`${TableName.SecretApprovalRequest}.committerUserId`, userId) ) .select(selectAllTableCols(TableName.SecretApprovalRequest)) .select( db.ref("projectId").withSchema(TableName.Environment), db.ref("slug").withSchema(TableName.Environment).as("environment"), - db.ref("id").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerMemberId"), + db.ref("id").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerId"), + db.ref("reviewerUserId").withSchema(TableName.SecretApprovalRequestReviewer), db.ref("status").withSchema(TableName.SecretApprovalRequestReviewer).as("reviewerStatus"), db.ref("id").withSchema(TableName.SecretApprovalPolicy).as("policyId"), db.ref("name").withSchema(TableName.SecretApprovalPolicy).as("policyName"), @@ -201,7 +283,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { ), db.ref("secretPath").withSchema(TableName.SecretApprovalPolicy).as("policySecretPath"), db.ref("approvals").withSchema(TableName.SecretApprovalPolicy).as("policyApprovals"), - db.ref("approverId").withSchema(TableName.SecretApprovalPolicyApprover) + db.ref("approverUserId").withSchema(TableName.SecretApprovalPolicyApprover), + db.ref("email").withSchema("committerUser").as("committerUserEmail"), + db.ref("username").withSchema("committerUser").as("committerUserUsername"), + db.ref("firstName").withSchema("committerUser").as("committerUserFirstName"), + db.ref("lastName").withSchema("committerUser").as("committerUserLastName") ) .orderBy("createdAt", "desc"); @@ -223,18 +309,26 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { name: el.policyName, approvals: el.policyApprovals, secretPath: el.policySecretPath + }, + committerUser: { + userId: el.committerUserId, + email: el.committerUserEmail, + firstName: el.committerUserFirstName, + lastName: el.committerUserLastName, + username: el.committerUserUsername } }), childrenMapper: [ { - key: "reviewerMemberId", + key: "reviewerId", label: "reviewers" as const, - mapper: ({ reviewerMemberId: member, reviewerStatus: s }) => (member ? { member, status: s } : undefined) + mapper: ({ reviewerUserId, reviewerStatus: s }) => + reviewerUserId ? { userId: reviewerUserId, status: s } : undefined }, { - key: "approverId", + key: "approverUserId", label: "approvers" as const, - mapper: ({ approverId }) => approverId + mapper: ({ approverUserId }) => approverUserId }, { key: "commitId", diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts index 5d0977134..a519af4fd 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts @@ -87,7 +87,7 @@ export const secretApprovalRequestServiceFactory = ({ const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => { if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); - const { membership } = await permissionService.getProjectPermission( + await permissionService.getProjectPermission( actor as ActorType.USER, actorId, projectId, @@ -95,7 +95,7 @@ export const secretApprovalRequestServiceFactory = ({ actorOrgId ); - const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id); + const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, actorId); return count; }; @@ -113,19 +113,13 @@ export const secretApprovalRequestServiceFactory = ({ }: TListApprovalsDTO) => { if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); - const { membership } = await permissionService.getProjectPermission( - actor, - actorId, - projectId, - actorAuthMethod, - actorOrgId - ); + await permissionService.getProjectPermission(actor, actorId, projectId, actorAuthMethod, actorOrgId); const approvals = await secretApprovalRequestDAL.findByProjectId({ projectId, committer, environment, status, - membershipId: membership.id, + userId: actorId, limit, offset }); @@ -145,7 +139,7 @@ export const secretApprovalRequestServiceFactory = ({ if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" }); const { policy } = secretApprovalRequest; - const { membership, hasRole } = await permissionService.getProjectPermission( + const { hasRole } = await permissionService.getProjectPermission( actor, actorId, secretApprovalRequest.projectId, @@ -154,8 +148,8 @@ export const secretApprovalRequestServiceFactory = ({ ); if ( !hasRole(ProjectMembershipRole.Admin) && - secretApprovalRequest.committerId !== membership.id && - !policy.approvers.find((approverId) => approverId === membership.id) + secretApprovalRequest.committerUserId !== actorId && + !policy.approvers.find(({ userId }) => userId === actorId) ) { throw new UnauthorizedError({ message: "User has no access" }); } @@ -180,7 +174,7 @@ export const secretApprovalRequestServiceFactory = ({ if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); const { policy } = secretApprovalRequest; - const { membership, hasRole } = await permissionService.getProjectPermission( + const { hasRole } = await permissionService.getProjectPermission( ActorType.USER, actorId, secretApprovalRequest.projectId, @@ -189,8 +183,8 @@ export const secretApprovalRequestServiceFactory = ({ ); if ( !hasRole(ProjectMembershipRole.Admin) && - secretApprovalRequest.committerId !== membership.id && - !policy.approvers.find((approverId) => approverId === membership.id) + secretApprovalRequest.committerUserId !== actorId && + !policy.approvers.find(({ userId }) => userId === actorId) ) { throw new UnauthorizedError({ message: "User has no access" }); } @@ -198,7 +192,7 @@ export const secretApprovalRequestServiceFactory = ({ const review = await secretApprovalRequestReviewerDAL.findOne( { requestId: secretApprovalRequest.id, - member: membership.id + reviewerUserId: actorId }, tx ); @@ -207,7 +201,7 @@ export const secretApprovalRequestServiceFactory = ({ { status, requestId: secretApprovalRequest.id, - member: membership.id + reviewerUserId: actorId }, tx ); @@ -230,7 +224,7 @@ export const secretApprovalRequestServiceFactory = ({ if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); const { policy } = secretApprovalRequest; - const { membership, hasRole } = await permissionService.getProjectPermission( + const { hasRole } = await permissionService.getProjectPermission( ActorType.USER, actorId, secretApprovalRequest.projectId, @@ -239,8 +233,8 @@ export const secretApprovalRequestServiceFactory = ({ ); if ( !hasRole(ProjectMembershipRole.Admin) && - secretApprovalRequest.committerId !== membership.id && - !policy.approvers.find((approverId) => approverId === membership.id) + secretApprovalRequest.committerUserId !== actorId && + !policy.approvers.find(({ userId }) => userId === actorId) ) { throw new UnauthorizedError({ message: "User has no access" }); } @@ -253,7 +247,7 @@ export const secretApprovalRequestServiceFactory = ({ const updatedRequest = await secretApprovalRequestDAL.updateById(secretApprovalRequest.id, { status, - statusChangeBy: membership.id + statusChangedByUserId: actorId }); return { ...secretApprovalRequest, ...updatedRequest }; }; @@ -270,7 +264,7 @@ export const secretApprovalRequestServiceFactory = ({ if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); const { policy, folderId, projectId } = secretApprovalRequest; - const { membership, hasRole } = await permissionService.getProjectPermission( + const { hasRole } = await permissionService.getProjectPermission( ActorType.USER, actorId, projectId, @@ -280,19 +274,19 @@ export const secretApprovalRequestServiceFactory = ({ if ( !hasRole(ProjectMembershipRole.Admin) && - secretApprovalRequest.committerId !== membership.id && - !policy.approvers.find((approverId) => approverId === membership.id) + secretApprovalRequest.committerUserId !== actorId && + !policy.approvers.find(({ userId }) => userId === actorId) ) { throw new UnauthorizedError({ message: "User has no access" }); } const reviewers = secretApprovalRequest.reviewers.reduce>( - (prev, curr) => ({ ...prev, [curr.member.toString()]: curr.status as ApprovalStatus }), + (prev, curr) => ({ ...prev, [curr.userId.toString()]: curr.status as ApprovalStatus }), {} ); const hasMinApproval = secretApprovalRequest.policy.approvals <= secretApprovalRequest.policy.approvers.filter( - (approverId) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED + ({ userId: approverId }) => reviewers[approverId.toString()] === ApprovalStatus.APPROVED ).length; if (!hasMinApproval) throw new BadRequestError({ message: "Doesn't have minimum approvals needed" }); @@ -472,7 +466,7 @@ export const secretApprovalRequestServiceFactory = ({ conflicts: JSON.stringify(conflicts), hasMerged: true, status: RequestState.Closed, - statusChangeBy: membership.id + statusChangedByUserId: actorId }, tx ); @@ -509,7 +503,7 @@ export const secretApprovalRequestServiceFactory = ({ }: TGenerateSecretApprovalRequestDTO) => { if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -663,7 +657,7 @@ export const secretApprovalRequestServiceFactory = ({ policyId: policy.id, status: "open", hasMerged: false, - committerId: membership.id + committerUserId: actorId }, tx ); diff --git a/backend/src/ee/services/secret-replication/secret-replication-service.ts b/backend/src/ee/services/secret-replication/secret-replication-service.ts index fd2f7cc1a..01f7d066c 100644 --- a/backend/src/ee/services/secret-replication/secret-replication-service.ts +++ b/backend/src/ee/services/secret-replication/secret-replication-service.ts @@ -11,7 +11,6 @@ import { alphaNumericNanoId } from "@app/lib/nanoid"; import { QueueName, TQueueServiceFactory } from "@app/queue"; import { ActorType } from "@app/services/auth/auth-type"; import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service"; -import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal"; import { TSecretDALFactory } from "@app/services/secret/secret-dal"; import { fnSecretBulkInsert, fnSecretBulkUpdate } from "@app/services/secret/secret-fns"; import { TSecretQueueFactory, uniqueSecretQueueKey } from "@app/services/secret/secret-queue"; @@ -46,7 +45,6 @@ type TSecretReplicationServiceFactoryDep = { secretBlindIndexDAL: Pick; secretTagDAL: Pick; secretApprovalRequestDAL: Pick; - projectMembershipDAL: Pick; secretApprovalRequestSecretDAL: Pick< TSecretApprovalRequestSecretDALFactory, "insertMany" | "insertApprovalSecretTags" @@ -92,7 +90,6 @@ export const secretReplicationServiceFactory = ({ secretApprovalRequestSecretDAL, secretApprovalRequestDAL, secretQueueService, - projectMembershipDAL, projectBotService }: TSecretReplicationServiceFactoryDep) => { const getReplicatedSecrets = ( @@ -297,12 +294,6 @@ export const secretReplicationServiceFactory = ({ ); // this means it should be a approval request rather than direct replication if (policy && actor === ActorType.USER) { - const membership = await projectMembershipDAL.findOne({ projectId, userId: actorId }); - if (!membership) { - logger.error("Project membership not found in %s for user %s", projectId, actorId); - return; - } - const localSecretsLatestVersions = destinationLocalSecrets.map(({ id }) => id); const latestSecretVersions = await secretVersionDAL.findLatestVersionMany( destinationReplicationFolderId, @@ -316,7 +307,7 @@ export const secretReplicationServiceFactory = ({ policyId: policy.id, status: "open", hasMerged: false, - committerId: membership.id, + committerUserId: actorId, isReplicated: true }, tx diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 54c5e51d6..e27d76af0 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -319,7 +319,6 @@ export const registerRoutes = async ( auditLogStreamDAL }); const secretApprovalPolicyService = secretApprovalPolicyServiceFactory({ - projectMembershipDAL, projectEnvDAL, secretApprovalPolicyApproverDAL: sapApproverDAL, permissionService, @@ -768,7 +767,6 @@ export const registerRoutes = async ( secretApprovalRequestDAL, secretApprovalRequestSecretDAL, secretQueueService, - projectMembershipDAL, projectBotService }); const secretRotationQueue = secretRotationQueueFactory({ diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index b92138ec8..910cc3db9 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -949,7 +949,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { event: { type: EventType.SECRET_APPROVAL_REQUEST, metadata: { - committedBy: approval.committerId, + committedBy: approval.committerUserId, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug } @@ -1133,7 +1133,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { event: { type: EventType.SECRET_APPROVAL_REQUEST, metadata: { - committedBy: approval.committerId, + committedBy: approval.committerUserId, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug } @@ -1271,7 +1271,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { event: { type: EventType.SECRET_APPROVAL_REQUEST, metadata: { - committedBy: approval.committerId, + committedBy: approval.committerUserId, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug } @@ -1397,7 +1397,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { event: { type: EventType.SECRET_APPROVAL_REQUEST, metadata: { - committedBy: approval.committerId, + committedBy: approval.committerUserId, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug } @@ -1524,7 +1524,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { event: { type: EventType.SECRET_APPROVAL_REQUEST, metadata: { - committedBy: approval.committerId, + committedBy: approval.committerUserId, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug } @@ -1638,7 +1638,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { event: { type: EventType.SECRET_APPROVAL_REQUEST, metadata: { - committedBy: approval.committerId, + committedBy: approval.committerUserId, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug } From ef3cdd11ac65fca4f8393cc3f7aa0653cdaf08d0 Mon Sep 17 00:00:00 2001 From: = Date: Wed, 3 Jul 2024 20:13:16 +0530 Subject: [PATCH 026/117] feat: ui changes for secret approval group --- .../src/hooks/api/secretApproval/mutation.tsx | 8 +-- .../src/hooks/api/secretApproval/types.ts | 6 +- .../hooks/api/secretApprovalRequest/types.ts | 34 ++++++++-- .../SecretApprovalPolicyList.tsx | 21 +++++-- .../components/SecretApprovalPolicyRow.tsx | 16 ++--- .../components/SecretPolicyForm.tsx | 38 ++++++----- .../SecretApprovalRequest.tsx | 38 +++++------ .../SecretApprovalRequestAction.tsx | 2 +- .../SecretApprovalRequestChanges.tsx | 63 +++++++++---------- 9 files changed, 124 insertions(+), 102 deletions(-) diff --git a/frontend/src/hooks/api/secretApproval/mutation.tsx b/frontend/src/hooks/api/secretApproval/mutation.tsx index e0a8df95d..991111ef9 100644 --- a/frontend/src/hooks/api/secretApproval/mutation.tsx +++ b/frontend/src/hooks/api/secretApproval/mutation.tsx @@ -9,12 +9,12 @@ export const useCreateSecretApprovalPolicy = () => { const queryClient = useQueryClient(); return useMutation<{}, {}, TCreateSecretPolicyDTO>({ - mutationFn: async ({ environment, workspaceId, approvals, approvers, secretPath, name }) => { + mutationFn: async ({ environment, workspaceId, approvals, approverUserIds, secretPath, name }) => { const { data } = await apiRequest.post("/api/v1/secret-approvals", { environment, workspaceId, approvals, - approvers, + approverUserIds, secretPath, name }); @@ -30,10 +30,10 @@ export const useUpdateSecretApprovalPolicy = () => { const queryClient = useQueryClient(); return useMutation<{}, {}, TUpdateSecretPolicyDTO>({ - mutationFn: async ({ id, approvers, approvals, secretPath, name }) => { + mutationFn: async ({ id, approverUserIds, approvals, secretPath, name }) => { const { data } = await apiRequest.patch(`/api/v1/secret-approvals/${id}`, { approvals, - approvers, + approverUserIds, secretPath, name }); diff --git a/frontend/src/hooks/api/secretApproval/types.ts b/frontend/src/hooks/api/secretApproval/types.ts index 38e8d7ee8..f3b8639f7 100644 --- a/frontend/src/hooks/api/secretApproval/types.ts +++ b/frontend/src/hooks/api/secretApproval/types.ts @@ -7,8 +7,8 @@ export type TSecretApprovalPolicy = { envId: string; environment: WorkspaceEnv; secretPath?: string; - approvers: string[]; approvals: number; + userApprovers: { userId: string }[]; }; export type TGetSecretApprovalPoliciesDTO = { @@ -26,14 +26,14 @@ export type TCreateSecretPolicyDTO = { name?: string; environment: string; secretPath?: string | null; - approvers?: string[]; + approverUserIds?: string[]; approvals?: number; }; export type TUpdateSecretPolicyDTO = { id: string; name?: string; - approvers?: string[]; + approverUserIds?: string[]; secretPath?: string | null; approvals?: number; // for invalidating list diff --git a/frontend/src/hooks/api/secretApprovalRequest/types.ts b/frontend/src/hooks/api/secretApprovalRequest/types.ts index 8c2ba6963..f039cc815 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/types.ts +++ b/frontend/src/hooks/api/secretApprovalRequest/types.ts @@ -47,10 +47,14 @@ export type TSecretApprovalRequest = { isReplicated?: boolean; slug: string; createdAt: string; - committerId: string; + committerUserId: string; reviewers: { - member: string; + userId: string; status: ApprovalStatus; + email: string; + firstName: string; + lastName: string; + username: string; }[]; workspace: string; environment: string; @@ -58,8 +62,30 @@ export type TSecretApprovalRequest = { secretPath: string; hasMerged: boolean; status: "open" | "close"; - policy: TSecretApprovalPolicy; - statusChangeBy: string; + policy: Omit & { + approvers: { + userId: string; + email: string; + firstName: string; + lastName: string; + username: string; + }[]; + }; + statusChangedByUserId: string; + statusChangedByUser?: { + userId: string; + email: string; + firstName: string; + lastName: string; + username: string; + }; + committerUser: { + userId: string; + email: string; + firstName: string; + lastName: string; + username: string; + }; conflicts: Array<{ secretId: string; op: CommitType.UPDATE }>; commits: ({ // if there is no secret means it was creation diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx index d3a36988c..f377f44e9 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx @@ -7,6 +7,8 @@ import { Button, DeleteActionModal, EmptyState, + Modal, + ModalContent, Table, TableContainer, TableSkeleton, @@ -145,13 +147,20 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => { - handlePopUpToggle("secretPolicyForm", isOpen)} - members={members} - editValues={popUp.secretPolicyForm.data as TSecretApprovalPolicy} - /> + onOpenChange={(isOpen) => handlePopUpToggle("secretPolicyForm", isOpen)} + > + + handlePopUpToggle("secretPolicyForm", isOpen)} + members={members} + editValues={popUp.secretPolicyForm.data as TSecretApprovalPolicy} + /> + + { @@ -60,7 +60,7 @@ export const SecretApprovalPolicyRow = ({ } ); } else { - setSelectedApprovers(policy.approvers); + setSelectedApprovers(policy.userApprovers.map(({ userId }) => userId)); } }} > @@ -73,7 +73,9 @@ export const SecretApprovalPolicyRow = ({ > @@ -84,17 +86,17 @@ export const SecretApprovalPolicyRow = ({ Select members that are allowed to approve changes - {members?.map(({ id, user }) => { - const isChecked = selectedApprovers.includes(id); + {members?.map(({ user }) => { + const isChecked = selectedApprovers.includes(user.id); return ( { evt.preventDefault(); setSelectedApprovers((state) => - isChecked ? state.filter((el) => el !== id) : [...state, id] + isChecked ? state.filter((el) => el !== user.id) : [...state, user.id] ); }} - key={`create-policy-members-${id}`} + key={`create-policy-members-${user.id}`} iconPos="right" icon={isChecked && } > diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/components/SecretPolicyForm.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/components/SecretPolicyForm.tsx index db59761c1..b0db2affd 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/components/SecretPolicyForm.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/components/SecretPolicyForm.tsx @@ -1,4 +1,3 @@ -import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; import { faCheckCircle } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -15,8 +14,6 @@ import { DropdownMenuTrigger, FormControl, Input, - Modal, - ModalContent, Select, SelectItem } from "@app/components/v2"; @@ -40,9 +37,9 @@ const formSchema = z name: z.string().optional(), secretPath: z.string().optional().nullable(), approvals: z.number().min(1), - approvers: z.string().array().min(1) + approverUserIds: z.string().array().min(1) }) - .refine((data) => data.approvals <= data.approvers.length, { + .refine((data) => data.approvals <= data.approverUserIds.length, { path: ["approvals"], message: "The number of approvals should be lower than the number of approvers." }); @@ -50,7 +47,6 @@ const formSchema = z type TFormSchema = z.infer; export const SecretPolicyForm = ({ - isOpen, onToggle, members = [], workspaceId, @@ -59,20 +55,22 @@ export const SecretPolicyForm = ({ const { control, handleSubmit, - reset, watch, formState: { isSubmitting } } = useForm({ resolver: zodResolver(formSchema), - values: editValues ? { ...editValues, environment: editValues.environment.slug } : undefined + values: editValues + ? { + ...editValues, + approverUserIds: editValues.userApprovers.map(({ userId }) => userId), + environment: editValues.environment.slug + } + : undefined }); const { currentWorkspace } = useWorkspace(); const selectedEnvironment = watch("environment"); const environments = currentWorkspace?.environments || []; - useEffect(() => { - if (!isOpen) reset({}); - }, [isOpen]); const isEditMode = Boolean(editValues); @@ -131,8 +129,6 @@ export const SecretPolicyForm = ({ }; return ( - -