mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 14:34:09 +00:00
feat(api): view secret value, WIP
This commit is contained in:
@@ -2,6 +2,7 @@ import { forwardRef, TextareaHTMLAttributes, useCallback, useMemo, useRef, useSt
|
||||
import { faCircle, faFolder, faKey } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import * as Popover from "@radix-ui/react-popover";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useDebounce, useToggle } from "@app/hooks";
|
||||
@@ -54,6 +55,7 @@ type Props = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange" | "val
|
||||
secretPath?: string;
|
||||
environment?: string;
|
||||
containerClassName?: string;
|
||||
secretValueHidden?: boolean;
|
||||
};
|
||||
|
||||
type ReferenceItem = {
|
||||
@@ -70,6 +72,7 @@ export const InfisicalSecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
||||
containerClassName,
|
||||
secretPath: propSecretPath,
|
||||
environment: propEnvironment,
|
||||
secretValueHidden,
|
||||
...props
|
||||
},
|
||||
ref
|
||||
@@ -275,6 +278,7 @@ export const InfisicalSecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
||||
ref={handleRef}
|
||||
onKeyDown={handleKeyDown}
|
||||
value={value}
|
||||
valueHidden={secretValueHidden}
|
||||
onFocus={() => setIsFocused.on()}
|
||||
onBlur={(evt) => {
|
||||
// should not on blur when its mouse down selecting a item from suggestion
|
||||
@@ -282,7 +286,7 @@ export const InfisicalSecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
||||
setIsFocused.off();
|
||||
}}
|
||||
onChange={(e) => onChange?.(e.target.value)}
|
||||
containerClassName={containerClassName}
|
||||
containerClassName={twMerge(containerClassName)}
|
||||
/>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
/* eslint-disable react/no-danger */
|
||||
import { forwardRef, TextareaHTMLAttributes } from "react";
|
||||
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useToggle } from "@app/hooks";
|
||||
|
||||
import { Tooltip } from "../Tooltip";
|
||||
|
||||
const REGEX = /(\${([a-zA-Z0-9-_.]+)})/g;
|
||||
const replaceContentWithDot = (str: string) => {
|
||||
let finalStr = "";
|
||||
@@ -14,7 +18,26 @@ const replaceContentWithDot = (str: string) => {
|
||||
return finalStr;
|
||||
};
|
||||
|
||||
const syntaxHighlight = (content?: string | null, isVisible?: boolean, isImport?: boolean) => {
|
||||
const syntaxHighlight = (
|
||||
content?: string | null,
|
||||
isVisible?: boolean,
|
||||
isImport?: boolean,
|
||||
valueHidden?: boolean
|
||||
) => {
|
||||
if (valueHidden && !content)
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="opacity-60">VALUE HIDDEN</span>
|
||||
<div className="relative z-50">
|
||||
<Tooltip
|
||||
className="!relative !z-50 !break-normal !font-inter"
|
||||
content="You do not have permission to read the value of this secret."
|
||||
>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} className="text-xs" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
if (isImport && !content) return "IMPORTED";
|
||||
if (content === "") return "EMPTY";
|
||||
if (!content) return "EMPTY";
|
||||
@@ -50,6 +73,7 @@ type Props = TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
||||
isImport?: boolean;
|
||||
isReadOnly?: boolean;
|
||||
isDisabled?: boolean;
|
||||
valueHidden?: boolean;
|
||||
containerClassName?: string;
|
||||
};
|
||||
|
||||
@@ -61,6 +85,7 @@ export const SecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
||||
value,
|
||||
isVisible,
|
||||
isImport,
|
||||
valueHidden,
|
||||
containerClassName,
|
||||
onBlur,
|
||||
isDisabled,
|
||||
@@ -81,7 +106,7 @@ export const SecretInput = forwardRef<HTMLTextAreaElement, Props>(
|
||||
<pre aria-hidden className="m-0">
|
||||
<code className={`inline-block w-full ${commonClassName}`}>
|
||||
<span style={{ whiteSpace: "break-spaces" }}>
|
||||
{syntaxHighlight(value, isVisible || isSecretFocused, isImport)}
|
||||
{syntaxHighlight(value, isVisible || isSecretFocused, isImport, valueHidden)}
|
||||
</span>
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
@@ -7,6 +7,14 @@ export enum ProjectPermissionActions {
|
||||
Delete = "delete"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionSecretActions {
|
||||
DescribeSecret = "read",
|
||||
ReadValue = "readValue",
|
||||
Create = "create",
|
||||
Edit = "edit",
|
||||
Delete = "delete"
|
||||
}
|
||||
|
||||
export enum ProjectPermissionDynamicSecretActions {
|
||||
ReadRootCredential = "read-root-credential",
|
||||
CreateRootCredential = "create-root-credential",
|
||||
@@ -138,7 +146,7 @@ export type SecretImportSubjectFields = {
|
||||
|
||||
export type ProjectPermissionSet =
|
||||
| [
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSecretActions,
|
||||
(
|
||||
| ProjectPermissionSub.Secrets
|
||||
| (ForcedSubject<ProjectPermissionSub.Secrets> & SecretSubjectFields)
|
||||
|
||||
@@ -207,6 +207,7 @@ export const useGetProjectSecretsDetails = (
|
||||
search = "",
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
viewSecretValue,
|
||||
includeImports,
|
||||
includeDynamicSecrets,
|
||||
tags
|
||||
@@ -231,6 +232,7 @@ export const useGetProjectSecretsDetails = (
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
viewSecretValue,
|
||||
offset,
|
||||
projectId,
|
||||
environment,
|
||||
@@ -247,6 +249,7 @@ export const useGetProjectSecretsDetails = (
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
viewSecretValue,
|
||||
offset,
|
||||
projectId,
|
||||
environment,
|
||||
|
||||
@@ -69,6 +69,7 @@ export type TGetDashboardProjectSecretsDetailsDTO = Omit<
|
||||
TGetDashboardProjectSecretsOverviewDTO,
|
||||
"environments"
|
||||
> & {
|
||||
viewSecretValue: boolean;
|
||||
environment: string;
|
||||
includeImports?: boolean;
|
||||
tags: Record<string, boolean>;
|
||||
|
||||
@@ -176,6 +176,7 @@ export const useGetImportedSecretsAllEnvs = ({
|
||||
env: encSecret.environment,
|
||||
key: encSecret.secretKey,
|
||||
value: encSecret.secretValue,
|
||||
secretValueHidden: encSecret.secretValueHidden,
|
||||
tags: encSecret.tags,
|
||||
comment: encSecret.secretComment,
|
||||
createdAt: encSecret.createdAt,
|
||||
|
||||
@@ -68,6 +68,7 @@ export const mergePersonalSecrets = (rawSecrets: SecretV3Raw[]) => {
|
||||
env: el.environment,
|
||||
key: el.secretKey,
|
||||
value: el.secretValue,
|
||||
secretValueHidden: el.secretValueHidden,
|
||||
tags: el.tags || [],
|
||||
comment: el.secretComment || "",
|
||||
reminderRepeatDays: el.secretReminderRepeatDays,
|
||||
|
||||
@@ -37,6 +37,7 @@ export type SecretV3RawSanitized = {
|
||||
version: number;
|
||||
key: string;
|
||||
value?: string;
|
||||
secretValueHidden: boolean;
|
||||
comment?: string;
|
||||
reminderRepeatDays?: number | null;
|
||||
reminderNote?: string | null;
|
||||
@@ -61,6 +62,7 @@ export type SecretV3Raw = {
|
||||
environment: string;
|
||||
version: number;
|
||||
type: string;
|
||||
secretValueHidden: boolean;
|
||||
secretKey: string;
|
||||
secretPath: string;
|
||||
secretValue?: string;
|
||||
|
||||
+28
-12
@@ -35,6 +35,11 @@ export const GeneralPermissionPolicies = <T extends keyof NonNullable<TFormSchem
|
||||
title,
|
||||
isDisabled
|
||||
}: Props<T>) => {
|
||||
if (subject === "secrets") {
|
||||
console.log("secret subject");
|
||||
console.log(actions);
|
||||
}
|
||||
|
||||
const { control } = useFormContext<TFormSchema>();
|
||||
const items = useFieldArray({
|
||||
control,
|
||||
@@ -116,25 +121,36 @@ export const GeneralPermissionPolicies = <T extends keyof NonNullable<TFormSchem
|
||||
<div className="w-1/4">Actions</div>
|
||||
<div className="flex flex-grow flex-wrap justify-start gap-8">
|
||||
{actions.map(({ label, value }) => {
|
||||
if (subject === "secrets") {
|
||||
console.log("value", value);
|
||||
}
|
||||
|
||||
if (typeof value !== "string") return undefined;
|
||||
|
||||
return (
|
||||
<Controller
|
||||
key={`${el.id}-${label}`}
|
||||
name={`permissions.${subject}.${rootIndex}.${value}` as any}
|
||||
control={control}
|
||||
defaultValue={false}
|
||||
render={({ field }) => (
|
||||
<div className="flex items-center justify-center">
|
||||
<Checkbox
|
||||
isDisabled={isDisabled}
|
||||
isChecked={Boolean(field.value)}
|
||||
onCheckedChange={field.onChange}
|
||||
id={`permissions.${subject}.${rootIndex}.${String(value)}`}
|
||||
>
|
||||
{label}
|
||||
</Checkbox>
|
||||
</div>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
if (subject === "secrets") {
|
||||
console.log("field", field);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center">
|
||||
<Checkbox
|
||||
isDisabled={isDisabled}
|
||||
isChecked={Boolean(field.value)}
|
||||
onCheckedChange={field.onChange}
|
||||
id={`permissions.${subject}.${rootIndex}.${String(value)}`}
|
||||
>
|
||||
{label}
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
+34
-2
@@ -9,6 +9,7 @@ import {
|
||||
PermissionConditionOperators,
|
||||
ProjectPermissionDynamicSecretActions,
|
||||
ProjectPermissionKmipActions,
|
||||
ProjectPermissionSecretActions,
|
||||
ProjectPermissionSecretSyncActions,
|
||||
TPermissionCondition,
|
||||
TPermissionConditionOperators
|
||||
@@ -22,6 +23,14 @@ const GeneralPolicyActionSchema = z.object({
|
||||
create: z.boolean().optional()
|
||||
});
|
||||
|
||||
const SecretPolicyActionSchema = z.object({
|
||||
read: z.boolean().optional(), // describe secret
|
||||
edit: z.boolean().optional(),
|
||||
delete: z.boolean().optional(),
|
||||
create: z.boolean().optional(),
|
||||
readValue: z.boolean().optional()
|
||||
});
|
||||
|
||||
const CmekPolicyActionSchema = z.object({
|
||||
read: z.boolean().optional(),
|
||||
edit: z.boolean().optional(),
|
||||
@@ -114,7 +123,7 @@ export const projectRoleFormSchema = z.object({
|
||||
.refine((val) => val !== "custom", { message: "Cannot use custom as its a keyword" }),
|
||||
permissions: z
|
||||
.object({
|
||||
[ProjectPermissionSub.Secrets]: GeneralPolicyActionSchema.extend({
|
||||
[ProjectPermissionSub.Secrets]: SecretPolicyActionSchema.extend({
|
||||
inverted: z.boolean().optional(),
|
||||
conditions: ConditionSchema
|
||||
})
|
||||
@@ -283,6 +292,28 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (subject === ProjectPermissionSub.Secrets) {
|
||||
const canRead = action.includes(ProjectPermissionSecretActions.DescribeSecret);
|
||||
const canEdit = action.includes(ProjectPermissionSecretActions.Edit);
|
||||
const canDelete = action.includes(ProjectPermissionSecretActions.Delete);
|
||||
const canCreate = action.includes(ProjectPermissionSecretActions.Create);
|
||||
const canReadValue = action.includes(ProjectPermissionSecretActions.ReadValue);
|
||||
|
||||
// from above statement we are sure it won't be undefined
|
||||
formVal[subject]!.push({
|
||||
read: canRead,
|
||||
create: canCreate,
|
||||
edit: canEdit,
|
||||
delete: canDelete,
|
||||
readValue: canReadValue,
|
||||
conditions: conditions ? convertCaslConditionToFormOperator(conditions) : [],
|
||||
inverted
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// for other subjects
|
||||
const canRead = action.includes(ProjectPermissionActions.Read);
|
||||
const canEdit = action.includes(ProjectPermissionActions.Edit);
|
||||
@@ -483,8 +514,9 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
||||
[ProjectPermissionSub.Secrets]: {
|
||||
title: "Secrets",
|
||||
actions: [
|
||||
{ label: "Read", value: "read" },
|
||||
{ label: "Describe Secret", value: "read" },
|
||||
{ label: "Create", value: "create" },
|
||||
{ label: "Read Value", value: "readValue" },
|
||||
{ label: "Modify", value: "edit" },
|
||||
{ label: "Remove", value: "delete" }
|
||||
]
|
||||
|
||||
+4
@@ -39,6 +39,7 @@ type Props = {
|
||||
isVisible?: boolean;
|
||||
isImportedSecret: boolean;
|
||||
environment: string;
|
||||
secretValueHidden: boolean;
|
||||
secretPath: string;
|
||||
onSecretCreate: (env: string, key: string, value: string) => Promise<void>;
|
||||
onSecretUpdate: (
|
||||
@@ -58,6 +59,7 @@ export const SecretEditRow = ({
|
||||
isImportedSecret,
|
||||
onSecretUpdate,
|
||||
secretName,
|
||||
secretValueHidden,
|
||||
onSecretCreate,
|
||||
onSecretDelete,
|
||||
environment,
|
||||
@@ -151,6 +153,7 @@ export const SecretEditRow = ({
|
||||
value={field.value as string}
|
||||
key="secret-input"
|
||||
isVisible={isVisible}
|
||||
secretValueHidden={secretValueHidden}
|
||||
secretPath={secretPath}
|
||||
environment={environment}
|
||||
isImport={isImportedSecret}
|
||||
@@ -158,6 +161,7 @@ export const SecretEditRow = ({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={twMerge(
|
||||
"flex w-24 justify-center space-x-3 pl-2 transition-all",
|
||||
|
||||
+6
-3
@@ -221,10 +221,13 @@ export const SecretOverviewTableRow = ({
|
||||
secretPath={secretPath}
|
||||
isVisible={isSecretVisible}
|
||||
secretName={secretKey}
|
||||
secretValueHidden={secret?.secretValueHidden || false}
|
||||
defaultValue={
|
||||
secret?.valueOverride ||
|
||||
secret?.value ||
|
||||
importedSecret?.secret?.value
|
||||
secret?.secretValueHidden
|
||||
? ""
|
||||
: secret?.valueOverride ||
|
||||
secret?.value ||
|
||||
importedSecret?.secret?.value
|
||||
}
|
||||
secretId={secret?.id}
|
||||
isOverride={Boolean(secret?.valueOverride)}
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
useSelectedSecrets
|
||||
} from "./SecretMainPage.store";
|
||||
import { Filter, RowType } from "./SecretMainPage.types";
|
||||
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||
|
||||
const LOADER_TEXT = [
|
||||
"Retrieving your encrypted secrets...",
|
||||
@@ -103,7 +104,7 @@ const Page = () => {
|
||||
const projectSlug = currentWorkspace?.slug || "";
|
||||
const secretPath = (routerQueryParams.secretPath as string) || "/";
|
||||
const canReadSecret = permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSecretActions.DescribeSecret,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
@@ -111,6 +112,17 @@ const Page = () => {
|
||||
secretTags: ["*"]
|
||||
})
|
||||
);
|
||||
const canReadSecretValue = permission.can(
|
||||
ProjectPermissionSecretActions.ReadValue,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: "*",
|
||||
secretTags: ["*"]
|
||||
})
|
||||
);
|
||||
|
||||
console.log("Can read secret value", canReadSecret);
|
||||
|
||||
const canReadSecretImports = permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
@@ -176,6 +188,7 @@ const Page = () => {
|
||||
orderDirection,
|
||||
includeImports: canReadSecretImports && filter.include.import,
|
||||
includeFolders: filter.include.folder,
|
||||
viewSecretValue: canReadSecretValue,
|
||||
includeDynamicSecrets: canReadDynamicSecret && filter.include.dynamic,
|
||||
includeSecrets: canReadSecret && filter.include.secret,
|
||||
tags: filter.tags
|
||||
|
||||
+28
-4
@@ -52,6 +52,8 @@ import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||
|
||||
import { CreateReminderForm } from "./CreateReminderForm";
|
||||
import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils";
|
||||
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||
import { useEffect } from "react";
|
||||
|
||||
type Props = {
|
||||
isOpen?: boolean;
|
||||
@@ -122,7 +124,7 @@ export const SecretDetailSidebar = ({
|
||||
const selectTagSlugs = selectedTags.map((i) => i.slug);
|
||||
|
||||
const cannotEditSecret = permission.cannot(
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSecretActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
@@ -130,16 +132,31 @@ export const SecretDetailSidebar = ({
|
||||
secretTags: selectTagSlugs
|
||||
})
|
||||
);
|
||||
|
||||
const cannotReadSecretValue = permission.cannot(
|
||||
ProjectPermissionSecretActions.ReadValue,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})
|
||||
);
|
||||
|
||||
const isReadOnly =
|
||||
permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSecretActions.DescribeSecret,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
secretName: secretKey,
|
||||
secretTags: selectTagSlugs
|
||||
})
|
||||
) && cannotEditSecret;
|
||||
) &&
|
||||
cannotEditSecret &&
|
||||
cannotReadSecretValue;
|
||||
|
||||
console.log("cannotReadSecretValue", cannotReadSecretValue);
|
||||
|
||||
const overrideAction = watch("overrideAction");
|
||||
const isOverridden =
|
||||
@@ -261,7 +278,14 @@ export const SecretDetailSidebar = ({
|
||||
key="secret-value"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormControl label="Value">
|
||||
<FormControl
|
||||
helperText={
|
||||
cannotReadSecretValue
|
||||
? "The value of this secret is hidden because you don't have the read secret value permission."
|
||||
: undefined
|
||||
}
|
||||
label="Value"
|
||||
>
|
||||
<InfisicalSecretInput
|
||||
isReadOnly={isReadOnly}
|
||||
environment={environment}
|
||||
|
||||
+17
-4
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-nested-ternary */
|
||||
/* eslint-disable simple-import-sort/imports */
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import {
|
||||
@@ -44,6 +45,7 @@ import {
|
||||
SecretReferenceTree
|
||||
} from "@app/components/secrets/SecretReferenceDetails";
|
||||
|
||||
import { ProjectPermissionSecretActions } from "@app/context/ProjectPermissionContext/types";
|
||||
import {
|
||||
FontAwesomeSpriteName,
|
||||
formSchema,
|
||||
@@ -99,8 +101,14 @@ export const SecretItem = memo(
|
||||
trigger,
|
||||
formState: { isDirty, isSubmitting, errors }
|
||||
} = useForm<TFormSchema>({
|
||||
defaultValues: secret,
|
||||
values: secret,
|
||||
defaultValues: {
|
||||
...secret,
|
||||
value: secret.secretValueHidden ? "" : secret.value
|
||||
},
|
||||
values: {
|
||||
...secret,
|
||||
value: secret.secretValueHidden ? "" : secret.value
|
||||
},
|
||||
resolver: zodResolver(formSchema)
|
||||
});
|
||||
|
||||
@@ -123,7 +131,7 @@ export const SecretItem = memo(
|
||||
|
||||
const isReadOnly =
|
||||
permission.can(
|
||||
ProjectPermissionActions.Read,
|
||||
ProjectPermissionSecretActions.DescribeSecret,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
@@ -132,7 +140,7 @@ export const SecretItem = memo(
|
||||
})
|
||||
) &&
|
||||
permission.cannot(
|
||||
ProjectPermissionActions.Edit,
|
||||
ProjectPermissionSecretActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, {
|
||||
environment,
|
||||
secretPath,
|
||||
@@ -141,6 +149,9 @@ export const SecretItem = memo(
|
||||
})
|
||||
);
|
||||
|
||||
const { secretValueHidden } = secret;
|
||||
console.log(`Secret Key: ${secret.key}, hidden: ${secretValueHidden}`);
|
||||
|
||||
const [isSecValueCopied, setIsSecValueCopied] = useToggle(false);
|
||||
useEffect(() => {
|
||||
let timer: NodeJS.Timeout;
|
||||
@@ -279,12 +290,14 @@ export const SecretItem = memo(
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<InfisicalSecretInput
|
||||
secretValueHidden={secretValueHidden}
|
||||
isReadOnly={isReadOnly}
|
||||
key="secret-value"
|
||||
isVisible={isVisible}
|
||||
environment={environment}
|
||||
secretPath={secretPath}
|
||||
{...field}
|
||||
defaultValue={secretValueHidden ? "" : undefined}
|
||||
containerClassName="py-1.5 rounded-md transition-all group-hover:mr-2"
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user