diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 2da7a245a..9fc4cff92 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -3,13 +3,13 @@ import { z } from "zod"; import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service"; import { crypto } from "@app/lib/crypto/cryptography"; import { QueueWorkerProfile } from "@app/lib/types"; +import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal"; import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal"; import { BadRequestError } from "../errors"; import { removeTrailingSlash } from "../fn"; import { CustomLogger } from "../logger/logger"; import { zpStr } from "../zod"; -import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal"; export const GITLAB_URL = "https://gitlab.com"; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts index 37efd67d4..751277254 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts @@ -12,3 +12,31 @@ export const BaseSqlAccountSchema = z.object({ .min(1, "Password required") .max(256, "Password must be 256 characters or less") }); + +export const BaseSqlRotationAccountSchema = z + .object({ + username: z.string().trim().max(63, "Username must be 63 characters or less"), + password: z.string().trim().max(256, "Password must be 256 characters or less") + }) + .superRefine((data, ctx) => { + if (data.username && !data.password) { + ctx.addIssue({ + path: ["password"], + message: "Password is required", + code: z.ZodIssueCode.custom + }); + } + if (data.password && !data.username) { + ctx.addIssue({ + path: ["username"], + message: "Username is required", + code: z.ZodIssueCode.custom + }); + } + }) + .transform((val) => { + if (!val.username && !val.password) { + return null; + } + return val; + }); diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx index 7e96fffda..fbca7bc87 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { Button, ModalClose } from "@app/components/v2"; import { PamResourceType, TPostgresResource } from "@app/hooks/api/pam"; import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants"; -import { BaseSqlAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas"; +import { BaseSqlRotationAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas"; import { BaseSqlResourceSchema } from "./shared/sql-resource-schemas"; import { SqlResourceFields } from "./shared/SqlResourceFields"; @@ -21,7 +21,7 @@ type Props = { const formSchema = genericResourceFieldsSchema.extend({ resourceType: z.literal(PamResourceType.Postgres), connectionDetails: BaseSqlResourceSchema, - rotationAccountCredentials: BaseSqlAccountSchema.nullable().optional() + rotationAccountCredentials: BaseSqlRotationAccountSchema.nullable().optional() }); type FormData = z.infer; diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx index e7e9023dd..c3a98a3f6 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from "react"; import { Controller, useFormContext, useWatch } from "react-hook-form"; +import { faTimes } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Accordion, @@ -44,7 +46,18 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { isError={Boolean(error?.message)} label="Username" > - +
+ + {field.value && ( + + )} +
)} /> @@ -58,23 +71,34 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { isError={Boolean(error?.message)} label="Password" > - { - if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) { - field.onChange(""); - } - setShowPassword(true); - }} - onBlur={() => { - if (isUpdate && field.value === "") { - field.onChange(UNCHANGED_PASSWORD_SENTINEL); - } - setShowPassword(false); - }} - /> +
+ { + if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) { + field.onChange(""); + } + setShowPassword(true); + }} + onBlur={() => { + if (isUpdate && field.value === "") { + field.onChange(UNCHANGED_PASSWORD_SENTINEL); + } + setShowPassword(false); + }} + /> + {field.value && ( + + )} +
)} />